michael@0: // Windows/FileIO.cpp michael@0: michael@0: #include "StdAfx.h" michael@0: michael@0: #include "FileIO.h" michael@0: #include "Defs.h" michael@0: #ifndef _UNICODE michael@0: #include "../Common/StringConvert.h" michael@0: #endif michael@0: michael@0: #ifndef _UNICODE michael@0: extern bool g_IsNT; michael@0: #endif michael@0: michael@0: namespace NWindows { michael@0: namespace NFile { michael@0: namespace NIO { michael@0: michael@0: CFileBase::~CFileBase() { Close(); } michael@0: michael@0: bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess, michael@0: DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) michael@0: { michael@0: Close(); michael@0: _handle = ::CreateFile(fileName, desiredAccess, shareMode, michael@0: (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, michael@0: flagsAndAttributes, (HANDLE) NULL); michael@0: return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE)); michael@0: } michael@0: michael@0: #ifndef _UNICODE michael@0: bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess, michael@0: DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) michael@0: { michael@0: if (g_IsNT) michael@0: { michael@0: Close(); michael@0: _handle = ::CreateFileW(fileName, desiredAccess, shareMode, michael@0: (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, michael@0: flagsAndAttributes, (HANDLE) NULL); michael@0: return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE)); michael@0: } michael@0: return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP), michael@0: desiredAccess, shareMode, creationDisposition, flagsAndAttributes); michael@0: } michael@0: #endif michael@0: michael@0: bool CFileBase::Close() michael@0: { michael@0: if(!_fileIsOpen) michael@0: return true; michael@0: bool result = BOOLToBool(::CloseHandle(_handle)); michael@0: _fileIsOpen = !result; michael@0: return result; michael@0: } michael@0: michael@0: bool CFileBase::GetPosition(UInt64 &position) const michael@0: { michael@0: return Seek(0, FILE_CURRENT, position); michael@0: } michael@0: michael@0: bool CFileBase::GetLength(UInt64 &length) const michael@0: { michael@0: DWORD sizeHigh; michael@0: DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh); michael@0: if(sizeLow == 0xFFFFFFFF) michael@0: if(::GetLastError() != NO_ERROR) michael@0: return false; michael@0: length = (((UInt64)sizeHigh) << 32) + sizeLow; michael@0: return true; michael@0: } michael@0: michael@0: bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const michael@0: { michael@0: LARGE_INTEGER value; michael@0: value.QuadPart = distanceToMove; michael@0: value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod); michael@0: if (value.LowPart == 0xFFFFFFFF) michael@0: if(::GetLastError() != NO_ERROR) michael@0: return false; michael@0: newPosition = value.QuadPart; michael@0: return true; michael@0: } michael@0: michael@0: bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) michael@0: { michael@0: return Seek(position, FILE_BEGIN, newPosition); michael@0: } michael@0: michael@0: bool CFileBase::SeekToBegin() michael@0: { michael@0: UInt64 newPosition; michael@0: return Seek(0, newPosition); michael@0: } michael@0: michael@0: bool CFileBase::SeekToEnd(UInt64 &newPosition) michael@0: { michael@0: return Seek(0, FILE_END, newPosition); michael@0: } michael@0: michael@0: bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const michael@0: { michael@0: BY_HANDLE_FILE_INFORMATION winFileInfo; michael@0: if(!::GetFileInformationByHandle(_handle, &winFileInfo)) michael@0: return false; michael@0: fileInfo.Attributes = winFileInfo.dwFileAttributes; michael@0: fileInfo.CreationTime = winFileInfo.ftCreationTime; michael@0: fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime; michael@0: fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime; michael@0: fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes; michael@0: fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) + winFileInfo.nFileSizeLow; michael@0: fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks; michael@0: fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow; michael@0: return true; michael@0: } michael@0: michael@0: ///////////////////////// michael@0: // CInFile michael@0: michael@0: bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) michael@0: { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } michael@0: michael@0: bool CInFile::Open(LPCTSTR fileName) michael@0: { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } michael@0: michael@0: #ifndef _UNICODE michael@0: bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) michael@0: { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } michael@0: michael@0: bool CInFile::Open(LPCWSTR fileName) michael@0: { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } michael@0: #endif michael@0: michael@0: // ReadFile and WriteFile functions in Windows have BUG: michael@0: // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) michael@0: // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES michael@0: // (Insufficient system resources exist to complete the requested service). michael@0: michael@0: static UInt32 kChunkSizeMax = (1 << 24); michael@0: michael@0: bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) michael@0: { michael@0: if (size > kChunkSizeMax) michael@0: size = kChunkSizeMax; michael@0: DWORD processedLoc = 0; michael@0: bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); michael@0: processedSize = (UInt32)processedLoc; michael@0: return res; michael@0: } michael@0: michael@0: bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) michael@0: { michael@0: processedSize = 0; michael@0: do michael@0: { michael@0: UInt32 processedLoc = 0; michael@0: bool res = ReadPart(data, size, processedLoc); michael@0: processedSize += processedLoc; michael@0: if (!res) michael@0: return false; michael@0: if (processedLoc == 0) michael@0: return true; michael@0: data = (void *)((unsigned char *)data + processedLoc); michael@0: size -= processedLoc; michael@0: } michael@0: while (size > 0); michael@0: return true; michael@0: } michael@0: michael@0: ///////////////////////// michael@0: // COutFile michael@0: michael@0: bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) michael@0: { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } michael@0: michael@0: static inline DWORD GetCreationDisposition(bool createAlways) michael@0: { return createAlways? CREATE_ALWAYS: CREATE_NEW; } michael@0: michael@0: bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition) michael@0: { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } michael@0: michael@0: bool COutFile::Create(LPCTSTR fileName, bool createAlways) michael@0: { return Open(fileName, GetCreationDisposition(createAlways)); } michael@0: michael@0: #ifndef _UNICODE michael@0: michael@0: bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) michael@0: { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } michael@0: michael@0: bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition) michael@0: { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } michael@0: michael@0: bool COutFile::Create(LPCWSTR fileName, bool createAlways) michael@0: { return Open(fileName, GetCreationDisposition(createAlways)); } michael@0: michael@0: #endif michael@0: michael@0: bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime) michael@0: { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); } michael@0: michael@0: bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime) michael@0: { return SetTime(NULL, NULL, lastWriteTime); } michael@0: michael@0: bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) michael@0: { michael@0: if (size > kChunkSizeMax) michael@0: size = kChunkSizeMax; michael@0: DWORD processedLoc = 0; michael@0: bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); michael@0: processedSize = (UInt32)processedLoc; michael@0: return res; michael@0: } michael@0: michael@0: bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) michael@0: { michael@0: processedSize = 0; michael@0: do michael@0: { michael@0: UInt32 processedLoc = 0; michael@0: bool res = WritePart(data, size, processedLoc); michael@0: processedSize += processedLoc; michael@0: if (!res) michael@0: return false; michael@0: if (processedLoc == 0) michael@0: return true; michael@0: data = (const void *)((const unsigned char *)data + processedLoc); michael@0: size -= processedLoc; michael@0: } michael@0: while (size > 0); michael@0: return true; michael@0: } michael@0: michael@0: bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); } michael@0: michael@0: bool COutFile::SetLength(UInt64 length) michael@0: { michael@0: UInt64 newPosition; michael@0: if(!Seek(length, newPosition)) michael@0: return false; michael@0: if(newPosition != length) michael@0: return false; michael@0: return SetEndOfFile(); michael@0: } michael@0: michael@0: }}}