From 0c8c47f8a1060b3a91e56c8db67f988de28aa434 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Fri, 7 Apr 2017 14:30:56 -0500 Subject: [PATCH] Fix multiple downloads on ReadFile() --- src/siadrive_dokan_api/siadokandrive.cpp | 220 ++++++++++++++++++----- 1 file changed, 180 insertions(+), 40 deletions(-) diff --git a/src/siadrive_dokan_api/siadokandrive.cpp b/src/siadrive_dokan_api/siadokandrive.cpp index eb10347..04edc04 100644 --- a/src/siadrive_dokan_api/siadokandrive.cpp +++ b/src/siadrive_dokan_api/siadokandrive.cpp @@ -39,6 +39,140 @@ private: DWORD AttributesAndFlags; } OpenFileInfo; + class DownloadToCacheBegin : + public CEvent + { + public: + DownloadToCacheBegin(const OpenFileInfo& openFileInfo, const SString& tempFilePath) : + _openFileInfo(openFileInfo), + _tempFilePath(tempFilePath) + { + + } + + public: + virtual ~DownloadToCacheBegin() {} + + private: + const OpenFileInfo _openFileInfo; + const SString _tempFilePath; + + public: + virtual SString GetSingleLineMessage() const override + { + return "DownloadToCacheBegin|FP|" + _openFileInfo.CacheFilePath + + "|SP|" + _openFileInfo.SiaPath + + "|TP|" + _tempFilePath; + } + + virtual std::shared_ptr Clone() const override + { + return std::shared_ptr(new DownloadToCacheBegin(_openFileInfo, _tempFilePath)); + } + }; + + class DownloadToCacheEnd : + public CEvent + { + public: + DownloadToCacheEnd(const OpenFileInfo& openFileInfo, const SString& tempFilePath, const bool& result) : + _openFileInfo(openFileInfo), + _tempFilePath(tempFilePath), + _result(result) + { + + } + + public: + virtual ~DownloadToCacheEnd() {} + + private: + const OpenFileInfo _openFileInfo; + const SString _tempFilePath; + const bool _result; + + public: + virtual SString GetSingleLineMessage() const override + { + return "DownloadToCacheEnd|FP|" + _openFileInfo.CacheFilePath + + "|SP|" + _openFileInfo.SiaPath + + "|TP|" + _tempFilePath + + "|RES|" + SString::FromBool(_result); + } + + virtual std::shared_ptr Clone() const override + { + return std::shared_ptr(new DownloadToCacheEnd(_openFileInfo, _tempFilePath, _result)); + } + }; + + class MoveTempToCacheResult : + public CEvent + { + public: + MoveTempToCacheResult(const OpenFileInfo& openFileInfo, const SString& tempFilePath, const bool& result) : + _openFileInfo(openFileInfo), + _tempFilePath(tempFilePath), + _result(result) + { + + } + + public: + virtual ~MoveTempToCacheResult() {} + + private: + const OpenFileInfo _openFileInfo; + const SString _tempFilePath; + const bool _result; + + public: + virtual SString GetSingleLineMessage() const override + { + return "MoveTempToCacheResult|FP|" + _openFileInfo.CacheFilePath + + "|SP|" + _openFileInfo.SiaPath + + "|TP|" + _tempFilePath + + "|RES|" + SString::FromBool(_result); + } + + virtual std::shared_ptr Clone() const override + { + return std::shared_ptr(new MoveTempToCacheResult(_openFileInfo, _tempFilePath, _result)); + } + }; + + class AddToCacheComplete : + public CEvent + { + public: + AddToCacheComplete(const OpenFileInfo& openFileInfo, const bool& result) : + _openFileInfo(openFileInfo), + _result(result) + { + + } + + public: + virtual ~AddToCacheComplete() {} + + private: + const OpenFileInfo _openFileInfo; + const bool _result; + + public: + virtual SString GetSingleLineMessage() const override + { + return "AddToCacheComplete|FP|" + _openFileInfo.CacheFilePath + + "|SP|" + _openFileInfo.SiaPath + + "|RES|" + SString::FromBool(_result); + } + + virtual std::shared_ptr Clone() const override + { + return std::shared_ptr(new AddToCacheComplete(_openFileInfo, _result)); + } + }; + private: static std::mutex _dokanMutex; static CSiaApi* _siaApi; @@ -50,7 +184,7 @@ private: static std::unique_ptr _fileListThread; static HANDLE _fileListStopEvent; static CSiaFileTreePtr _siaFileTree; - static std::mutex _fileTreeMutex; + static std::mutex _openFileMutex; static std::unique_ptr _mountThread; static NTSTATUS _mountStatus; static SString _mountPoint; @@ -70,50 +204,56 @@ private: static bool AddFileToCache(OpenFileInfo& openFileInfo, PDOKAN_FILE_INFO dokanFileInfo) { - FilePath tempFilePath = FilePath::GetTempDirectory(); - tempFilePath.Append(GenerateSha256(openFileInfo.SiaPath) + ".siatmp"); - bool ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(openFileInfo.SiaPath, tempFilePath)); - if (ret) + bool ret = true; + if (openFileInfo.Dummy) { - // Find all open handles for requested file - std::vector matched; - matched.push_back(&openFileInfo); - { - std::lock_guard l(_fileTreeMutex); - std::for_each(_openFiles.begin(), _openFiles.end(), [&](OpenFileInfo* ofi) - { - if ((ofi->FileHandle != openFileInfo.FileHandle) && (ofi->SiaPath == openFileInfo.SiaPath)) - { - matched.push_back(ofi); - } - }); - } + FilePath tempFilePath = FilePath::GetTempDirectory(); + tempFilePath.Append(GenerateSha256(openFileInfo.SiaPath) + ".siatmp"); - // Close all to allow move to complete - for (auto* ofi : matched) - { - ::CloseHandle(ofi->FileHandle); - } - - FilePath src(tempFilePath); - FilePath dest(openFileInfo.CacheFilePath); - ret = dest.DeleteFile() && src.MoveFile(dest); + CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DownloadToCacheBegin(openFileInfo, tempFilePath))); + ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(openFileInfo.SiaPath, tempFilePath)); + CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DownloadToCacheEnd(openFileInfo, tempFilePath, ret))); if (ret) { - openFileInfo.Dummy = false; - } - else - { - src.DeleteFile(); - } + // Find all open handles for requested file + std::vector matched; + matched.push_back(&openFileInfo); + std::lock_guard l(_openFileMutex); + { + std::for_each(_openFiles.begin(), _openFiles.end(), [&](OpenFileInfo* ofi) + { + if ((ofi->FileHandle != openFileInfo.FileHandle) && (ofi->SiaPath == openFileInfo.SiaPath)) + { + matched.push_back(ofi); + } + }); + } - // Re-open all files - for (auto& ofi : matched) - { - ofi->FileHandle = ::CreateFile(&ofi->CacheFilePath[0], ofi->DesiredAccess, ofi->ShareMode, ofi->SecurityAttrib.nLength ? &ofi->SecurityAttrib : nullptr, ofi->CreateDisp, ofi->AttributesAndFlags, nullptr); + // Close all to allow move to complete + for (auto* ofi : matched) + { + ::CloseHandle(ofi->FileHandle); + } + + FilePath src(tempFilePath); + FilePath dest(openFileInfo.CacheFilePath); + ret = dest.DeleteFile() && src.MoveFile(dest); + if (!ret) + { + src.DeleteFile(); + } + CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(MoveTempToCacheResult(openFileInfo, tempFilePath, ret))); + + // Re-open all files + for (auto& ofi : matched) + { + ofi->FileHandle = ::CreateFile(&ofi->CacheFilePath[0], ofi->DesiredAccess, ofi->ShareMode, ofi->SecurityAttrib.nLength ? &ofi->SecurityAttrib : nullptr, ofi->CreateDisp, ofi->AttributesAndFlags, nullptr); + ofi->Dummy = !ret; + } } } + CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(AddToCacheComplete(openFileInfo, ret))); return ret; } @@ -162,7 +302,7 @@ private: ::CloseHandle(openFileInfo.FileHandle); } - std::lock_guard l(_fileTreeMutex); + std::lock_guard l(_openFileMutex); _openFiles.erase(std::remove(_openFiles.begin(), _openFiles.end(), &openFileInfo), _openFiles.end()); } @@ -433,6 +573,7 @@ private: if (ret == STATUS_SUCCESS) { + std::lock_guard l(_openFileMutex); // Create file as specified HANDLE handle = ::CreateFile( &cacheFilePath[0], @@ -469,7 +610,6 @@ private: ofi->CreateDisp = createDisposition; ofi->AttributesAndFlags = fileAttributesAndFlags; dokanFileInfo->Context = reinterpret_cast(ofi); - std::lock_guard l(_fileTreeMutex); _openFiles.push_back(ofi); } } @@ -1510,7 +1650,7 @@ DOKAN_OPTIONS DokanImpl::_dokanOptions; FilePath DokanImpl::_cacheLocation; HANDLE DokanImpl::_fileListStopEvent; CSiaFileTreePtr DokanImpl::_siaFileTree; -std::mutex DokanImpl::_fileTreeMutex; +std::mutex DokanImpl::_openFileMutex; std::unique_ptr DokanImpl::_fileListThread; std::unique_ptr DokanImpl::_mountThread; NTSTATUS DokanImpl::_mountStatus = STATUS_SUCCESS;