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