1
0
This commit is contained in:
Scott E. Graves
2017-03-27 13:25:40 -05:00
parent 1a40b1935f
commit 54d0c50d35

View File

@@ -33,7 +33,7 @@ private:
static FilePath _cacheLocation; static FilePath _cacheLocation;
static std::unordered_map<ULONG64, OpenFileInfo> _openFileMap; static std::unordered_map<ULONG64, OpenFileInfo> _openFileMap;
static std::unique_ptr<std::thread> _fileListThread; static std::unique_ptr<std::thread> _fileListThread;
static bool _fileListStopRequested; static HANDLE _fileListStopEvent;
static CSiaFileTreePtr _siaFileTree; static CSiaFileTreePtr _siaFileTree;
static std::mutex _fileTreeMutex; static std::mutex _fileTreeMutex;
static std::unique_ptr<std::thread> _mountThread; static std::unique_ptr<std::thread> _mountThread;
@@ -48,12 +48,11 @@ private:
static bool AddFileToCache(const SString& siaPath, const SString& cacheLocation) static bool AddFileToCache(const SString& siaPath, const SString& cacheLocation)
{ {
bool ret = false;
FilePath tempFilePath = FilePath::GetTempDirectory(); FilePath tempFilePath = FilePath::GetTempDirectory();
tempFilePath.Append(GenerateSha256(siaPath) + ".siatmp"); tempFilePath.Append(GenerateSha256(siaPath) + ".siatmp");
// TODO Check cache size is large enough to hold new file // TODO Check cache size is large enough to hold new file
ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(siaPath, tempFilePath)); bool ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(siaPath, tempFilePath));
if (ret) if (ret)
{ {
FilePath src(tempFilePath); FilePath src(tempFilePath);
@@ -106,10 +105,10 @@ private:
{ {
if (!_fileListThread) if (!_fileListThread)
{ {
_fileListStopRequested = false; _fileListStopEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
_fileListThread.reset(new std::thread([]() _fileListThread.reset(new std::thread([]()
{ {
while (!_fileListStopRequested) do
{ {
CSiaFileTreePtr siaFileTree; CSiaFileTreePtr siaFileTree;
_siaApi->GetRenter()->GetFileTree(siaFileTree); _siaApi->GetRenter()->GetFileTree(siaFileTree);
@@ -117,13 +116,7 @@ private:
std::lock_guard<std::mutex> l(_fileTreeMutex); std::lock_guard<std::mutex> l(_fileTreeMutex);
_siaFileTree = siaFileTree; _siaFileTree = siaFileTree;
} }
} while (::WaitForSingleObject(_fileListStopEvent, 1000) == WAIT_TIMEOUT);
if (!_fileListStopRequested)
{
// TODO Change to WaitForSingleObject() for immediate termination
Sleep(1000);
}
}
})); }));
} }
} }
@@ -132,63 +125,64 @@ private:
{ {
if (_fileListThread) if (_fileListThread)
{ {
_fileListStopRequested = true; ::SetEvent(_fileListStopEvent);
_fileListThread->join(); _fileListThread->join();
_fileListThread.reset(nullptr); _fileListThread.reset(nullptr);
::CloseHandle(_fileListStopEvent);
} }
} }
// Dokan callbacks // Dokan callbacks
private: private:
static NTSTATUS DOKAN_CALLBACK Sia_ZwCreateFile( static NTSTATUS DOKAN_CALLBACK Sia_ZwCreateFile(
LPCWSTR FileName, LPCWSTR fileName,
PDOKAN_IO_SECURITY_CONTEXT SecurityContext, PDOKAN_IO_SECURITY_CONTEXT securityContext,
ACCESS_MASK DesiredAccess, ACCESS_MASK desiredAccess,
ULONG FileAttributes, ULONG fileAttributes,
ULONG ShareAccess, ULONG shareAccess,
ULONG CreateDisposition, ULONG createDisposition,
ULONG CreateOptions, ULONG createOptions,
PDOKAN_FILE_INFO DokanFileInfo) PDOKAN_FILE_INFO dokanFileInfo)
{ {
SECURITY_ATTRIBUTES securityAttrib; SECURITY_ATTRIBUTES securityAttrib;
securityAttrib.nLength = sizeof(securityAttrib); securityAttrib.nLength = sizeof(securityAttrib);
securityAttrib.lpSecurityDescriptor = SecurityContext->AccessState.SecurityDescriptor; securityAttrib.lpSecurityDescriptor = securityContext->AccessState.SecurityDescriptor;
securityAttrib.bInheritHandle = FALSE; securityAttrib.bInheritHandle = FALSE;
DWORD fileAttributesAndFlags; DWORD fileAttributesAndFlags;
DWORD creationDisposition; DWORD creationDisposition;
DokanMapKernelToUserCreateFileFlags(FileAttributes, CreateOptions, CreateDisposition, &fileAttributesAndFlags, &creationDisposition); DokanMapKernelToUserCreateFileFlags(fileAttributes, createOptions, createDisposition, &fileAttributesAndFlags, &creationDisposition);
ACCESS_MASK genericDesiredAccess = DokanMapStandardToGenericAccess(DesiredAccess); ACCESS_MASK genericDesiredAccess = DokanMapStandardToGenericAccess(desiredAccess);
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
// Probably not going to happen, but just in case // Probably not going to happen, but just in case
if (FilePath(FileName).IsUNC()) if (FilePath(fileName).IsUNC())
{ {
ret = STATUS_ILLEGAL_ELEMENT_ADDRESS; ret = STATUS_ILLEGAL_ELEMENT_ADDRESS;
CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanCreateFile(FileName, fileAttributesAndFlags, creationDisposition, genericDesiredAccess, ret))); CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanCreateFile(fileName, fileAttributesAndFlags, creationDisposition, genericDesiredAccess, ret)));
} }
else else
{ {
// When filePath is a directory, needs to change the flag so that the file can // When filePath is a directory, needs to change the flag so that the file can
// be opened. // be opened.
FilePath cacheFilePath(GetCacheLocation(), &FileName[1]); FilePath cacheFilePath(GetCacheLocation(), &fileName[1]);
DWORD fileAttr = ::GetFileAttributes(&cacheFilePath[0]); DWORD fileAttr = ::GetFileAttributes(&cacheFilePath[0]);
if ((fileAttr != INVALID_FILE_ATTRIBUTES) && if ((fileAttr != INVALID_FILE_ATTRIBUTES) &&
(fileAttr & FILE_ATTRIBUTE_DIRECTORY) && (fileAttr & FILE_ATTRIBUTE_DIRECTORY) &&
!(CreateOptions & FILE_NON_DIRECTORY_FILE)) !(createOptions & FILE_NON_DIRECTORY_FILE))
{ {
DokanFileInfo->IsDirectory = TRUE; dokanFileInfo->IsDirectory = TRUE;
if (DesiredAccess & DELETE) if (desiredAccess & DELETE)
{ {
// Needed by FindFirstFile to see if directory is empty or not // Needed by FindFirstFile to see if directory is empty or not
ShareAccess |= FILE_SHARE_READ; shareAccess |= FILE_SHARE_READ;
} }
} }
// Folder (cache operation only) // Folder (cache operation only)
if (DokanFileInfo->IsDirectory) if (dokanFileInfo->IsDirectory)
{ {
if (creationDisposition == CREATE_NEW) if (creationDisposition == CREATE_NEW)
{ {
@@ -215,13 +209,13 @@ private:
//Check first if we're trying to open a file as a directory. //Check first if we're trying to open a file as a directory.
if (fileAttr != INVALID_FILE_ATTRIBUTES && if (fileAttr != INVALID_FILE_ATTRIBUTES &&
!(fileAttr & FILE_ATTRIBUTE_DIRECTORY) && !(fileAttr & FILE_ATTRIBUTE_DIRECTORY) &&
(CreateOptions & FILE_DIRECTORY_FILE)) (createOptions & FILE_DIRECTORY_FILE))
{ {
return STATUS_NOT_A_DIRECTORY; return STATUS_NOT_A_DIRECTORY;
} }
// FILE_FLAG_BACKUP_SEMANTICS is required for opening directory handles // 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, nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
@@ -229,14 +223,14 @@ private:
} }
else else
{ {
DokanFileInfo->Context = reinterpret_cast<ULONG64>(handle); // save the file handle in Context dokanFileInfo->Context = reinterpret_cast<ULONG64>(handle); // save the file handle in Context
} }
} }
} }
else // File (cache and/or Sia operation) else // File (cache and/or Sia operation)
{ {
// Formulate Sia path // Formulate Sia path
SString siaPath = CSiaApi::FormatToSiaPath(FilePath(FileName).SkipRoot()); // Strip drive letter to get Sia path SString siaPath = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot()); // Strip drive letter to get Sia path
if (siaPath.Length()) if (siaPath.Length())
{ {
// If cache file already exists and is a directory, requested file operation isn't valid // If cache file already exists and is a directory, requested file operation isn't valid
@@ -351,7 +345,7 @@ private:
HANDLE handle = ::CreateFile( HANDLE handle = ::CreateFile(
&cacheFilePath[0], &cacheFilePath[0],
genericDesiredAccess, genericDesiredAccess,
ShareAccess, shareAccess,
&securityAttrib, &securityAttrib,
creationDisposition, creationDisposition,
fileAttributesAndFlags, fileAttributesAndFlags,
@@ -362,7 +356,7 @@ private:
} }
else else
{ {
DokanFileInfo->Context = reinterpret_cast<ULONG64>(handle); // save the file handle in Context dokanFileInfo->Context = reinterpret_cast<ULONG64>(handle); // save the file handle in Context
if ((creationDisposition == OPEN_ALWAYS) || (creationDisposition == CREATE_ALWAYS)) if ((creationDisposition == OPEN_ALWAYS) || (creationDisposition == CREATE_ALWAYS))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
@@ -376,10 +370,9 @@ private:
ofi.SiaPath = siaPath; ofi.SiaPath = siaPath;
ofi.CacheFilePath = cacheFilePath; ofi.CacheFilePath = cacheFilePath;
// TODO Detect if file is read-only // TODO Detect if file is read-only
// TODO Quick hash to detect changes
ofi.Changed = false; ofi.Changed = false;
std::lock_guard<std::mutex> l(_dokanMutex); std::lock_guard<std::mutex> l(_dokanMutex);
_openFileMap.insert({ DokanFileInfo->Context, ofi }); _openFileMap.insert({ dokanFileInfo->Context, ofi });
} }
} }
} }
@@ -403,22 +396,23 @@ private:
return ret; return ret;
} }
static NTSTATUS DOKAN_CALLBACK Sia_FindFiles(LPCWSTR FileName, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_FindFiles(LPCWSTR fileName, PFillFindData fillFindData, PDOKAN_FILE_INFO dokanFileInfo)
{ {
NTSTATUS ret = STATUS_SUCCESS;
auto siaFileTree = _siaFileTree; auto siaFileTree = _siaFileTree;
if (siaFileTree) if (siaFileTree)
{ {
SString siaQuery = CSiaApi::FormatToSiaPath(FilePath(FileName).SkipRoot()); SString siaQuery = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot());
FilePath cachePath = GetCacheLocation();; FilePath cachePath = GetCacheLocation();;
FilePath rootPath = siaQuery; FilePath rootPath = siaQuery;
if (FilePath::DirSep == FileName) if (FilePath::DirSep == fileName)
{ {
siaQuery += L"/*.*"; siaQuery += L"/*.*";
} }
else else
{ {
cachePath.Append(&FileName[1]); cachePath.Append(&fileName[1]);
if (cachePath.IsDirectory()) if (cachePath.IsDirectory())
{ {
siaQuery += L"/*.*"; siaQuery += L"/*.*";
@@ -432,79 +426,120 @@ private:
CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanFindFiles(cachePath, rootPath, siaQuery))); CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DokanFindFiles(cachePath, rootPath, siaQuery)));
// TODO Grab live filesystem items WIN32_FIND_DATA findData = { 0 };
HANDLE findHandle = ::FindFirstFile(&cachePath[0], &findData);
if (findHandle == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
ret = DokanNtStatusFromWin32(error);
}
else
{
// Find local files
std::vector<SString> dirs;
std::vector<SString> files;
do
{
if ((wcscmp(findData.cFileName, L".") != 0) && (wcscmp(findData.cFileName, L"..") != 0))
{
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
dirs.push_back(findData.cFileName);
}
else
{
files.push_back(findData.cFileName);
}
fillFindData(&findData, dokanFileInfo);
}
} while (::FindNextFile(findHandle, &findData) != 0);
::FindClose(findHandle);
auto dirList = siaFileTree->QueryDirectories(rootPath); // Find Sia directories
for (auto& dir : dirList) auto dirList = siaFileTree->QueryDirectories(rootPath);
{ for (auto& dir : dirList)
WIN32_FIND_DATA fd = { 0 }; {
wcscpy_s(fd.cFileName, dir.str().c_str()); if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end())
fd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; {
FillFindData(&fd, DokanFileInfo); WIN32_FIND_DATA fd = { 0 };
wcscpy_s(fd.cFileName, dir.str().c_str());
// Create cache sub-folder fd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
FilePath subCachePath(cachePath, dir); fillFindData(&fd, dokanFileInfo);
if (!subCachePath.IsDirectory())
{
subCachePath.CreateDirectory();
}
}
auto fileList = siaFileTree->Query(siaQuery); // Create cache sub-folder
for (auto& file : fileList) FilePath subCachePath(cachePath, dir);
{ if (!subCachePath.IsDirectory())
WIN32_FIND_DATA fd = { 0 }; {
wcscpy_s(fd.cFileName, ::PathFindFileName(file->GetSiaPath().str().c_str())); subCachePath.CreateDirectory();
}
}
}
LARGE_INTEGER li = { 0 }; // Find Sia files
li.QuadPart = file->GetFileSize(); auto fileList = siaFileTree->Query(siaQuery);
fd.nFileSizeHigh = li.HighPart; for (auto& file : fileList)
fd.nFileSizeLow = li.LowPart; {
fd.dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL; FilePath fp = file->GetSiaPath();
FillFindData(&fd, DokanFileInfo); fp.RemoveFileName();
} if (std::find(files.begin(), files.end(), 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);
}
}
}
} }
return STATUS_SUCCESS; return ret;
} }
static void DOKAN_CALLBACK Sia_CloseFile(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) static void DOKAN_CALLBACK Sia_CloseFile(LPCWSTR fileName, PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
if (DokanFileInfo->Context) if (dokanFileInfo->Context)
{ {
auto id = DokanFileInfo->Context; auto id = dokanFileInfo->Context;
HANDLE handle = reinterpret_cast<HANDLE>(id); HANDLE handle = reinterpret_cast<HANDLE>(id);
if (!DokanFileInfo->IsDirectory) if (!dokanFileInfo->IsDirectory)
{ {
LARGE_INTEGER li = { 0 }; LARGE_INTEGER li = { 0 };
::GetFileSizeEx(handle, &li); ::GetFileSizeEx(handle, &li);
HandleFileClose(filePath, id, li.QuadPart); HandleFileClose(filePath, id, li.QuadPart);
} }
::CloseHandle(reinterpret_cast<HANDLE>(DokanFileInfo->Context)); ::CloseHandle(reinterpret_cast<HANDLE>(dokanFileInfo->Context));
DokanFileInfo->Context = 0; dokanFileInfo->Context = 0;
} }
} }
static NTSTATUS DOKAN_CALLBACK Sia_GetFileInformation(LPCWSTR FileName, LPBY_HANDLE_FILE_INFORMATION HandleFileInformation, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_GetFileInformation(LPCWSTR fileName, LPBY_HANDLE_FILE_INFORMATION handleFileInfo, PDOKAN_FILE_INFO dokanFileInfo)
{ {
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
BOOL opened = FALSE; BOOL opened = FALSE;
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
FilePath cachePath = GetCacheLocation(); FilePath cachePath = GetCacheLocation();
if (FilePath::DirSep == FileName) if (FilePath::DirSep == fileName)
{ {
cachePath.Append(FileName); cachePath.Append(fileName);
} }
if (!handle || (handle == INVALID_HANDLE_VALUE)) SString siaPath = CSiaApi::FormatToSiaPath(FilePath(fileName).SkipRoot());
auto siaFileTree = _siaFileTree;
auto siaFile = siaFileTree->GetFile(siaPath);
if (!siaFile && (!handle || (handle == INVALID_HANDLE_VALUE)))
{ {
handle = ::CreateFile(&cachePath[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); handle = ::CreateFile(&cachePath[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
{ {
ret = DokanNtStatusFromWin32(GetLastError()); ret = DokanNtStatusFromWin32(::GetLastError());
} }
else else
{ {
@@ -514,13 +549,13 @@ private:
if (ret == STATUS_SUCCESS) if (ret == STATUS_SUCCESS)
{ {
if (!::GetFileInformationByHandle(handle, HandleFileInformation)) if (!::GetFileInformationByHandle(handle, handleFileInfo))
{ {
// FileName is a root directory // fileName is a root directory
// in this case, FindFirstFile can't get directory information // in this case, FindFirstFile can't get directory information
if (wcslen(FileName) == 1) if (wcslen(fileName) == 1)
{ {
HandleFileInformation->dwFileAttributes = ::GetFileAttributes(&cachePath[0]); handleFileInfo->dwFileAttributes = ::GetFileAttributes(&cachePath[0]);
} }
else else
{ {
@@ -528,33 +563,45 @@ private:
HANDLE findHandle = ::FindFirstFile(&cachePath[0], &find); HANDLE findHandle = ::FindFirstFile(&cachePath[0], &find);
if (findHandle == INVALID_HANDLE_VALUE) if (findHandle == INVALID_HANDLE_VALUE)
{ {
// TODO Not Cached, so manual attributes DWORD error = ::GetLastError();
ret = STATUS_SUCCESS;// DokanNtStatusFromWin32(::GetLastError()); if (siaFile)
{
LARGE_INTEGER li = { 0 };
li.QuadPart = siaFile->GetFileSize();
handleFileInfo->dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE;
handleFileInfo->nFileSizeHigh = li.HighPart;
handleFileInfo->nFileSizeLow = li.LowPart;
ret = STATUS_SUCCESS;
}
else
{
ret = DokanNtStatusFromWin32(error);
}
} }
else else
{ {
HandleFileInformation->dwFileAttributes = find.dwFileAttributes; handleFileInfo->dwFileAttributes = find.dwFileAttributes;
HandleFileInformation->ftCreationTime = find.ftCreationTime; handleFileInfo->ftCreationTime = find.ftCreationTime;
HandleFileInformation->ftLastAccessTime = find.ftLastAccessTime; handleFileInfo->ftLastAccessTime = find.ftLastAccessTime;
HandleFileInformation->ftLastWriteTime = find.ftLastWriteTime; handleFileInfo->ftLastWriteTime = find.ftLastWriteTime;
HandleFileInformation->nFileSizeHigh = find.nFileSizeHigh; handleFileInfo->nFileSizeHigh = find.nFileSizeHigh;
HandleFileInformation->nFileSizeLow = find.nFileSizeLow; handleFileInfo->nFileSizeLow = find.nFileSizeLow;
::FindClose(findHandle); ::FindClose(findHandle);
} }
} }
} }
}
if (opened) if (opened)
{ {
::CloseHandle(handle); ::CloseHandle(handle);
}
} }
return ret; return ret;
} }
static NTSTATUS DOKAN_CALLBACK Sia_Mounted(PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_Mounted(PDOKAN_FILE_INFO dokanFileInfo)
{ {
// May spend a little wait time here while files are cleaned-up and re-added to queue // May spend a little wait time here while files are cleaned-up and re-added to queue
_uploadManager.reset(new CUploadManager(CSiaCurl(_siaApi->GetHostConfig()), _siaDriveConfig)); _uploadManager.reset(new CUploadManager(CSiaCurl(_siaApi->GetHostConfig()), _siaDriveConfig));
@@ -564,7 +611,7 @@ private:
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS DOKAN_CALLBACK Sia_Unmounted(PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_Unmounted(PDOKAN_FILE_INFO dokanFileInfo)
{ {
_uploadManager.reset(nullptr); _uploadManager.reset(nullptr);
StopFileListThread(); StopFileListThread();
@@ -574,9 +621,9 @@ private:
static NTSTATUS DOKAN_CALLBACK Sia_GetDiskFreeSpaceW( static NTSTATUS DOKAN_CALLBACK Sia_GetDiskFreeSpaceW(
PULONGLONG FreeBytesAvailable, PULONGLONG TotalNumberOfBytes, PULONGLONG FreeBytesAvailable, PULONGLONG TotalNumberOfBytes,
PULONGLONG TotalNumberOfFreeBytes, PDOKAN_FILE_INFO DokanFileInfo) PULONGLONG TotalNumberOfFreeBytes, PDOKAN_FILE_INFO dokanFileInfo)
{ {
UNREFERENCED_PARAMETER(DokanFileInfo); UNREFERENCED_PARAMETER(dokanFileInfo);
// TODO Implement this correctly // TODO Implement this correctly
*FreeBytesAvailable = static_cast<ULONGLONG>(512 * 1024 * 1024); *FreeBytesAvailable = static_cast<ULONGLONG>(512 * 1024 * 1024);
@@ -590,8 +637,8 @@ private:
LPWSTR VolumeNameBuffer, DWORD VolumeNameSize, LPDWORD VolumeSerialNumber, LPWSTR VolumeNameBuffer, DWORD VolumeNameSize, LPDWORD VolumeSerialNumber,
LPDWORD MaximumComponentLength, LPDWORD FileSystemFlags, LPDWORD MaximumComponentLength, LPDWORD FileSystemFlags,
LPWSTR FileSystemNameBuffer, DWORD FileSystemNameSize, LPWSTR FileSystemNameBuffer, DWORD FileSystemNameSize,
PDOKAN_FILE_INFO DokanFileInfo) { PDOKAN_FILE_INFO dokanFileInfo) {
UNREFERENCED_PARAMETER(DokanFileInfo); UNREFERENCED_PARAMETER(dokanFileInfo);
wcscpy_s(VolumeNameBuffer, VolumeNameSize, L"SiaDrive"); wcscpy_s(VolumeNameBuffer, VolumeNameSize, L"SiaDrive");
*VolumeSerialNumber = 0x19831116; *VolumeSerialNumber = 0x19831116;
@@ -609,15 +656,15 @@ private:
} }
static NTSTATUS DOKAN_CALLBACK Sia_ReadFile(LPCWSTR FileName, LPVOID Buffer, static NTSTATUS DOKAN_CALLBACK Sia_ReadFile(LPCWSTR fileName, LPVOID buffer,
DWORD BufferLength, DWORD bufferLen,
LPDWORD ReadLength, LPDWORD readLength,
LONGLONG Offset, LONGLONG offset,
PDOKAN_FILE_INFO DokanFileInfo) PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
BOOL opened = FALSE; BOOL opened = FALSE;
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
@@ -633,7 +680,7 @@ private:
} }
LARGE_INTEGER distanceToMove; LARGE_INTEGER distanceToMove;
distanceToMove.QuadPart = Offset; distanceToMove.QuadPart = offset;
if (!::SetFilePointerEx(handle, distanceToMove, nullptr, FILE_BEGIN)) if (!::SetFilePointerEx(handle, distanceToMove, nullptr, FILE_BEGIN))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
@@ -642,7 +689,7 @@ private:
return DokanNtStatusFromWin32(error); return DokanNtStatusFromWin32(error);
} }
if (!ReadFile(handle, Buffer, BufferLength, ReadLength, nullptr)) if (!ReadFile(handle, buffer, bufferLen, readLength, nullptr))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
if (opened) if (opened)
@@ -659,14 +706,14 @@ private:
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS DOKAN_CALLBACK Sia_WriteFile(LPCWSTR FileName, LPCVOID Buffer, static NTSTATUS DOKAN_CALLBACK Sia_WriteFile(LPCWSTR fileName, LPCVOID buffer,
DWORD NumberOfBytesToWrite, DWORD bytesToWrite,
LPDWORD NumberOfBytesWritten, LPDWORD bytesWritten,
LONGLONG Offset, LONGLONG offset,
PDOKAN_FILE_INFO DokanFileInfo) PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
BOOL opened = FALSE; BOOL opened = FALSE;
// reopen the file // reopen the file
@@ -692,46 +739,45 @@ private:
} }
LARGE_INTEGER distanceToMove; LARGE_INTEGER distanceToMove;
if (DokanFileInfo->WriteToEndOfFile) if (dokanFileInfo->WriteToEndOfFile)
{ {
LARGE_INTEGER z; LARGE_INTEGER z = {0};
z.QuadPart = 0;
if (!::SetFilePointerEx(handle, z, nullptr, FILE_END)) if (!::SetFilePointerEx(handle, z, nullptr, FILE_END))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
if (opened) if (opened)
CloseHandle(handle); ::CloseHandle(handle);
return DokanNtStatusFromWin32(error); return DokanNtStatusFromWin32(error);
} }
} }
else else
{ {
// Paging IO cannot write after allocate file size. // Paging IO cannot write after allocate file size.
if (DokanFileInfo->PagingIo) if (dokanFileInfo->PagingIo)
{ {
if (static_cast<UINT64>(Offset) >= li.QuadPart) if (static_cast<UINT64>(offset) >= li.QuadPart)
{ {
*NumberOfBytesWritten = 0; *bytesWritten = 0;
if (opened) if (opened)
CloseHandle(handle); CloseHandle(handle);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
if ((static_cast<UINT64>(Offset) + NumberOfBytesToWrite) > li.QuadPart) if ((static_cast<UINT64>(offset) + bytesToWrite) > li.QuadPart)
{ {
UINT64 bytes = li.QuadPart - Offset; UINT64 bytes = li.QuadPart - offset;
if (bytes >> 32) if (bytes >> 32)
{ {
NumberOfBytesToWrite = static_cast<DWORD>(bytes & 0xFFFFFFFFUL); bytesToWrite = static_cast<DWORD>(bytes & 0xFFFFFFFFUL);
} }
else else
{ {
NumberOfBytesToWrite = static_cast<DWORD>(bytes); bytesToWrite = static_cast<DWORD>(bytes);
} }
} }
} }
if (static_cast<UINT64>(Offset) > li.QuadPart) if (static_cast<UINT64>(offset) > li.QuadPart)
{ {
// In the mirror sample helperZeroFileData is not necessary. NTFS will // In the mirror sample helperZeroFileData is not necessary. NTFS will
// zero a hole. // zero a hole.
@@ -739,7 +785,7 @@ private:
// file systems ) then users will have to zero the hole themselves. // file systems ) then users will have to zero the hole themselves.
} }
distanceToMove.QuadPart = Offset; distanceToMove.QuadPart = offset;
if (!::SetFilePointerEx(handle, distanceToMove, nullptr, FILE_BEGIN)) if (!::SetFilePointerEx(handle, distanceToMove, nullptr, FILE_BEGIN))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
@@ -749,7 +795,7 @@ private:
} }
} }
if (::WriteFile(handle, Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, nullptr)) if (::WriteFile(handle, buffer, bytesToWrite, bytesWritten, nullptr))
{ {
// TODO Set status to changed // TODO Set status to changed
} }
@@ -768,11 +814,11 @@ private:
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS DOKAN_CALLBACK Sia_SetEndOfFile(LPCWSTR FileName, LONGLONG ByteOffset, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_SetEndOfFile(LPCWSTR fileName, LONGLONG byteOffset, PDOKAN_FILE_INFO dokanFileInfo)
{ {
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
{ {
ret = STATUS_INVALID_HANDLE; ret = STATUS_INVALID_HANDLE;
@@ -781,7 +827,7 @@ private:
{ {
// TODO Set status to changed // TODO Set status to changed
LARGE_INTEGER offset; LARGE_INTEGER offset;
offset.QuadPart = ByteOffset; offset.QuadPart = byteOffset;
if (!::SetFilePointerEx(handle, offset, nullptr, FILE_BEGIN)) if (!::SetFilePointerEx(handle, offset, nullptr, FILE_BEGIN))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
@@ -797,28 +843,28 @@ private:
return ret; return ret;
} }
static void DOKAN_CALLBACK Sia_Cleanup(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) static void DOKAN_CALLBACK Sia_Cleanup(LPCWSTR fileName, PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
if (DokanFileInfo->Context) if (dokanFileInfo->Context)
{ {
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!DokanFileInfo->IsDirectory) if (!dokanFileInfo->IsDirectory)
{ {
LARGE_INTEGER li = { 0 }; LARGE_INTEGER li = { 0 };
::GetFileSizeEx(handle, &li); ::GetFileSizeEx(handle, &li);
HandleFileClose(filePath, DokanFileInfo->Context, li.QuadPart); HandleFileClose(filePath, dokanFileInfo->Context, li.QuadPart);
} }
::CloseHandle(handle); ::CloseHandle(handle);
DokanFileInfo->Context = 0; dokanFileInfo->Context = 0;
} }
if (DokanFileInfo->DeleteOnClose) if (dokanFileInfo->DeleteOnClose)
{ {
// Should already be deleted by CloseHandle // Should already be deleted by CloseHandle
// if open with FILE_FLAG_DELETE_ON_CLOSE // if open with FILE_FLAG_DELETE_ON_CLOSE
if (DokanFileInfo->IsDirectory) if (dokanFileInfo->IsDirectory)
{ {
if (filePath.RemoveDirectory()) if (filePath.RemoveDirectory())
{ {
@@ -840,9 +886,9 @@ private:
} }
} }
static NTSTATUS DOKAN_CALLBACK Sia_FlushFileBuffers(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_FlushFileBuffers(LPCWSTR fileName, PDOKAN_FILE_INFO dokanFileInfo)
{ {
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
{ {
return STATUS_SUCCESS; return STATUS_SUCCESS;
@@ -859,11 +905,11 @@ private:
} }
} }
static NTSTATUS DOKAN_CALLBACK Sia_DeleteDirectory(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_DeleteDirectory(LPCWSTR fileName, PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath filePath = FilePath(GetCacheLocation(), FileName); FilePath filePath = FilePath(GetCacheLocation(), fileName);
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
if (DokanFileInfo->DeleteOnClose) if (dokanFileInfo->DeleteOnClose)
{ {
filePath.Append("*"); filePath.Append("*");
@@ -899,13 +945,13 @@ private:
} }
static NTSTATUS DOKAN_CALLBACK Sia_DeleteFileW(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_DeleteFileW(LPCWSTR fileName, PDOKAN_FILE_INFO dokanFileInfo)
{ {
// TODO Handle files that aren't cached // TODO Handle files that aren't cached
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
DWORD dwAttrib = ::GetFileAttributes(&filePath[0]); DWORD dwAttrib = ::GetFileAttributes(&filePath[0]);
if ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) if ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
@@ -915,7 +961,7 @@ private:
else if (handle && (handle != INVALID_HANDLE_VALUE)) else if (handle && (handle != INVALID_HANDLE_VALUE))
{ {
FILE_DISPOSITION_INFO fdi; FILE_DISPOSITION_INFO fdi;
fdi.DeleteFile = DokanFileInfo->DeleteOnClose; fdi.DeleteFile = dokanFileInfo->DeleteOnClose;
if (!::SetFileInformationByHandle(handle, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO))) if (!::SetFileInformationByHandle(handle, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)))
{ {
ret = DokanNtStatusFromWin32(GetLastError()); ret = DokanNtStatusFromWin32(GetLastError());
@@ -925,15 +971,15 @@ private:
return ret; return ret;
} }
static NTSTATUS DOKAN_CALLBACK Sia_MoveFileW(LPCWSTR FileName, LPCWSTR NewFileName, BOOL ReplaceIfExisting, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_MoveFileW(LPCWSTR fileName, LPCWSTR NewFileName, BOOL ReplaceIfExisting, PDOKAN_FILE_INFO dokanFileInfo)
{ {
// TODO Handle files that aren't cached // TODO Handle files that aren't cached
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
FilePath newFilePath(GetCacheLocation(), NewFileName); FilePath newFilePath(GetCacheLocation(), NewFileName);
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
{ {
ret = STATUS_INVALID_HANDLE; ret = STATUS_INVALID_HANDLE;
@@ -972,13 +1018,13 @@ private:
return ret; return ret;
} }
static NTSTATUS DOKAN_CALLBACK Sia_SetFileAttributesW(LPCWSTR FileName, DWORD FileAttributes, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_SetFileAttributesW(LPCWSTR fileName, DWORD fileAttributes, PDOKAN_FILE_INFO dokanFileInfo)
{ {
UNREFERENCED_PARAMETER(DokanFileInfo); UNREFERENCED_PARAMETER(dokanFileInfo);
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
if (!::SetFileAttributes(&filePath[0], FileAttributes)) if (!::SetFileAttributes(&filePath[0], fileAttributes))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
ret = DokanNtStatusFromWin32(error); ret = DokanNtStatusFromWin32(error);
@@ -988,19 +1034,19 @@ private:
} }
static NTSTATUS DOKAN_CALLBACK Sia_GetFileSecurityW( static NTSTATUS DOKAN_CALLBACK Sia_GetFileSecurityW(
LPCWSTR FileName, PSECURITY_INFORMATION SecurityInformation, LPCWSTR fileName, PSECURITY_INFORMATION securityInfo,
PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG BufferLength, PSECURITY_DESCRIPTOR securityDescriptor, ULONG bufferLen,
PULONG LengthNeeded, PDOKAN_FILE_INFO DokanFileInfo) PULONG lengthNeeded, PDOKAN_FILE_INFO dokanFileInfo)
{ {
UNREFERENCED_PARAMETER(DokanFileInfo); UNREFERENCED_PARAMETER(dokanFileInfo);
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
SECURITY_INFORMATION requestingSaclInfo = ((*SecurityInformation & SACL_SECURITY_INFORMATION) || (*SecurityInformation & BACKUP_SECURITY_INFORMATION)); SECURITY_INFORMATION requestingSaclInfo = ((*securityInfo & SACL_SECURITY_INFORMATION) || (*securityInfo & BACKUP_SECURITY_INFORMATION));
//if (!g_HasSeSecurityPrivilege) { //if (!g_HasSeSecurityPrivilege) {
if (true) if (true)
{ {
*SecurityInformation &= ~SACL_SECURITY_INFORMATION; *securityInfo &= ~SACL_SECURITY_INFORMATION;
*SecurityInformation &= ~BACKUP_SECURITY_INFORMATION; *securityInfo &= ~BACKUP_SECURITY_INFORMATION;
} }
HANDLE handle = ::CreateFile(&filePath[0], READ_CONTROL | ((requestingSaclInfo && false) ? ACCESS_SYSTEM_SECURITY : 0), HANDLE handle = ::CreateFile(&filePath[0], READ_CONTROL | ((requestingSaclInfo && false) ? ACCESS_SYSTEM_SECURITY : 0),
@@ -1016,7 +1062,7 @@ private:
return DokanNtStatusFromWin32(error); return DokanNtStatusFromWin32(error);
} }
if (!::GetUserObjectSecurity(handle, SecurityInformation, SecurityDescriptor, BufferLength, LengthNeeded)) if (!::GetUserObjectSecurity(handle, securityInfo, securityDescriptor, bufferLen, lengthNeeded))
{ {
int error = ::GetLastError(); int error = ::GetLastError();
if (error == ERROR_INSUFFICIENT_BUFFER) if (error == ERROR_INSUFFICIENT_BUFFER)
@@ -1037,21 +1083,21 @@ private:
static NTSTATUS DOKAN_CALLBACK Sia_SetFileSecurityW( static NTSTATUS DOKAN_CALLBACK Sia_SetFileSecurityW(
LPCWSTR FileName, PSECURITY_INFORMATION SecurityInformation, LPCWSTR fileName, PSECURITY_INFORMATION securityInfo,
PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG SecurityDescriptorLength, PSECURITY_DESCRIPTOR securityDescriptor, ULONG securityDescriptorLength,
PDOKAN_FILE_INFO DokanFileInfo) PDOKAN_FILE_INFO dokanFileInfo)
{ {
UNREFERENCED_PARAMETER(SecurityDescriptorLength); UNREFERENCED_PARAMETER(securityDescriptorLength);
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
{ {
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
} }
if (!::SetUserObjectSecurity(handle, SecurityInformation, SecurityDescriptor)) if (!::SetUserObjectSecurity(handle, securityInfo, securityDescriptor))
{ {
int error = ::GetLastError(); int error = ::GetLastError();
return DokanNtStatusFromWin32(error); return DokanNtStatusFromWin32(error);
@@ -1060,19 +1106,19 @@ private:
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS DOKAN_CALLBACK Sia_SetFileTime(LPCWSTR FileName, CONST FILETIME *CreationTime, static NTSTATUS DOKAN_CALLBACK Sia_SetFileTime(LPCWSTR fileName, CONST FILETIME *creationTime,
CONST FILETIME *LastAccessTime, CONST FILETIME *LastWriteTime, CONST FILETIME *lastAccessTime, CONST FILETIME *lastWriteTime,
PDOKAN_FILE_INFO DokanFileInfo) PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
{ {
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
} }
if (!::SetFileTime(handle, CreationTime, LastAccessTime, LastWriteTime)) if (!::SetFileTime(handle, creationTime, lastAccessTime, lastWriteTime))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
return DokanNtStatusFromWin32(error); return DokanNtStatusFromWin32(error);
@@ -1081,12 +1127,12 @@ private:
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS DOKAN_CALLBACK Sia_SetAllocationSize(LPCWSTR FileName, LONGLONG AllocSize, PDOKAN_FILE_INFO DokanFileInfo) static NTSTATUS DOKAN_CALLBACK Sia_SetAllocationSize(LPCWSTR fileName, LONGLONG allocSize, PDOKAN_FILE_INFO dokanFileInfo)
{ {
NTSTATUS ret = STATUS_SUCCESS; NTSTATUS ret = STATUS_SUCCESS;
FilePath filePath(GetCacheLocation(), FileName); FilePath filePath(GetCacheLocation(), fileName);
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context); HANDLE handle = reinterpret_cast<HANDLE>(dokanFileInfo->Context);
if (!handle || (handle == INVALID_HANDLE_VALUE)) if (!handle || (handle == INVALID_HANDLE_VALUE))
{ {
ret = STATUS_INVALID_HANDLE; ret = STATUS_INVALID_HANDLE;
@@ -1096,9 +1142,9 @@ private:
LARGE_INTEGER fileSize = { 0 }; LARGE_INTEGER fileSize = { 0 };
if (::GetFileSizeEx(handle, &fileSize)) if (::GetFileSizeEx(handle, &fileSize))
{ {
if (AllocSize < fileSize.QuadPart) if (allocSize < fileSize.QuadPart)
{ {
fileSize.QuadPart = AllocSize; fileSize.QuadPart = allocSize;
if (!::SetFilePointerEx(handle, fileSize, nullptr, FILE_BEGIN)) if (!::SetFilePointerEx(handle, fileSize, nullptr, FILE_BEGIN))
{ {
DWORD error = GetLastError(); DWORD error = GetLastError();
@@ -1217,7 +1263,7 @@ std::unique_ptr<CUploadManager> DokanImpl::_uploadManager;
DOKAN_OPERATIONS DokanImpl::_dokanOps; DOKAN_OPERATIONS DokanImpl::_dokanOps;
DOKAN_OPTIONS DokanImpl::_dokanOptions; DOKAN_OPTIONS DokanImpl::_dokanOptions;
FilePath DokanImpl::_cacheLocation; FilePath DokanImpl::_cacheLocation;
bool DokanImpl::_fileListStopRequested; HANDLE DokanImpl::_fileListStopEvent;
CSiaFileTreePtr DokanImpl::_siaFileTree; CSiaFileTreePtr DokanImpl::_siaFileTree;
std::mutex DokanImpl::_fileTreeMutex; std::mutex DokanImpl::_fileTreeMutex;
std::unique_ptr<std::thread> DokanImpl::_fileListThread; std::unique_ptr<std::thread> DokanImpl::_fileListThread;