De-duplicate BASE_IMPLEMENTATION define in the GN build.
[chromium-blink-merge.git] / base / files / file_posix.cc
blob663f099f11fa9c7a5770e1ba488793246cef7dd9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/files/file.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
12 #include "base/files/file_path.h"
13 #include "base/files/file_posix_hooks_internal.h"
14 #include "base/logging.h"
15 #include "base/metrics/sparse_histogram.h"
16 #include "base/posix/eintr_wrapper.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread_restrictions.h"
20 #if defined(OS_ANDROID)
21 #include "base/os_compat_android.h"
22 #endif
24 namespace base {
26 // Make sure our Whence mappings match the system headers.
27 COMPILE_ASSERT(File::FROM_BEGIN == SEEK_SET &&
28 File::FROM_CURRENT == SEEK_CUR &&
29 File::FROM_END == SEEK_END, whence_matches_system);
31 namespace {
33 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
34 static int CallFstat(int fd, stat_wrapper_t *sb) {
35 base::ThreadRestrictions::AssertIOAllowed();
36 return fstat(fd, sb);
38 #else
39 static int CallFstat(int fd, stat_wrapper_t *sb) {
40 base::ThreadRestrictions::AssertIOAllowed();
41 return fstat64(fd, sb);
43 #endif
45 // NaCl doesn't provide the following system calls, so either simulate them or
46 // wrap them in order to minimize the number of #ifdef's in this file.
47 #if !defined(OS_NACL)
48 static bool IsOpenAppend(PlatformFile file) {
49 return (fcntl(file, F_GETFL) & O_APPEND) != 0;
52 static int CallFtruncate(PlatformFile file, int64 length) {
53 return HANDLE_EINTR(ftruncate(file, length));
56 static int CallFsync(PlatformFile file) {
57 return HANDLE_EINTR(fsync(file));
60 static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
61 #ifdef __USE_XOPEN2K8
62 // futimens should be available, but futimes might not be
63 // http://pubs.opengroup.org/onlinepubs/9699919799/
65 timespec ts_times[2];
66 ts_times[0].tv_sec = times[0].tv_sec;
67 ts_times[0].tv_nsec = times[0].tv_usec * 1000;
68 ts_times[1].tv_sec = times[1].tv_sec;
69 ts_times[1].tv_nsec = times[1].tv_usec * 1000;
71 return futimens(file, ts_times);
72 #else
73 return futimes(file, times);
74 #endif
77 static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
78 struct flock lock;
79 lock.l_type = F_WRLCK;
80 lock.l_whence = SEEK_SET;
81 lock.l_start = 0;
82 lock.l_len = 0; // Lock entire file.
83 if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
84 return File::OSErrorToFileError(errno);
85 return File::FILE_OK;
87 #else // defined(OS_NACL)
89 static bool IsOpenAppend(PlatformFile file) {
90 // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
91 // standard and always appends if the file is opened with O_APPEND, just
92 // return false here.
93 return false;
96 static int CallFtruncate(PlatformFile file, int64 length) {
97 NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
98 return 0;
101 static int CallFsync(PlatformFile file) {
102 NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
103 return 0;
106 static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
107 NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
108 return 0;
111 static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
112 NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
113 return File::FILE_ERROR_INVALID_OPERATION;
115 #endif // defined(OS_NACL)
117 } // namespace
119 void File::Info::FromStat(const stat_wrapper_t& stat_info) {
120 is_directory = S_ISDIR(stat_info.st_mode);
121 is_symbolic_link = S_ISLNK(stat_info.st_mode);
122 size = stat_info.st_size;
124 #if defined(OS_LINUX)
125 time_t last_modified_sec = stat_info.st_mtim.tv_sec;
126 int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
127 time_t last_accessed_sec = stat_info.st_atim.tv_sec;
128 int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
129 time_t creation_time_sec = stat_info.st_ctim.tv_sec;
130 int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
131 #elif defined(OS_ANDROID)
132 time_t last_modified_sec = stat_info.st_mtime;
133 int64 last_modified_nsec = stat_info.st_mtime_nsec;
134 time_t last_accessed_sec = stat_info.st_atime;
135 int64 last_accessed_nsec = stat_info.st_atime_nsec;
136 time_t creation_time_sec = stat_info.st_ctime;
137 int64 creation_time_nsec = stat_info.st_ctime_nsec;
138 #elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
139 time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
140 int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
141 time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
142 int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
143 time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
144 int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
145 #else
146 time_t last_modified_sec = stat_info.st_mtime;
147 int64 last_modified_nsec = 0;
148 time_t last_accessed_sec = stat_info.st_atime;
149 int64 last_accessed_nsec = 0;
150 time_t creation_time_sec = stat_info.st_ctime;
151 int64 creation_time_nsec = 0;
152 #endif
154 last_modified =
155 Time::FromTimeT(last_modified_sec) +
156 TimeDelta::FromMicroseconds(last_modified_nsec /
157 Time::kNanosecondsPerMicrosecond);
159 last_accessed =
160 Time::FromTimeT(last_accessed_sec) +
161 TimeDelta::FromMicroseconds(last_accessed_nsec /
162 Time::kNanosecondsPerMicrosecond);
164 creation_time =
165 Time::FromTimeT(creation_time_sec) +
166 TimeDelta::FromMicroseconds(creation_time_nsec /
167 Time::kNanosecondsPerMicrosecond);
170 // Default implementations of Protect/Unprotect hooks defined as weak symbols
171 // where possible.
172 void ProtectFileDescriptor(int fd) {
175 void UnprotectFileDescriptor(int fd) {
178 // NaCl doesn't implement system calls to open files directly.
179 #if !defined(OS_NACL)
180 // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
181 void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
182 base::ThreadRestrictions::AssertIOAllowed();
183 DCHECK(!IsValid());
185 int open_flags = 0;
186 if (flags & FLAG_CREATE)
187 open_flags = O_CREAT | O_EXCL;
189 created_ = false;
191 if (flags & FLAG_CREATE_ALWAYS) {
192 DCHECK(!open_flags);
193 DCHECK(flags & FLAG_WRITE);
194 open_flags = O_CREAT | O_TRUNC;
197 if (flags & FLAG_OPEN_TRUNCATED) {
198 DCHECK(!open_flags);
199 DCHECK(flags & FLAG_WRITE);
200 open_flags = O_TRUNC;
203 if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
204 NOTREACHED();
205 errno = EOPNOTSUPP;
206 error_details_ = FILE_ERROR_FAILED;
207 return;
210 if (flags & FLAG_WRITE && flags & FLAG_READ) {
211 open_flags |= O_RDWR;
212 } else if (flags & FLAG_WRITE) {
213 open_flags |= O_WRONLY;
214 } else if (!(flags & FLAG_READ) &&
215 !(flags & FLAG_WRITE_ATTRIBUTES) &&
216 !(flags & FLAG_APPEND) &&
217 !(flags & FLAG_OPEN_ALWAYS)) {
218 NOTREACHED();
221 if (flags & FLAG_TERMINAL_DEVICE)
222 open_flags |= O_NOCTTY | O_NDELAY;
224 if (flags & FLAG_APPEND && flags & FLAG_READ)
225 open_flags |= O_APPEND | O_RDWR;
226 else if (flags & FLAG_APPEND)
227 open_flags |= O_APPEND | O_WRONLY;
229 COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
231 int mode = S_IRUSR | S_IWUSR;
232 #if defined(OS_CHROMEOS)
233 mode |= S_IRGRP | S_IROTH;
234 #endif
236 int descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
238 if (flags & FLAG_OPEN_ALWAYS) {
239 if (descriptor < 0) {
240 open_flags |= O_CREAT;
241 if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
242 open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
244 descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
245 if (descriptor >= 0)
246 created_ = true;
250 if (descriptor < 0) {
251 error_details_ = File::OSErrorToFileError(errno);
252 return;
255 if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
256 created_ = true;
258 if (flags & FLAG_DELETE_ON_CLOSE)
259 unlink(name.value().c_str());
261 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
262 error_details_ = FILE_OK;
263 file_.reset(descriptor);
264 ProtectFileDescriptor(descriptor);
266 #endif // !defined(OS_NACL)
268 bool File::IsValid() const {
269 return file_.is_valid();
272 PlatformFile File::GetPlatformFile() const {
273 return file_.get();
276 PlatformFile File::TakePlatformFile() {
277 if (IsValid())
278 UnprotectFileDescriptor(GetPlatformFile());
279 return file_.release();
282 void File::Close() {
283 if (!IsValid())
284 return;
286 base::ThreadRestrictions::AssertIOAllowed();
287 UnprotectFileDescriptor(GetPlatformFile());
288 file_.reset();
291 int64 File::Seek(Whence whence, int64 offset) {
292 base::ThreadRestrictions::AssertIOAllowed();
293 DCHECK(IsValid());
295 #if defined(OS_ANDROID)
296 COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
297 return lseek64(file_.get(), static_cast<off64_t>(offset),
298 static_cast<int>(whence));
299 #else
300 COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
301 return lseek(file_.get(), static_cast<off_t>(offset),
302 static_cast<int>(whence));
303 #endif
306 int File::Read(int64 offset, char* data, int size) {
307 base::ThreadRestrictions::AssertIOAllowed();
308 DCHECK(IsValid());
309 if (size < 0)
310 return -1;
312 int bytes_read = 0;
313 int rv;
314 do {
315 rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
316 size - bytes_read, offset + bytes_read));
317 if (rv <= 0)
318 break;
320 bytes_read += rv;
321 } while (bytes_read < size);
323 return bytes_read ? bytes_read : rv;
326 int File::ReadAtCurrentPos(char* data, int size) {
327 base::ThreadRestrictions::AssertIOAllowed();
328 DCHECK(IsValid());
329 if (size < 0)
330 return -1;
332 int bytes_read = 0;
333 int rv;
334 do {
335 rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read));
336 if (rv <= 0)
337 break;
339 bytes_read += rv;
340 } while (bytes_read < size);
342 return bytes_read ? bytes_read : rv;
345 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
346 base::ThreadRestrictions::AssertIOAllowed();
347 DCHECK(IsValid());
349 return HANDLE_EINTR(pread(file_.get(), data, size, offset));
352 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
353 base::ThreadRestrictions::AssertIOAllowed();
354 DCHECK(IsValid());
355 if (size < 0)
356 return -1;
358 return HANDLE_EINTR(read(file_.get(), data, size));
361 int File::Write(int64 offset, const char* data, int size) {
362 base::ThreadRestrictions::AssertIOAllowed();
364 if (IsOpenAppend(file_.get()))
365 return WriteAtCurrentPos(data, size);
367 DCHECK(IsValid());
368 if (size < 0)
369 return -1;
371 int bytes_written = 0;
372 int rv;
373 do {
374 rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
375 size - bytes_written, offset + bytes_written));
376 if (rv <= 0)
377 break;
379 bytes_written += rv;
380 } while (bytes_written < size);
382 return bytes_written ? bytes_written : rv;
385 int File::WriteAtCurrentPos(const char* data, int size) {
386 base::ThreadRestrictions::AssertIOAllowed();
387 DCHECK(IsValid());
388 if (size < 0)
389 return -1;
391 int bytes_written = 0;
392 int rv;
393 do {
394 rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
395 size - bytes_written));
396 if (rv <= 0)
397 break;
399 bytes_written += rv;
400 } while (bytes_written < size);
402 return bytes_written ? bytes_written : rv;
405 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
406 base::ThreadRestrictions::AssertIOAllowed();
407 DCHECK(IsValid());
408 if (size < 0)
409 return -1;
411 return HANDLE_EINTR(write(file_.get(), data, size));
414 int64 File::GetLength() {
415 DCHECK(IsValid());
417 stat_wrapper_t file_info;
418 if (CallFstat(file_.get(), &file_info))
419 return false;
421 return file_info.st_size;
424 bool File::SetLength(int64 length) {
425 base::ThreadRestrictions::AssertIOAllowed();
426 DCHECK(IsValid());
427 return !CallFtruncate(file_.get(), length);
430 bool File::Flush() {
431 base::ThreadRestrictions::AssertIOAllowed();
432 DCHECK(IsValid());
433 return !CallFsync(file_.get());
436 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
437 base::ThreadRestrictions::AssertIOAllowed();
438 DCHECK(IsValid());
440 timeval times[2];
441 times[0] = last_access_time.ToTimeVal();
442 times[1] = last_modified_time.ToTimeVal();
444 return !CallFutimes(file_.get(), times);
447 bool File::GetInfo(Info* info) {
448 DCHECK(IsValid());
450 stat_wrapper_t file_info;
451 if (CallFstat(file_.get(), &file_info))
452 return false;
454 info->FromStat(file_info);
455 return true;
458 File::Error File::Lock() {
459 return CallFctnlFlock(file_.get(), true);
462 File::Error File::Unlock() {
463 return CallFctnlFlock(file_.get(), false);
466 // Static.
467 File::Error File::OSErrorToFileError(int saved_errno) {
468 switch (saved_errno) {
469 case EACCES:
470 case EISDIR:
471 case EROFS:
472 case EPERM:
473 return FILE_ERROR_ACCESS_DENIED;
474 case EBUSY:
475 #if !defined(OS_NACL) // ETXTBSY not defined by NaCl.
476 case ETXTBSY:
477 #endif
478 return FILE_ERROR_IN_USE;
479 case EEXIST:
480 return FILE_ERROR_EXISTS;
481 case EIO:
482 return FILE_ERROR_IO;
483 case ENOENT:
484 return FILE_ERROR_NOT_FOUND;
485 case EMFILE:
486 return FILE_ERROR_TOO_MANY_OPENED;
487 case ENOMEM:
488 return FILE_ERROR_NO_MEMORY;
489 case ENOSPC:
490 return FILE_ERROR_NO_SPACE;
491 case ENOTDIR:
492 return FILE_ERROR_NOT_A_DIRECTORY;
493 default:
494 #if !defined(OS_NACL) // NaCl build has no metrics code.
495 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
496 saved_errno);
497 #endif
498 return FILE_ERROR_FAILED;
502 File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
503 UpdateChecksum();
506 File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
507 UpdateChecksum();
510 File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
512 // static
513 void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
514 unsigned int* out_checksum) const {
515 // Use a single iteration of a linear congruentional generator (lcg) to
516 // provide a cheap checksum unlikely to be accidentally matched by a random
517 // memory corruption.
519 // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
520 // length, we insure that each distinct fd value maps to a distinct checksum,
521 // which maximises the utility of our checksum.
523 // This code uses "unsigned int" throughout for its defined modular semantics,
524 // which implicitly gives us a divisor that is a power of two.
526 const unsigned int kMultiplier = 13035 * 4 + 1;
527 COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
528 const unsigned int kIncrement = 1595649551;
529 COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
531 *out_checksum =
532 static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
535 void File::MemoryCheckingScopedFD::Check() const {
536 unsigned int computed_checksum;
537 ComputeMemoryChecksum(&computed_checksum);
538 CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
541 void File::MemoryCheckingScopedFD::UpdateChecksum() {
542 ComputeMemoryChecksum(&file_memory_checksum_);
545 void File::SetPlatformFile(PlatformFile file) {
546 CHECK(!file_.is_valid());
547 file_.reset(file);
548 if (file_.is_valid())
549 ProtectFileDescriptor(GetPlatformFile());
552 } // namespace base