xref: /aosp_15_r20/external/libchrome/base/files/file_posix.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/files/file.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <errno.h>
8*635a8641SAndroid Build Coastguard Worker #include <fcntl.h>
9*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
10*635a8641SAndroid Build Coastguard Worker #include <sys/stat.h>
11*635a8641SAndroid Build Coastguard Worker #include <unistd.h>
12*635a8641SAndroid Build Coastguard Worker 
13*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/posix/eintr_wrapper.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
18*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker #if defined(OS_ANDROID)
21*635a8641SAndroid Build Coastguard Worker #include "base/os_compat_android.h"
22*635a8641SAndroid Build Coastguard Worker #endif
23*635a8641SAndroid Build Coastguard Worker 
24*635a8641SAndroid Build Coastguard Worker namespace base {
25*635a8641SAndroid Build Coastguard Worker 
26*635a8641SAndroid Build Coastguard Worker // Make sure our Whence mappings match the system headers.
27*635a8641SAndroid Build Coastguard Worker static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
28*635a8641SAndroid Build Coastguard Worker                   File::FROM_END == SEEK_END,
29*635a8641SAndroid Build Coastguard Worker               "whence mapping must match the system headers");
30*635a8641SAndroid Build Coastguard Worker 
31*635a8641SAndroid Build Coastguard Worker namespace {
32*635a8641SAndroid Build Coastguard Worker 
33*635a8641SAndroid Build Coastguard Worker #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \
34*635a8641SAndroid Build Coastguard Worker   defined(OS_FUCHSIA) || (defined(OS_ANDROID) && __ANDROID_API__ < 21)
CallFstat(int fd,stat_wrapper_t * sb)35*635a8641SAndroid Build Coastguard Worker int CallFstat(int fd, stat_wrapper_t *sb) {
36*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
37*635a8641SAndroid Build Coastguard Worker   return fstat(fd, sb);
38*635a8641SAndroid Build Coastguard Worker }
39*635a8641SAndroid Build Coastguard Worker #else
40*635a8641SAndroid Build Coastguard Worker int CallFstat(int fd, stat_wrapper_t *sb) {
41*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
42*635a8641SAndroid Build Coastguard Worker   return fstat64(fd, sb);
43*635a8641SAndroid Build Coastguard Worker }
44*635a8641SAndroid Build Coastguard Worker #endif
45*635a8641SAndroid Build Coastguard Worker 
46*635a8641SAndroid Build Coastguard Worker // NaCl doesn't provide the following system calls, so either simulate them or
47*635a8641SAndroid Build Coastguard Worker // wrap them in order to minimize the number of #ifdef's in this file.
48*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL) && !defined(OS_AIX)
IsOpenAppend(PlatformFile file)49*635a8641SAndroid Build Coastguard Worker bool IsOpenAppend(PlatformFile file) {
50*635a8641SAndroid Build Coastguard Worker   return (fcntl(file, F_GETFL) & O_APPEND) != 0;
51*635a8641SAndroid Build Coastguard Worker }
52*635a8641SAndroid Build Coastguard Worker 
CallFtruncate(PlatformFile file,int64_t length)53*635a8641SAndroid Build Coastguard Worker int CallFtruncate(PlatformFile file, int64_t length) {
54*635a8641SAndroid Build Coastguard Worker   return HANDLE_EINTR(ftruncate(file, length));
55*635a8641SAndroid Build Coastguard Worker }
56*635a8641SAndroid Build Coastguard Worker 
CallFutimes(PlatformFile file,const struct timeval times[2])57*635a8641SAndroid Build Coastguard Worker int CallFutimes(PlatformFile file, const struct timeval times[2]) {
58*635a8641SAndroid Build Coastguard Worker #ifdef __USE_XOPEN2K8
59*635a8641SAndroid Build Coastguard Worker   // futimens should be available, but futimes might not be
60*635a8641SAndroid Build Coastguard Worker   // http://pubs.opengroup.org/onlinepubs/9699919799/
61*635a8641SAndroid Build Coastguard Worker 
62*635a8641SAndroid Build Coastguard Worker   timespec ts_times[2];
63*635a8641SAndroid Build Coastguard Worker   ts_times[0].tv_sec  = times[0].tv_sec;
64*635a8641SAndroid Build Coastguard Worker   ts_times[0].tv_nsec = times[0].tv_usec * 1000;
65*635a8641SAndroid Build Coastguard Worker   ts_times[1].tv_sec  = times[1].tv_sec;
66*635a8641SAndroid Build Coastguard Worker   ts_times[1].tv_nsec = times[1].tv_usec * 1000;
67*635a8641SAndroid Build Coastguard Worker 
68*635a8641SAndroid Build Coastguard Worker   return futimens(file, ts_times);
69*635a8641SAndroid Build Coastguard Worker #else
70*635a8641SAndroid Build Coastguard Worker   return futimes(file, times);
71*635a8641SAndroid Build Coastguard Worker #endif
72*635a8641SAndroid Build Coastguard Worker }
73*635a8641SAndroid Build Coastguard Worker 
74*635a8641SAndroid Build Coastguard Worker #if !defined(OS_FUCHSIA)
CallFcntlFlock(PlatformFile file,bool do_lock)75*635a8641SAndroid Build Coastguard Worker File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
76*635a8641SAndroid Build Coastguard Worker   struct flock lock;
77*635a8641SAndroid Build Coastguard Worker   lock.l_type = do_lock ? F_WRLCK : F_UNLCK;
78*635a8641SAndroid Build Coastguard Worker   lock.l_whence = SEEK_SET;
79*635a8641SAndroid Build Coastguard Worker   lock.l_start = 0;
80*635a8641SAndroid Build Coastguard Worker   lock.l_len = 0;  // Lock entire file.
81*635a8641SAndroid Build Coastguard Worker   if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1)
82*635a8641SAndroid Build Coastguard Worker     return File::GetLastFileError();
83*635a8641SAndroid Build Coastguard Worker   return File::FILE_OK;
84*635a8641SAndroid Build Coastguard Worker }
85*635a8641SAndroid Build Coastguard Worker #endif
86*635a8641SAndroid Build Coastguard Worker 
87*635a8641SAndroid Build Coastguard Worker #else   // defined(OS_NACL) && !defined(OS_AIX)
88*635a8641SAndroid Build Coastguard Worker 
IsOpenAppend(PlatformFile file)89*635a8641SAndroid Build Coastguard Worker bool IsOpenAppend(PlatformFile file) {
90*635a8641SAndroid Build Coastguard Worker   // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
91*635a8641SAndroid Build Coastguard Worker   // standard and always appends if the file is opened with O_APPEND, just
92*635a8641SAndroid Build Coastguard Worker   // return false here.
93*635a8641SAndroid Build Coastguard Worker   return false;
94*635a8641SAndroid Build Coastguard Worker }
95*635a8641SAndroid Build Coastguard Worker 
CallFtruncate(PlatformFile file,int64_t length)96*635a8641SAndroid Build Coastguard Worker int CallFtruncate(PlatformFile file, int64_t length) {
97*635a8641SAndroid Build Coastguard Worker   NOTIMPLEMENTED();  // NaCl doesn't implement ftruncate.
98*635a8641SAndroid Build Coastguard Worker   return 0;
99*635a8641SAndroid Build Coastguard Worker }
100*635a8641SAndroid Build Coastguard Worker 
CallFutimes(PlatformFile file,const struct timeval times[2])101*635a8641SAndroid Build Coastguard Worker int CallFutimes(PlatformFile file, const struct timeval times[2]) {
102*635a8641SAndroid Build Coastguard Worker   NOTIMPLEMENTED();  // NaCl doesn't implement futimes.
103*635a8641SAndroid Build Coastguard Worker   return 0;
104*635a8641SAndroid Build Coastguard Worker }
105*635a8641SAndroid Build Coastguard Worker 
CallFcntlFlock(PlatformFile file,bool do_lock)106*635a8641SAndroid Build Coastguard Worker File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
107*635a8641SAndroid Build Coastguard Worker   NOTIMPLEMENTED();  // NaCl doesn't implement flock struct.
108*635a8641SAndroid Build Coastguard Worker   return File::FILE_ERROR_INVALID_OPERATION;
109*635a8641SAndroid Build Coastguard Worker }
110*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_NACL)
111*635a8641SAndroid Build Coastguard Worker 
112*635a8641SAndroid Build Coastguard Worker }  // namespace
113*635a8641SAndroid Build Coastguard Worker 
FromStat(const stat_wrapper_t & stat_info)114*635a8641SAndroid Build Coastguard Worker void File::Info::FromStat(const stat_wrapper_t& stat_info) {
115*635a8641SAndroid Build Coastguard Worker   is_directory = S_ISDIR(stat_info.st_mode);
116*635a8641SAndroid Build Coastguard Worker   is_symbolic_link = S_ISLNK(stat_info.st_mode);
117*635a8641SAndroid Build Coastguard Worker   size = stat_info.st_size;
118*635a8641SAndroid Build Coastguard Worker 
119*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX)
120*635a8641SAndroid Build Coastguard Worker   time_t last_modified_sec = stat_info.st_mtim.tv_sec;
121*635a8641SAndroid Build Coastguard Worker   int64_t last_modified_nsec = stat_info.st_mtim.tv_nsec;
122*635a8641SAndroid Build Coastguard Worker   time_t last_accessed_sec = stat_info.st_atim.tv_sec;
123*635a8641SAndroid Build Coastguard Worker   int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec;
124*635a8641SAndroid Build Coastguard Worker   time_t creation_time_sec = stat_info.st_ctim.tv_sec;
125*635a8641SAndroid Build Coastguard Worker   int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec;
126*635a8641SAndroid Build Coastguard Worker #elif defined(OS_ANDROID)
127*635a8641SAndroid Build Coastguard Worker   time_t last_modified_sec = stat_info.st_mtime;
128*635a8641SAndroid Build Coastguard Worker   int64_t last_modified_nsec = stat_info.st_mtime_nsec;
129*635a8641SAndroid Build Coastguard Worker   time_t last_accessed_sec = stat_info.st_atime;
130*635a8641SAndroid Build Coastguard Worker   int64_t last_accessed_nsec = stat_info.st_atime_nsec;
131*635a8641SAndroid Build Coastguard Worker   time_t creation_time_sec = stat_info.st_ctime;
132*635a8641SAndroid Build Coastguard Worker   int64_t creation_time_nsec = stat_info.st_ctime_nsec;
133*635a8641SAndroid Build Coastguard Worker #elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
134*635a8641SAndroid Build Coastguard Worker   time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
135*635a8641SAndroid Build Coastguard Worker   int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
136*635a8641SAndroid Build Coastguard Worker   time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
137*635a8641SAndroid Build Coastguard Worker   int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
138*635a8641SAndroid Build Coastguard Worker   time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
139*635a8641SAndroid Build Coastguard Worker   int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
140*635a8641SAndroid Build Coastguard Worker #else
141*635a8641SAndroid Build Coastguard Worker   time_t last_modified_sec = stat_info.st_mtime;
142*635a8641SAndroid Build Coastguard Worker   int64_t last_modified_nsec = 0;
143*635a8641SAndroid Build Coastguard Worker   time_t last_accessed_sec = stat_info.st_atime;
144*635a8641SAndroid Build Coastguard Worker   int64_t last_accessed_nsec = 0;
145*635a8641SAndroid Build Coastguard Worker   time_t creation_time_sec = stat_info.st_ctime;
146*635a8641SAndroid Build Coastguard Worker   int64_t creation_time_nsec = 0;
147*635a8641SAndroid Build Coastguard Worker #endif
148*635a8641SAndroid Build Coastguard Worker 
149*635a8641SAndroid Build Coastguard Worker   last_modified =
150*635a8641SAndroid Build Coastguard Worker       Time::FromTimeT(last_modified_sec) +
151*635a8641SAndroid Build Coastguard Worker       TimeDelta::FromMicroseconds(last_modified_nsec /
152*635a8641SAndroid Build Coastguard Worker                                   Time::kNanosecondsPerMicrosecond);
153*635a8641SAndroid Build Coastguard Worker 
154*635a8641SAndroid Build Coastguard Worker   last_accessed =
155*635a8641SAndroid Build Coastguard Worker       Time::FromTimeT(last_accessed_sec) +
156*635a8641SAndroid Build Coastguard Worker       TimeDelta::FromMicroseconds(last_accessed_nsec /
157*635a8641SAndroid Build Coastguard Worker                                   Time::kNanosecondsPerMicrosecond);
158*635a8641SAndroid Build Coastguard Worker 
159*635a8641SAndroid Build Coastguard Worker   creation_time =
160*635a8641SAndroid Build Coastguard Worker       Time::FromTimeT(creation_time_sec) +
161*635a8641SAndroid Build Coastguard Worker       TimeDelta::FromMicroseconds(creation_time_nsec /
162*635a8641SAndroid Build Coastguard Worker                                   Time::kNanosecondsPerMicrosecond);
163*635a8641SAndroid Build Coastguard Worker }
164*635a8641SAndroid Build Coastguard Worker 
IsValid() const165*635a8641SAndroid Build Coastguard Worker bool File::IsValid() const {
166*635a8641SAndroid Build Coastguard Worker   return file_.is_valid();
167*635a8641SAndroid Build Coastguard Worker }
168*635a8641SAndroid Build Coastguard Worker 
GetPlatformFile() const169*635a8641SAndroid Build Coastguard Worker PlatformFile File::GetPlatformFile() const {
170*635a8641SAndroid Build Coastguard Worker   return file_.get();
171*635a8641SAndroid Build Coastguard Worker }
172*635a8641SAndroid Build Coastguard Worker 
TakePlatformFile()173*635a8641SAndroid Build Coastguard Worker PlatformFile File::TakePlatformFile() {
174*635a8641SAndroid Build Coastguard Worker   return file_.release();
175*635a8641SAndroid Build Coastguard Worker }
176*635a8641SAndroid Build Coastguard Worker 
Close()177*635a8641SAndroid Build Coastguard Worker void File::Close() {
178*635a8641SAndroid Build Coastguard Worker   if (!IsValid())
179*635a8641SAndroid Build Coastguard Worker     return;
180*635a8641SAndroid Build Coastguard Worker 
181*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("Close");
182*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
183*635a8641SAndroid Build Coastguard Worker   file_.reset();
184*635a8641SAndroid Build Coastguard Worker }
185*635a8641SAndroid Build Coastguard Worker 
Seek(Whence whence,int64_t offset)186*635a8641SAndroid Build Coastguard Worker int64_t File::Seek(Whence whence, int64_t offset) {
187*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
188*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
189*635a8641SAndroid Build Coastguard Worker 
190*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
191*635a8641SAndroid Build Coastguard Worker 
192*635a8641SAndroid Build Coastguard Worker // Additionally check __BIONIC__ since older versions of Android don't define
193*635a8641SAndroid Build Coastguard Worker // _FILE_OFFSET_BITS.
194*635a8641SAndroid Build Coastguard Worker #if _FILE_OFFSET_BITS != 64 || defined(__BIONIC__)
195*635a8641SAndroid Build Coastguard Worker   static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
196*635a8641SAndroid Build Coastguard Worker   return lseek64(file_.get(), static_cast<off64_t>(offset),
197*635a8641SAndroid Build Coastguard Worker                  static_cast<int>(whence));
198*635a8641SAndroid Build Coastguard Worker #else
199*635a8641SAndroid Build Coastguard Worker   static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits");
200*635a8641SAndroid Build Coastguard Worker   return lseek(file_.get(), static_cast<off_t>(offset),
201*635a8641SAndroid Build Coastguard Worker                static_cast<int>(whence));
202*635a8641SAndroid Build Coastguard Worker #endif
203*635a8641SAndroid Build Coastguard Worker }
204*635a8641SAndroid Build Coastguard Worker 
Read(int64_t offset,char * data,int size)205*635a8641SAndroid Build Coastguard Worker int File::Read(int64_t offset, char* data, int size) {
206*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
207*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
208*635a8641SAndroid Build Coastguard Worker   if (size < 0)
209*635a8641SAndroid Build Coastguard Worker     return -1;
210*635a8641SAndroid Build Coastguard Worker 
211*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
212*635a8641SAndroid Build Coastguard Worker 
213*635a8641SAndroid Build Coastguard Worker   int bytes_read = 0;
214*635a8641SAndroid Build Coastguard Worker   int rv;
215*635a8641SAndroid Build Coastguard Worker   do {
216*635a8641SAndroid Build Coastguard Worker     rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
217*635a8641SAndroid Build Coastguard Worker                             size - bytes_read, offset + bytes_read));
218*635a8641SAndroid Build Coastguard Worker     if (rv <= 0)
219*635a8641SAndroid Build Coastguard Worker       break;
220*635a8641SAndroid Build Coastguard Worker 
221*635a8641SAndroid Build Coastguard Worker     bytes_read += rv;
222*635a8641SAndroid Build Coastguard Worker   } while (bytes_read < size);
223*635a8641SAndroid Build Coastguard Worker 
224*635a8641SAndroid Build Coastguard Worker   return bytes_read ? bytes_read : rv;
225*635a8641SAndroid Build Coastguard Worker }
226*635a8641SAndroid Build Coastguard Worker 
ReadAtCurrentPos(char * data,int size)227*635a8641SAndroid Build Coastguard Worker int File::ReadAtCurrentPos(char* data, int size) {
228*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
229*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
230*635a8641SAndroid Build Coastguard Worker   if (size < 0)
231*635a8641SAndroid Build Coastguard Worker     return -1;
232*635a8641SAndroid Build Coastguard Worker 
233*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
234*635a8641SAndroid Build Coastguard Worker 
235*635a8641SAndroid Build Coastguard Worker   int bytes_read = 0;
236*635a8641SAndroid Build Coastguard Worker   int rv;
237*635a8641SAndroid Build Coastguard Worker   do {
238*635a8641SAndroid Build Coastguard Worker     rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read));
239*635a8641SAndroid Build Coastguard Worker     if (rv <= 0)
240*635a8641SAndroid Build Coastguard Worker       break;
241*635a8641SAndroid Build Coastguard Worker 
242*635a8641SAndroid Build Coastguard Worker     bytes_read += rv;
243*635a8641SAndroid Build Coastguard Worker   } while (bytes_read < size);
244*635a8641SAndroid Build Coastguard Worker 
245*635a8641SAndroid Build Coastguard Worker   return bytes_read ? bytes_read : rv;
246*635a8641SAndroid Build Coastguard Worker }
247*635a8641SAndroid Build Coastguard Worker 
ReadNoBestEffort(int64_t offset,char * data,int size)248*635a8641SAndroid Build Coastguard Worker int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
249*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
250*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
251*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
252*635a8641SAndroid Build Coastguard Worker   return HANDLE_EINTR(pread(file_.get(), data, size, offset));
253*635a8641SAndroid Build Coastguard Worker }
254*635a8641SAndroid Build Coastguard Worker 
ReadAtCurrentPosNoBestEffort(char * data,int size)255*635a8641SAndroid Build Coastguard Worker int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
256*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
257*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
258*635a8641SAndroid Build Coastguard Worker   if (size < 0)
259*635a8641SAndroid Build Coastguard Worker     return -1;
260*635a8641SAndroid Build Coastguard Worker 
261*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPosNoBestEffort", size);
262*635a8641SAndroid Build Coastguard Worker   return HANDLE_EINTR(read(file_.get(), data, size));
263*635a8641SAndroid Build Coastguard Worker }
264*635a8641SAndroid Build Coastguard Worker 
Write(int64_t offset,const char * data,int size)265*635a8641SAndroid Build Coastguard Worker int File::Write(int64_t offset, const char* data, int size) {
266*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
267*635a8641SAndroid Build Coastguard Worker 
268*635a8641SAndroid Build Coastguard Worker   if (IsOpenAppend(file_.get()))
269*635a8641SAndroid Build Coastguard Worker     return WriteAtCurrentPos(data, size);
270*635a8641SAndroid Build Coastguard Worker 
271*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
272*635a8641SAndroid Build Coastguard Worker   if (size < 0)
273*635a8641SAndroid Build Coastguard Worker     return -1;
274*635a8641SAndroid Build Coastguard Worker 
275*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
276*635a8641SAndroid Build Coastguard Worker 
277*635a8641SAndroid Build Coastguard Worker   int bytes_written = 0;
278*635a8641SAndroid Build Coastguard Worker   int rv;
279*635a8641SAndroid Build Coastguard Worker   do {
280*635a8641SAndroid Build Coastguard Worker #if _FILE_OFFSET_BITS != 64 || defined(__BIONIC__)
281*635a8641SAndroid Build Coastguard Worker     // In case __USE_FILE_OFFSET64 is not used, we need to call pwrite64()
282*635a8641SAndroid Build Coastguard Worker     // instead of pwrite().
283*635a8641SAndroid Build Coastguard Worker     static_assert(sizeof(int64_t) == sizeof(off64_t),
284*635a8641SAndroid Build Coastguard Worker                   "off64_t must be 64 bits");
285*635a8641SAndroid Build Coastguard Worker     rv = HANDLE_EINTR(pwrite64(file_.get(), data + bytes_written,
286*635a8641SAndroid Build Coastguard Worker                                size - bytes_written, offset + bytes_written));
287*635a8641SAndroid Build Coastguard Worker #else
288*635a8641SAndroid Build Coastguard Worker     rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
289*635a8641SAndroid Build Coastguard Worker                              size - bytes_written, offset + bytes_written));
290*635a8641SAndroid Build Coastguard Worker #endif
291*635a8641SAndroid Build Coastguard Worker     if (rv <= 0)
292*635a8641SAndroid Build Coastguard Worker       break;
293*635a8641SAndroid Build Coastguard Worker 
294*635a8641SAndroid Build Coastguard Worker     bytes_written += rv;
295*635a8641SAndroid Build Coastguard Worker   } while (bytes_written < size);
296*635a8641SAndroid Build Coastguard Worker 
297*635a8641SAndroid Build Coastguard Worker   return bytes_written ? bytes_written : rv;
298*635a8641SAndroid Build Coastguard Worker }
299*635a8641SAndroid Build Coastguard Worker 
WriteAtCurrentPos(const char * data,int size)300*635a8641SAndroid Build Coastguard Worker int File::WriteAtCurrentPos(const char* data, int size) {
301*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
302*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
303*635a8641SAndroid Build Coastguard Worker   if (size < 0)
304*635a8641SAndroid Build Coastguard Worker     return -1;
305*635a8641SAndroid Build Coastguard Worker 
306*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
307*635a8641SAndroid Build Coastguard Worker 
308*635a8641SAndroid Build Coastguard Worker   int bytes_written = 0;
309*635a8641SAndroid Build Coastguard Worker   int rv;
310*635a8641SAndroid Build Coastguard Worker   do {
311*635a8641SAndroid Build Coastguard Worker     rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
312*635a8641SAndroid Build Coastguard Worker                             size - bytes_written));
313*635a8641SAndroid Build Coastguard Worker     if (rv <= 0)
314*635a8641SAndroid Build Coastguard Worker       break;
315*635a8641SAndroid Build Coastguard Worker 
316*635a8641SAndroid Build Coastguard Worker     bytes_written += rv;
317*635a8641SAndroid Build Coastguard Worker   } while (bytes_written < size);
318*635a8641SAndroid Build Coastguard Worker 
319*635a8641SAndroid Build Coastguard Worker   return bytes_written ? bytes_written : rv;
320*635a8641SAndroid Build Coastguard Worker }
321*635a8641SAndroid Build Coastguard Worker 
WriteAtCurrentPosNoBestEffort(const char * data,int size)322*635a8641SAndroid Build Coastguard Worker int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
323*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
324*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
325*635a8641SAndroid Build Coastguard Worker   if (size < 0)
326*635a8641SAndroid Build Coastguard Worker     return -1;
327*635a8641SAndroid Build Coastguard Worker 
328*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPosNoBestEffort", size);
329*635a8641SAndroid Build Coastguard Worker   return HANDLE_EINTR(write(file_.get(), data, size));
330*635a8641SAndroid Build Coastguard Worker }
331*635a8641SAndroid Build Coastguard Worker 
GetLength()332*635a8641SAndroid Build Coastguard Worker int64_t File::GetLength() {
333*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
334*635a8641SAndroid Build Coastguard Worker 
335*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("GetLength");
336*635a8641SAndroid Build Coastguard Worker 
337*635a8641SAndroid Build Coastguard Worker   stat_wrapper_t file_info;
338*635a8641SAndroid Build Coastguard Worker   if (CallFstat(file_.get(), &file_info))
339*635a8641SAndroid Build Coastguard Worker     return -1;
340*635a8641SAndroid Build Coastguard Worker 
341*635a8641SAndroid Build Coastguard Worker   return file_info.st_size;
342*635a8641SAndroid Build Coastguard Worker }
343*635a8641SAndroid Build Coastguard Worker 
SetLength(int64_t length)344*635a8641SAndroid Build Coastguard Worker bool File::SetLength(int64_t length) {
345*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
346*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
347*635a8641SAndroid Build Coastguard Worker 
348*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
349*635a8641SAndroid Build Coastguard Worker   return !CallFtruncate(file_.get(), length);
350*635a8641SAndroid Build Coastguard Worker }
351*635a8641SAndroid Build Coastguard Worker 
SetTimes(Time last_access_time,Time last_modified_time)352*635a8641SAndroid Build Coastguard Worker bool File::SetTimes(Time last_access_time, Time last_modified_time) {
353*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
354*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
355*635a8641SAndroid Build Coastguard Worker 
356*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("SetTimes");
357*635a8641SAndroid Build Coastguard Worker 
358*635a8641SAndroid Build Coastguard Worker   timeval times[2];
359*635a8641SAndroid Build Coastguard Worker   times[0] = last_access_time.ToTimeVal();
360*635a8641SAndroid Build Coastguard Worker   times[1] = last_modified_time.ToTimeVal();
361*635a8641SAndroid Build Coastguard Worker 
362*635a8641SAndroid Build Coastguard Worker   return !CallFutimes(file_.get(), times);
363*635a8641SAndroid Build Coastguard Worker }
364*635a8641SAndroid Build Coastguard Worker 
GetInfo(Info * info)365*635a8641SAndroid Build Coastguard Worker bool File::GetInfo(Info* info) {
366*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
367*635a8641SAndroid Build Coastguard Worker 
368*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("GetInfo");
369*635a8641SAndroid Build Coastguard Worker 
370*635a8641SAndroid Build Coastguard Worker   stat_wrapper_t file_info;
371*635a8641SAndroid Build Coastguard Worker   if (CallFstat(file_.get(), &file_info))
372*635a8641SAndroid Build Coastguard Worker     return false;
373*635a8641SAndroid Build Coastguard Worker 
374*635a8641SAndroid Build Coastguard Worker   info->FromStat(file_info);
375*635a8641SAndroid Build Coastguard Worker   return true;
376*635a8641SAndroid Build Coastguard Worker }
377*635a8641SAndroid Build Coastguard Worker 
378*635a8641SAndroid Build Coastguard Worker #if !defined(OS_FUCHSIA)
Lock()379*635a8641SAndroid Build Coastguard Worker File::Error File::Lock() {
380*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("Lock");
381*635a8641SAndroid Build Coastguard Worker   return CallFcntlFlock(file_.get(), true);
382*635a8641SAndroid Build Coastguard Worker }
383*635a8641SAndroid Build Coastguard Worker 
Unlock()384*635a8641SAndroid Build Coastguard Worker File::Error File::Unlock() {
385*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("Unlock");
386*635a8641SAndroid Build Coastguard Worker   return CallFcntlFlock(file_.get(), false);
387*635a8641SAndroid Build Coastguard Worker }
388*635a8641SAndroid Build Coastguard Worker #endif
389*635a8641SAndroid Build Coastguard Worker 
Duplicate() const390*635a8641SAndroid Build Coastguard Worker File File::Duplicate() const {
391*635a8641SAndroid Build Coastguard Worker   if (!IsValid())
392*635a8641SAndroid Build Coastguard Worker     return File();
393*635a8641SAndroid Build Coastguard Worker 
394*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("Duplicate");
395*635a8641SAndroid Build Coastguard Worker 
396*635a8641SAndroid Build Coastguard Worker   PlatformFile other_fd = HANDLE_EINTR(dup(GetPlatformFile()));
397*635a8641SAndroid Build Coastguard Worker   if (other_fd == -1)
398*635a8641SAndroid Build Coastguard Worker     return File(File::GetLastFileError());
399*635a8641SAndroid Build Coastguard Worker 
400*635a8641SAndroid Build Coastguard Worker   return File(other_fd, async());
401*635a8641SAndroid Build Coastguard Worker }
402*635a8641SAndroid Build Coastguard Worker 
403*635a8641SAndroid Build Coastguard Worker // Static.
OSErrorToFileError(int saved_errno)404*635a8641SAndroid Build Coastguard Worker File::Error File::OSErrorToFileError(int saved_errno) {
405*635a8641SAndroid Build Coastguard Worker   switch (saved_errno) {
406*635a8641SAndroid Build Coastguard Worker     case EACCES:
407*635a8641SAndroid Build Coastguard Worker     case EISDIR:
408*635a8641SAndroid Build Coastguard Worker     case EROFS:
409*635a8641SAndroid Build Coastguard Worker     case EPERM:
410*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_ACCESS_DENIED;
411*635a8641SAndroid Build Coastguard Worker     case EBUSY:
412*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL)  // ETXTBSY not defined by NaCl.
413*635a8641SAndroid Build Coastguard Worker     case ETXTBSY:
414*635a8641SAndroid Build Coastguard Worker #endif
415*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_IN_USE;
416*635a8641SAndroid Build Coastguard Worker     case EEXIST:
417*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_EXISTS;
418*635a8641SAndroid Build Coastguard Worker     case EIO:
419*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_IO;
420*635a8641SAndroid Build Coastguard Worker     case ENOENT:
421*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_NOT_FOUND;
422*635a8641SAndroid Build Coastguard Worker     case ENFILE:  // fallthrough
423*635a8641SAndroid Build Coastguard Worker     case EMFILE:
424*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_TOO_MANY_OPENED;
425*635a8641SAndroid Build Coastguard Worker     case ENOMEM:
426*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_NO_MEMORY;
427*635a8641SAndroid Build Coastguard Worker     case ENOSPC:
428*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_NO_SPACE;
429*635a8641SAndroid Build Coastguard Worker     case ENOTDIR:
430*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_NOT_A_DIRECTORY;
431*635a8641SAndroid Build Coastguard Worker     default:
432*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL)  // NaCl build has no metrics code.
433*635a8641SAndroid Build Coastguard Worker       UmaHistogramSparse("PlatformFile.UnknownErrors.Posix", saved_errno);
434*635a8641SAndroid Build Coastguard Worker #endif
435*635a8641SAndroid Build Coastguard Worker       // This function should only be called for errors.
436*635a8641SAndroid Build Coastguard Worker       DCHECK_NE(0, saved_errno);
437*635a8641SAndroid Build Coastguard Worker       return FILE_ERROR_FAILED;
438*635a8641SAndroid Build Coastguard Worker   }
439*635a8641SAndroid Build Coastguard Worker }
440*635a8641SAndroid Build Coastguard Worker 
441*635a8641SAndroid Build Coastguard Worker // NaCl doesn't implement system calls to open files directly.
442*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL)
443*635a8641SAndroid Build Coastguard Worker // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
DoInitialize(const FilePath & path,uint32_t flags)444*635a8641SAndroid Build Coastguard Worker void File::DoInitialize(const FilePath& path, uint32_t flags) {
445*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
446*635a8641SAndroid Build Coastguard Worker   DCHECK(!IsValid());
447*635a8641SAndroid Build Coastguard Worker 
448*635a8641SAndroid Build Coastguard Worker   int open_flags = 0;
449*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_CREATE)
450*635a8641SAndroid Build Coastguard Worker     open_flags = O_CREAT | O_EXCL;
451*635a8641SAndroid Build Coastguard Worker 
452*635a8641SAndroid Build Coastguard Worker   created_ = false;
453*635a8641SAndroid Build Coastguard Worker 
454*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_CREATE_ALWAYS) {
455*635a8641SAndroid Build Coastguard Worker     DCHECK(!open_flags);
456*635a8641SAndroid Build Coastguard Worker     DCHECK(flags & FLAG_WRITE);
457*635a8641SAndroid Build Coastguard Worker     open_flags = O_CREAT | O_TRUNC;
458*635a8641SAndroid Build Coastguard Worker   }
459*635a8641SAndroid Build Coastguard Worker 
460*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_OPEN_TRUNCATED) {
461*635a8641SAndroid Build Coastguard Worker     DCHECK(!open_flags);
462*635a8641SAndroid Build Coastguard Worker     DCHECK(flags & FLAG_WRITE);
463*635a8641SAndroid Build Coastguard Worker     open_flags = O_TRUNC;
464*635a8641SAndroid Build Coastguard Worker   }
465*635a8641SAndroid Build Coastguard Worker 
466*635a8641SAndroid Build Coastguard Worker   if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
467*635a8641SAndroid Build Coastguard Worker     NOTREACHED();
468*635a8641SAndroid Build Coastguard Worker     errno = EOPNOTSUPP;
469*635a8641SAndroid Build Coastguard Worker     error_details_ = FILE_ERROR_FAILED;
470*635a8641SAndroid Build Coastguard Worker     return;
471*635a8641SAndroid Build Coastguard Worker   }
472*635a8641SAndroid Build Coastguard Worker 
473*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_WRITE && flags & FLAG_READ) {
474*635a8641SAndroid Build Coastguard Worker     open_flags |= O_RDWR;
475*635a8641SAndroid Build Coastguard Worker   } else if (flags & FLAG_WRITE) {
476*635a8641SAndroid Build Coastguard Worker     open_flags |= O_WRONLY;
477*635a8641SAndroid Build Coastguard Worker   } else if (!(flags & FLAG_READ) &&
478*635a8641SAndroid Build Coastguard Worker              !(flags & FLAG_WRITE_ATTRIBUTES) &&
479*635a8641SAndroid Build Coastguard Worker              !(flags & FLAG_APPEND) &&
480*635a8641SAndroid Build Coastguard Worker              !(flags & FLAG_OPEN_ALWAYS)) {
481*635a8641SAndroid Build Coastguard Worker     NOTREACHED();
482*635a8641SAndroid Build Coastguard Worker   }
483*635a8641SAndroid Build Coastguard Worker 
484*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_TERMINAL_DEVICE)
485*635a8641SAndroid Build Coastguard Worker     open_flags |= O_NOCTTY | O_NDELAY;
486*635a8641SAndroid Build Coastguard Worker 
487*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_APPEND && flags & FLAG_READ)
488*635a8641SAndroid Build Coastguard Worker     open_flags |= O_APPEND | O_RDWR;
489*635a8641SAndroid Build Coastguard Worker   else if (flags & FLAG_APPEND)
490*635a8641SAndroid Build Coastguard Worker     open_flags |= O_APPEND | O_WRONLY;
491*635a8641SAndroid Build Coastguard Worker 
492*635a8641SAndroid Build Coastguard Worker   static_assert(O_RDONLY == 0, "O_RDONLY must equal zero");
493*635a8641SAndroid Build Coastguard Worker 
494*635a8641SAndroid Build Coastguard Worker   int mode = S_IRUSR | S_IWUSR;
495*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
496*635a8641SAndroid Build Coastguard Worker   mode |= S_IRGRP | S_IROTH;
497*635a8641SAndroid Build Coastguard Worker #endif
498*635a8641SAndroid Build Coastguard Worker 
499*635a8641SAndroid Build Coastguard Worker   int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
500*635a8641SAndroid Build Coastguard Worker 
501*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_OPEN_ALWAYS) {
502*635a8641SAndroid Build Coastguard Worker     if (descriptor < 0) {
503*635a8641SAndroid Build Coastguard Worker       open_flags |= O_CREAT;
504*635a8641SAndroid Build Coastguard Worker       if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
505*635a8641SAndroid Build Coastguard Worker         open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
506*635a8641SAndroid Build Coastguard Worker 
507*635a8641SAndroid Build Coastguard Worker       descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
508*635a8641SAndroid Build Coastguard Worker       if (descriptor >= 0)
509*635a8641SAndroid Build Coastguard Worker         created_ = true;
510*635a8641SAndroid Build Coastguard Worker     }
511*635a8641SAndroid Build Coastguard Worker   }
512*635a8641SAndroid Build Coastguard Worker 
513*635a8641SAndroid Build Coastguard Worker   if (descriptor < 0) {
514*635a8641SAndroid Build Coastguard Worker     error_details_ = File::GetLastFileError();
515*635a8641SAndroid Build Coastguard Worker     return;
516*635a8641SAndroid Build Coastguard Worker   }
517*635a8641SAndroid Build Coastguard Worker 
518*635a8641SAndroid Build Coastguard Worker   if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
519*635a8641SAndroid Build Coastguard Worker     created_ = true;
520*635a8641SAndroid Build Coastguard Worker 
521*635a8641SAndroid Build Coastguard Worker   if (flags & FLAG_DELETE_ON_CLOSE)
522*635a8641SAndroid Build Coastguard Worker     unlink(path.value().c_str());
523*635a8641SAndroid Build Coastguard Worker 
524*635a8641SAndroid Build Coastguard Worker   async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
525*635a8641SAndroid Build Coastguard Worker   error_details_ = FILE_OK;
526*635a8641SAndroid Build Coastguard Worker   file_.reset(descriptor);
527*635a8641SAndroid Build Coastguard Worker }
528*635a8641SAndroid Build Coastguard Worker #endif  // !defined(OS_NACL)
529*635a8641SAndroid Build Coastguard Worker 
Flush()530*635a8641SAndroid Build Coastguard Worker bool File::Flush() {
531*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
532*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
533*635a8641SAndroid Build Coastguard Worker   SCOPED_FILE_TRACE("Flush");
534*635a8641SAndroid Build Coastguard Worker 
535*635a8641SAndroid Build Coastguard Worker #if defined(OS_NACL)
536*635a8641SAndroid Build Coastguard Worker   NOTIMPLEMENTED();  // NaCl doesn't implement fsync.
537*635a8641SAndroid Build Coastguard Worker   return true;
538*635a8641SAndroid Build Coastguard Worker #elif defined(OS_LINUX) || defined(OS_ANDROID)
539*635a8641SAndroid Build Coastguard Worker   return !HANDLE_EINTR(fdatasync(file_.get()));
540*635a8641SAndroid Build Coastguard Worker #else
541*635a8641SAndroid Build Coastguard Worker   return !HANDLE_EINTR(fsync(file_.get()));
542*635a8641SAndroid Build Coastguard Worker #endif
543*635a8641SAndroid Build Coastguard Worker }
544*635a8641SAndroid Build Coastguard Worker 
SetPlatformFile(PlatformFile file)545*635a8641SAndroid Build Coastguard Worker void File::SetPlatformFile(PlatformFile file) {
546*635a8641SAndroid Build Coastguard Worker   DCHECK(!file_.is_valid());
547*635a8641SAndroid Build Coastguard Worker   file_.reset(file);
548*635a8641SAndroid Build Coastguard Worker }
549*635a8641SAndroid Build Coastguard Worker 
550*635a8641SAndroid Build Coastguard Worker // static
GetLastFileError()551*635a8641SAndroid Build Coastguard Worker File::Error File::GetLastFileError() {
552*635a8641SAndroid Build Coastguard Worker   return base::File::OSErrorToFileError(errno);
553*635a8641SAndroid Build Coastguard Worker }
554*635a8641SAndroid Build Coastguard Worker 
555*635a8641SAndroid Build Coastguard Worker }  // namespace base
556