Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | // Windows/FileIO.cpp |
michael@0 | 2 | |
michael@0 | 3 | #include "StdAfx.h" |
michael@0 | 4 | |
michael@0 | 5 | #include "FileIO.h" |
michael@0 | 6 | #include "Defs.h" |
michael@0 | 7 | #ifndef _UNICODE |
michael@0 | 8 | #include "../Common/StringConvert.h" |
michael@0 | 9 | #endif |
michael@0 | 10 | |
michael@0 | 11 | #ifndef _UNICODE |
michael@0 | 12 | extern bool g_IsNT; |
michael@0 | 13 | #endif |
michael@0 | 14 | |
michael@0 | 15 | namespace NWindows { |
michael@0 | 16 | namespace NFile { |
michael@0 | 17 | namespace NIO { |
michael@0 | 18 | |
michael@0 | 19 | CFileBase::~CFileBase() { Close(); } |
michael@0 | 20 | |
michael@0 | 21 | bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess, |
michael@0 | 22 | DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
michael@0 | 23 | { |
michael@0 | 24 | Close(); |
michael@0 | 25 | _handle = ::CreateFile(fileName, desiredAccess, shareMode, |
michael@0 | 26 | (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, |
michael@0 | 27 | flagsAndAttributes, (HANDLE) NULL); |
michael@0 | 28 | return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE)); |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | #ifndef _UNICODE |
michael@0 | 32 | bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess, |
michael@0 | 33 | DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
michael@0 | 34 | { |
michael@0 | 35 | if (g_IsNT) |
michael@0 | 36 | { |
michael@0 | 37 | Close(); |
michael@0 | 38 | _handle = ::CreateFileW(fileName, desiredAccess, shareMode, |
michael@0 | 39 | (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, |
michael@0 | 40 | flagsAndAttributes, (HANDLE) NULL); |
michael@0 | 41 | return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE)); |
michael@0 | 42 | } |
michael@0 | 43 | return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP), |
michael@0 | 44 | desiredAccess, shareMode, creationDisposition, flagsAndAttributes); |
michael@0 | 45 | } |
michael@0 | 46 | #endif |
michael@0 | 47 | |
michael@0 | 48 | bool CFileBase::Close() |
michael@0 | 49 | { |
michael@0 | 50 | if(!_fileIsOpen) |
michael@0 | 51 | return true; |
michael@0 | 52 | bool result = BOOLToBool(::CloseHandle(_handle)); |
michael@0 | 53 | _fileIsOpen = !result; |
michael@0 | 54 | return result; |
michael@0 | 55 | } |
michael@0 | 56 | |
michael@0 | 57 | bool CFileBase::GetPosition(UInt64 &position) const |
michael@0 | 58 | { |
michael@0 | 59 | return Seek(0, FILE_CURRENT, position); |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | bool CFileBase::GetLength(UInt64 &length) const |
michael@0 | 63 | { |
michael@0 | 64 | DWORD sizeHigh; |
michael@0 | 65 | DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh); |
michael@0 | 66 | if(sizeLow == 0xFFFFFFFF) |
michael@0 | 67 | if(::GetLastError() != NO_ERROR) |
michael@0 | 68 | return false; |
michael@0 | 69 | length = (((UInt64)sizeHigh) << 32) + sizeLow; |
michael@0 | 70 | return true; |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const |
michael@0 | 74 | { |
michael@0 | 75 | LARGE_INTEGER value; |
michael@0 | 76 | value.QuadPart = distanceToMove; |
michael@0 | 77 | value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod); |
michael@0 | 78 | if (value.LowPart == 0xFFFFFFFF) |
michael@0 | 79 | if(::GetLastError() != NO_ERROR) |
michael@0 | 80 | return false; |
michael@0 | 81 | newPosition = value.QuadPart; |
michael@0 | 82 | return true; |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) |
michael@0 | 86 | { |
michael@0 | 87 | return Seek(position, FILE_BEGIN, newPosition); |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | bool CFileBase::SeekToBegin() |
michael@0 | 91 | { |
michael@0 | 92 | UInt64 newPosition; |
michael@0 | 93 | return Seek(0, newPosition); |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | bool CFileBase::SeekToEnd(UInt64 &newPosition) |
michael@0 | 97 | { |
michael@0 | 98 | return Seek(0, FILE_END, newPosition); |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const |
michael@0 | 102 | { |
michael@0 | 103 | BY_HANDLE_FILE_INFORMATION winFileInfo; |
michael@0 | 104 | if(!::GetFileInformationByHandle(_handle, &winFileInfo)) |
michael@0 | 105 | return false; |
michael@0 | 106 | fileInfo.Attributes = winFileInfo.dwFileAttributes; |
michael@0 | 107 | fileInfo.CreationTime = winFileInfo.ftCreationTime; |
michael@0 | 108 | fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime; |
michael@0 | 109 | fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime; |
michael@0 | 110 | fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes; |
michael@0 | 111 | fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) + winFileInfo.nFileSizeLow; |
michael@0 | 112 | fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks; |
michael@0 | 113 | fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow; |
michael@0 | 114 | return true; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | ///////////////////////// |
michael@0 | 118 | // CInFile |
michael@0 | 119 | |
michael@0 | 120 | bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
michael@0 | 121 | { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } |
michael@0 | 122 | |
michael@0 | 123 | bool CInFile::Open(LPCTSTR fileName) |
michael@0 | 124 | { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } |
michael@0 | 125 | |
michael@0 | 126 | #ifndef _UNICODE |
michael@0 | 127 | bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
michael@0 | 128 | { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } |
michael@0 | 129 | |
michael@0 | 130 | bool CInFile::Open(LPCWSTR fileName) |
michael@0 | 131 | { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } |
michael@0 | 132 | #endif |
michael@0 | 133 | |
michael@0 | 134 | // ReadFile and WriteFile functions in Windows have BUG: |
michael@0 | 135 | // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) |
michael@0 | 136 | // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES |
michael@0 | 137 | // (Insufficient system resources exist to complete the requested service). |
michael@0 | 138 | |
michael@0 | 139 | static UInt32 kChunkSizeMax = (1 << 24); |
michael@0 | 140 | |
michael@0 | 141 | bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) |
michael@0 | 142 | { |
michael@0 | 143 | if (size > kChunkSizeMax) |
michael@0 | 144 | size = kChunkSizeMax; |
michael@0 | 145 | DWORD processedLoc = 0; |
michael@0 | 146 | bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); |
michael@0 | 147 | processedSize = (UInt32)processedLoc; |
michael@0 | 148 | return res; |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) |
michael@0 | 152 | { |
michael@0 | 153 | processedSize = 0; |
michael@0 | 154 | do |
michael@0 | 155 | { |
michael@0 | 156 | UInt32 processedLoc = 0; |
michael@0 | 157 | bool res = ReadPart(data, size, processedLoc); |
michael@0 | 158 | processedSize += processedLoc; |
michael@0 | 159 | if (!res) |
michael@0 | 160 | return false; |
michael@0 | 161 | if (processedLoc == 0) |
michael@0 | 162 | return true; |
michael@0 | 163 | data = (void *)((unsigned char *)data + processedLoc); |
michael@0 | 164 | size -= processedLoc; |
michael@0 | 165 | } |
michael@0 | 166 | while (size > 0); |
michael@0 | 167 | return true; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | ///////////////////////// |
michael@0 | 171 | // COutFile |
michael@0 | 172 | |
michael@0 | 173 | bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
michael@0 | 174 | { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } |
michael@0 | 175 | |
michael@0 | 176 | static inline DWORD GetCreationDisposition(bool createAlways) |
michael@0 | 177 | { return createAlways? CREATE_ALWAYS: CREATE_NEW; } |
michael@0 | 178 | |
michael@0 | 179 | bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition) |
michael@0 | 180 | { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } |
michael@0 | 181 | |
michael@0 | 182 | bool COutFile::Create(LPCTSTR fileName, bool createAlways) |
michael@0 | 183 | { return Open(fileName, GetCreationDisposition(createAlways)); } |
michael@0 | 184 | |
michael@0 | 185 | #ifndef _UNICODE |
michael@0 | 186 | |
michael@0 | 187 | bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
michael@0 | 188 | { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } |
michael@0 | 189 | |
michael@0 | 190 | bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition) |
michael@0 | 191 | { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } |
michael@0 | 192 | |
michael@0 | 193 | bool COutFile::Create(LPCWSTR fileName, bool createAlways) |
michael@0 | 194 | { return Open(fileName, GetCreationDisposition(createAlways)); } |
michael@0 | 195 | |
michael@0 | 196 | #endif |
michael@0 | 197 | |
michael@0 | 198 | bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime) |
michael@0 | 199 | { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); } |
michael@0 | 200 | |
michael@0 | 201 | bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime) |
michael@0 | 202 | { return SetTime(NULL, NULL, lastWriteTime); } |
michael@0 | 203 | |
michael@0 | 204 | bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) |
michael@0 | 205 | { |
michael@0 | 206 | if (size > kChunkSizeMax) |
michael@0 | 207 | size = kChunkSizeMax; |
michael@0 | 208 | DWORD processedLoc = 0; |
michael@0 | 209 | bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); |
michael@0 | 210 | processedSize = (UInt32)processedLoc; |
michael@0 | 211 | return res; |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) |
michael@0 | 215 | { |
michael@0 | 216 | processedSize = 0; |
michael@0 | 217 | do |
michael@0 | 218 | { |
michael@0 | 219 | UInt32 processedLoc = 0; |
michael@0 | 220 | bool res = WritePart(data, size, processedLoc); |
michael@0 | 221 | processedSize += processedLoc; |
michael@0 | 222 | if (!res) |
michael@0 | 223 | return false; |
michael@0 | 224 | if (processedLoc == 0) |
michael@0 | 225 | return true; |
michael@0 | 226 | data = (const void *)((const unsigned char *)data + processedLoc); |
michael@0 | 227 | size -= processedLoc; |
michael@0 | 228 | } |
michael@0 | 229 | while (size > 0); |
michael@0 | 230 | return true; |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); } |
michael@0 | 234 | |
michael@0 | 235 | bool COutFile::SetLength(UInt64 length) |
michael@0 | 236 | { |
michael@0 | 237 | UInt64 newPosition; |
michael@0 | 238 | if(!Seek(length, newPosition)) |
michael@0 | 239 | return false; |
michael@0 | 240 | if(newPosition != length) |
michael@0 | 241 | return false; |
michael@0 | 242 | return SetEndOfFile(); |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | }}} |