file_posix.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  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 <errno.h>
  6. #include <fcntl.h>
  7. #include <stdint.h>
  8. #include <sys/stat.h>
  9. #include <unistd.h>
  10. #include "base/check_op.h"
  11. #include "base/notreached.h"
  12. #include "base/numerics/safe_conversions.h"
  13. #include "base/posix/eintr_wrapper.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "base/threading/scoped_blocking_call.h"
  16. #include "build/build_config.h"
  17. #include "third_party/abseil-cpp/absl/types/optional.h"
  18. #if BUILDFLAG(IS_ANDROID)
  19. #include "base/os_compat_android.h"
  20. #endif
  21. namespace base {
  22. // Make sure our Whence mappings match the system headers.
  23. static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
  24. File::FROM_END == SEEK_END,
  25. "whence mapping must match the system headers");
  26. namespace {
  27. // NaCl doesn't provide the following system calls, so either simulate them or
  28. // wrap them in order to minimize the number of #ifdef's in this file.
  29. #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
  30. bool IsOpenAppend(PlatformFile file) {
  31. return (fcntl(file, F_GETFL) & O_APPEND) != 0;
  32. }
  33. int CallFtruncate(PlatformFile file, int64_t length) {
  34. #if BUILDFLAG(IS_BSD) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
  35. static_assert(sizeof(off_t) >= sizeof(int64_t),
  36. "off_t is not a 64-bit integer");
  37. return HANDLE_EINTR(ftruncate(file, length));
  38. #else
  39. return HANDLE_EINTR(ftruncate64(file, length));
  40. #endif
  41. }
  42. int CallFutimes(PlatformFile file, const struct timeval times[2]) {
  43. #ifdef __USE_XOPEN2K8
  44. // futimens should be available, but futimes might not be
  45. // http://pubs.opengroup.org/onlinepubs/9699919799/
  46. timespec ts_times[2];
  47. ts_times[0].tv_sec = times[0].tv_sec;
  48. ts_times[0].tv_nsec = times[0].tv_usec * 1000;
  49. ts_times[1].tv_sec = times[1].tv_sec;
  50. ts_times[1].tv_nsec = times[1].tv_usec * 1000;
  51. return futimens(file, ts_times);
  52. #else
  53. return futimes(file, times);
  54. #endif
  55. }
  56. #if !BUILDFLAG(IS_FUCHSIA)
  57. short FcntlFlockType(absl::optional<File::LockMode> mode) {
  58. if (!mode.has_value())
  59. return F_UNLCK;
  60. switch (mode.value()) {
  61. case File::LockMode::kShared:
  62. return F_RDLCK;
  63. case File::LockMode::kExclusive:
  64. return F_WRLCK;
  65. }
  66. NOTREACHED();
  67. }
  68. File::Error CallFcntlFlock(PlatformFile file,
  69. absl::optional<File::LockMode> mode) {
  70. struct flock lock;
  71. lock.l_type = FcntlFlockType(std::move(mode));
  72. lock.l_whence = SEEK_SET;
  73. lock.l_start = 0;
  74. lock.l_len = 0; // Lock entire file.
  75. if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1)
  76. return File::GetLastFileError();
  77. return File::FILE_OK;
  78. }
  79. #endif
  80. #else // BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
  81. bool IsOpenAppend(PlatformFile file) {
  82. // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
  83. // standard and always appends if the file is opened with O_APPEND, just
  84. // return false here.
  85. return false;
  86. }
  87. int CallFtruncate(PlatformFile file, int64_t length) {
  88. NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
  89. return 0;
  90. }
  91. int CallFutimes(PlatformFile file, const struct timeval times[2]) {
  92. NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
  93. return 0;
  94. }
  95. File::Error CallFcntlFlock(PlatformFile file,
  96. absl::optional<File::LockMode> mode) {
  97. NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
  98. return File::FILE_ERROR_INVALID_OPERATION;
  99. }
  100. #endif // BUILDFLAG(IS_NACL)
  101. } // namespace
  102. void File::Info::FromStat(const stat_wrapper_t& stat_info) {
  103. is_directory = S_ISDIR(stat_info.st_mode);
  104. is_symbolic_link = S_ISLNK(stat_info.st_mode);
  105. size = stat_info.st_size;
  106. // Get last modification time, last access time, and creation time from
  107. // |stat_info|.
  108. // Note: st_ctime is actually last status change time when the inode was last
  109. // updated, which happens on any metadata change. It is not the file's
  110. // creation time. However, other than on Mac & iOS where the actual file
  111. // creation time is included as st_birthtime, the rest of POSIX platforms have
  112. // no portable way to get the creation time.
  113. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
  114. time_t last_modified_sec = stat_info.st_mtim.tv_sec;
  115. int64_t last_modified_nsec = stat_info.st_mtim.tv_nsec;
  116. time_t last_accessed_sec = stat_info.st_atim.tv_sec;
  117. int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec;
  118. time_t creation_time_sec = stat_info.st_ctim.tv_sec;
  119. int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec;
  120. #elif BUILDFLAG(IS_ANDROID)
  121. time_t last_modified_sec = stat_info.st_mtime;
  122. int64_t last_modified_nsec = stat_info.st_mtime_nsec;
  123. time_t last_accessed_sec = stat_info.st_atime;
  124. int64_t last_accessed_nsec = stat_info.st_atime_nsec;
  125. time_t creation_time_sec = stat_info.st_ctime;
  126. int64_t creation_time_nsec = stat_info.st_ctime_nsec;
  127. #elif BUILDFLAG(IS_APPLE)
  128. time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
  129. int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
  130. time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
  131. int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
  132. time_t creation_time_sec = stat_info.st_birthtimespec.tv_sec;
  133. int64_t creation_time_nsec = stat_info.st_birthtimespec.tv_nsec;
  134. #elif BUILDFLAG(IS_BSD)
  135. time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
  136. int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
  137. time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
  138. int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
  139. time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
  140. int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
  141. #else
  142. time_t last_modified_sec = stat_info.st_mtime;
  143. int64_t last_modified_nsec = 0;
  144. time_t last_accessed_sec = stat_info.st_atime;
  145. int64_t last_accessed_nsec = 0;
  146. time_t creation_time_sec = stat_info.st_ctime;
  147. int64_t creation_time_nsec = 0;
  148. #endif
  149. last_modified =
  150. Time::FromTimeT(last_modified_sec) +
  151. Microseconds(last_modified_nsec / Time::kNanosecondsPerMicrosecond);
  152. last_accessed =
  153. Time::FromTimeT(last_accessed_sec) +
  154. Microseconds(last_accessed_nsec / Time::kNanosecondsPerMicrosecond);
  155. creation_time =
  156. Time::FromTimeT(creation_time_sec) +
  157. Microseconds(creation_time_nsec / Time::kNanosecondsPerMicrosecond);
  158. }
  159. bool File::IsValid() const {
  160. return file_.is_valid();
  161. }
  162. PlatformFile File::GetPlatformFile() const {
  163. return file_.get();
  164. }
  165. PlatformFile File::TakePlatformFile() {
  166. return file_.release();
  167. }
  168. void File::Close() {
  169. if (!IsValid())
  170. return;
  171. SCOPED_FILE_TRACE("Close");
  172. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  173. file_.reset();
  174. }
  175. int64_t File::Seek(Whence whence, int64_t offset) {
  176. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  177. DCHECK(IsValid());
  178. SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
  179. #if BUILDFLAG(IS_ANDROID)
  180. static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
  181. return lseek64(file_.get(), static_cast<off64_t>(offset),
  182. static_cast<int>(whence));
  183. #else
  184. static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits");
  185. return lseek(file_.get(), static_cast<off_t>(offset),
  186. static_cast<int>(whence));
  187. #endif
  188. }
  189. int File::Read(int64_t offset, char* data, int size) {
  190. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  191. DCHECK(IsValid());
  192. if (size < 0 || !IsValueInRangeForNumericType<off_t>(offset + size - 1))
  193. return -1;
  194. SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
  195. int bytes_read = 0;
  196. long rv;
  197. do {
  198. rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
  199. static_cast<size_t>(size - bytes_read),
  200. static_cast<off_t>(offset + bytes_read)));
  201. if (rv <= 0)
  202. break;
  203. bytes_read += rv;
  204. } while (bytes_read < size);
  205. return bytes_read ? bytes_read : checked_cast<int>(rv);
  206. }
  207. int File::ReadAtCurrentPos(char* data, int size) {
  208. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  209. DCHECK(IsValid());
  210. if (size < 0)
  211. return -1;
  212. SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
  213. int bytes_read = 0;
  214. long rv;
  215. do {
  216. rv = HANDLE_EINTR(read(file_.get(), data + bytes_read,
  217. static_cast<size_t>(size - bytes_read)));
  218. if (rv <= 0)
  219. break;
  220. bytes_read += rv;
  221. } while (bytes_read < size);
  222. return bytes_read ? bytes_read : checked_cast<int>(rv);
  223. }
  224. int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
  225. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  226. DCHECK(IsValid());
  227. if (size < 0 || !IsValueInRangeForNumericType<off_t>(offset))
  228. return -1;
  229. SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
  230. return checked_cast<int>(
  231. HANDLE_EINTR(pread(file_.get(), data, static_cast<size_t>(size),
  232. static_cast<off_t>(offset))));
  233. }
  234. int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
  235. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  236. DCHECK(IsValid());
  237. if (size < 0)
  238. return -1;
  239. SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPosNoBestEffort", size);
  240. return checked_cast<int>(
  241. HANDLE_EINTR(read(file_.get(), data, static_cast<size_t>(size))));
  242. }
  243. int File::Write(int64_t offset, const char* data, int size) {
  244. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  245. if (IsOpenAppend(file_.get()))
  246. return WriteAtCurrentPos(data, size);
  247. DCHECK(IsValid());
  248. if (size < 0)
  249. return -1;
  250. SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
  251. int bytes_written = 0;
  252. long rv;
  253. do {
  254. #if BUILDFLAG(IS_ANDROID)
  255. // In case __USE_FILE_OFFSET64 is not used, we need to call pwrite64()
  256. // instead of pwrite().
  257. static_assert(sizeof(int64_t) == sizeof(off64_t),
  258. "off64_t must be 64 bits");
  259. rv = HANDLE_EINTR(pwrite64(file_.get(), data + bytes_written,
  260. static_cast<size_t>(size - bytes_written),
  261. offset + bytes_written));
  262. #else
  263. rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
  264. static_cast<size_t>(size - bytes_written),
  265. offset + bytes_written));
  266. #endif
  267. if (rv <= 0)
  268. break;
  269. bytes_written += rv;
  270. } while (bytes_written < size);
  271. return bytes_written ? bytes_written : checked_cast<int>(rv);
  272. }
  273. int File::WriteAtCurrentPos(const char* data, int size) {
  274. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  275. DCHECK(IsValid());
  276. if (size < 0)
  277. return -1;
  278. SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
  279. int bytes_written = 0;
  280. long rv;
  281. do {
  282. rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
  283. static_cast<size_t>(size - bytes_written)));
  284. if (rv <= 0)
  285. break;
  286. bytes_written += rv;
  287. } while (bytes_written < size);
  288. return bytes_written ? bytes_written : checked_cast<int>(rv);
  289. }
  290. int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
  291. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  292. DCHECK(IsValid());
  293. if (size < 0)
  294. return -1;
  295. SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPosNoBestEffort", size);
  296. return checked_cast<int>(
  297. HANDLE_EINTR(write(file_.get(), data, static_cast<size_t>(size))));
  298. }
  299. int64_t File::GetLength() {
  300. DCHECK(IsValid());
  301. SCOPED_FILE_TRACE("GetLength");
  302. stat_wrapper_t file_info;
  303. if (Fstat(file_.get(), &file_info))
  304. return -1;
  305. return file_info.st_size;
  306. }
  307. bool File::SetLength(int64_t length) {
  308. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  309. DCHECK(IsValid());
  310. SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
  311. return !CallFtruncate(file_.get(), length);
  312. }
  313. bool File::SetTimes(Time last_access_time, Time last_modified_time) {
  314. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  315. DCHECK(IsValid());
  316. SCOPED_FILE_TRACE("SetTimes");
  317. timeval times[2];
  318. times[0] = last_access_time.ToTimeVal();
  319. times[1] = last_modified_time.ToTimeVal();
  320. return !CallFutimes(file_.get(), times);
  321. }
  322. bool File::GetInfo(Info* info) {
  323. DCHECK(IsValid());
  324. SCOPED_FILE_TRACE("GetInfo");
  325. stat_wrapper_t file_info;
  326. if (Fstat(file_.get(), &file_info))
  327. return false;
  328. info->FromStat(file_info);
  329. return true;
  330. }
  331. #if !BUILDFLAG(IS_FUCHSIA)
  332. File::Error File::Lock(File::LockMode mode) {
  333. SCOPED_FILE_TRACE("Lock");
  334. return CallFcntlFlock(file_.get(), mode);
  335. }
  336. File::Error File::Unlock() {
  337. SCOPED_FILE_TRACE("Unlock");
  338. return CallFcntlFlock(file_.get(), absl::optional<File::LockMode>());
  339. }
  340. #endif
  341. File File::Duplicate() const {
  342. if (!IsValid())
  343. return File();
  344. SCOPED_FILE_TRACE("Duplicate");
  345. ScopedPlatformFile other_fd(HANDLE_EINTR(dup(GetPlatformFile())));
  346. if (!other_fd.is_valid())
  347. return File(File::GetLastFileError());
  348. return File(std::move(other_fd), async());
  349. }
  350. // Static.
  351. File::Error File::OSErrorToFileError(int saved_errno) {
  352. switch (saved_errno) {
  353. case EACCES:
  354. case EISDIR:
  355. case EROFS:
  356. case EPERM:
  357. return FILE_ERROR_ACCESS_DENIED;
  358. case EBUSY:
  359. #if !BUILDFLAG(IS_NACL) // ETXTBSY not defined by NaCl.
  360. case ETXTBSY:
  361. #endif
  362. return FILE_ERROR_IN_USE;
  363. case EEXIST:
  364. return FILE_ERROR_EXISTS;
  365. case EIO:
  366. return FILE_ERROR_IO;
  367. case ENOENT:
  368. return FILE_ERROR_NOT_FOUND;
  369. case ENFILE: // fallthrough
  370. case EMFILE:
  371. return FILE_ERROR_TOO_MANY_OPENED;
  372. case ENOMEM:
  373. return FILE_ERROR_NO_MEMORY;
  374. case ENOSPC:
  375. return FILE_ERROR_NO_SPACE;
  376. case ENOTDIR:
  377. return FILE_ERROR_NOT_A_DIRECTORY;
  378. default:
  379. // This function should only be called for errors.
  380. DCHECK_NE(0, saved_errno);
  381. return FILE_ERROR_FAILED;
  382. }
  383. }
  384. // NaCl doesn't implement system calls to open files directly.
  385. #if !BUILDFLAG(IS_NACL)
  386. // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
  387. void File::DoInitialize(const FilePath& path, uint32_t flags) {
  388. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  389. DCHECK(!IsValid());
  390. int open_flags = 0;
  391. if (flags & FLAG_CREATE)
  392. open_flags = O_CREAT | O_EXCL;
  393. created_ = false;
  394. if (flags & FLAG_CREATE_ALWAYS) {
  395. DCHECK(!open_flags);
  396. DCHECK(flags & FLAG_WRITE);
  397. open_flags = O_CREAT | O_TRUNC;
  398. }
  399. if (flags & FLAG_OPEN_TRUNCATED) {
  400. DCHECK(!open_flags);
  401. DCHECK(flags & FLAG_WRITE);
  402. open_flags = O_TRUNC;
  403. }
  404. if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
  405. NOTREACHED();
  406. errno = EOPNOTSUPP;
  407. error_details_ = FILE_ERROR_FAILED;
  408. return;
  409. }
  410. if (flags & FLAG_WRITE && flags & FLAG_READ) {
  411. open_flags |= O_RDWR;
  412. } else if (flags & FLAG_WRITE) {
  413. open_flags |= O_WRONLY;
  414. } else if (!(flags & FLAG_READ) && !(flags & FLAG_WRITE_ATTRIBUTES) &&
  415. !(flags & FLAG_APPEND) && !(flags & FLAG_OPEN_ALWAYS)) {
  416. // Note: For FLAG_WRITE_ATTRIBUTES and no other read/write flags, we'll
  417. // open the file in O_RDONLY mode (== 0, see static_assert below), so that
  418. // we get a fd that can be used for SetTimes().
  419. NOTREACHED();
  420. }
  421. if (flags & FLAG_TERMINAL_DEVICE)
  422. open_flags |= O_NOCTTY | O_NDELAY;
  423. if (flags & FLAG_APPEND && flags & FLAG_READ)
  424. open_flags |= O_APPEND | O_RDWR;
  425. else if (flags & FLAG_APPEND)
  426. open_flags |= O_APPEND | O_WRONLY;
  427. static_assert(O_RDONLY == 0, "O_RDONLY must equal zero");
  428. mode_t mode = S_IRUSR | S_IWUSR;
  429. #if BUILDFLAG(IS_CHROMEOS)
  430. mode |= S_IRGRP | S_IROTH;
  431. #endif
  432. int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
  433. if (flags & FLAG_OPEN_ALWAYS) {
  434. if (descriptor < 0) {
  435. open_flags |= O_CREAT;
  436. descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
  437. if (descriptor >= 0)
  438. created_ = true;
  439. }
  440. }
  441. if (descriptor < 0) {
  442. error_details_ = File::GetLastFileError();
  443. return;
  444. }
  445. if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
  446. created_ = true;
  447. if (flags & FLAG_DELETE_ON_CLOSE)
  448. unlink(path.value().c_str());
  449. async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
  450. error_details_ = FILE_OK;
  451. file_.reset(descriptor);
  452. }
  453. #endif // !BUILDFLAG(IS_NACL)
  454. bool File::Flush() {
  455. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  456. DCHECK(IsValid());
  457. SCOPED_FILE_TRACE("Flush");
  458. #if BUILDFLAG(IS_NACL)
  459. NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
  460. return true;
  461. #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || \
  462. BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_LINUX)
  463. return !HANDLE_EINTR(fdatasync(file_.get()));
  464. #elif BUILDFLAG(IS_APPLE)
  465. // On macOS and iOS, fsync() is guaranteed to send the file's data to the
  466. // underlying storage device, but may return before the device actually writes
  467. // the data to the medium. When used by database systems, this may result in
  468. // unexpected data loss.
  469. // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html
  470. if (!HANDLE_EINTR(fcntl(file_.get(), F_FULLFSYNC)))
  471. return true;
  472. // Some filesystms do not support fcntl(F_FULLFSYNC). We handle these cases by
  473. // falling back to fsync(). Unfortunately, lack of F_FULLFSYNC support results
  474. // in various error codes, so we cannot use the error code as a definitive
  475. // indicator that F_FULLFSYNC was not supported. So, if fcntl() errors out for
  476. // any reason, we may end up making an unnecessary system call.
  477. //
  478. // See the CL description at https://crrev.com/c/1400159 for details.
  479. return !HANDLE_EINTR(fsync(file_.get()));
  480. #else
  481. return !HANDLE_EINTR(fsync(file_.get()));
  482. #endif
  483. }
  484. void File::SetPlatformFile(PlatformFile file) {
  485. DCHECK(!file_.is_valid());
  486. file_.reset(file);
  487. }
  488. // static
  489. File::Error File::GetLastFileError() {
  490. return base::File::OSErrorToFileError(errno);
  491. }
  492. #if BUILDFLAG(IS_BSD) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_NACL) || \
  493. BUILDFLAG(IS_FUCHSIA) || (BUILDFLAG(IS_ANDROID) && __ANDROID_API__ < 21)
  494. int File::Stat(const char* path, stat_wrapper_t* sb) {
  495. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  496. return stat(path, sb);
  497. }
  498. int File::Fstat(int fd, stat_wrapper_t* sb) {
  499. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  500. return fstat(fd, sb);
  501. }
  502. int File::Lstat(const char* path, stat_wrapper_t* sb) {
  503. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  504. return lstat(path, sb);
  505. }
  506. #else
  507. int File::Stat(const char* path, stat_wrapper_t* sb) {
  508. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  509. return stat64(path, sb);
  510. }
  511. int File::Fstat(int fd, stat_wrapper_t* sb) {
  512. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  513. return fstat64(fd, sb);
  514. }
  515. int File::Lstat(const char* path, stat_wrapper_t* sb) {
  516. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  517. return lstat64(path, sb);
  518. }
  519. #endif
  520. } // namespace base