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