Try to fix download
This commit is contained in:
@@ -49,6 +49,7 @@ private:
|
|||||||
static std::unique_ptr<std::thread> _mountThread;
|
static std::unique_ptr<std::thread> _mountThread;
|
||||||
static NTSTATUS _mountStatus;
|
static NTSTATUS _mountStatus;
|
||||||
static SString _mountPoint;
|
static SString _mountPoint;
|
||||||
|
static std::vector<SString> _activeDownloads;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static const FilePath& GetCacheLocation()
|
inline static const FilePath& GetCacheLocation()
|
||||||
@@ -64,47 +65,44 @@ private:
|
|||||||
|
|
||||||
static bool AddFileToCache(OpenFileInfo& openFileInfo, PDOKAN_FILE_INFO dokanFileInfo)
|
static bool AddFileToCache(OpenFileInfo& openFileInfo, PDOKAN_FILE_INFO dokanFileInfo)
|
||||||
{
|
{
|
||||||
bool active = true;
|
{
|
||||||
bool ret = false;
|
std::lock_guard<std::mutex> l(_fileTreeMutex);
|
||||||
|
_activeDownloads.push_back(openFileInfo.SiaPath);
|
||||||
|
}
|
||||||
|
|
||||||
std::thread th([&] {
|
FilePath tempFilePath = FilePath::GetTempDirectory();
|
||||||
FilePath tempFilePath = FilePath::GetTempDirectory();
|
tempFilePath.Append(GenerateSha256(openFileInfo.SiaPath) + ".siatmp");
|
||||||
tempFilePath.Append(GenerateSha256(openFileInfo.SiaPath) + ".siatmp");
|
bool ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(openFileInfo.SiaPath, tempFilePath));
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
::CloseHandle(openFileInfo.FileHandle);
|
||||||
|
|
||||||
// TODO Check cache size is large enough to hold new file
|
FilePath src(tempFilePath);
|
||||||
ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(openFileInfo.SiaPath, tempFilePath));
|
FilePath dest(GetCacheLocation(), openFileInfo.SiaPath);
|
||||||
|
ret = dest.DeleteFile();
|
||||||
|
ret = ret && src.MoveFile(dest);
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
::CloseHandle(openFileInfo.FileHandle);
|
HANDLE handle = ::CreateFile(&dest[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
FilePath src(tempFilePath);
|
|
||||||
FilePath dest(GetCacheLocation(), openFileInfo.SiaPath);
|
|
||||||
ret = dest.DeleteFile() && src.MoveFile(dest);
|
|
||||||
if (ret)
|
|
||||||
{
|
{
|
||||||
HANDLE handle = ::CreateFile(&dest[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
ret = false;
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
openFileInfo.Dummy = false;
|
|
||||||
openFileInfo.FileHandle = handle;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
src.DeleteFile();
|
openFileInfo.Dummy = false;
|
||||||
|
openFileInfo.FileHandle = handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
active = false;
|
else
|
||||||
});
|
{
|
||||||
th.detach();
|
src.DeleteFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (active)
|
|
||||||
{
|
{
|
||||||
::Sleep(10);
|
std::lock_guard<std::mutex> l(_fileTreeMutex);
|
||||||
|
_activeDownloads.erase(std::remove(_activeDownloads.begin(), _activeDownloads.end(), openFileInfo.SiaPath), _activeDownloads.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -302,167 +300,178 @@ private:
|
|||||||
SString siaPath = CSiaApi::FormatToSiaPath(fileName); // Strip drive letter to get Sia path
|
SString siaPath = CSiaApi::FormatToSiaPath(fileName); // 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
|
{
|
||||||
DWORD attribs = ::GetFileAttributes(&cacheFilePath[0]);
|
std::lock_guard<std::mutex> l(_fileTreeMutex);
|
||||||
if ((attribs != INVALID_FILE_ATTRIBUTES) && (attribs & FILE_ATTRIBUTE_DIRECTORY))
|
if (std::find(_activeDownloads.begin(), _activeDownloads.end(), siaPath) != _activeDownloads.end())
|
||||||
{
|
{
|
||||||
ret = STATUS_OBJECT_NAME_COLLISION;
|
ret = STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
bool siaExists;
|
|
||||||
if (ApiSuccess(_siaApi->GetRenter()->FileExists(siaPath, siaExists)))
|
|
||||||
{
|
|
||||||
bool exists = siaExists || cacheFilePath.IsFile();
|
|
||||||
// Operations on existing files that are requested to be truncated, overwritten or re-created
|
|
||||||
// will first be deleted and then replaced if, after the file operation is done, the resulting file
|
|
||||||
// size is > 0. Sia doesn't support random access to files (upload/download/rename/delete).
|
|
||||||
bool isCreateOp = false;
|
|
||||||
bool isReplaceOp = false;
|
|
||||||
switch (creationDisposition)
|
|
||||||
{
|
|
||||||
case CREATE_ALWAYS:
|
|
||||||
{
|
|
||||||
isCreateOp = true;
|
|
||||||
isReplaceOp = exists;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CREATE_NEW:
|
if (ret == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
if (exists)
|
// If cache file already exists and is a directory, requested file operation isn't valid
|
||||||
{
|
DWORD attribs = ::GetFileAttributes(&cacheFilePath[0]);
|
||||||
ret = STATUS_OBJECT_NAME_EXISTS;
|
if ((attribs != INVALID_FILE_ATTRIBUTES) && (attribs & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
}
|
{
|
||||||
else
|
ret = STATUS_OBJECT_NAME_COLLISION;
|
||||||
{
|
}
|
||||||
isCreateOp = true;
|
else
|
||||||
}
|
{
|
||||||
}
|
bool siaExists;
|
||||||
break;
|
if (ApiSuccess(_siaApi->GetRenter()->FileExists(siaPath, siaExists)))
|
||||||
|
{
|
||||||
|
bool exists = siaExists || cacheFilePath.IsFile();
|
||||||
|
// Operations on existing files that are requested to be truncated, overwritten or re-created
|
||||||
|
// will first be deleted and then replaced if, after the file operation is done, the resulting file
|
||||||
|
// size is > 0. Sia doesn't support random access to files (upload/download/rename/delete).
|
||||||
|
bool isCreateOp = false;
|
||||||
|
bool isReplaceOp = false;
|
||||||
|
switch (creationDisposition)
|
||||||
|
{
|
||||||
|
case CREATE_ALWAYS:
|
||||||
|
{
|
||||||
|
isCreateOp = true;
|
||||||
|
isReplaceOp = exists;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPEN_ALWAYS:
|
case CREATE_NEW:
|
||||||
{
|
{
|
||||||
if (!exists)
|
if (exists)
|
||||||
{
|
{
|
||||||
isCreateOp = true;
|
ret = STATUS_OBJECT_NAME_EXISTS;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
break;
|
{
|
||||||
|
isCreateOp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPEN_EXISTING:
|
case OPEN_ALWAYS:
|
||||||
{
|
{
|
||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
ret = STATUS_OBJECT_NAME_NOT_FOUND;
|
isCreateOp = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRUNCATE_EXISTING:
|
case OPEN_EXISTING:
|
||||||
{
|
{
|
||||||
if (exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
isCreateOp = isReplaceOp = true;
|
ret = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
break;
|
||||||
ret = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
case TRUNCATE_EXISTING:
|
||||||
// Nothing to do
|
{
|
||||||
break;
|
if (exists)
|
||||||
}
|
{
|
||||||
|
isCreateOp = isReplaceOp = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (ret == STATUS_SUCCESS)
|
default:
|
||||||
{
|
// Nothing to do
|
||||||
if (isReplaceOp)
|
break;
|
||||||
{
|
}
|
||||||
// Since this is a request to replace an existing file, make sure cache is deleted first.
|
|
||||||
// If file isn't cached, delete from Sia only
|
|
||||||
if (!cacheFilePath.IsFile() || cacheFilePath.DeleteFile())
|
|
||||||
{
|
|
||||||
if (!ApiSuccess(_uploadManager->Remove(siaPath)))
|
|
||||||
{
|
|
||||||
ret = STATUS_INVALID_SERVER_STATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = DokanNtStatusFromWin32(GetLastError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDummy = false;
|
if (ret == STATUS_SUCCESS)
|
||||||
if (ret == STATUS_SUCCESS)
|
{
|
||||||
{
|
if (isReplaceOp)
|
||||||
if (!isCreateOp)
|
{
|
||||||
{
|
// Since this is a request to replace an existing file, make sure cache is deleted first.
|
||||||
if (cacheFilePath.IsFile())
|
// If file isn't cached, delete from Sia only
|
||||||
|
if (!cacheFilePath.IsFile() || cacheFilePath.DeleteFile())
|
||||||
{
|
{
|
||||||
isDummy = (siaExists && (FileSize(&cacheFilePath[0]) == 0));
|
if (!ApiSuccess(_uploadManager->Remove(siaPath)))
|
||||||
}
|
|
||||||
else if (siaExists)
|
|
||||||
{
|
|
||||||
isDummy = AddDummyFileToCache(siaPath);
|
|
||||||
if (!isDummy)
|
|
||||||
{
|
{
|
||||||
ret = STATUS_ACCESS_DENIED;
|
ret = STATUS_INVALID_SERVER_STATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = STATUS_NOT_FOUND;
|
ret = DokanNtStatusFromWin32(GetLastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == STATUS_SUCCESS)
|
bool isDummy = false;
|
||||||
{
|
if (ret == STATUS_SUCCESS)
|
||||||
// Create file as specified
|
{
|
||||||
HANDLE handle = ::CreateFile(
|
if (!isCreateOp)
|
||||||
&cacheFilePath[0],
|
{
|
||||||
genericDesiredAccess,
|
if (cacheFilePath.IsFile())
|
||||||
shareAccess,
|
|
||||||
&securityAttrib,
|
|
||||||
creationDisposition,
|
|
||||||
fileAttributesAndFlags,
|
|
||||||
nullptr);
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
ret = DokanNtStatusFromWin32(GetLastError());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((creationDisposition == OPEN_ALWAYS) || (creationDisposition == CREATE_ALWAYS))
|
|
||||||
{
|
{
|
||||||
DWORD error = GetLastError();
|
isDummy = (siaExists && (FileSize(&cacheFilePath[0]) == 0));
|
||||||
if (error == ERROR_ALREADY_EXISTS)
|
}
|
||||||
|
else if (siaExists)
|
||||||
|
{
|
||||||
|
isDummy = AddDummyFileToCache(siaPath);
|
||||||
|
if (!isDummy)
|
||||||
{
|
{
|
||||||
ret = STATUS_OBJECT_NAME_COLLISION;
|
ret = STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OpenFileInfo* ofi = new OpenFileInfo();
|
if (ret == STATUS_SUCCESS)
|
||||||
ofi->SiaPath = siaPath;
|
{
|
||||||
ofi->CacheFilePath = cacheFilePath;
|
// Create file as specified
|
||||||
// TODO Detect if file is read-only
|
HANDLE handle = ::CreateFile(
|
||||||
ofi->Dummy = isDummy;
|
&cacheFilePath[0],
|
||||||
ofi->Changed = false;
|
genericDesiredAccess,
|
||||||
ofi->FileHandle = handle;
|
shareAccess,
|
||||||
dokanFileInfo->Context = reinterpret_cast<ULONG64>(ofi);
|
&securityAttrib,
|
||||||
}
|
creationDisposition,
|
||||||
}
|
fileAttributesAndFlags,
|
||||||
}
|
nullptr);
|
||||||
}
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
}
|
{
|
||||||
else
|
ret = DokanNtStatusFromWin32(GetLastError());
|
||||||
{
|
}
|
||||||
ret = STATUS_INVALID_SERVER_STATE;
|
else
|
||||||
}
|
{
|
||||||
}
|
if ((creationDisposition == OPEN_ALWAYS) || (creationDisposition == CREATE_ALWAYS))
|
||||||
|
{
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
if (error == ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
|
ret = STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenFileInfo* ofi = new OpenFileInfo();
|
||||||
|
ofi->SiaPath = siaPath;
|
||||||
|
ofi->CacheFilePath = cacheFilePath;
|
||||||
|
// TODO Detect if file is read-only
|
||||||
|
ofi->Dummy = isDummy;
|
||||||
|
ofi->Changed = false;
|
||||||
|
ofi->FileHandle = handle;
|
||||||
|
dokanFileInfo->Context = reinterpret_cast<ULONG64>(ofi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = STATUS_INVALID_SERVER_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1492,6 +1501,7 @@ std::unique_ptr<std::thread> DokanImpl::_fileListThread;
|
|||||||
std::unique_ptr<std::thread> DokanImpl::_mountThread;
|
std::unique_ptr<std::thread> DokanImpl::_mountThread;
|
||||||
NTSTATUS DokanImpl::_mountStatus = STATUS_SUCCESS;
|
NTSTATUS DokanImpl::_mountStatus = STATUS_SUCCESS;
|
||||||
SString DokanImpl::_mountPoint;
|
SString DokanImpl::_mountPoint;
|
||||||
|
std::vector<SString> DokanImpl::_activeDownloads;
|
||||||
|
|
||||||
CSiaDokanDrive::CSiaDokanDrive(CSiaApi& siaApi, CSiaDriveConfig* siaDriveConfig) :
|
CSiaDokanDrive::CSiaDokanDrive(CSiaApi& siaApi, CSiaDriveConfig* siaDriveConfig) :
|
||||||
_siaApi(siaApi),
|
_siaApi(siaApi),
|
||||||
|
Reference in New Issue
Block a user