HttpServer: don't crash in SetReceiveBufferSize/SetSendBufferSize if connection is...
[chromium-blink-merge.git] / base / files / file_posix.cc
blob252c3687a15d0584f081df45cbd6caafef4ae6b6
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 CallFutimes(PlatformFile file, const struct timeval times[2]) {
57 #ifdef __USE_XOPEN2K8
58 // futimens should be available, but futimes might not be
59 // http://pubs.opengroup.org/onlinepubs/9699919799/
61 timespec ts_times[2];
62 ts_times[0].tv_sec = times[0].tv_sec;
63 ts_times[0].tv_nsec = times[0].tv_usec * 1000;
64 ts_times[1].tv_sec = times[1].tv_sec;
65 ts_times[1].tv_nsec = times[1].tv_usec * 1000;
67 return futimens(file, ts_times);
68 #else
69 return futimes(file, times);
70 #endif
73 static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
74 struct flock lock;
75 lock.l_type = F_WRLCK;
76 lock.l_whence = SEEK_SET;
77 lock.l_start = 0;
78 lock.l_len = 0; // Lock entire file.
79 if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
80 return File::OSErrorToFileError(errno);
81 return File::FILE_OK;
83 #else // defined(OS_NACL)
85 static bool IsOpenAppend(PlatformFile file) {
86 // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
87 // standard and always appends if the file is opened with O_APPEND, just
88 // return false here.
89 return false;
92 static int CallFtruncate(PlatformFile file, int64 length) {
93 NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
94 return 0;
97 static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
98 NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
99 return 0;
102 static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
103 NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
104 return File::FILE_ERROR_INVALID_OPERATION;
106 #endif // defined(OS_NACL)
108 } // namespace
110 void File::Info::FromStat(const stat_wrapper_t& stat_info) {
111 is_directory = S_ISDIR(stat_info.st_mode);
112 is_symbolic_link = S_ISLNK(stat_info.st_mode);
113 size = stat_info.st_size;
115 #if defined(OS_LINUX)
116 time_t last_modified_sec = stat_info.st_mtim.tv_sec;
117 int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
118 time_t last_accessed_sec = stat_info.st_atim.tv_sec;
119 int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
120 time_t creation_time_sec = stat_info.st_ctim.tv_sec;
121 int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
122 #elif defined(OS_ANDROID)
123 time_t last_modified_sec = stat_info.st_mtime;
124 int64 last_modified_nsec = stat_info.st_mtime_nsec;
125 time_t last_accessed_sec = stat_info.st_atime;
126 int64 last_accessed_nsec = stat_info.st_atime_nsec;
127 time_t creation_time_sec = stat_info.st_ctime;
128 int64 creation_time_nsec = stat_info.st_ctime_nsec;
129 #elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
130 time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
131 int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
132 time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
133 int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
134 time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
135 int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
136 #else
137 time_t last_modified_sec = stat_info.st_mtime;
138 int64 last_modified_nsec = 0;
139 time_t last_accessed_sec = stat_info.st_atime;
140 int64 last_accessed_nsec = 0;
141 time_t creation_time_sec = stat_info.st_ctime;
142 int64 creation_time_nsec = 0;
143 #endif
145 last_modified =
146 Time::FromTimeT(last_modified_sec) +
147 TimeDelta::FromMicroseconds(last_modified_nsec /
148 Time::kNanosecondsPerMicrosecond);
150 last_accessed =
151 Time::FromTimeT(last_accessed_sec) +
152 TimeDelta::FromMicroseconds(last_accessed_nsec /
153 Time::kNanosecondsPerMicrosecond);
155 creation_time =
156 Time::FromTimeT(creation_time_sec) +
157 TimeDelta::FromMicroseconds(creation_time_nsec /
158 Time::kNanosecondsPerMicrosecond);
161 // Default implementations of Protect/Unprotect hooks defined as weak symbols
162 // where possible.
163 void ProtectFileDescriptor(int fd) {
166 void UnprotectFileDescriptor(int fd) {
169 // NaCl doesn't implement system calls to open files directly.
170 #if !defined(OS_NACL)
171 // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
172 void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
173 base::ThreadRestrictions::AssertIOAllowed();
174 DCHECK(!IsValid());
176 int open_flags = 0;
177 if (flags & FLAG_CREATE)
178 open_flags = O_CREAT | O_EXCL;
180 created_ = false;
182 if (flags & FLAG_CREATE_ALWAYS) {
183 DCHECK(!open_flags);
184 DCHECK(flags & FLAG_WRITE);
185 open_flags = O_CREAT | O_TRUNC;
188 if (flags & FLAG_OPEN_TRUNCATED) {
189 DCHECK(!open_flags);
190 DCHECK(flags & FLAG_WRITE);
191 open_flags = O_TRUNC;
194 if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
195 NOTREACHED();
196 errno = EOPNOTSUPP;
197 error_details_ = FILE_ERROR_FAILED;
198 return;
201 if (flags & FLAG_WRITE && flags & FLAG_READ) {
202 open_flags |= O_RDWR;
203 } else if (flags & FLAG_WRITE) {
204 open_flags |= O_WRONLY;
205 } else if (!(flags & FLAG_READ) &&
206 !(flags & FLAG_WRITE_ATTRIBUTES) &&
207 !(flags & FLAG_APPEND) &&
208 !(flags & FLAG_OPEN_ALWAYS)) {
209 NOTREACHED();
212 if (flags & FLAG_TERMINAL_DEVICE)
213 open_flags |= O_NOCTTY | O_NDELAY;
215 if (flags & FLAG_APPEND && flags & FLAG_READ)
216 open_flags |= O_APPEND | O_RDWR;
217 else if (flags & FLAG_APPEND)
218 open_flags |= O_APPEND | O_WRONLY;
220 COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
222 int mode = S_IRUSR | S_IWUSR;
223 #if defined(OS_CHROMEOS)
224 mode |= S_IRGRP | S_IROTH;
225 #endif
227 int descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
229 if (flags & FLAG_OPEN_ALWAYS) {
230 if (descriptor < 0) {
231 open_flags |= O_CREAT;
232 if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
233 open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
235 descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
236 if (descriptor >= 0)
237 created_ = true;
241 if (descriptor < 0) {
242 error_details_ = File::OSErrorToFileError(errno);
243 return;
246 if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
247 created_ = true;
249 if (flags & FLAG_DELETE_ON_CLOSE)
250 unlink(name.value().c_str());
252 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
253 error_details_ = FILE_OK;
254 file_.reset(descriptor);
255 ProtectFileDescriptor(descriptor);
257 #endif // !defined(OS_NACL)
259 bool File::IsValid() const {
260 return file_.is_valid();
263 PlatformFile File::GetPlatformFile() const {
264 return file_.get();
267 PlatformFile File::TakePlatformFile() {
268 if (IsValid())
269 UnprotectFileDescriptor(GetPlatformFile());
270 return file_.release();
273 void File::Close() {
274 if (!IsValid())
275 return;
277 base::ThreadRestrictions::AssertIOAllowed();
278 UnprotectFileDescriptor(GetPlatformFile());
279 file_.reset();
282 int64 File::Seek(Whence whence, int64 offset) {
283 base::ThreadRestrictions::AssertIOAllowed();
284 DCHECK(IsValid());
286 #if defined(OS_ANDROID)
287 COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
288 return lseek64(file_.get(), static_cast<off64_t>(offset),
289 static_cast<int>(whence));
290 #else
291 COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
292 return lseek(file_.get(), static_cast<off_t>(offset),
293 static_cast<int>(whence));
294 #endif
297 int File::Read(int64 offset, char* data, int size) {
298 base::ThreadRestrictions::AssertIOAllowed();
299 DCHECK(IsValid());
300 if (size < 0)
301 return -1;
303 int bytes_read = 0;
304 int rv;
305 do {
306 rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
307 size - bytes_read, offset + bytes_read));
308 if (rv <= 0)
309 break;
311 bytes_read += rv;
312 } while (bytes_read < size);
314 return bytes_read ? bytes_read : rv;
317 int File::ReadAtCurrentPos(char* data, int size) {
318 base::ThreadRestrictions::AssertIOAllowed();
319 DCHECK(IsValid());
320 if (size < 0)
321 return -1;
323 int bytes_read = 0;
324 int rv;
325 do {
326 rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read));
327 if (rv <= 0)
328 break;
330 bytes_read += rv;
331 } while (bytes_read < size);
333 return bytes_read ? bytes_read : rv;
336 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
337 base::ThreadRestrictions::AssertIOAllowed();
338 DCHECK(IsValid());
340 return HANDLE_EINTR(pread(file_.get(), data, size, offset));
343 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
344 base::ThreadRestrictions::AssertIOAllowed();
345 DCHECK(IsValid());
346 if (size < 0)
347 return -1;
349 return HANDLE_EINTR(read(file_.get(), data, size));
352 int File::Write(int64 offset, const char* data, int size) {
353 base::ThreadRestrictions::AssertIOAllowed();
355 if (IsOpenAppend(file_.get()))
356 return WriteAtCurrentPos(data, size);
358 DCHECK(IsValid());
359 if (size < 0)
360 return -1;
362 int bytes_written = 0;
363 int rv;
364 do {
365 rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
366 size - bytes_written, offset + bytes_written));
367 if (rv <= 0)
368 break;
370 bytes_written += rv;
371 } while (bytes_written < size);
373 return bytes_written ? bytes_written : rv;
376 int File::WriteAtCurrentPos(const char* data, int size) {
377 base::ThreadRestrictions::AssertIOAllowed();
378 DCHECK(IsValid());
379 if (size < 0)
380 return -1;
382 int bytes_written = 0;
383 int rv;
384 do {
385 rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
386 size - bytes_written));
387 if (rv <= 0)
388 break;
390 bytes_written += rv;
391 } while (bytes_written < size);
393 return bytes_written ? bytes_written : rv;
396 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
397 base::ThreadRestrictions::AssertIOAllowed();
398 DCHECK(IsValid());
399 if (size < 0)
400 return -1;
402 return HANDLE_EINTR(write(file_.get(), data, size));
405 int64 File::GetLength() {
406 DCHECK(IsValid());
408 stat_wrapper_t file_info;
409 if (CallFstat(file_.get(), &file_info))
410 return false;
412 return file_info.st_size;
415 bool File::SetLength(int64 length) {
416 base::ThreadRestrictions::AssertIOAllowed();
417 DCHECK(IsValid());
418 return !CallFtruncate(file_.get(), length);
421 bool File::Flush() {
422 base::ThreadRestrictions::AssertIOAllowed();
423 DCHECK(IsValid());
424 #if defined(OS_NACL)
425 NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
426 return true;
427 #elif defined(OS_LINUX) || defined(OS_ANDROID)
428 return !HANDLE_EINTR(fdatasync(file_.get()));
429 #else
430 return !HANDLE_EINTR(fsync(file_.get()));
431 #endif
434 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
435 base::ThreadRestrictions::AssertIOAllowed();
436 DCHECK(IsValid());
438 timeval times[2];
439 times[0] = last_access_time.ToTimeVal();
440 times[1] = last_modified_time.ToTimeVal();
442 return !CallFutimes(file_.get(), times);
445 bool File::GetInfo(Info* info) {
446 DCHECK(IsValid());
448 stat_wrapper_t file_info;
449 if (CallFstat(file_.get(), &file_info))
450 return false;
452 info->FromStat(file_info);
453 return true;
456 File::Error File::Lock() {
457 return CallFctnlFlock(file_.get(), true);
460 File::Error File::Unlock() {
461 return CallFctnlFlock(file_.get(), false);
464 File File::Duplicate() {
465 if (!IsValid())
466 return File();
468 PlatformFile other_fd = dup(GetPlatformFile());
469 if (other_fd == -1)
470 return File(OSErrorToFileError(errno));
472 File other(other_fd);
473 if (async())
474 other.async_ = true;
475 return other.Pass();
478 // Static.
479 File::Error File::OSErrorToFileError(int saved_errno) {
480 switch (saved_errno) {
481 case EACCES:
482 case EISDIR:
483 case EROFS:
484 case EPERM:
485 return FILE_ERROR_ACCESS_DENIED;
486 case EBUSY:
487 #if !defined(OS_NACL) // ETXTBSY not defined by NaCl.
488 case ETXTBSY:
489 #endif
490 return FILE_ERROR_IN_USE;
491 case EEXIST:
492 return FILE_ERROR_EXISTS;
493 case EIO:
494 return FILE_ERROR_IO;
495 case ENOENT:
496 return FILE_ERROR_NOT_FOUND;
497 case EMFILE:
498 return FILE_ERROR_TOO_MANY_OPENED;
499 case ENOMEM:
500 return FILE_ERROR_NO_MEMORY;
501 case ENOSPC:
502 return FILE_ERROR_NO_SPACE;
503 case ENOTDIR:
504 return FILE_ERROR_NOT_A_DIRECTORY;
505 default:
506 #if !defined(OS_NACL) // NaCl build has no metrics code.
507 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
508 saved_errno);
509 #endif
510 return FILE_ERROR_FAILED;
514 File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
515 UpdateChecksum();
518 File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
519 UpdateChecksum();
522 File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
524 // static
525 void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
526 unsigned int* out_checksum) const {
527 // Use a single iteration of a linear congruentional generator (lcg) to
528 // provide a cheap checksum unlikely to be accidentally matched by a random
529 // memory corruption.
531 // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
532 // length, we insure that each distinct fd value maps to a distinct checksum,
533 // which maximises the utility of our checksum.
535 // This code uses "unsigned int" throughout for its defined modular semantics,
536 // which implicitly gives us a divisor that is a power of two.
538 const unsigned int kMultiplier = 13035 * 4 + 1;
539 COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
540 const unsigned int kIncrement = 1595649551;
541 COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
543 *out_checksum =
544 static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
547 void File::MemoryCheckingScopedFD::Check() const {
548 unsigned int computed_checksum;
549 ComputeMemoryChecksum(&computed_checksum);
550 CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
553 void File::MemoryCheckingScopedFD::UpdateChecksum() {
554 ComputeMemoryChecksum(&file_memory_checksum_);
557 void File::SetPlatformFile(PlatformFile file) {
558 CHECK(!file_.is_valid());
559 file_.reset(file);
560 if (file_.is_valid())
561 ProtectFileDescriptor(GetPlatformFile());
564 } // namespace base