diff --git a/include/siadrive_dokan_api/siadokandrive.h b/include/siadrive_dokan_api/siadokandrive.h index dc5d1fb..dfdc51b 100644 --- a/include/siadrive_dokan_api/siadokandrive.h +++ b/include/siadrive_dokan_api/siadokandrive.h @@ -196,11 +196,12 @@ class SIADRIVE_DOKAN_EXPORTABLE DokanFindFiles : public CEvent { public: - DokanFindFiles(const SString& cachePath, const SString& rootPath, const SString& siaQuery, const SString& findFile) : + DokanFindFiles(const SString& cachePath, const SString& rootPath, const SString& siaQuery, const SString& findFile, const SString& fileName) : _cachePath(cachePath), _rootPath(rootPath), _siaQuery(siaQuery), - _findFile(findFile) + _findFile(findFile), + _fileName(fileName) { } @@ -214,11 +215,12 @@ private: const SString _rootPath; const SString _siaQuery; const SString _findFile; + const SString _fileName; public: virtual std::shared_ptr Clone() const override { - return std::shared_ptr(new DokanFindFiles(_cachePath, _rootPath, _siaQuery, _findFile)); + return std::shared_ptr(new DokanFindFiles(_cachePath, _rootPath, _siaQuery, _findFile, _fileName)); } virtual SString GetSingleLineMessage() const override @@ -226,7 +228,8 @@ public: return L"DokanFindFiles|PATH|" + _cachePath + "|ROOT|" + _rootPath + "|QUERY|" + _siaQuery + - "|FIND|" + _findFile; + "|FIND|" + _findFile + + "|FN|" + _fileName; } }; @@ -265,8 +268,10 @@ class SIADRIVE_DOKAN_EXPORTABLE DokanGetFileInformation : public CEvent { public: - DokanGetFileInformation(const SString& cachePath) : - _cachePath(cachePath) + DokanGetFileInformation(const SString& cachePath, const SString& fileName, const NTSTATUS& result) : + _cachePath(cachePath), + _fileName(fileName), + _result(result) { } @@ -277,16 +282,18 @@ public: private: const SString _cachePath; + const SString _fileName; + const NTSTATUS _result; public: virtual std::shared_ptr Clone() const override { - return std::shared_ptr(new DokanGetFileInformation(_cachePath)); + return std::shared_ptr(new DokanGetFileInformation(_cachePath, _fileName, _result)); } virtual SString GetSingleLineMessage() const override { - return L"DokanGetFileInformation|PATH|" + _cachePath; + return L"DokanGetFileInformation|PATH|" + _cachePath + "|FN|" + _fileName + "|RES|" + SString::FromUInt32(_result); } }; diff --git a/src/siadrive_dokan_api/siadokandrive.cpp b/src/siadrive_dokan_api/siadokandrive.cpp index ac87867..8490e58 100644 --- a/src/siadrive_dokan_api/siadokandrive.cpp +++ b/src/siadrive_dokan_api/siadokandrive.cpp @@ -274,7 +274,7 @@ private: else { // FILE_FLAG_BACKUP_SEMANTICS is required for opening directory handles - HANDLE handle = ::CreateFile(&cacheFilePath[0], genericDesiredAccess, shareAccess, &securityAttrib, OPEN_EXISTING, fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS, nullptr); + HANDLE handle = ::CreateFile(&cacheFilePath[0], genericDesiredAccess, shareAccess, &securityAttrib, OPEN_EXISTING, fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); if (handle == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); @@ -295,7 +295,7 @@ private: else // File (cache and/or Sia operation) { // Formulate Sia path - SString siaPath = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot()); // Strip drive letter to get Sia path + SString siaPath = CSiaApi::FormatToSiaPath(fileName); // Strip drive letter to get Sia path if (siaPath.Length()) { // If cache file already exists and is a directory, requested file operation isn't valid @@ -474,37 +474,36 @@ private: static NTSTATUS DOKAN_CALLBACK Sia_FindFiles(LPCWSTR fileName, PFillFindData fillFindData, PDOKAN_FILE_INFO dokanFileInfo) { - NTSTATUS ret = STATUS_SUCCESS; + NTSTATUS ret = STATUS_INVALID_SERVER_STATE; auto siaFileTree = GetFileTree(); if (siaFileTree) { - SString siaFileQuery = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot()); - SString siaRootPath = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot()); + SString siaFileQuery = CSiaApi::FormatToSiaPath(fileName); + SString siaRootPath = CSiaApi::FormatToSiaPath(fileName); FilePath siaDirQuery = siaFileQuery; FilePath findFile = GetCacheLocation(); FilePath cachePath = GetCacheLocation(); if (FilePath::DirSep == fileName) { siaFileQuery += L"/*.*"; - findFile.Append("*.*"); + findFile.Append("*"); } else { cachePath.Append(fileName); findFile.Append(fileName); - if (cachePath.IsDirectory()) + if (dokanFileInfo->IsDirectory) { siaFileQuery += L"/*.*"; - findFile.Append("*.*"); + findFile.Append("*"); } else { - siaDirQuery = cachePath; - siaDirQuery = CSiaApi::FormatToSiaPath(siaDirQuery.RemoveFileName()); + siaDirQuery = FilePath(); } } - CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanFindFiles(cachePath, siaDirQuery, siaFileQuery, findFile))); + CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanFindFiles(cachePath, siaDirQuery, siaFileQuery, findFile, fileName))); WIN32_FIND_DATA findData = { 0 }; HANDLE findHandle = ::FindFirstFile(&findFile[0], &findData); @@ -525,62 +524,79 @@ private: if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { dirs.insert({ findData.cFileName, 0 }); - } - - bool exists; - if (!ApiSuccess(_siaApi->GetRenter()->FileExists(CSiaApi::FormatToSiaPath(FilePath(siaRootPath, findData.cFileName)), exists))) - { - ::FindClose(findHandle); - return STATUS_INVALID_DEVICE_STATE; - } - - if (findData.nFileSizeHigh || findData.nFileSizeLow || !exists) - { fillFindData(&findData, dokanFileInfo); - files.insert({ findData.cFileName, 1 }); + } + else + { + bool exists; + if (!ApiSuccess(_siaApi->GetRenter()->FileExists(CSiaApi::FormatToSiaPath(FilePath(fileName, findData.cFileName)), exists))) + { + ::FindClose(findHandle); + return STATUS_INVALID_DEVICE_STATE; + } + + if (findData.nFileSizeHigh || findData.nFileSizeLow || !exists) + { + fillFindData(&findData, dokanFileInfo); + files.insert({ findData.cFileName, 1 }); + } } } } while (::FindNextFile(findHandle, &findData) != 0); + + DWORD error = GetLastError(); ::FindClose(findHandle); - // Find Sia directories - auto dirList = siaFileTree->QueryDirectories(siaDirQuery); - for (auto& dir : dirList) + if (error == ERROR_NO_MORE_FILES) { - if (dirs.find(dir) == dirs.end()) + // Find Sia directories + if (!static_cast(siaDirQuery).IsNullOrEmpty()) { - WIN32_FIND_DATA fd = { 0 }; - wcscpy_s(fd.cFileName, dir.str().c_str()); - fd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; - fillFindData(&fd, dokanFileInfo); - - // Create cache sub-folder - FilePath subCachePath(cachePath, dir); - if (!subCachePath.IsDirectory()) + auto dirList = siaFileTree->QueryDirectories(siaDirQuery); + for (auto& dir : dirList) { - subCachePath.CreateDirectory(); + if (dirs.find(dir) == dirs.end()) + { + // Create cache sub-folder + FilePath subCachePath(cachePath, dir); + if (!subCachePath.IsDirectory()) + { + subCachePath.CreateDirectory(); + } + + WIN32_FIND_DATA fd = { 0 }; + wcscpy_s(fd.cFileName, dir.str().c_str()); + fd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; + fillFindData(&fd, dokanFileInfo); + } } } - } - // Find Sia files - auto fileList = siaFileTree->Query(siaFileQuery); - for (auto& file : fileList) - { - FilePath fp = file->GetSiaPath(); - fp.StripToFileName(); - if (files.find(fp) == files.end()) + // Find Sia files + auto fileList = siaFileTree->Query(siaFileQuery); + for (auto& file : fileList) { - WIN32_FIND_DATA fd = { 0 }; - wcscpy_s(fd.cFileName, &fp[0]); + FilePath fp = file->GetSiaPath(); + fp.StripToFileName(); + if (files.find(fp) == files.end()) + { + WIN32_FIND_DATA fd = { 0 }; + wcscpy_s(fd.cFileName, &fp[0]); - LARGE_INTEGER li = { 0 }; - li.QuadPart = file->GetFileSize(); - fd.nFileSizeHigh = li.HighPart; - fd.nFileSizeLow = li.LowPart; - fd.dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL; - fillFindData(&fd, dokanFileInfo); + LARGE_INTEGER li = { 0 }; + li.QuadPart = file->GetFileSize(); + fd.nFileSizeHigh = li.HighPart; + fd.nFileSizeLow = li.LowPart; + fd.dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL; + fillFindData(&fd, dokanFileInfo); + } } + + ret = STATUS_SUCCESS; + } + else + { + ret = DokanNtStatusFromWin32(error); } } } @@ -612,17 +628,13 @@ private: BOOL opened = FALSE; NTSTATUS ret = STATUS_SUCCESS; - FilePath cachePath(GetCacheLocation(), fileName); - - SString siaPath = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot()); auto siaFileTree = GetFileTree(); - auto siaFile = siaFileTree ? siaFileTree->GetFile(siaPath) : nullptr; - CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanGetFileInformation(cachePath))); + auto siaFile = siaFileTree ? siaFileTree->GetFile(openFileInfo->SiaPath) : nullptr; HANDLE tempHandle = openFileInfo->FileHandle; - if (!siaFile && (!openFileInfo->FileHandle || (openFileInfo->FileHandle == INVALID_HANDLE_VALUE))) + if (!siaFile && (!tempHandle || (tempHandle == INVALID_HANDLE_VALUE))) { - tempHandle = ::CreateFile(&cachePath[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + tempHandle = ::CreateFile(&openFileInfo->CacheFilePath[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (tempHandle == INVALID_HANDLE_VALUE) { ret = DokanNtStatusFromWin32(::GetLastError()); @@ -650,12 +662,12 @@ private: // in this case, FindFirstFile can't get directory information if (wcscmp(fileName, L"\\") == 0) { - handleFileInfo->dwFileAttributes = ::GetFileAttributes(&cachePath[0]); + handleFileInfo->dwFileAttributes = ::GetFileAttributes(&openFileInfo->CacheFilePath[0]); } else { WIN32_FIND_DATAW find = { 0 }; - HANDLE findHandle = ::FindFirstFile(&cachePath[0], &find); + HANDLE findHandle = ::FindFirstFile(&openFileInfo->CacheFilePath[0], &find); if (findHandle == INVALID_HANDLE_VALUE) { DWORD error = ::GetLastError(); @@ -681,6 +693,8 @@ private: ::CloseHandle(tempHandle); } + CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanGetFileInformation(openFileInfo->CacheFilePath, fileName, ret))); + return ret; } @@ -709,7 +723,7 @@ private: UNREFERENCED_PARAMETER(dokanFileInfo); // TODO Implement this correctly - *FreeBytesAvailable = static_cast(512 * 1024 * 1024); + *FreeBytesAvailable = static_cast(1024 * 1024 * 1024); *TotalNumberOfBytes = 9223372036854775807; *TotalNumberOfFreeBytes = 9223372036854775807; @@ -724,7 +738,7 @@ private: UNREFERENCED_PARAMETER(dokanFileInfo); wcscpy_s(VolumeNameBuffer, VolumeNameSize, L"SiaDrive"); - *VolumeSerialNumber = 0x19831116; + *VolumeSerialNumber = 0x19831186; *MaximumComponentLength = 256; *FileSystemFlags = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_SUPPORTS_REMOTE_STORAGE | FILE_UNICODE_ON_DISK | @@ -971,7 +985,7 @@ private: // if open with FILE_FLAG_DELETE_ON_CLOSE if (dokanFileInfo->IsDirectory) { - if (filePath.RemoveDirectory()) + if (RetryableAction(filePath.RemoveDirectory(), DEFAULT_RETRY_COUNT, DEFAULT_RETRY_DELAY_MS)) { } else @@ -980,7 +994,7 @@ private: } else { - if (filePath.DeleteFile()) + if (RetryableAction(filePath.RemoveDirectory(), DEFAULT_RETRY_COUNT, DEFAULT_RETRY_DELAY_MS)) { } else @@ -1040,11 +1054,13 @@ private: } } while ((ret == STATUS_SUCCESS) && (::FindNextFile(findHandle, &findData) != 0)); - - DWORD error = GetLastError(); - if (error != ERROR_NO_MORE_FILES) + if (ret != STATUS_DIRECTORY_NOT_EMPTY) { - ret = DokanNtStatusFromWin32(error); + DWORD error = GetLastError(); + if (error != ERROR_NO_MORE_FILES) + { + ret = DokanNtStatusFromWin32(error); + } } ::FindClose(findHandle); @@ -1321,6 +1337,9 @@ public: _dokanOptions.ThreadCount = 0; // use default #ifdef _DEBUG _dokanOptions.Options = DOKAN_OPTION_DEBUG | DOKAN_OPTION_DEBUG_LOG_FILE; + _dokanOptions.Timeout = (60 * 1000) * 60; +#else + _dokanOptions.Options = 0; #endif }