123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/files/file.h"
- #include <errno.h>
- #include <fcntl.h>
- #include <stdint.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include "base/check_op.h"
- #include "base/notreached.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/posix/eintr_wrapper.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/threading/scoped_blocking_call.h"
- #include "build/build_config.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #if BUILDFLAG(IS_ANDROID)
- #include "base/os_compat_android.h"
- #endif
- namespace base {
- // Make sure our Whence mappings match the system headers.
- static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
- File::FROM_END == SEEK_END,
- "whence mapping must match the system headers");
- namespace {
- // NaCl doesn't provide the following system calls, so either simulate them or
- // wrap them in order to minimize the number of #ifdef's in this file.
- #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
- bool IsOpenAppend(PlatformFile file) {
- return (fcntl(file, F_GETFL) & O_APPEND) != 0;
- }
- int CallFtruncate(PlatformFile file, int64_t length) {
- #if BUILDFLAG(IS_BSD) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
- static_assert(sizeof(off_t) >= sizeof(int64_t),
- "off_t is not a 64-bit integer");
- return HANDLE_EINTR(ftruncate(file, length));
- #else
- return HANDLE_EINTR(ftruncate64(file, length));
- #endif
- }
- int CallFutimes(PlatformFile file, const struct timeval times[2]) {
- #ifdef __USE_XOPEN2K8
- // futimens should be available, but futimes might not be
- // http://pubs.opengroup.org/onlinepubs/9699919799/
- timespec ts_times[2];
- ts_times[0].tv_sec = times[0].tv_sec;
- ts_times[0].tv_nsec = times[0].tv_usec * 1000;
- ts_times[1].tv_sec = times[1].tv_sec;
- ts_times[1].tv_nsec = times[1].tv_usec * 1000;
- return futimens(file, ts_times);
- #else
- return futimes(file, times);
- #endif
- }
- #if !BUILDFLAG(IS_FUCHSIA)
- short FcntlFlockType(absl::optional<File::LockMode> mode) {
- if (!mode.has_value())
- return F_UNLCK;
- switch (mode.value()) {
- case File::LockMode::kShared:
- return F_RDLCK;
- case File::LockMode::kExclusive:
- return F_WRLCK;
- }
- NOTREACHED();
- }
- File::Error CallFcntlFlock(PlatformFile file,
- absl::optional<File::LockMode> mode) {
- struct flock lock;
- lock.l_type = FcntlFlockType(std::move(mode));
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0; // Lock entire file.
- if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1)
- return File::GetLastFileError();
- return File::FILE_OK;
- }
- #endif
- #else // BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
- bool IsOpenAppend(PlatformFile file) {
- // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
- // standard and always appends if the file is opened with O_APPEND, just
- // return false here.
- return false;
- }
- int CallFtruncate(PlatformFile file, int64_t length) {
- NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
- return 0;
- }
- int CallFutimes(PlatformFile file, const struct timeval times[2]) {
- NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
- return 0;
- }
- File::Error CallFcntlFlock(PlatformFile file,
- absl::optional<File::LockMode> mode) {
- NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
- return File::FILE_ERROR_INVALID_OPERATION;
- }
- #endif // BUILDFLAG(IS_NACL)
- } // namespace
- void File::Info::FromStat(const stat_wrapper_t& stat_info) {
- is_directory = S_ISDIR(stat_info.st_mode);
- is_symbolic_link = S_ISLNK(stat_info.st_mode);
- size = stat_info.st_size;
- // Get last modification time, last access time, and creation time from
- // |stat_info|.
- // Note: st_ctime is actually last status change time when the inode was last
- // updated, which happens on any metadata change. It is not the file's
- // creation time. However, other than on Mac & iOS where the actual file
- // creation time is included as st_birthtime, the rest of POSIX platforms have
- // no portable way to get the creation time.
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
- time_t last_modified_sec = stat_info.st_mtim.tv_sec;
- int64_t last_modified_nsec = stat_info.st_mtim.tv_nsec;
- time_t last_accessed_sec = stat_info.st_atim.tv_sec;
- int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec;
- time_t creation_time_sec = stat_info.st_ctim.tv_sec;
- int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec;
- #elif BUILDFLAG(IS_ANDROID)
- time_t last_modified_sec = stat_info.st_mtime;
- int64_t last_modified_nsec = stat_info.st_mtime_nsec;
- time_t last_accessed_sec = stat_info.st_atime;
- int64_t last_accessed_nsec = stat_info.st_atime_nsec;
- time_t creation_time_sec = stat_info.st_ctime;
- int64_t creation_time_nsec = stat_info.st_ctime_nsec;
- #elif BUILDFLAG(IS_APPLE)
- time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
- int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
- time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
- int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
- time_t creation_time_sec = stat_info.st_birthtimespec.tv_sec;
- int64_t creation_time_nsec = stat_info.st_birthtimespec.tv_nsec;
- #elif BUILDFLAG(IS_BSD)
- time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
- int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
- time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
- int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
- time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
- int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
- #else
- time_t last_modified_sec = stat_info.st_mtime;
- int64_t last_modified_nsec = 0;
- time_t last_accessed_sec = stat_info.st_atime;
- int64_t last_accessed_nsec = 0;
- time_t creation_time_sec = stat_info.st_ctime;
- int64_t creation_time_nsec = 0;
- #endif
- last_modified =
- Time::FromTimeT(last_modified_sec) +
- Microseconds(last_modified_nsec / Time::kNanosecondsPerMicrosecond);
- last_accessed =
- Time::FromTimeT(last_accessed_sec) +
- Microseconds(last_accessed_nsec / Time::kNanosecondsPerMicrosecond);
- creation_time =
- Time::FromTimeT(creation_time_sec) +
- Microseconds(creation_time_nsec / Time::kNanosecondsPerMicrosecond);
- }
- bool File::IsValid() const {
- return file_.is_valid();
- }
- PlatformFile File::GetPlatformFile() const {
- return file_.get();
- }
- PlatformFile File::TakePlatformFile() {
- return file_.release();
- }
- void File::Close() {
- if (!IsValid())
- return;
- SCOPED_FILE_TRACE("Close");
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- file_.reset();
- }
- int64_t File::Seek(Whence whence, int64_t offset) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
- #if BUILDFLAG(IS_ANDROID)
- static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
- return lseek64(file_.get(), static_cast<off64_t>(offset),
- static_cast<int>(whence));
- #else
- static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits");
- return lseek(file_.get(), static_cast<off_t>(offset),
- static_cast<int>(whence));
- #endif
- }
- int File::Read(int64_t offset, char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- if (size < 0 || !IsValueInRangeForNumericType<off_t>(offset + size - 1))
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
- int bytes_read = 0;
- long rv;
- do {
- rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
- static_cast<size_t>(size - bytes_read),
- static_cast<off_t>(offset + bytes_read)));
- if (rv <= 0)
- break;
- bytes_read += rv;
- } while (bytes_read < size);
- return bytes_read ? bytes_read : checked_cast<int>(rv);
- }
- int File::ReadAtCurrentPos(char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- if (size < 0)
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
- int bytes_read = 0;
- long rv;
- do {
- rv = HANDLE_EINTR(read(file_.get(), data + bytes_read,
- static_cast<size_t>(size - bytes_read)));
- if (rv <= 0)
- break;
- bytes_read += rv;
- } while (bytes_read < size);
- return bytes_read ? bytes_read : checked_cast<int>(rv);
- }
- int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- if (size < 0 || !IsValueInRangeForNumericType<off_t>(offset))
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
- return checked_cast<int>(
- HANDLE_EINTR(pread(file_.get(), data, static_cast<size_t>(size),
- static_cast<off_t>(offset))));
- }
- int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- if (size < 0)
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPosNoBestEffort", size);
- return checked_cast<int>(
- HANDLE_EINTR(read(file_.get(), data, static_cast<size_t>(size))));
- }
- int File::Write(int64_t offset, const char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- if (IsOpenAppend(file_.get()))
- return WriteAtCurrentPos(data, size);
- DCHECK(IsValid());
- if (size < 0)
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
- int bytes_written = 0;
- long rv;
- do {
- #if BUILDFLAG(IS_ANDROID)
- // In case __USE_FILE_OFFSET64 is not used, we need to call pwrite64()
- // instead of pwrite().
- static_assert(sizeof(int64_t) == sizeof(off64_t),
- "off64_t must be 64 bits");
- rv = HANDLE_EINTR(pwrite64(file_.get(), data + bytes_written,
- static_cast<size_t>(size - bytes_written),
- offset + bytes_written));
- #else
- rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
- static_cast<size_t>(size - bytes_written),
- offset + bytes_written));
- #endif
- if (rv <= 0)
- break;
- bytes_written += rv;
- } while (bytes_written < size);
- return bytes_written ? bytes_written : checked_cast<int>(rv);
- }
- int File::WriteAtCurrentPos(const char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- if (size < 0)
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
- int bytes_written = 0;
- long rv;
- do {
- rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
- static_cast<size_t>(size - bytes_written)));
- if (rv <= 0)
- break;
- bytes_written += rv;
- } while (bytes_written < size);
- return bytes_written ? bytes_written : checked_cast<int>(rv);
- }
- int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- if (size < 0)
- return -1;
- SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPosNoBestEffort", size);
- return checked_cast<int>(
- HANDLE_EINTR(write(file_.get(), data, static_cast<size_t>(size))));
- }
- int64_t File::GetLength() {
- DCHECK(IsValid());
- SCOPED_FILE_TRACE("GetLength");
- stat_wrapper_t file_info;
- if (Fstat(file_.get(), &file_info))
- return -1;
- return file_info.st_size;
- }
- bool File::SetLength(int64_t length) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
- return !CallFtruncate(file_.get(), length);
- }
- bool File::SetTimes(Time last_access_time, Time last_modified_time) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- SCOPED_FILE_TRACE("SetTimes");
- timeval times[2];
- times[0] = last_access_time.ToTimeVal();
- times[1] = last_modified_time.ToTimeVal();
- return !CallFutimes(file_.get(), times);
- }
- bool File::GetInfo(Info* info) {
- DCHECK(IsValid());
- SCOPED_FILE_TRACE("GetInfo");
- stat_wrapper_t file_info;
- if (Fstat(file_.get(), &file_info))
- return false;
- info->FromStat(file_info);
- return true;
- }
- #if !BUILDFLAG(IS_FUCHSIA)
- File::Error File::Lock(File::LockMode mode) {
- SCOPED_FILE_TRACE("Lock");
- return CallFcntlFlock(file_.get(), mode);
- }
- File::Error File::Unlock() {
- SCOPED_FILE_TRACE("Unlock");
- return CallFcntlFlock(file_.get(), absl::optional<File::LockMode>());
- }
- #endif
- File File::Duplicate() const {
- if (!IsValid())
- return File();
- SCOPED_FILE_TRACE("Duplicate");
- ScopedPlatformFile other_fd(HANDLE_EINTR(dup(GetPlatformFile())));
- if (!other_fd.is_valid())
- return File(File::GetLastFileError());
- return File(std::move(other_fd), async());
- }
- // Static.
- File::Error File::OSErrorToFileError(int saved_errno) {
- switch (saved_errno) {
- case EACCES:
- case EISDIR:
- case EROFS:
- case EPERM:
- return FILE_ERROR_ACCESS_DENIED;
- case EBUSY:
- #if !BUILDFLAG(IS_NACL) // ETXTBSY not defined by NaCl.
- case ETXTBSY:
- #endif
- return FILE_ERROR_IN_USE;
- case EEXIST:
- return FILE_ERROR_EXISTS;
- case EIO:
- return FILE_ERROR_IO;
- case ENOENT:
- return FILE_ERROR_NOT_FOUND;
- case ENFILE: // fallthrough
- case EMFILE:
- return FILE_ERROR_TOO_MANY_OPENED;
- case ENOMEM:
- return FILE_ERROR_NO_MEMORY;
- case ENOSPC:
- return FILE_ERROR_NO_SPACE;
- case ENOTDIR:
- return FILE_ERROR_NOT_A_DIRECTORY;
- default:
- // This function should only be called for errors.
- DCHECK_NE(0, saved_errno);
- return FILE_ERROR_FAILED;
- }
- }
- // NaCl doesn't implement system calls to open files directly.
- #if !BUILDFLAG(IS_NACL)
- // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
- void File::DoInitialize(const FilePath& path, uint32_t flags) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(!IsValid());
- int open_flags = 0;
- if (flags & FLAG_CREATE)
- open_flags = O_CREAT | O_EXCL;
- created_ = false;
- if (flags & FLAG_CREATE_ALWAYS) {
- DCHECK(!open_flags);
- DCHECK(flags & FLAG_WRITE);
- open_flags = O_CREAT | O_TRUNC;
- }
- if (flags & FLAG_OPEN_TRUNCATED) {
- DCHECK(!open_flags);
- DCHECK(flags & FLAG_WRITE);
- open_flags = O_TRUNC;
- }
- if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
- NOTREACHED();
- errno = EOPNOTSUPP;
- error_details_ = FILE_ERROR_FAILED;
- return;
- }
- if (flags & FLAG_WRITE && flags & FLAG_READ) {
- open_flags |= O_RDWR;
- } else if (flags & FLAG_WRITE) {
- open_flags |= O_WRONLY;
- } else if (!(flags & FLAG_READ) && !(flags & FLAG_WRITE_ATTRIBUTES) &&
- !(flags & FLAG_APPEND) && !(flags & FLAG_OPEN_ALWAYS)) {
- // Note: For FLAG_WRITE_ATTRIBUTES and no other read/write flags, we'll
- // open the file in O_RDONLY mode (== 0, see static_assert below), so that
- // we get a fd that can be used for SetTimes().
- NOTREACHED();
- }
- if (flags & FLAG_TERMINAL_DEVICE)
- open_flags |= O_NOCTTY | O_NDELAY;
- if (flags & FLAG_APPEND && flags & FLAG_READ)
- open_flags |= O_APPEND | O_RDWR;
- else if (flags & FLAG_APPEND)
- open_flags |= O_APPEND | O_WRONLY;
- static_assert(O_RDONLY == 0, "O_RDONLY must equal zero");
- mode_t mode = S_IRUSR | S_IWUSR;
- #if BUILDFLAG(IS_CHROMEOS)
- mode |= S_IRGRP | S_IROTH;
- #endif
- int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
- if (flags & FLAG_OPEN_ALWAYS) {
- if (descriptor < 0) {
- open_flags |= O_CREAT;
- descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
- if (descriptor >= 0)
- created_ = true;
- }
- }
- if (descriptor < 0) {
- error_details_ = File::GetLastFileError();
- return;
- }
- if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
- created_ = true;
- if (flags & FLAG_DELETE_ON_CLOSE)
- unlink(path.value().c_str());
- async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
- error_details_ = FILE_OK;
- file_.reset(descriptor);
- }
- #endif // !BUILDFLAG(IS_NACL)
- bool File::Flush() {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- DCHECK(IsValid());
- SCOPED_FILE_TRACE("Flush");
- #if BUILDFLAG(IS_NACL)
- NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
- return true;
- #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || \
- BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_LINUX)
- return !HANDLE_EINTR(fdatasync(file_.get()));
- #elif BUILDFLAG(IS_APPLE)
- // On macOS and iOS, fsync() is guaranteed to send the file's data to the
- // underlying storage device, but may return before the device actually writes
- // the data to the medium. When used by database systems, this may result in
- // unexpected data loss.
- // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html
- if (!HANDLE_EINTR(fcntl(file_.get(), F_FULLFSYNC)))
- return true;
- // Some filesystms do not support fcntl(F_FULLFSYNC). We handle these cases by
- // falling back to fsync(). Unfortunately, lack of F_FULLFSYNC support results
- // in various error codes, so we cannot use the error code as a definitive
- // indicator that F_FULLFSYNC was not supported. So, if fcntl() errors out for
- // any reason, we may end up making an unnecessary system call.
- //
- // See the CL description at https://crrev.com/c/1400159 for details.
- return !HANDLE_EINTR(fsync(file_.get()));
- #else
- return !HANDLE_EINTR(fsync(file_.get()));
- #endif
- }
- void File::SetPlatformFile(PlatformFile file) {
- DCHECK(!file_.is_valid());
- file_.reset(file);
- }
- // static
- File::Error File::GetLastFileError() {
- return base::File::OSErrorToFileError(errno);
- }
- #if BUILDFLAG(IS_BSD) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_NACL) || \
- BUILDFLAG(IS_FUCHSIA) || (BUILDFLAG(IS_ANDROID) && __ANDROID_API__ < 21)
- int File::Stat(const char* path, stat_wrapper_t* sb) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- return stat(path, sb);
- }
- int File::Fstat(int fd, stat_wrapper_t* sb) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- return fstat(fd, sb);
- }
- int File::Lstat(const char* path, stat_wrapper_t* sb) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- return lstat(path, sb);
- }
- #else
- int File::Stat(const char* path, stat_wrapper_t* sb) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- return stat64(path, sb);
- }
- int File::Fstat(int fd, stat_wrapper_t* sb) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- return fstat64(fd, sb);
- }
- int File::Lstat(const char* path, stat_wrapper_t* sb) {
- ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
- return lstat64(path, sb);
- }
- #endif
- } // namespace base
|