1
0

Fix multiple downloads on ReadFile()

This commit is contained in:
Scott E. Graves
2017-04-07 14:30:56 -05:00
parent d9189c80bb
commit 0c8c47f8a1

View File

@@ -39,6 +39,140 @@ private:
DWORD AttributesAndFlags; DWORD AttributesAndFlags;
} OpenFileInfo; } OpenFileInfo;
class DownloadToCacheBegin :
public CEvent
{
public:
DownloadToCacheBegin(const OpenFileInfo& openFileInfo, const SString& tempFilePath) :
_openFileInfo(openFileInfo),
_tempFilePath(tempFilePath)
{
}
public:
virtual ~DownloadToCacheBegin() {}
private:
const OpenFileInfo _openFileInfo;
const SString _tempFilePath;
public:
virtual SString GetSingleLineMessage() const override
{
return "DownloadToCacheBegin|FP|" + _openFileInfo.CacheFilePath +
"|SP|" + _openFileInfo.SiaPath +
"|TP|" + _tempFilePath;
}
virtual std::shared_ptr<CEvent> Clone() const override
{
return std::shared_ptr<CEvent>(new DownloadToCacheBegin(_openFileInfo, _tempFilePath));
}
};
class DownloadToCacheEnd :
public CEvent
{
public:
DownloadToCacheEnd(const OpenFileInfo& openFileInfo, const SString& tempFilePath, const bool& result) :
_openFileInfo(openFileInfo),
_tempFilePath(tempFilePath),
_result(result)
{
}
public:
virtual ~DownloadToCacheEnd() {}
private:
const OpenFileInfo _openFileInfo;
const SString _tempFilePath;
const bool _result;
public:
virtual SString GetSingleLineMessage() const override
{
return "DownloadToCacheEnd|FP|" + _openFileInfo.CacheFilePath +
"|SP|" + _openFileInfo.SiaPath +
"|TP|" + _tempFilePath +
"|RES|" + SString::FromBool(_result);
}
virtual std::shared_ptr<CEvent> Clone() const override
{
return std::shared_ptr<CEvent>(new DownloadToCacheEnd(_openFileInfo, _tempFilePath, _result));
}
};
class MoveTempToCacheResult :
public CEvent
{
public:
MoveTempToCacheResult(const OpenFileInfo& openFileInfo, const SString& tempFilePath, const bool& result) :
_openFileInfo(openFileInfo),
_tempFilePath(tempFilePath),
_result(result)
{
}
public:
virtual ~MoveTempToCacheResult() {}
private:
const OpenFileInfo _openFileInfo;
const SString _tempFilePath;
const bool _result;
public:
virtual SString GetSingleLineMessage() const override
{
return "MoveTempToCacheResult|FP|" + _openFileInfo.CacheFilePath +
"|SP|" + _openFileInfo.SiaPath +
"|TP|" + _tempFilePath +
"|RES|" + SString::FromBool(_result);
}
virtual std::shared_ptr<CEvent> Clone() const override
{
return std::shared_ptr<CEvent>(new MoveTempToCacheResult(_openFileInfo, _tempFilePath, _result));
}
};
class AddToCacheComplete :
public CEvent
{
public:
AddToCacheComplete(const OpenFileInfo& openFileInfo, const bool& result) :
_openFileInfo(openFileInfo),
_result(result)
{
}
public:
virtual ~AddToCacheComplete() {}
private:
const OpenFileInfo _openFileInfo;
const bool _result;
public:
virtual SString GetSingleLineMessage() const override
{
return "AddToCacheComplete|FP|" + _openFileInfo.CacheFilePath +
"|SP|" + _openFileInfo.SiaPath +
"|RES|" + SString::FromBool(_result);
}
virtual std::shared_ptr<CEvent> Clone() const override
{
return std::shared_ptr<CEvent>(new AddToCacheComplete(_openFileInfo, _result));
}
};
private: private:
static std::mutex _dokanMutex; static std::mutex _dokanMutex;
static CSiaApi* _siaApi; static CSiaApi* _siaApi;
@@ -50,7 +184,7 @@ private:
static std::unique_ptr<std::thread> _fileListThread; static std::unique_ptr<std::thread> _fileListThread;
static HANDLE _fileListStopEvent; static HANDLE _fileListStopEvent;
static CSiaFileTreePtr _siaFileTree; static CSiaFileTreePtr _siaFileTree;
static std::mutex _fileTreeMutex; static std::mutex _openFileMutex;
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;
@@ -70,50 +204,56 @@ private:
static bool AddFileToCache(OpenFileInfo& openFileInfo, PDOKAN_FILE_INFO dokanFileInfo) static bool AddFileToCache(OpenFileInfo& openFileInfo, PDOKAN_FILE_INFO dokanFileInfo)
{ {
FilePath tempFilePath = FilePath::GetTempDirectory(); bool ret = true;
tempFilePath.Append(GenerateSha256(openFileInfo.SiaPath) + ".siatmp"); if (openFileInfo.Dummy)
bool ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(openFileInfo.SiaPath, tempFilePath));
if (ret)
{ {
// Find all open handles for requested file FilePath tempFilePath = FilePath::GetTempDirectory();
std::vector<OpenFileInfo*> matched; tempFilePath.Append(GenerateSha256(openFileInfo.SiaPath) + ".siatmp");
matched.push_back(&openFileInfo);
{
std::lock_guard<std::mutex> l(_fileTreeMutex);
std::for_each(_openFiles.begin(), _openFiles.end(), [&](OpenFileInfo* ofi)
{
if ((ofi->FileHandle != openFileInfo.FileHandle) && (ofi->SiaPath == openFileInfo.SiaPath))
{
matched.push_back(ofi);
}
});
}
// Close all to allow move to complete CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DownloadToCacheBegin(openFileInfo, tempFilePath)));
for (auto* ofi : matched) ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(openFileInfo.SiaPath, tempFilePath));
{ CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(DownloadToCacheEnd(openFileInfo, tempFilePath, ret)));
::CloseHandle(ofi->FileHandle);
}
FilePath src(tempFilePath);
FilePath dest(openFileInfo.CacheFilePath);
ret = dest.DeleteFile() && src.MoveFile(dest);
if (ret) if (ret)
{ {
openFileInfo.Dummy = false; // Find all open handles for requested file
} std::vector<OpenFileInfo*> matched;
else matched.push_back(&openFileInfo);
{ std::lock_guard<std::mutex> l(_openFileMutex);
src.DeleteFile(); {
} std::for_each(_openFiles.begin(), _openFiles.end(), [&](OpenFileInfo* ofi)
{
if ((ofi->FileHandle != openFileInfo.FileHandle) && (ofi->SiaPath == openFileInfo.SiaPath))
{
matched.push_back(ofi);
}
});
}
// Re-open all files // Close all to allow move to complete
for (auto& ofi : matched) for (auto* ofi : matched)
{ {
ofi->FileHandle = ::CreateFile(&ofi->CacheFilePath[0], ofi->DesiredAccess, ofi->ShareMode, ofi->SecurityAttrib.nLength ? &ofi->SecurityAttrib : nullptr, ofi->CreateDisp, ofi->AttributesAndFlags, nullptr); ::CloseHandle(ofi->FileHandle);
}
FilePath src(tempFilePath);
FilePath dest(openFileInfo.CacheFilePath);
ret = dest.DeleteFile() && src.MoveFile(dest);
if (!ret)
{
src.DeleteFile();
}
CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(MoveTempToCacheResult(openFileInfo, tempFilePath, ret)));
// Re-open all files
for (auto& ofi : matched)
{
ofi->FileHandle = ::CreateFile(&ofi->CacheFilePath[0], ofi->DesiredAccess, ofi->ShareMode, ofi->SecurityAttrib.nLength ? &ofi->SecurityAttrib : nullptr, ofi->CreateDisp, ofi->AttributesAndFlags, nullptr);
ofi->Dummy = !ret;
}
} }
} }
CEventSystem::EventSystem.NotifyEvent(CreateSystemEvent(AddToCacheComplete(openFileInfo, ret)));
return ret; return ret;
} }
@@ -162,7 +302,7 @@ private:
::CloseHandle(openFileInfo.FileHandle); ::CloseHandle(openFileInfo.FileHandle);
} }
std::lock_guard<std::mutex> l(_fileTreeMutex); std::lock_guard<std::mutex> l(_openFileMutex);
_openFiles.erase(std::remove(_openFiles.begin(), _openFiles.end(), &openFileInfo), _openFiles.end()); _openFiles.erase(std::remove(_openFiles.begin(), _openFiles.end(), &openFileInfo), _openFiles.end());
} }
@@ -433,6 +573,7 @@ private:
if (ret == STATUS_SUCCESS) if (ret == STATUS_SUCCESS)
{ {
std::lock_guard<std::mutex> l(_openFileMutex);
// Create file as specified // Create file as specified
HANDLE handle = ::CreateFile( HANDLE handle = ::CreateFile(
&cacheFilePath[0], &cacheFilePath[0],
@@ -469,7 +610,6 @@ private:
ofi->CreateDisp = createDisposition; ofi->CreateDisp = createDisposition;
ofi->AttributesAndFlags = fileAttributesAndFlags; ofi->AttributesAndFlags = fileAttributesAndFlags;
dokanFileInfo->Context = reinterpret_cast<ULONG64>(ofi); dokanFileInfo->Context = reinterpret_cast<ULONG64>(ofi);
std::lock_guard<std::mutex> l(_fileTreeMutex);
_openFiles.push_back(ofi); _openFiles.push_back(ofi);
} }
} }
@@ -1510,7 +1650,7 @@ DOKAN_OPTIONS DokanImpl::_dokanOptions;
FilePath DokanImpl::_cacheLocation; FilePath DokanImpl::_cacheLocation;
HANDLE DokanImpl::_fileListStopEvent; HANDLE DokanImpl::_fileListStopEvent;
CSiaFileTreePtr DokanImpl::_siaFileTree; CSiaFileTreePtr DokanImpl::_siaFileTree;
std::mutex DokanImpl::_fileTreeMutex; std::mutex DokanImpl::_openFileMutex;
std::unique_ptr<std::thread> DokanImpl::_fileListThread; 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;