FileIO.cpp 9.4 KB

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