Index: src/libchcore/TLocalFilesystemFile.cpp =================================================================== diff -u -N -r8068e0c351055554340ac9755d1bc846893bf2b8 -rf8fcbbd1d2321cf0c8be79526c449384af654e49 --- src/libchcore/TLocalFilesystemFile.cpp (.../TLocalFilesystemFile.cpp) (revision 8068e0c351055554340ac9755d1bc846893bf2b8) +++ src/libchcore/TLocalFilesystemFile.cpp (.../TLocalFilesystemFile.cpp) (revision f8fcbbd1d2321cf0c8be79526c449384af654e49) @@ -28,16 +28,18 @@ #include "TCoreWin32Exception.h" #include "TFileException.h" #include "TFileInfo.h" +#include "StreamingHelpers.h" namespace chcore { // compile-time check - ensure the buffer granularity used for transfers are bigger than expected sector size static_assert(TLocalFilesystemFile::MaxSectorSize <= TBufferSizes::BufferGranularity, "Buffer granularity must be equal to or bigger than the max sector size"); - TLocalFilesystemFile::TLocalFilesystemFile(const TSmartPath& pathFile, bool bNoBuffering) : + TLocalFilesystemFile::TLocalFilesystemFile(const TSmartPath& pathFile, bool bNoBuffering, const logger::TLogFileDataPtr& spLogFileData) : m_pathFile(TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile)), m_hFile(INVALID_HANDLE_VALUE), - m_bNoBuffering(bNoBuffering) + m_bNoBuffering(bNoBuffering), + m_spLog(logger::MakeLogger(spLogFileData, L"Filesystem-File")) { if (pathFile.IsEmpty()) throw TCoreException(eErr_InvalidArgument, L"pathFile", LOCATION); @@ -63,24 +65,34 @@ { Close(); + LOG_DEBUG(m_spLog) << L"Opening existing file for reading" << GetFileInfoForLog(m_bNoBuffering); + m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, GetFlagsAndAttributes(m_bNoBuffering), nullptr); if (m_hFile == INVALID_HANDLE_VALUE) { DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << "Opening file for reading failed with error: " << dwLastError << GetFileInfoForLog(m_bNoBuffering); + throw TFileException(eErr_CannotOpenFile, dwLastError, m_pathFile, L"Cannot open for reading", LOCATION); } + + LOG_DEBUG(m_spLog) << "Opening file for reading succeeded. New handle: " << m_hFile << GetFileInfoForLog(m_bNoBuffering); } void TLocalFilesystemFile::CreateNewForWriting() { Close(); + LOG_DEBUG(m_spLog) << "Creating new file for writing" << GetFileInfoForLog(m_bNoBuffering); + m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_NEW, GetFlagsAndAttributes(m_bNoBuffering), nullptr); if (m_hFile == INVALID_HANDLE_VALUE) { DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << "CreateNewForWriting failed with error: " << dwLastError << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_CannotOpenFile, dwLastError, m_pathFile, L"Cannot create file.", LOCATION); } + LOG_DEBUG(m_spLog) << "CreateNewForWriting succeeded. New handle: " << m_hFile << GetFileInfoForLog(m_bNoBuffering); } void TLocalFilesystemFile::OpenExistingForWriting() @@ -92,24 +104,36 @@ { Close(); + LOG_DEBUG(m_spLog) << "OpenExistingForWriting" << GetFileInfoForLog(bNoBuffering); + m_hFile = CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, GetFlagsAndAttributes(bNoBuffering), nullptr); if (m_hFile == INVALID_HANDLE_VALUE) { DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << "OpenExistingForWriting failed with error: " << dwLastError << GetFileInfoForLog(bNoBuffering); + throw TFileException(eErr_CannotOpenFile, dwLastError, m_pathFile, L"Cannot open for reading.", LOCATION); } + LOG_DEBUG(m_spLog) << "OpenExistingForWriting succeeded. New handle: " << m_hFile << GetFileInfoForLog(bNoBuffering); } file_size_t TLocalFilesystemFile::GetSeekPositionForResume(file_size_t fsLastAvailablePosition) { file_size_t fsMove = (m_bNoBuffering ? RoundDown(fsLastAvailablePosition, MaxSectorSize) : fsLastAvailablePosition); + LOG_DEBUG(m_spLog) << "Calculated seek position for last-available-pos: " << fsLastAvailablePosition << L" = " << fsMove << GetFileInfoForLog(m_bNoBuffering); + return fsMove; } void TLocalFilesystemFile::Truncate(file_size_t fsNewSize) { + LOG_TRACE(m_spLog) << "Truncating file to: " << fsNewSize << GetFileInfoForLog(m_bNoBuffering); + if (!IsOpen()) + { + LOG_ERROR(m_spLog) << L"Cannot truncate - file not open" << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"File not open yet. Cannot truncate.", LOCATION); + } // when no-buffering is used, there are cases where we'd need to switch to buffered ops // to adjust file size @@ -119,6 +143,8 @@ file_size_t fsNewAlignedSize = RoundUp(fsNewSize, MaxSectorSize); if (fsNewAlignedSize != fsNewSize) { + LOG_TRACE(m_spLog) << "Truncating to non-aligned size. Requested: " << fsNewSize << L", aligned: " << fsNewAlignedSize << L". Will reopen file in buffering mode." << GetFileInfoForLog(m_bNoBuffering); + Close(); OpenExistingForWriting(false); @@ -131,39 +157,58 @@ li.QuadPart = fsNewSize; + LOG_TRACE(m_spLog) << L"Setting file pointer to: " << li.QuadPart << GetFileInfoForLog(m_bNoBuffering); if (!SetFilePointerEx(m_hFile, li, &liNew, FILE_BEGIN)) { DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << L"Setting file pointer to: " << li.QuadPart << L" failed." << GetFileInfoForLog(m_bNoBuffering); + throw TFileException(eErr_SeekFailed, dwLastError, m_pathFile, L"Cannot seek to appropriate position", LOCATION); } + LOG_TRACE(m_spLog) << L"Setting EOF" << GetFileInfoForLog(m_bNoBuffering); if(!::SetEndOfFile(m_hFile)) { DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << L"Setting EOF failed" << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_CannotTruncate, dwLastError, m_pathFile, L"Cannot mark the end of file", LOCATION); } // close the file that was open in inappropriate mode if(bFileSettingsChanged) + { + LOG_DEBUG(m_spLog) << L"Closing file due to mode change in truncate function" << GetFileInfoForLog(m_bNoBuffering); + Close(); + } } void TLocalFilesystemFile::ReadFile(TOverlappedDataBuffer& rBuffer) { + LOG_TRACE(m_spLog) << L"Requesting read of " << rBuffer.GetRequestedDataSize() << + L" bytes at position " << rBuffer.GetFilePosition() << + L"; buffer-order: " << rBuffer.GetBufferOrder() << + GetFileInfoForLog(m_bNoBuffering); + if (!IsOpen()) + { + LOG_ERROR(m_spLog) << L"Read request failed - file not open" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"Cannot read from closed file", LOCATION); + } - //ATLTRACE(_T("Reading %lu bytes\n"), rBuffer.GetRequestedDataSize()); if (!::ReadFileEx(m_hFile, rBuffer.GetBufferPtr(), rBuffer.GetRequestedDataSize(), &rBuffer, OverlappedReadCompleted)) { DWORD dwLastError = GetLastError(); switch (dwLastError) { case ERROR_IO_PENDING: + LOG_TRACE(m_spLog) << L"Read requested and is pending" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); return; case ERROR_HANDLE_EOF: { + LOG_TRACE(m_spLog) << L"Read request marked as EOF" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); + rBuffer.SetBytesTransferred(0); rBuffer.SetStatusCode(0); rBuffer.SetErrorCode(ERROR_SUCCESS); @@ -174,47 +219,80 @@ } default: - throw TFileException(eErr_CannotReadFile, dwLastError, m_pathFile, L"Error reading data from file", LOCATION); + { + LOG_ERROR(m_spLog) << L"Read request failed with error " << dwLastError << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); + + throw TFileException(eErr_CannotReadFile, dwLastError, m_pathFile, L"Error reading data from file", LOCATION); + } } } + else + LOG_TRACE(m_spLog) << L"Read request succeeded" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); } void TLocalFilesystemFile::WriteFile(TOverlappedDataBuffer& rBuffer) { + LOG_TRACE(m_spLog) << L"Requesting writing of " << rBuffer.GetRealDataSize() << + L" bytes at position " << rBuffer.GetFilePosition() << + L"; buffer-order: " << rBuffer.GetBufferOrder() << + GetFileInfoForLog(m_bNoBuffering); + if (!IsOpen()) + { + LOG_ERROR(m_spLog) << L"Write request failed - file not open" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"Cannot write to closed file", LOCATION); + } DWORD dwToWrite = boost::numeric_cast(rBuffer.GetRealDataSize()); if (m_bNoBuffering && rBuffer.IsLastPart()) + { dwToWrite = RoundUp(dwToWrite, MaxSectorSize); + LOG_TRACE(m_spLog) << L"Writing last part of file in no-buffering mode. Rounding up last write to " << dwToWrite << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); + } - //ATLTRACE(_T("Writing %lu bytes\n"), dwToWrite); if (!::WriteFileEx(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rBuffer, OverlappedWriteCompleted)) { DWORD dwLastError = GetLastError(); if (dwLastError != ERROR_IO_PENDING) + { + LOG_ERROR(m_spLog) << L"Write request failed with error " << dwLastError << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_CannotWriteFile, dwLastError, m_pathFile, L"Error while writing to file", LOCATION); + } + + LOG_TRACE(m_spLog) << L"Write requested and is pending" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); } + else + LOG_TRACE(m_spLog) << L"Write request succeeded" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); } void TLocalFilesystemFile::FinalizeFile(TOverlappedDataBuffer& rBuffer) { + LOG_TRACE(m_spLog) << L"Finalizing file" << + L"; buffer-order: " << rBuffer.GetBufferOrder() << + GetFileInfoForLog(m_bNoBuffering); + if (!IsOpen()) + { + LOG_ERROR(m_spLog) << L"Cannot finalize file - file not open" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"Cannot write to closed file", LOCATION); + } if (m_bNoBuffering && rBuffer.IsLastPart()) { DWORD dwToWrite = boost::numeric_cast(rBuffer.GetRealDataSize()); DWORD dwReallyWritten = RoundUp(dwToWrite, MaxSectorSize); - //ATLTRACE(_T("Finalize file - size diff: written: %I64u, required: %I64u\n"), dwReallyWritten, dwToWrite); if (dwToWrite != dwReallyWritten) { file_size_t fsNewFileSize = rBuffer.GetFilePosition() + dwToWrite; // new size - //seek - //ATLTRACE(_T("Truncating file to %I64u bytes\n"), fsNewFileSize); + LOG_TRACE(m_spLog) << L"File need truncating - really written " << dwReallyWritten << + L", should write " << dwToWrite << + L". Truncating file to " << fsNewFileSize << + L"; buffer-order: " << rBuffer.GetBufferOrder() << + GetFileInfoForLog(m_bNoBuffering); + Truncate(fsNewFileSize); } } @@ -223,42 +301,70 @@ void TLocalFilesystemFile::InternalClose() { if (m_hFile != INVALID_HANDLE_VALUE) + { + LOG_DEBUG(m_spLog) << L"Closing file" << GetFileInfoForLog(m_bNoBuffering); ::CloseHandle(m_hFile); + } m_hFile = INVALID_HANDLE_VALUE; } + std::wstring TLocalFilesystemFile::GetFileInfoForLog(bool bNoBuffering) const + { + std::wstringstream wss; + wss << L" (handle: " << m_hFile << ", path : " << m_pathFile << L", no-buffering : " << bNoBuffering << L")"; + return wss.str(); + } + void TLocalFilesystemFile::Close() { InternalClose(); } file_size_t TLocalFilesystemFile::GetFileSize() const { + LOG_DEBUG(m_spLog) << L"Retrieving file size" << GetFileInfoForLog(m_bNoBuffering); + if (!IsOpen()) + { + LOG_ERROR(m_spLog) << L"Retrieving file size failed - file not open" << GetFileInfoForLog(m_bNoBuffering); return 0; + } BY_HANDLE_FILE_INFORMATION bhfi; if (!::GetFileInformationByHandle(m_hFile, &bhfi)) + { + DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << L"Retrieving file size failed with error " << dwLastError << GetFileInfoForLog(m_bNoBuffering); + return 0; + } ULARGE_INTEGER uli; uli.HighPart = bhfi.nFileSizeHigh; uli.LowPart = bhfi.nFileSizeLow; + LOG_DEBUG(m_spLog) << L"File size retrieved -> " << uli.QuadPart << GetFileInfoForLog(m_bNoBuffering); + return uli.QuadPart; } void TLocalFilesystemFile::GetFileInfo(TFileInfo& tFileInfo) const { + LOG_DEBUG(m_spLog) << L"Retrieving file information" << GetFileInfoForLog(m_bNoBuffering); + if (!IsOpen()) + { + LOG_ERROR(m_spLog) << L"Retrieving file information failed - file not open" << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"File not open. Cannot get file info.", LOCATION); + } BY_HANDLE_FILE_INFORMATION bhfi; if (!::GetFileInformationByHandle(m_hFile, &bhfi)) { DWORD dwLastError = GetLastError(); + LOG_ERROR(m_spLog) << L"Retrieving file information failed with error " << dwLastError << GetFileInfoForLog(m_bNoBuffering); throw TFileException(eErr_CannotGetFileInfo, dwLastError, m_pathFile, L"Retrieving file info from handle failed.", LOCATION); } @@ -270,6 +376,14 @@ tFileInfo.SetAttributes(bhfi.dwFileAttributes); tFileInfo.SetFileTimes(TFileTime(bhfi.ftCreationTime), TFileTime(bhfi.ftLastAccessTime), TFileTime(bhfi.ftLastWriteTime)); tFileInfo.SetLength64(uli.QuadPart); + + LOG_DEBUG(m_spLog) << L"Retrieving file information succeeded. Attributes: " << + bhfi.dwFileAttributes << + L", creation-time: " << bhfi.ftCreationTime << + L", last-access-time: " << bhfi.ftLastAccessTime<< + L", last-write-time: " << bhfi.ftLastWriteTime << + L", size: " << uli.QuadPart << + GetFileInfoForLog(m_bNoBuffering); } TSmartPath TLocalFilesystemFile::GetFilePath() const