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