Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // For 64-bit file access (off_t = off64_t, lseek64, etc). | 5 // For 64-bit file access (off_t = off64_t, lseek64, etc). |
| 6 #define _FILE_OFFSET_BITS 64 | 6 #define _FILE_OFFSET_BITS 64 |
| 7 | 7 |
| 8 #include "net/base/file_stream.h" | 8 #include "net/base/file_stream.h" |
| 9 | 9 |
| 10 #include <sys/types.h> | 10 #include <sys/types.h> |
| 11 #include <sys/stat.h> | 11 #include <sys/stat.h> |
| 12 #include <fcntl.h> | 12 #include <fcntl.h> |
| 13 #include <unistd.h> | 13 #include <unistd.h> |
| 14 #include <errno.h> | 14 #include <errno.h> |
| 15 | 15 |
| 16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
| 17 #include "base/callback.h" | 17 #include "base/callback.h" |
| 18 #include "base/eintr_wrapper.h" | 18 #include "base/eintr_wrapper.h" |
| 19 #include "base/file_path.h" | 19 #include "base/file_path.h" |
| 20 #include "base/logging.h" | 20 #include "base/logging.h" |
| 21 #include "base/message_loop.h" | 21 #include "base/message_loop.h" |
| 22 #include "base/metrics/histogram.h" | 22 #include "base/metrics/histogram.h" |
| 23 #include "base/string_util.h" | 23 #include "base/string_util.h" |
| 24 #include "base/threading/thread_restrictions.h" | |
| 24 #include "base/threading/worker_pool.h" | 25 #include "base/threading/worker_pool.h" |
| 25 #include "base/synchronization/waitable_event.h" | 26 #include "base/synchronization/waitable_event.h" |
| 26 #include "net/base/net_errors.h" | 27 #include "net/base/net_errors.h" |
| 27 | 28 |
| 28 // We cast back and forth, so make sure it's the size we're expecting. | 29 // We cast back and forth, so make sure it's the size we're expecting. |
| 29 COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit); | 30 COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit); |
| 30 | 31 |
| 31 // Make sure our Whence mappings match the system headers. | 32 // Make sure our Whence mappings match the system headers. |
| 32 COMPILE_ASSERT(net::FROM_BEGIN == SEEK_SET && | 33 COMPILE_ASSERT(net::FROM_BEGIN == SEEK_SET && |
| 33 net::FROM_CURRENT == SEEK_CUR && | 34 net::FROM_CURRENT == SEEK_CUR && |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 45 return ERR_ACCESS_DENIED; | 46 return ERR_ACCESS_DENIED; |
| 46 default: | 47 default: |
| 47 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 48 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; |
| 48 return ERR_FAILED; | 49 return ERR_FAILED; |
| 49 } | 50 } |
| 50 } | 51 } |
| 51 | 52 |
| 52 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 53 // ReadFile() is a simple wrapper around read() that handles EINTR signals and |
| 53 // calls MapErrorCode() to map errno to net error codes. | 54 // calls MapErrorCode() to map errno to net error codes. |
| 54 int ReadFile(base::PlatformFile file, char* buf, int buf_len) { | 55 int ReadFile(base::PlatformFile file, char* buf, int buf_len) { |
| 56 base::ThreadRestrictions::AssertIOAllowed(); | |
| 55 // read(..., 0) returns 0 to indicate end-of-file. | 57 // read(..., 0) returns 0 to indicate end-of-file. |
| 56 | 58 |
| 57 // Loop in the case of getting interrupted by a signal. | 59 // Loop in the case of getting interrupted by a signal. |
| 58 ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); | 60 ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); |
| 59 if (res == static_cast<ssize_t>(-1)) | 61 if (res == static_cast<ssize_t>(-1)) |
| 60 return MapErrorCode(errno); | 62 return MapErrorCode(errno); |
| 61 return static_cast<int>(res); | 63 return static_cast<int>(res); |
| 62 } | 64 } |
| 63 | 65 |
| 64 // WriteFile() is a simple wrapper around write() that handles EINTR signals and | 66 // WriteFile() is a simple wrapper around write() that handles EINTR signals and |
| 65 // calls MapErrorCode() to map errno to net error codes. It tries to write to | 67 // calls MapErrorCode() to map errno to net error codes. It tries to write to |
| 66 // completion. | 68 // completion. |
| 67 int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { | 69 int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { |
| 70 base::ThreadRestrictions::AssertIOAllowed(); | |
| 68 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 71 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); |
| 69 if (res == -1) | 72 if (res == -1) |
| 70 return MapErrorCode(errno); | 73 return MapErrorCode(errno); |
| 71 return res; | 74 return res; |
| 72 } | 75 } |
| 73 | 76 |
| 74 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and | 77 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and |
| 75 // calls MapErrorCode() to map errno to net error codes. It tries to flush to | 78 // calls MapErrorCode() to map errno to net error codes. It tries to flush to |
| 76 // completion. | 79 // completion. |
| 77 int FlushFile(base::PlatformFile file) { | 80 int FlushFile(base::PlatformFile file) { |
| 81 base::ThreadRestrictions::AssertIOAllowed(); | |
| 78 ssize_t res = HANDLE_EINTR(fsync(file)); | 82 ssize_t res = HANDLE_EINTR(fsync(file)); |
| 79 if (res == -1) | 83 if (res == -1) |
| 80 return MapErrorCode(errno); | 84 return MapErrorCode(errno); |
| 81 return res; | 85 return res; |
| 82 } | 86 } |
| 83 | 87 |
| 84 // BackgroundReadTask is a simple task that reads a file and then runs | 88 // BackgroundReadTask is a simple task that reads a file and then runs |
| 85 // |callback|. AsyncContext will post this task to the WorkerPool. | 89 // |callback|. AsyncContext will post this task to the WorkerPool. |
| 86 class BackgroundReadTask : public Task { | 90 class BackgroundReadTask : public Task { |
| 87 public: | 91 public: |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 } | 359 } |
| 356 | 360 |
| 357 return OK; | 361 return OK; |
| 358 } | 362 } |
| 359 | 363 |
| 360 bool FileStream::IsOpen() const { | 364 bool FileStream::IsOpen() const { |
| 361 return file_ != base::kInvalidPlatformFileValue; | 365 return file_ != base::kInvalidPlatformFileValue; |
| 362 } | 366 } |
| 363 | 367 |
| 364 int64 FileStream::Seek(Whence whence, int64 offset) { | 368 int64 FileStream::Seek(Whence whence, int64 offset) { |
| 369 base::ThreadRestrictions::AssertIOAllowed(); | |
| 370 | |
| 365 if (!IsOpen()) | 371 if (!IsOpen()) |
| 366 return ERR_UNEXPECTED; | 372 return ERR_UNEXPECTED; |
| 367 | 373 |
| 368 // If we're in async, make sure we don't have a request in flight. | 374 // If we're in async, make sure we don't have a request in flight. |
| 369 DCHECK(!async_context_.get() || !async_context_->callback()); | 375 DCHECK(!async_context_.get() || !async_context_->callback()); |
| 370 | 376 |
| 371 off_t res = lseek(file_, static_cast<off_t>(offset), | 377 off_t res = lseek(file_, static_cast<off_t>(offset), |
| 372 static_cast<int>(whence)); | 378 static_cast<int>(whence)); |
| 373 if (res == static_cast<off_t>(-1)) | 379 if (res == static_cast<off_t>(-1)) |
| 374 return MapErrorCode(errno); | 380 return MapErrorCode(errno); |
| 375 | 381 |
| 376 return res; | 382 return res; |
| 377 } | 383 } |
| 378 | 384 |
| 379 int64 FileStream::Available() { | 385 int64 FileStream::Available() { |
| 386 base::ThreadRestrictions::AssertIOAllowed(); | |
| 387 | |
| 380 if (!IsOpen()) | 388 if (!IsOpen()) |
| 381 return ERR_UNEXPECTED; | 389 return ERR_UNEXPECTED; |
| 382 | 390 |
| 383 int64 cur_pos = Seek(FROM_CURRENT, 0); | 391 int64 cur_pos = Seek(FROM_CURRENT, 0); |
| 384 if (cur_pos < 0) | 392 if (cur_pos < 0) |
| 385 return cur_pos; | 393 return cur_pos; |
| 386 | 394 |
| 387 struct stat info; | 395 struct stat info; |
| 388 if (fstat(file_, &info) != 0) | 396 if (fstat(file_, &info) != 0) |
| 389 return MapErrorCode(errno); | 397 return MapErrorCode(errno); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 buf += bytes_read; | 439 buf += bytes_read; |
| 432 to_read -= bytes_read; | 440 to_read -= bytes_read; |
| 433 } while (bytes_total < buf_len); | 441 } while (bytes_total < buf_len); |
| 434 | 442 |
| 435 return bytes_total; | 443 return bytes_total; |
| 436 } | 444 } |
| 437 | 445 |
| 438 int FileStream::Write( | 446 int FileStream::Write( |
| 439 const char* buf, int buf_len, CompletionCallback* callback) { | 447 const char* buf, int buf_len, CompletionCallback* callback) { |
| 440 // write(..., 0) will return 0, which indicates end-of-file. | 448 // write(..., 0) will return 0, which indicates end-of-file. |
| 441 DCHECK(buf_len > 0); | 449 DCHECK_GT(buf_len, 0); |
| 442 | 450 |
| 443 if (!IsOpen()) | 451 if (!IsOpen()) |
| 444 return ERR_UNEXPECTED; | 452 return ERR_UNEXPECTED; |
| 445 | 453 |
| 446 if (async_context_.get()) { | 454 if (async_context_.get()) { |
| 447 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 455 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); |
| 448 // If we're in async, make sure we don't have a request in flight. | 456 // If we're in async, make sure we don't have a request in flight. |
| 449 DCHECK(!async_context_->callback()); | 457 DCHECK(!async_context_->callback()); |
| 450 async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); | 458 async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); |
| 451 return ERR_IO_PENDING; | 459 return ERR_IO_PENDING; |
| 452 } else { | 460 } else { |
| 453 return WriteFile(file_, buf, buf_len); | 461 return WriteFile(file_, buf, buf_len); |
| 454 } | 462 } |
| 455 } | 463 } |
| 456 | 464 |
| 457 int64 FileStream::Truncate(int64 bytes) { | 465 int64 FileStream::Truncate(int64 bytes) { |
| 466 base::ThreadRestrictions::AssertIOAllowed(); | |
| 467 | |
| 458 if (!IsOpen()) | 468 if (!IsOpen()) |
| 459 return ERR_UNEXPECTED; | 469 return ERR_UNEXPECTED; |
| 460 | 470 |
| 461 // We better be open for reading. | 471 // We better be open for reading. |
| 462 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 472 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 463 | 473 |
| 464 // Seek to the position to truncate from. | 474 // Seek to the position to truncate from. |
| 465 int64 seek_position = Seek(FROM_BEGIN, bytes); | 475 int64 seek_position = Seek(FROM_BEGIN, bytes); |
| 466 if (seek_position != bytes) | 476 if (seek_position != bytes) |
| 467 return ERR_UNEXPECTED; | 477 return ERR_UNEXPECTED; |
| 468 | 478 |
| 469 // And truncate the file. | 479 // And truncate the file. |
| 470 int result = ftruncate(file_, bytes); | 480 int result = ftruncate(file_, bytes); |
| 471 return result == 0 ? seek_position : MapErrorCode(errno); | 481 return result == 0 ? seek_position : MapErrorCode(errno); |
| 472 } | 482 } |
| 473 | 483 |
| 474 int FileStream::Flush() { | 484 int FileStream::Flush() { |
| 485 base::ThreadRestrictions::AssertIOAllowed(); | |
|
Evan Martin
2011/03/09 19:14:26
Is this one necessary? Typically we put the asser
| |
| 486 | |
| 475 if (!IsOpen()) | 487 if (!IsOpen()) |
| 476 return ERR_UNEXPECTED; | 488 return ERR_UNEXPECTED; |
| 477 | 489 |
| 478 return FlushFile(file_); | 490 return FlushFile(file_); |
| 479 } | 491 } |
| 480 | 492 |
| 481 } // namespace net | 493 } // namespace net |
| OLD | NEW |