Continue drive support
This commit is contained in:
@@ -130,7 +130,7 @@ private:
|
||||
|
||||
// Dokan callbacks
|
||||
private:
|
||||
static NTSTATUS DOKAN_CALLBACK SiaDrive_ZwCreateFile(
|
||||
static NTSTATUS DOKAN_CALLBACK Sia_ZwCreateFile(
|
||||
LPCWSTR FileName,
|
||||
PDOKAN_IO_SECURITY_CONTEXT SecurityContext,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
@@ -180,14 +180,48 @@ private:
|
||||
// Folder (cache operation only)
|
||||
if (DokanFileInfo->IsDirectory)
|
||||
{
|
||||
HANDLE handle = ::CreateFile(cacheFilePath.c_str(), genericDesiredAccess, ShareAccess, &securityAttrib, creationDisposition, fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
if (creationDisposition == CREATE_NEW)
|
||||
{
|
||||
ret = DokanNtStatusFromWin32(GetLastError());
|
||||
if (!::CreateDirectory(cacheFilePath.c_str(), &securityAttrib))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
ret = DokanNtStatusFromWin32(error);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (creationDisposition == OPEN_ALWAYS)
|
||||
{
|
||||
DokanFileInfo->Context = reinterpret_cast<ULONG64>(handle); // save the file handle in Context
|
||||
if (!CreateDirectory(cacheFilePath.c_str(), &securityAttrib))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
|
||||
if (error != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
ret = DokanNtStatusFromWin32(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == STATUS_SUCCESS)
|
||||
{
|
||||
//Check first if we're trying to open a file as a directory.
|
||||
if (fileAttr != INVALID_FILE_ATTRIBUTES &&
|
||||
!(fileAttr & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
(CreateOptions & FILE_DIRECTORY_FILE))
|
||||
{
|
||||
return STATUS_NOT_A_DIRECTORY;
|
||||
}
|
||||
|
||||
// FILE_FLAG_BACKUP_SEMANTICS is required for opening directory handles
|
||||
HANDLE handle = CreateFile(cacheFilePath.c_str(), genericDesiredAccess, ShareAccess, &securityAttrib, OPEN_EXISTING, fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
ret = DokanNtStatusFromWin32(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
DokanFileInfo->Context = reinterpret_cast<ULONG64>(handle); // save the file handle in Context
|
||||
}
|
||||
}
|
||||
}
|
||||
else // File (cache and/or Sia operation)
|
||||
@@ -359,7 +393,7 @@ private:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static NTSTATUS DOKAN_CALLBACK SiaDrive_FindFiles(LPCWSTR FileName, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo)
|
||||
static NTSTATUS DOKAN_CALLBACK Sia_FindFiles(LPCWSTR FileName, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_dokanMutex);
|
||||
auto siaFileTree = _siaFileTree;
|
||||
@@ -573,6 +607,236 @@ private:
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS DOKAN_CALLBACK Sia_ReadFile(LPCWSTR FileName, LPVOID Buffer,
|
||||
DWORD BufferLength,
|
||||
LPDWORD ReadLength,
|
||||
LONGLONG Offset,
|
||||
PDOKAN_FILE_INFO DokanFileInfo)
|
||||
{
|
||||
String filePath = StdConstructPath(GetCacheLocation(), FileName);
|
||||
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context);
|
||||
ULONG offset = static_cast<ULONG>(Offset);
|
||||
BOOL opened = FALSE;
|
||||
|
||||
if (!handle || (handle == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
handle = ::CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
opened = TRUE;
|
||||
}
|
||||
|
||||
LARGE_INTEGER distanceToMove;
|
||||
distanceToMove.QuadPart = Offset;
|
||||
if (!::SetFilePointerEx(handle, distanceToMove, nullptr, FILE_BEGIN))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
|
||||
if (!ReadFile(handle, Buffer, BufferLength, ReadLength, nullptr))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return DokanNtStatusFromWin32(error);
|
||||
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS DOKAN_CALLBACK Sia_WriteFile(LPCWSTR FileName, LPCVOID Buffer,
|
||||
DWORD NumberOfBytesToWrite,
|
||||
LPDWORD NumberOfBytesWritten,
|
||||
LONGLONG Offset,
|
||||
PDOKAN_FILE_INFO DokanFileInfo)
|
||||
{
|
||||
String filePath = StdConstructPath(GetCacheLocation(), FileName);
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context);
|
||||
BOOL opened = FALSE;
|
||||
|
||||
// reopen the file
|
||||
if (!handle || (handle == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
// TODO Get from cache if not found
|
||||
handle = ::CreateFile(filePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
opened = TRUE;
|
||||
}
|
||||
|
||||
UINT64 fileSize = 0;
|
||||
DWORD fileSizeLow = 0;
|
||||
DWORD fileSizeHigh = 0;
|
||||
fileSizeLow = ::GetFileSize(handle, &fileSizeHigh);
|
||||
if (fileSizeLow == INVALID_FILE_SIZE)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
|
||||
fileSize = (static_cast<UINT64>(fileSizeHigh) << 32) | fileSizeLow;
|
||||
|
||||
LARGE_INTEGER distanceToMove;
|
||||
if (DokanFileInfo->WriteToEndOfFile)
|
||||
{
|
||||
LARGE_INTEGER z;
|
||||
z.QuadPart = 0;
|
||||
if (!::SetFilePointerEx(handle, z, nullptr, FILE_END))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Paging IO cannot write after allocate file size.
|
||||
if (DokanFileInfo->PagingIo)
|
||||
{
|
||||
if (static_cast<UINT64>(Offset) >= fileSize)
|
||||
{
|
||||
*NumberOfBytesWritten = 0;
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ((static_cast<UINT64>(Offset) + NumberOfBytesToWrite) > fileSize)
|
||||
{
|
||||
UINT64 bytes = fileSize - Offset;
|
||||
if (bytes >> 32)
|
||||
{
|
||||
NumberOfBytesToWrite = static_cast<DWORD>(bytes & 0xFFFFFFFFUL);
|
||||
}
|
||||
else
|
||||
{
|
||||
NumberOfBytesToWrite = static_cast<DWORD>(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<UINT64>(Offset) > fileSize)
|
||||
{
|
||||
// In the mirror sample helperZeroFileData is not necessary. NTFS will
|
||||
// zero a hole.
|
||||
// But if user's file system is different from NTFS( or other Windows's
|
||||
// file systems ) then users will have to zero the hole themselves.
|
||||
}
|
||||
|
||||
distanceToMove.QuadPart = Offset;
|
||||
if (!::SetFilePointerEx(handle, distanceToMove, nullptr, FILE_BEGIN))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!::WriteFile(handle, Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, nullptr))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
return DokanNtStatusFromWin32(error);
|
||||
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
// close the file when it is reopened
|
||||
if (opened)
|
||||
CloseHandle(handle);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS DOKAN_CALLBACK Sia_SetEndOfFile(LPCWSTR FileName, LONGLONG ByteOffset, PDOKAN_FILE_INFO DokanFileInfo)
|
||||
{
|
||||
String filePath = StdConstructPath(GetCacheLocation(), FileName);
|
||||
HANDLE handle;
|
||||
LARGE_INTEGER offset;
|
||||
|
||||
handle = reinterpret_cast<HANDLE>(DokanFileInfo->Context);
|
||||
if (!handle || handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
offset.QuadPart = ByteOffset;
|
||||
if (!::SetFilePointerEx(handle, offset, nullptr, FILE_BEGIN))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
|
||||
if (!::SetEndOfFile(handle))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
return DokanNtStatusFromWin32(error);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void DOKAN_CALLBACK Sia_Cleanup(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo)
|
||||
{
|
||||
String filePath = StdConstructPath(GetCacheLocation(), FileName);
|
||||
|
||||
if (DokanFileInfo->Context)
|
||||
{
|
||||
::CloseHandle(reinterpret_cast<HANDLE>(DokanFileInfo->Context));
|
||||
_openFileMap.erase(DokanFileInfo->Context);
|
||||
DokanFileInfo->Context = 0;
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
if (DokanFileInfo->DeleteOnClose)
|
||||
{
|
||||
// Should already be deleted by CloseHandle
|
||||
// if open with FILE_FLAG_DELETE_ON_CLOSE
|
||||
if (DokanFileInfo->IsDirectory)
|
||||
{
|
||||
if (::RemoveDirectory(filePath.c_str()))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (::DeleteFile(filePath.c_str()) == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static void Initialize(CSiaApi* siaApi, CSiaDriveConfig* siaDriveConfig)
|
||||
{
|
||||
@@ -580,11 +844,11 @@ public:
|
||||
_siaDriveConfig = siaDriveConfig;
|
||||
// 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));
|
||||
_dokanOps.Cleanup = nullptr;
|
||||
_dokanOps.Cleanup = Sia_Cleanup;
|
||||
_dokanOps.CloseFile = Sia_CloseFile;
|
||||
_dokanOps.DeleteDirectory = nullptr;
|
||||
_dokanOps.DeleteFileW = nullptr;
|
||||
_dokanOps.FindFiles = SiaDrive_FindFiles;
|
||||
_dokanOps.FindFiles = Sia_FindFiles;
|
||||
_dokanOps.FindFilesWithPattern = nullptr;
|
||||
_dokanOps.FindStreams = nullptr;
|
||||
_dokanOps.FlushFileBuffers = nullptr;
|
||||
@@ -595,16 +859,16 @@ public:
|
||||
_dokanOps.LockFile = nullptr;
|
||||
_dokanOps.Mounted = Sia_Mounted;
|
||||
_dokanOps.MoveFileW = nullptr;
|
||||
_dokanOps.ReadFile = nullptr;
|
||||
_dokanOps.ReadFile = Sia_ReadFile;
|
||||
_dokanOps.SetAllocationSize = nullptr;
|
||||
_dokanOps.SetEndOfFile = nullptr;
|
||||
_dokanOps.SetEndOfFile = Sia_SetEndOfFile;
|
||||
_dokanOps.SetFileAttributesW = nullptr;
|
||||
_dokanOps.SetFileSecurityW = nullptr;
|
||||
_dokanOps.SetFileTime = nullptr;
|
||||
_dokanOps.UnlockFile = nullptr;
|
||||
_dokanOps.Unmounted = Sia_Unmounted;
|
||||
_dokanOps.WriteFile = nullptr;
|
||||
_dokanOps.ZwCreateFile = SiaDrive_ZwCreateFile;
|
||||
_dokanOps.WriteFile = Sia_WriteFile;
|
||||
_dokanOps.ZwCreateFile = Sia_ZwCreateFile;
|
||||
|
||||
ZeroMemory(&_dokanOptions, sizeof(DOKAN_OPTIONS));
|
||||
_dokanOptions.Version = DOKAN_VERSION;
|
||||
|
@@ -226,11 +226,6 @@ void CSiaDriveDlg::OnDocumentComplete(LPDISPATCH, LPCTSTR)
|
||||
}
|
||||
ClearDisplay();
|
||||
CallClientScript(L"setAvailableDrives", json(GetAvailableDrives()), nullptr);
|
||||
if (!_dokan)
|
||||
{
|
||||
_dokan.reset(new Dokan::CSiaDokanDrive(*_siaApi, &_siaConfig));
|
||||
_dokan->Mount('Y', CA2W(_siaConfig.GetCacheFolder().c_str()).m_psz, 10);
|
||||
}
|
||||
|
||||
SetTimer(IDT_UPDATE, 2000, nullptr);
|
||||
SetTimer(IDT_UI_ACTION_QUEUE, 100, nullptr);
|
||||
@@ -491,6 +486,11 @@ void CSiaDriveDlg::ConfigureWallet()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_dokan)
|
||||
{
|
||||
_dokan.reset(new Dokan::CSiaDokanDrive(*_siaApi, &_siaConfig));
|
||||
_dokan->Mount('Y', CA2W(_siaConfig.GetCacheFolder().c_str()).m_psz, 10);
|
||||
}
|
||||
SetMainWindow(L"ID_TabWindow");
|
||||
|
||||
switch (_siaConfig.GetUI_Main_TabIndex())
|
||||
|
Reference in New Issue
Block a user