/dep/lzma/CPP/Windows/FileIO.cpp

http://github.com/SingularityCore/Singularity · C++ · 434 lines · 359 code · 60 blank · 15 comment · 121 complexity · 35060d847ae644bea7137b4db65222ab MD5 · raw file

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