|
1 // Windows/FileIO.cpp |
|
2 |
|
3 #include "StdAfx.h" |
|
4 |
|
5 #include "FileIO.h" |
|
6 #include "Defs.h" |
|
7 #ifdef WIN_LONG_PATH |
|
8 #include "../Common/MyString.h" |
|
9 #endif |
|
10 #ifndef _UNICODE |
|
11 #include "../Common/StringConvert.h" |
|
12 #endif |
|
13 |
|
14 #ifndef _UNICODE |
|
15 extern bool g_IsNT; |
|
16 #endif |
|
17 |
|
18 namespace NWindows { |
|
19 namespace NFile { |
|
20 |
|
21 #if defined(WIN_LONG_PATH) && defined(_UNICODE) |
|
22 #define WIN_LONG_PATH2 |
|
23 #endif |
|
24 |
|
25 #ifdef WIN_LONG_PATH |
|
26 bool GetLongPathBase(LPCWSTR s, UString &res) |
|
27 { |
|
28 res.Empty(); |
|
29 int len = MyStringLen(s); |
|
30 wchar_t c = s[0]; |
|
31 if (len < 1 || c == L'\\' || c == L'.' && (len == 1 || len == 2 && s[1] == L'.')) |
|
32 return true; |
|
33 UString curDir; |
|
34 bool isAbs = false; |
|
35 if (len > 3) |
|
36 isAbs = (s[1] == L':' && s[2] == L'\\' && (c >= L'a' && c <= L'z' || c >= L'A' && c <= L'Z')); |
|
37 |
|
38 if (!isAbs) |
|
39 { |
|
40 DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, curDir.GetBuffer(MAX_PATH + 1)); |
|
41 curDir.ReleaseBuffer(); |
|
42 if (needLength == 0 || needLength > MAX_PATH) |
|
43 return false; |
|
44 if (curDir[curDir.Length() - 1] != L'\\') |
|
45 curDir += L'\\'; |
|
46 } |
|
47 res = UString(L"\\\\?\\") + curDir + s; |
|
48 return true; |
|
49 } |
|
50 |
|
51 bool GetLongPath(LPCWSTR path, UString &longPath) |
|
52 { |
|
53 if (GetLongPathBase(path, longPath)) |
|
54 return !longPath.IsEmpty(); |
|
55 return false; |
|
56 } |
|
57 #endif |
|
58 |
|
59 namespace NIO { |
|
60 |
|
61 CFileBase::~CFileBase() { Close(); } |
|
62 |
|
63 bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess, |
|
64 DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
|
65 { |
|
66 if (!Close()) |
|
67 return false; |
|
68 _handle = ::CreateFile(fileName, desiredAccess, shareMode, |
|
69 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, |
|
70 flagsAndAttributes, (HANDLE)NULL); |
|
71 #ifdef WIN_LONG_PATH2 |
|
72 if (_handle == INVALID_HANDLE_VALUE) |
|
73 { |
|
74 UString longPath; |
|
75 if (GetLongPath(fileName, longPath)) |
|
76 _handle = ::CreateFileW(longPath, desiredAccess, shareMode, |
|
77 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, |
|
78 flagsAndAttributes, (HANDLE)NULL); |
|
79 } |
|
80 #endif |
|
81 return (_handle != INVALID_HANDLE_VALUE); |
|
82 } |
|
83 |
|
84 #ifndef _UNICODE |
|
85 bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess, |
|
86 DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
|
87 { |
|
88 if (!g_IsNT) |
|
89 return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP), |
|
90 desiredAccess, shareMode, creationDisposition, flagsAndAttributes); |
|
91 if (!Close()) |
|
92 return false; |
|
93 _handle = ::CreateFileW(fileName, desiredAccess, shareMode, |
|
94 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, |
|
95 flagsAndAttributes, (HANDLE)NULL); |
|
96 #ifdef WIN_LONG_PATH |
|
97 if (_handle == INVALID_HANDLE_VALUE) |
|
98 { |
|
99 UString longPath; |
|
100 if (GetLongPath(fileName, longPath)) |
|
101 _handle = ::CreateFileW(longPath, desiredAccess, shareMode, |
|
102 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, |
|
103 flagsAndAttributes, (HANDLE)NULL); |
|
104 } |
|
105 #endif |
|
106 return (_handle != INVALID_HANDLE_VALUE); |
|
107 } |
|
108 #endif |
|
109 |
|
110 bool CFileBase::Close() |
|
111 { |
|
112 if (_handle == INVALID_HANDLE_VALUE) |
|
113 return true; |
|
114 if (!::CloseHandle(_handle)) |
|
115 return false; |
|
116 _handle = INVALID_HANDLE_VALUE; |
|
117 return true; |
|
118 } |
|
119 |
|
120 bool CFileBase::GetPosition(UInt64 &position) const |
|
121 { |
|
122 return Seek(0, FILE_CURRENT, position); |
|
123 } |
|
124 |
|
125 bool CFileBase::GetLength(UInt64 &length) const |
|
126 { |
|
127 DWORD sizeHigh; |
|
128 DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh); |
|
129 if(sizeLow == 0xFFFFFFFF) |
|
130 if(::GetLastError() != NO_ERROR) |
|
131 return false; |
|
132 length = (((UInt64)sizeHigh) << 32) + sizeLow; |
|
133 return true; |
|
134 } |
|
135 |
|
136 bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const |
|
137 { |
|
138 LARGE_INTEGER value; |
|
139 value.QuadPart = distanceToMove; |
|
140 value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod); |
|
141 if (value.LowPart == 0xFFFFFFFF) |
|
142 if(::GetLastError() != NO_ERROR) |
|
143 return false; |
|
144 newPosition = value.QuadPart; |
|
145 return true; |
|
146 } |
|
147 |
|
148 bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) |
|
149 { |
|
150 return Seek(position, FILE_BEGIN, newPosition); |
|
151 } |
|
152 |
|
153 bool CFileBase::SeekToBegin() |
|
154 { |
|
155 UInt64 newPosition; |
|
156 return Seek(0, newPosition); |
|
157 } |
|
158 |
|
159 bool CFileBase::SeekToEnd(UInt64 &newPosition) |
|
160 { |
|
161 return Seek(0, FILE_END, newPosition); |
|
162 } |
|
163 |
|
164 bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const |
|
165 { |
|
166 BY_HANDLE_FILE_INFORMATION winFileInfo; |
|
167 if(!::GetFileInformationByHandle(_handle, &winFileInfo)) |
|
168 return false; |
|
169 fileInfo.Attributes = winFileInfo.dwFileAttributes; |
|
170 fileInfo.CreationTime = winFileInfo.ftCreationTime; |
|
171 fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime; |
|
172 fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime; |
|
173 fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes; |
|
174 fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) + winFileInfo.nFileSizeLow; |
|
175 fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks; |
|
176 fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow; |
|
177 return true; |
|
178 } |
|
179 |
|
180 ///////////////////////// |
|
181 // CInFile |
|
182 |
|
183 bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
|
184 { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } |
|
185 |
|
186 bool CInFile::OpenShared(LPCTSTR fileName, bool shareForWrite) |
|
187 { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } |
|
188 |
|
189 bool CInFile::Open(LPCTSTR fileName) |
|
190 { return OpenShared(fileName, false); } |
|
191 |
|
192 #ifndef _UNICODE |
|
193 bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
|
194 { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } |
|
195 |
|
196 bool CInFile::OpenShared(LPCWSTR fileName, bool shareForWrite) |
|
197 { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } |
|
198 |
|
199 bool CInFile::Open(LPCWSTR fileName) |
|
200 { return OpenShared(fileName, false); } |
|
201 #endif |
|
202 |
|
203 // ReadFile and WriteFile functions in Windows have BUG: |
|
204 // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) |
|
205 // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES |
|
206 // (Insufficient system resources exist to complete the requested service). |
|
207 |
|
208 // Probably in some version of Windows there are problems with other sizes: |
|
209 // for 32 MB (maybe also for 16 MB). |
|
210 // And message can be "Network connection was lost" |
|
211 |
|
212 static UInt32 kChunkSizeMax = (1 << 22); |
|
213 |
|
214 bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) |
|
215 { |
|
216 if (size > kChunkSizeMax) |
|
217 size = kChunkSizeMax; |
|
218 DWORD processedLoc = 0; |
|
219 bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); |
|
220 processedSize = (UInt32)processedLoc; |
|
221 return res; |
|
222 } |
|
223 |
|
224 bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) |
|
225 { |
|
226 processedSize = 0; |
|
227 do |
|
228 { |
|
229 UInt32 processedLoc = 0; |
|
230 bool res = ReadPart(data, size, processedLoc); |
|
231 processedSize += processedLoc; |
|
232 if (!res) |
|
233 return false; |
|
234 if (processedLoc == 0) |
|
235 return true; |
|
236 data = (void *)((unsigned char *)data + processedLoc); |
|
237 size -= processedLoc; |
|
238 } |
|
239 while (size > 0); |
|
240 return true; |
|
241 } |
|
242 |
|
243 ///////////////////////// |
|
244 // COutFile |
|
245 |
|
246 bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
|
247 { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } |
|
248 |
|
249 static inline DWORD GetCreationDisposition(bool createAlways) |
|
250 { return createAlways? CREATE_ALWAYS: CREATE_NEW; } |
|
251 |
|
252 bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition) |
|
253 { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } |
|
254 |
|
255 bool COutFile::Create(LPCTSTR fileName, bool createAlways) |
|
256 { return Open(fileName, GetCreationDisposition(createAlways)); } |
|
257 |
|
258 #ifndef _UNICODE |
|
259 |
|
260 bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) |
|
261 { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } |
|
262 |
|
263 bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition) |
|
264 { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } |
|
265 |
|
266 bool COutFile::Create(LPCWSTR fileName, bool createAlways) |
|
267 { return Open(fileName, GetCreationDisposition(createAlways)); } |
|
268 |
|
269 #endif |
|
270 |
|
271 bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime) |
|
272 { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); } |
|
273 |
|
274 bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime) |
|
275 { return SetTime(NULL, NULL, lastWriteTime); } |
|
276 |
|
277 bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) |
|
278 { |
|
279 if (size > kChunkSizeMax) |
|
280 size = kChunkSizeMax; |
|
281 DWORD processedLoc = 0; |
|
282 bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); |
|
283 processedSize = (UInt32)processedLoc; |
|
284 return res; |
|
285 } |
|
286 |
|
287 bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) |
|
288 { |
|
289 processedSize = 0; |
|
290 do |
|
291 { |
|
292 UInt32 processedLoc = 0; |
|
293 bool res = WritePart(data, size, processedLoc); |
|
294 processedSize += processedLoc; |
|
295 if (!res) |
|
296 return false; |
|
297 if (processedLoc == 0) |
|
298 return true; |
|
299 data = (const void *)((const unsigned char *)data + processedLoc); |
|
300 size -= processedLoc; |
|
301 } |
|
302 while (size > 0); |
|
303 return true; |
|
304 } |
|
305 |
|
306 bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); } |
|
307 |
|
308 bool COutFile::SetLength(UInt64 length) |
|
309 { |
|
310 UInt64 newPosition; |
|
311 if(!Seek(length, newPosition)) |
|
312 return false; |
|
313 if(newPosition != length) |
|
314 return false; |
|
315 return SetEndOfFile(); |
|
316 } |
|
317 |
|
318 }}} |