Index: src/libchcore/TLocalFilesystem.cpp =================================================================== diff -u -N -r16df8fcf9d5b3317338aece64762771419beaf4a -r6103ac74583f2136b821dc67515ed8469abd8155 --- src/libchcore/TLocalFilesystem.cpp (.../TLocalFilesystem.cpp) (revision 16df8fcf9d5b3317338aece64762771419beaf4a) +++ src/libchcore/TLocalFilesystem.cpp (.../TLocalFilesystem.cpp) (revision 6103ac74583f2136b821dc67515ed8469abd8155) @@ -23,6 +23,7 @@ #include "stdafx.h" #include "TLocalFilesystem.h" #include +#include #include "TAutoHandles.h" #include "TFileInfo.h" #include "DataBuffer.h" @@ -33,11 +34,12 @@ #pragma warning(disable: 4201) #include #pragma warning(pop) -#include "TDataBuffer.h" #include "TCoreException.h" #include "ErrorCodes.h" #include "TPathContainer.h" #include "TFileTime.h" +#include "TOverlappedDataBuffer.h" +#include "RoundingFunctions.h" BEGIN_CHCORE_NAMESPACE @@ -376,7 +378,8 @@ TLocalFilesystemFile::TLocalFilesystemFile() : m_hFile(INVALID_HANDLE_VALUE), - m_pathFile() + m_pathFile(), + m_bNoBuffering(false) { } @@ -389,29 +392,38 @@ { Close(); - m_hFile = ::CreateFile(TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile).ToString(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + m_pathFile = TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile); + m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); if(m_hFile == INVALID_HANDLE_VALUE) return false; + + m_bNoBuffering = bNoBuffering; return true; } bool TLocalFilesystemFile::CreateNewForWriting(const TSmartPath& pathFile, bool bNoBuffering) { Close(); - m_hFile = ::CreateFile(TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile).ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + m_pathFile = TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile); + m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); if(m_hFile == INVALID_HANDLE_VALUE) return false; + + m_bNoBuffering = bNoBuffering; return true; } bool TLocalFilesystemFile::OpenExistingForWriting(const TSmartPath& pathFile, bool bNoBuffering) { Close(); - m_hFile = CreateFile(TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile).ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + m_pathFile = TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile); + m_hFile = CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); if(m_hFile == INVALID_HANDLE_VALUE) return false; + + m_bNoBuffering = bNoBuffering; return true; } @@ -436,20 +448,69 @@ return ::SetEndOfFile(m_hFile) != FALSE; } -bool TLocalFilesystemFile::ReadFile(TSimpleDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead) +bool TLocalFilesystemFile::ReadFile(TOverlappedDataBuffer& rBuffer) { - if(!IsOpen()) - return false; + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - return ::ReadFile(m_hFile, rBuffer.GetBufferPtr(), dwToRead, &rdwBytesRead, NULL) != FALSE; + if (!::ReadFileEx(m_hFile, rBuffer.GetBufferPtr(), rBuffer.GetRequestedDataSize(), &rBuffer, OverlappedReadCompleted)) + { + DWORD dwLastError = GetLastError(); + switch(dwLastError) + { + case ERROR_IO_PENDING: + return true; + + case ERROR_HANDLE_EOF: + { + rBuffer.SetBytesTransferred(0); + rBuffer.SetStatusCode(ERROR_SUCCESS); + rBuffer.SetLastPart(true); + + rBuffer.RequeueAsFull(); // basically the same as OverlappedReadCompleted + + return true; + } + } + + return false; + } + return true; } -bool TLocalFilesystemFile::WriteFile(TSimpleDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten) +bool TLocalFilesystemFile::WriteFile(TOverlappedDataBuffer& rBuffer) { - if(!IsOpen()) + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + + DWORD dwToWrite = boost::numeric_cast(rBuffer.GetBytesTransferred()); + unsigned long long ullNewFileSize = 0; + + if (m_bNoBuffering && rBuffer.IsLastPart()) + { + dwToWrite = RoundUp(dwToWrite, MaxSectorSize); + if(dwToWrite != boost::numeric_cast(rBuffer.GetBytesTransferred())) + ullNewFileSize = rBuffer.GetFilePosition() + dwToWrite; // new size + } + + if (!::WriteFileEx(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rBuffer, OverlappedWriteCompleted)) return false; - return ::WriteFile(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rdwBytesWritten, NULL) != NULL && dwToWrite == rdwBytesWritten; + if(ullNewFileSize != 0) + { + if(!OpenExistingForWriting(m_pathFile, false)) + return false; + + //seek + if(!SetFilePointer(ullNewFileSize, FILE_BEGIN)) + return false; + + //set eof + if(!SetEndOfFile()) + return false; + } + + return true; } void TLocalFilesystemFile::Close()