Upload 2.0.2
[physicsfs] / lzma / CPP / Windows / FileIO.cpp
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 }}}