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