file_win.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/files/file.h"
  5. #include <io.h>
  6. #include <stdint.h>
  7. #include "base/check_op.h"
  8. #include "base/metrics/histogram_functions.h"
  9. #include "base/notreached.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/threading/scoped_blocking_call.h"
  12. #include <windows.h>
  13. namespace base {
  14. // Make sure our Whence mappings match the system headers.
  15. static_assert(File::FROM_BEGIN == FILE_BEGIN &&
  16. File::FROM_CURRENT == FILE_CURRENT &&
  17. File::FROM_END == FILE_END,
  18. "whence mapping must match the system headers");
  19. bool File::IsValid() const {
  20. return file_.is_valid();
  21. }
  22. PlatformFile File::GetPlatformFile() const {
  23. return file_.get();
  24. }
  25. PlatformFile File::TakePlatformFile() {
  26. return file_.release();
  27. }
  28. void File::Close() {
  29. if (!file_.is_valid())
  30. return;
  31. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  32. SCOPED_FILE_TRACE("Close");
  33. file_.Close();
  34. }
  35. int64_t File::Seek(Whence whence, int64_t offset) {
  36. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  37. DCHECK(IsValid());
  38. SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
  39. LARGE_INTEGER distance, res;
  40. distance.QuadPart = offset;
  41. DWORD move_method = static_cast<DWORD>(whence);
  42. if (!SetFilePointerEx(file_.get(), distance, &res, move_method))
  43. return -1;
  44. return res.QuadPart;
  45. }
  46. int File::Read(int64_t offset, char* data, int size) {
  47. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  48. DCHECK(IsValid());
  49. DCHECK(!async_);
  50. if (size < 0 || offset < 0)
  51. return -1;
  52. SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
  53. ULARGE_INTEGER offset_li;
  54. offset_li.QuadPart = static_cast<uint64_t>(offset);
  55. OVERLAPPED overlapped = {};
  56. overlapped.Offset = offset_li.LowPart;
  57. overlapped.OffsetHigh = offset_li.HighPart;
  58. DWORD bytes_read;
  59. if (::ReadFile(file_.get(), data, static_cast<DWORD>(size), &bytes_read,
  60. &overlapped)) {
  61. // TODO(crbug.com/1333521): Change to return some type with a uint64_t size
  62. // and eliminate this cast.
  63. return checked_cast<int>(bytes_read);
  64. }
  65. if (ERROR_HANDLE_EOF == GetLastError())
  66. return 0;
  67. return -1;
  68. }
  69. int File::ReadAtCurrentPos(char* data, int size) {
  70. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  71. DCHECK(IsValid());
  72. DCHECK(!async_);
  73. if (size < 0)
  74. return -1;
  75. SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
  76. DWORD bytes_read;
  77. if (::ReadFile(file_.get(), data, static_cast<DWORD>(size), &bytes_read,
  78. NULL)) {
  79. // TODO(crbug.com/1333521): Change to return some type with a uint64_t size
  80. // and eliminate this cast.
  81. return checked_cast<int>(bytes_read);
  82. }
  83. if (ERROR_HANDLE_EOF == GetLastError())
  84. return 0;
  85. return -1;
  86. }
  87. int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
  88. // TODO(dbeam): trace this separately?
  89. return Read(offset, data, size);
  90. }
  91. int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
  92. // TODO(dbeam): trace this separately?
  93. return ReadAtCurrentPos(data, size);
  94. }
  95. int File::Write(int64_t offset, const char* data, int size) {
  96. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  97. DCHECK(IsValid());
  98. DCHECK(!async_);
  99. if (size < 0 || offset < 0)
  100. return -1;
  101. SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
  102. ULARGE_INTEGER offset_li;
  103. offset_li.QuadPart = static_cast<uint64_t>(offset);
  104. OVERLAPPED overlapped = {};
  105. overlapped.Offset = offset_li.LowPart;
  106. overlapped.OffsetHigh = offset_li.HighPart;
  107. DWORD bytes_written;
  108. if (::WriteFile(file_.get(), data, static_cast<DWORD>(size), &bytes_written,
  109. &overlapped))
  110. return static_cast<int>(bytes_written);
  111. return -1;
  112. }
  113. int File::WriteAtCurrentPos(const char* data, int size) {
  114. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  115. DCHECK(IsValid());
  116. DCHECK(!async_);
  117. if (size < 0)
  118. return -1;
  119. SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
  120. DWORD bytes_written;
  121. if (::WriteFile(file_.get(), data, static_cast<DWORD>(size), &bytes_written,
  122. NULL))
  123. return static_cast<int>(bytes_written);
  124. return -1;
  125. }
  126. int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
  127. return WriteAtCurrentPos(data, size);
  128. }
  129. int64_t File::GetLength() {
  130. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  131. DCHECK(IsValid());
  132. SCOPED_FILE_TRACE("GetLength");
  133. LARGE_INTEGER size;
  134. if (!::GetFileSizeEx(file_.get(), &size))
  135. return -1;
  136. return static_cast<int64_t>(size.QuadPart);
  137. }
  138. bool File::SetLength(int64_t length) {
  139. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  140. DCHECK(IsValid());
  141. SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
  142. // Get the current file pointer.
  143. LARGE_INTEGER file_pointer;
  144. LARGE_INTEGER zero;
  145. zero.QuadPart = 0;
  146. if (!::SetFilePointerEx(file_.get(), zero, &file_pointer, FILE_CURRENT))
  147. return false;
  148. LARGE_INTEGER length_li;
  149. length_li.QuadPart = length;
  150. // If length > file size, SetFilePointerEx() should extend the file
  151. // with zeroes on all Windows standard file systems (NTFS, FATxx).
  152. if (!::SetFilePointerEx(file_.get(), length_li, NULL, FILE_BEGIN))
  153. return false;
  154. // Set the new file length and move the file pointer to its old position.
  155. // This is consistent with ftruncate()'s behavior, even when the file
  156. // pointer points to a location beyond the end of the file.
  157. // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
  158. // promised by the interface (nor was promised by PlatformFile). See if this
  159. // implementation detail can be removed.
  160. return ((::SetEndOfFile(file_.get()) != FALSE) &&
  161. (::SetFilePointerEx(file_.get(), file_pointer, NULL, FILE_BEGIN) !=
  162. FALSE));
  163. }
  164. bool File::SetTimes(Time last_access_time, Time last_modified_time) {
  165. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  166. DCHECK(IsValid());
  167. SCOPED_FILE_TRACE("SetTimes");
  168. FILETIME last_access_filetime = last_access_time.ToFileTime();
  169. FILETIME last_modified_filetime = last_modified_time.ToFileTime();
  170. return (::SetFileTime(file_.get(), NULL, &last_access_filetime,
  171. &last_modified_filetime) != FALSE);
  172. }
  173. bool File::GetInfo(Info* info) {
  174. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  175. DCHECK(IsValid());
  176. SCOPED_FILE_TRACE("GetInfo");
  177. BY_HANDLE_FILE_INFORMATION file_info;
  178. if (!GetFileInformationByHandle(file_.get(), &file_info))
  179. return false;
  180. ULARGE_INTEGER size;
  181. size.HighPart = file_info.nFileSizeHigh;
  182. size.LowPart = file_info.nFileSizeLow;
  183. // TODO(crbug.com/1333521): Change Info::size to uint64_t and eliminate this
  184. // cast.
  185. info->size = checked_cast<int64_t>(size.QuadPart);
  186. info->is_directory =
  187. (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  188. info->is_symbolic_link = false; // Windows doesn't have symbolic links.
  189. info->last_modified = Time::FromFileTime(file_info.ftLastWriteTime);
  190. info->last_accessed = Time::FromFileTime(file_info.ftLastAccessTime);
  191. info->creation_time = Time::FromFileTime(file_info.ftCreationTime);
  192. return true;
  193. }
  194. namespace {
  195. DWORD LockFileFlagsForMode(File::LockMode mode) {
  196. DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
  197. switch (mode) {
  198. case File::LockMode::kShared:
  199. return flags;
  200. case File::LockMode::kExclusive:
  201. return flags | LOCKFILE_EXCLUSIVE_LOCK;
  202. }
  203. NOTREACHED();
  204. }
  205. } // namespace
  206. File::Error File::Lock(File::LockMode mode) {
  207. DCHECK(IsValid());
  208. SCOPED_FILE_TRACE("Lock");
  209. OVERLAPPED overlapped = {};
  210. BOOL result =
  211. LockFileEx(file_.get(), LockFileFlagsForMode(mode), /*dwReserved=*/0,
  212. /*nNumberOfBytesToLockLow=*/MAXDWORD,
  213. /*nNumberOfBytesToLockHigh=*/MAXDWORD, &overlapped);
  214. if (!result)
  215. return GetLastFileError();
  216. return FILE_OK;
  217. }
  218. File::Error File::Unlock() {
  219. DCHECK(IsValid());
  220. SCOPED_FILE_TRACE("Unlock");
  221. OVERLAPPED overlapped = {};
  222. BOOL result =
  223. UnlockFileEx(file_.get(), /*dwReserved=*/0,
  224. /*nNumberOfBytesToLockLow=*/MAXDWORD,
  225. /*nNumberOfBytesToLockHigh=*/MAXDWORD, &overlapped);
  226. if (!result)
  227. return GetLastFileError();
  228. return FILE_OK;
  229. }
  230. File File::Duplicate() const {
  231. if (!IsValid())
  232. return File();
  233. SCOPED_FILE_TRACE("Duplicate");
  234. HANDLE other_handle = nullptr;
  235. if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle
  236. GetPlatformFile(),
  237. GetCurrentProcess(), // hTargetProcessHandle
  238. &other_handle,
  239. 0, // dwDesiredAccess ignored due to SAME_ACCESS
  240. FALSE, // !bInheritHandle
  241. DUPLICATE_SAME_ACCESS)) {
  242. return File(GetLastFileError());
  243. }
  244. return File(ScopedPlatformFile(other_handle), async());
  245. }
  246. bool File::DeleteOnClose(bool delete_on_close) {
  247. FILE_DISPOSITION_INFO disposition = {delete_on_close};
  248. return ::SetFileInformationByHandle(GetPlatformFile(), FileDispositionInfo,
  249. &disposition, sizeof(disposition)) != 0;
  250. }
  251. // Static.
  252. File::Error File::OSErrorToFileError(DWORD last_error) {
  253. switch (last_error) {
  254. case ERROR_SHARING_VIOLATION:
  255. case ERROR_UNABLE_TO_REMOVE_REPLACED: // ReplaceFile failure cases.
  256. case ERROR_UNABLE_TO_MOVE_REPLACEMENT:
  257. case ERROR_UNABLE_TO_MOVE_REPLACEMENT_2:
  258. return FILE_ERROR_IN_USE;
  259. case ERROR_ALREADY_EXISTS:
  260. case ERROR_FILE_EXISTS:
  261. return FILE_ERROR_EXISTS;
  262. case ERROR_FILE_NOT_FOUND:
  263. case ERROR_PATH_NOT_FOUND:
  264. return FILE_ERROR_NOT_FOUND;
  265. case ERROR_ACCESS_DENIED:
  266. case ERROR_LOCK_VIOLATION:
  267. return FILE_ERROR_ACCESS_DENIED;
  268. case ERROR_TOO_MANY_OPEN_FILES:
  269. return FILE_ERROR_TOO_MANY_OPENED;
  270. case ERROR_OUTOFMEMORY:
  271. case ERROR_NOT_ENOUGH_MEMORY:
  272. return FILE_ERROR_NO_MEMORY;
  273. case ERROR_HANDLE_DISK_FULL:
  274. case ERROR_DISK_FULL:
  275. case ERROR_DISK_RESOURCES_EXHAUSTED:
  276. return FILE_ERROR_NO_SPACE;
  277. case ERROR_USER_MAPPED_FILE:
  278. return FILE_ERROR_INVALID_OPERATION;
  279. case ERROR_NOT_READY: // The device is not ready.
  280. case ERROR_SECTOR_NOT_FOUND: // The drive cannot find the sector requested.
  281. case ERROR_GEN_FAILURE: // A device ... is not functioning.
  282. case ERROR_DEV_NOT_EXIST: // Net resource or device is no longer available.
  283. case ERROR_IO_DEVICE:
  284. case ERROR_DISK_OPERATION_FAILED:
  285. case ERROR_FILE_CORRUPT: // File or directory is corrupted and unreadable.
  286. case ERROR_DISK_CORRUPT: // The disk structure is corrupted and unreadable.
  287. return FILE_ERROR_IO;
  288. default:
  289. UmaHistogramSparse("PlatformFile.UnknownErrors.Windows",
  290. static_cast<int>(last_error));
  291. // This function should only be called for errors.
  292. DCHECK_NE(static_cast<DWORD>(ERROR_SUCCESS), last_error);
  293. return FILE_ERROR_FAILED;
  294. }
  295. }
  296. void File::DoInitialize(const FilePath& path, uint32_t flags) {
  297. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  298. DCHECK(!IsValid());
  299. DWORD disposition = 0;
  300. if (flags & FLAG_OPEN)
  301. disposition = OPEN_EXISTING;
  302. if (flags & FLAG_CREATE) {
  303. DCHECK(!disposition);
  304. disposition = CREATE_NEW;
  305. }
  306. if (flags & FLAG_OPEN_ALWAYS) {
  307. DCHECK(!disposition);
  308. disposition = OPEN_ALWAYS;
  309. }
  310. if (flags & FLAG_CREATE_ALWAYS) {
  311. DCHECK(!disposition);
  312. DCHECK(flags & FLAG_WRITE);
  313. disposition = CREATE_ALWAYS;
  314. }
  315. if (flags & FLAG_OPEN_TRUNCATED) {
  316. DCHECK(!disposition);
  317. DCHECK(flags & FLAG_WRITE);
  318. disposition = TRUNCATE_EXISTING;
  319. }
  320. if (!disposition) {
  321. ::SetLastError(ERROR_INVALID_PARAMETER);
  322. error_details_ = FILE_ERROR_FAILED;
  323. NOTREACHED();
  324. return;
  325. }
  326. DWORD access = 0;
  327. if (flags & FLAG_WRITE)
  328. access = GENERIC_WRITE;
  329. if (flags & FLAG_APPEND) {
  330. DCHECK(!access);
  331. access = FILE_APPEND_DATA;
  332. }
  333. if (flags & FLAG_READ)
  334. access |= GENERIC_READ;
  335. if (flags & FLAG_WRITE_ATTRIBUTES)
  336. access |= FILE_WRITE_ATTRIBUTES;
  337. if (flags & FLAG_WIN_EXECUTE)
  338. access |= GENERIC_EXECUTE;
  339. if (flags & FLAG_CAN_DELETE_ON_CLOSE)
  340. access |= DELETE;
  341. DWORD sharing = (flags & FLAG_WIN_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
  342. if (!(flags & FLAG_WIN_EXCLUSIVE_WRITE))
  343. sharing |= FILE_SHARE_WRITE;
  344. if (flags & FLAG_WIN_SHARE_DELETE)
  345. sharing |= FILE_SHARE_DELETE;
  346. DWORD create_flags = 0;
  347. if (flags & FLAG_ASYNC)
  348. create_flags |= FILE_FLAG_OVERLAPPED;
  349. if (flags & FLAG_WIN_TEMPORARY)
  350. create_flags |= FILE_ATTRIBUTE_TEMPORARY;
  351. if (flags & FLAG_WIN_HIDDEN)
  352. create_flags |= FILE_ATTRIBUTE_HIDDEN;
  353. if (flags & FLAG_DELETE_ON_CLOSE)
  354. create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
  355. if (flags & FLAG_WIN_BACKUP_SEMANTICS)
  356. create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
  357. if (flags & FLAG_WIN_SEQUENTIAL_SCAN)
  358. create_flags |= FILE_FLAG_SEQUENTIAL_SCAN;
  359. file_.Set(CreateFile(path.value().c_str(), access, sharing, NULL, disposition,
  360. create_flags, NULL));
  361. if (file_.is_valid()) {
  362. error_details_ = FILE_OK;
  363. async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
  364. if (flags & (FLAG_OPEN_ALWAYS))
  365. created_ = (ERROR_ALREADY_EXISTS != GetLastError());
  366. else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
  367. created_ = true;
  368. } else {
  369. error_details_ = GetLastFileError();
  370. }
  371. }
  372. bool File::Flush() {
  373. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  374. DCHECK(IsValid());
  375. SCOPED_FILE_TRACE("Flush");
  376. // On Windows 8 and above, FlushFileBuffers is guaranteed to flush the storage
  377. // device's internal buffers (if they exist) before returning.
  378. // https://blogs.msdn.microsoft.com/oldnewthing/20170510-00/?p=95505
  379. return ::FlushFileBuffers(file_.get()) != FALSE;
  380. }
  381. void File::SetPlatformFile(PlatformFile file) {
  382. file_.Set(file);
  383. }
  384. // static
  385. File::Error File::GetLastFileError() {
  386. return File::OSErrorToFileError(GetLastError());
  387. }
  388. } // namespace base