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