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