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