1
0

Continue drive support

This commit is contained in:
Scott E. Graves
2017-03-15 02:27:27 -05:00
parent 1acae236c8
commit c1914a5e21
2 changed files with 282 additions and 18 deletions

View File

@@ -130,7 +130,7 @@ private:
// Dokan callbacks // Dokan callbacks
private: private:
static NTSTATUS DOKAN_CALLBACK SiaDrive_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,
@@ -180,16 +180,50 @@ private:
// Folder (cache operation only) // Folder (cache operation only)
if (DokanFileInfo->IsDirectory) if (DokanFileInfo->IsDirectory)
{ {
HANDLE handle = ::CreateFile(cacheFilePath.c_str(), genericDesiredAccess, ShareAccess, &securityAttrib, creationDisposition, fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (creationDisposition == CREATE_NEW)
{
if (!::CreateDirectory(cacheFilePath.c_str(), &securityAttrib))
{
DWORD error = GetLastError();
ret = DokanNtStatusFromWin32(error);
}
}
else if (creationDisposition == OPEN_ALWAYS)
{
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) if (handle == INVALID_HANDLE_VALUE)
{ {
ret = DokanNtStatusFromWin32(GetLastError()); DWORD error = GetLastError();
ret = DokanNtStatusFromWin32(error);
} }
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 and cache path // Formulate Sia path and cache path
@@ -359,7 +393,7 @@ private:
return ret; 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); std::lock_guard<std::mutex> l(_dokanMutex);
auto siaFileTree = _siaFileTree; auto siaFileTree = _siaFileTree;
@@ -573,6 +607,236 @@ private:
return STATUS_SUCCESS; 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: public:
static void Initialize(CSiaApi* siaApi, CSiaDriveConfig* siaDriveConfig) static void Initialize(CSiaApi* siaApi, CSiaDriveConfig* siaDriveConfig)
{ {
@@ -580,11 +844,11 @@ public:
_siaDriveConfig = siaDriveConfig; _siaDriveConfig = siaDriveConfig;
// 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));
_dokanOps.Cleanup = nullptr; _dokanOps.Cleanup = Sia_Cleanup;
_dokanOps.CloseFile = Sia_CloseFile; _dokanOps.CloseFile = Sia_CloseFile;
_dokanOps.DeleteDirectory = nullptr; _dokanOps.DeleteDirectory = nullptr;
_dokanOps.DeleteFileW = nullptr; _dokanOps.DeleteFileW = nullptr;
_dokanOps.FindFiles = SiaDrive_FindFiles; _dokanOps.FindFiles = Sia_FindFiles;
_dokanOps.FindFilesWithPattern = nullptr; _dokanOps.FindFilesWithPattern = nullptr;
_dokanOps.FindStreams = nullptr; _dokanOps.FindStreams = nullptr;
_dokanOps.FlushFileBuffers = nullptr; _dokanOps.FlushFileBuffers = nullptr;
@@ -595,16 +859,16 @@ public:
_dokanOps.LockFile = nullptr; _dokanOps.LockFile = nullptr;
_dokanOps.Mounted = Sia_Mounted; _dokanOps.Mounted = Sia_Mounted;
_dokanOps.MoveFileW = nullptr; _dokanOps.MoveFileW = nullptr;
_dokanOps.ReadFile = nullptr; _dokanOps.ReadFile = Sia_ReadFile;
_dokanOps.SetAllocationSize = nullptr; _dokanOps.SetAllocationSize = nullptr;
_dokanOps.SetEndOfFile = nullptr; _dokanOps.SetEndOfFile = Sia_SetEndOfFile;
_dokanOps.SetFileAttributesW = nullptr; _dokanOps.SetFileAttributesW = nullptr;
_dokanOps.SetFileSecurityW = nullptr; _dokanOps.SetFileSecurityW = nullptr;
_dokanOps.SetFileTime = nullptr; _dokanOps.SetFileTime = nullptr;
_dokanOps.UnlockFile = nullptr; _dokanOps.UnlockFile = nullptr;
_dokanOps.Unmounted = Sia_Unmounted; _dokanOps.Unmounted = Sia_Unmounted;
_dokanOps.WriteFile = nullptr; _dokanOps.WriteFile = Sia_WriteFile;
_dokanOps.ZwCreateFile = SiaDrive_ZwCreateFile; _dokanOps.ZwCreateFile = Sia_ZwCreateFile;
ZeroMemory(&_dokanOptions, sizeof(DOKAN_OPTIONS)); ZeroMemory(&_dokanOptions, sizeof(DOKAN_OPTIONS));
_dokanOptions.Version = DOKAN_VERSION; _dokanOptions.Version = DOKAN_VERSION;

View File

@@ -226,11 +226,6 @@ void CSiaDriveDlg::OnDocumentComplete(LPDISPATCH, LPCTSTR)
} }
ClearDisplay(); ClearDisplay();
CallClientScript(L"setAvailableDrives", json(GetAvailableDrives()), nullptr); 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_UPDATE, 2000, nullptr);
SetTimer(IDT_UI_ACTION_QUEUE, 100, nullptr); SetTimer(IDT_UI_ACTION_QUEUE, 100, nullptr);
@@ -491,6 +486,11 @@ void CSiaDriveDlg::ConfigureWallet()
} }
else 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"); SetMainWindow(L"ID_TabWindow");
switch (_siaConfig.GetUI_Main_TabIndex()) switch (_siaConfig.GetUI_Main_TabIndex())