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
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;