| OLD | NEW | 
|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/task.h" | 24 #include "base/task.h" | 
| 25 #include "base/threading/thread_restrictions.h" | 25 #include "base/threading/thread_restrictions.h" | 
| 26 #include "base/threading/worker_pool.h" | 26 #include "base/threading/worker_pool.h" | 
| 27 #include "base/synchronization/waitable_event.h" | 27 #include "base/synchronization/waitable_event.h" | 
|  | 28 #include "net/base/file_stream_metrics.h" | 
| 28 #include "net/base/net_errors.h" | 29 #include "net/base/net_errors.h" | 
| 29 | 30 | 
| 30 #if defined(OS_ANDROID) | 31 #if defined(OS_ANDROID) | 
| 31 // Android's bionic libc only supports the LFS transitional API. | 32 // Android's bionic libc only supports the LFS transitional API. | 
| 32 #define off_t off64_t | 33 #define off_t off64_t | 
| 33 #define lseek lseek64 | 34 #define lseek lseek64 | 
| 34 #define stat stat64 | 35 #define stat stat64 | 
| 35 #define fstat fstat64 | 36 #define fstat fstat64 | 
| 36 #endif | 37 #endif | 
| 37 | 38 | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 53     case ENOENT: | 54     case ENOENT: | 
| 54       return ERR_FILE_NOT_FOUND; | 55       return ERR_FILE_NOT_FOUND; | 
| 55     case EACCES: | 56     case EACCES: | 
| 56       return ERR_ACCESS_DENIED; | 57       return ERR_ACCESS_DENIED; | 
| 57     default: | 58     default: | 
| 58       LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 59       LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 
| 59       return ERR_FAILED; | 60       return ERR_FAILED; | 
| 60   } | 61   } | 
| 61 } | 62 } | 
| 62 | 63 | 
|  | 64 int RecordAndMapError(int error, FileErrorSource source, bool record_uma) { | 
|  | 65   RecordFileError(error, source, record_uma); | 
|  | 66   return MapErrorCode(error); | 
|  | 67 } | 
|  | 68 | 
| 63 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 69 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 
| 64 // calls MapErrorCode() to map errno to net error codes. | 70 // calls MapErrorCode() to map errno to net error codes. | 
| 65 int ReadFile(base::PlatformFile file, char* buf, int buf_len) { | 71 int ReadFile(base::PlatformFile file, char* buf, int buf_len, bool record_uma) { | 
| 66   base::ThreadRestrictions::AssertIOAllowed(); | 72   base::ThreadRestrictions::AssertIOAllowed(); | 
| 67   // read(..., 0) returns 0 to indicate end-of-file. | 73   // read(..., 0) returns 0 to indicate end-of-file. | 
| 68 | 74 | 
| 69   // Loop in the case of getting interrupted by a signal. | 75   // Loop in the case of getting interrupted by a signal. | 
| 70   ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); | 76   ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); | 
| 71   if (res == static_cast<ssize_t>(-1)) | 77   if (res == static_cast<ssize_t>(-1)) | 
| 72     return MapErrorCode(errno); | 78     RecordAndMapError(errno, FILE_ERROR_SOURCE_READ, record_uma); | 
| 73   return static_cast<int>(res); | 79   return static_cast<int>(res); | 
| 74 } | 80 } | 
| 75 | 81 | 
| 76 void ReadFileTask(base::PlatformFile file, | 82 void ReadFileTask(base::PlatformFile file, | 
| 77                   char* buf, | 83                   char* buf, | 
| 78                   int buf_len, | 84                   int buf_len, | 
|  | 85                   bool record_uma, | 
| 79                   CompletionCallback* callback) { | 86                   CompletionCallback* callback) { | 
| 80   callback->Run(ReadFile(file, buf, buf_len)); | 87   callback->Run(ReadFile(file, buf, buf_len, record_uma)); | 
| 81 } | 88 } | 
| 82 | 89 | 
| 83 // WriteFile() is a simple wrapper around write() that handles EINTR signals and | 90 // WriteFile() is a simple wrapper around write() that handles EINTR signals and | 
| 84 // calls MapErrorCode() to map errno to net error codes.  It tries to write to | 91 // calls MapErrorCode() to map errno to net error codes.  It tries to write to | 
| 85 // completion. | 92 // completion. | 
| 86 int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { | 93 int WriteFile(base::PlatformFile file, const char* buf, int buf_len, | 
|  | 94               bool record_uma) { | 
| 87   base::ThreadRestrictions::AssertIOAllowed(); | 95   base::ThreadRestrictions::AssertIOAllowed(); | 
| 88   ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 96   ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 
| 89   if (res == -1) | 97   if (res == -1) | 
| 90     return MapErrorCode(errno); | 98     RecordAndMapError(errno, FILE_ERROR_SOURCE_WRITE, record_uma); | 
| 91   return res; | 99   return res; | 
| 92 } | 100 } | 
| 93 | 101 | 
| 94 void WriteFileTask(base::PlatformFile file, | 102 void WriteFileTask(base::PlatformFile file, | 
| 95                    const char* buf, | 103                    const char* buf, | 
| 96                    int buf_len, | 104                    int buf_len, bool record_uma, | 
| 97                    CompletionCallback* callback) { | 105                    CompletionCallback* callback) { | 
| 98   callback->Run(WriteFile(file, buf, buf_len)); | 106   callback->Run(WriteFile(file, buf, buf_len, record_uma)); | 
| 99 } | 107 } | 
| 100 | 108 | 
| 101 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and | 109 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and | 
| 102 // calls MapErrorCode() to map errno to net error codes.  It tries to flush to | 110 // calls MapErrorCode() to map errno to net error codes.  It tries to flush to | 
| 103 // completion. | 111 // completion. | 
| 104 int FlushFile(base::PlatformFile file) { | 112 int FlushFile(base::PlatformFile file, bool record_uma) { | 
| 105   base::ThreadRestrictions::AssertIOAllowed(); | 113   base::ThreadRestrictions::AssertIOAllowed(); | 
| 106   ssize_t res = HANDLE_EINTR(fsync(file)); | 114   ssize_t res = HANDLE_EINTR(fsync(file)); | 
| 107   if (res == -1) | 115   if (res == -1) | 
| 108     return MapErrorCode(errno); | 116     RecordAndMapError(errno, FILE_ERROR_SOURCE_FLUSH, record_uma); | 
| 109   return res; | 117   return res; | 
| 110 } | 118 } | 
| 111 | 119 | 
| 112 }  // namespace | 120 }  // namespace | 
| 113 | 121 | 
| 114 // CancelableCallbackTask takes ownership of the Callback.  This task gets | 122 // CancelableCallbackTask takes ownership of the Callback.  This task gets | 
| 115 // posted to the MessageLoopForIO instance. | 123 // posted to the MessageLoopForIO instance. | 
| 116 class CancelableCallbackTask : public CancelableTask { | 124 class CancelableCallbackTask : public CancelableTask { | 
| 117  public: | 125  public: | 
| 118   explicit CancelableCallbackTask(Callback0::Type* callback) | 126   explicit CancelableCallbackTask(Callback0::Type* callback) | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 150   CompletionCallback* callback() const { return callback_; } | 158   CompletionCallback* callback() const { return callback_; } | 
| 151 | 159 | 
| 152   // Called by the WorkerPool thread executing the IO after the IO completes. | 160   // Called by the WorkerPool thread executing the IO after the IO completes. | 
| 153   // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 161   // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 
| 154   // |background_io_completed_callback_|, in case the destructor is waiting.  In | 162   // |background_io_completed_callback_|, in case the destructor is waiting.  In | 
| 155   // that case, the destructor will call RunAsynchronousCallback() instead, and | 163   // that case, the destructor will call RunAsynchronousCallback() instead, and | 
| 156   // cancel |message_loop_task_|. | 164   // cancel |message_loop_task_|. | 
| 157   // |result| is the result of the Read/Write task. | 165   // |result| is the result of the Read/Write task. | 
| 158   void OnBackgroundIOCompleted(int result); | 166   void OnBackgroundIOCompleted(int result); | 
| 159 | 167 | 
|  | 168   void EnableErrorStatistics() { | 
|  | 169     record_uma_ = true; | 
|  | 170   } | 
|  | 171 | 
| 160  private: | 172  private: | 
| 161   // Always called on the IO thread, either directly by a task on the | 173   // Always called on the IO thread, either directly by a task on the | 
| 162   // MessageLoop or by ~AsyncContext(). | 174   // MessageLoop or by ~AsyncContext(). | 
| 163   void RunAsynchronousCallback(); | 175   void RunAsynchronousCallback(); | 
| 164 | 176 | 
| 165   // The MessageLoopForIO that this AsyncContext is running on. | 177   // The MessageLoopForIO that this AsyncContext is running on. | 
| 166   MessageLoopForIO* const message_loop_; | 178   MessageLoopForIO* const message_loop_; | 
| 167   CompletionCallback* callback_;  // The user provided callback. | 179   CompletionCallback* callback_;  // The user provided callback. | 
| 168 | 180 | 
| 169   // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool | 181   // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool | 
| 170   // thread doing the background IO on our behalf. | 182   // thread doing the background IO on our behalf. | 
| 171   CompletionCallbackImpl<AsyncContext> background_io_completed_callback_; | 183   CompletionCallbackImpl<AsyncContext> background_io_completed_callback_; | 
| 172 | 184 | 
| 173   // This is used to synchronize between the AsyncContext destructor (which runs | 185   // This is used to synchronize between the AsyncContext destructor (which runs | 
| 174   // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool | 186   // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool | 
| 175   // thread. | 187   // thread. | 
| 176   base::WaitableEvent background_io_completed_; | 188   base::WaitableEvent background_io_completed_; | 
| 177 | 189 | 
| 178   // These variables are only valid when background_io_completed is signaled. | 190   // These variables are only valid when background_io_completed is signaled. | 
| 179   int result_; | 191   int result_; | 
| 180   CancelableCallbackTask* message_loop_task_; | 192   CancelableCallbackTask* message_loop_task_; | 
| 181 | 193 | 
| 182   bool is_closing_; | 194   bool is_closing_; | 
|  | 195   bool record_uma_; | 
| 183 | 196 | 
| 184   DISALLOW_COPY_AND_ASSIGN(AsyncContext); | 197   DISALLOW_COPY_AND_ASSIGN(AsyncContext); | 
| 185 }; | 198 }; | 
| 186 | 199 | 
| 187 FileStream::AsyncContext::AsyncContext() | 200 FileStream::AsyncContext::AsyncContext() | 
| 188     : message_loop_(MessageLoopForIO::current()), | 201     : message_loop_(MessageLoopForIO::current()), | 
| 189       callback_(NULL), | 202       callback_(NULL), | 
| 190       background_io_completed_callback_( | 203       background_io_completed_callback_( | 
| 191           this, &AsyncContext::OnBackgroundIOCompleted), | 204           this, &AsyncContext::OnBackgroundIOCompleted), | 
| 192       background_io_completed_(true, false), | 205       background_io_completed_(true, false), | 
| 193       message_loop_task_(NULL), | 206       message_loop_task_(NULL), | 
| 194       is_closing_(false) {} | 207       is_closing_(false), | 
|  | 208       record_uma_(false) {} | 
| 195 | 209 | 
| 196 FileStream::AsyncContext::~AsyncContext() { | 210 FileStream::AsyncContext::~AsyncContext() { | 
| 197   is_closing_ = true; | 211   is_closing_ = true; | 
| 198   if (callback_) { | 212   if (callback_) { | 
| 199     // If |callback_| is non-NULL, that implies either the worker thread is | 213     // If |callback_| is non-NULL, that implies either the worker thread is | 
| 200     // still running the IO task, or the completion callback is queued up on the | 214     // still running the IO task, or the completion callback is queued up on the | 
| 201     // MessageLoopForIO, but AsyncContext() got deleted before then. | 215     // MessageLoopForIO, but AsyncContext() got deleted before then. | 
| 202     const bool need_to_wait = !background_io_completed_.IsSignaled(); | 216     const bool need_to_wait = !background_io_completed_.IsSignaled(); | 
| 203     base::TimeTicks start = base::TimeTicks::Now(); | 217     base::TimeTicks start = base::TimeTicks::Now(); | 
| 204     RunAsynchronousCallback(); | 218     RunAsynchronousCallback(); | 
| 205     if (need_to_wait) { | 219     if (need_to_wait) { | 
| 206       // We want to see if we block the message loop for too long. | 220       // We want to see if we block the message loop for too long. | 
| 207       UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 221       UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 
| 208                           base::TimeTicks::Now() - start); | 222                           base::TimeTicks::Now() - start); | 
| 209     } | 223     } | 
| 210   } | 224   } | 
| 211 } | 225 } | 
| 212 | 226 | 
| 213 void FileStream::AsyncContext::InitiateAsyncRead( | 227 void FileStream::AsyncContext::InitiateAsyncRead( | 
| 214     base::PlatformFile file, char* buf, int buf_len, | 228     base::PlatformFile file, char* buf, int buf_len, | 
| 215     CompletionCallback* callback) { | 229     CompletionCallback* callback) { | 
| 216   DCHECK(!callback_); | 230   DCHECK(!callback_); | 
| 217   callback_ = callback; | 231   callback_ = callback; | 
| 218 | 232 | 
| 219   base::WorkerPool::PostTask(FROM_HERE, | 233   base::WorkerPool::PostTask(FROM_HERE, | 
| 220                              NewRunnableFunction( | 234                              NewRunnableFunction( | 
| 221                                  &ReadFileTask, | 235                                  &ReadFileTask, | 
| 222                                  file, buf, buf_len, | 236                                  file, buf, buf_len, | 
|  | 237                                  record_uma_, | 
| 223                                  &background_io_completed_callback_), | 238                                  &background_io_completed_callback_), | 
| 224                              true /* task_is_slow */); | 239                              true /* task_is_slow */); | 
| 225 } | 240 } | 
| 226 | 241 | 
| 227 void FileStream::AsyncContext::InitiateAsyncWrite( | 242 void FileStream::AsyncContext::InitiateAsyncWrite( | 
| 228     base::PlatformFile file, const char* buf, int buf_len, | 243     base::PlatformFile file, const char* buf, int buf_len, | 
| 229     CompletionCallback* callback) { | 244     CompletionCallback* callback) { | 
| 230   DCHECK(!callback_); | 245   DCHECK(!callback_); | 
| 231   callback_ = callback; | 246   callback_ = callback; | 
| 232 | 247 | 
| 233   base::WorkerPool::PostTask(FROM_HERE, | 248   base::WorkerPool::PostTask(FROM_HERE, | 
| 234                              NewRunnableFunction( | 249                              NewRunnableFunction( | 
| 235                                  &WriteFileTask, | 250                                  &WriteFileTask, | 
| 236                                  file, buf, buf_len, | 251                                  file, buf, buf_len, | 
|  | 252                                  record_uma_, | 
| 237                                  &background_io_completed_callback_), | 253                                  &background_io_completed_callback_), | 
| 238                              true /* task_is_slow */); | 254                              true /* task_is_slow */); | 
| 239 } | 255 } | 
| 240 | 256 | 
| 241 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 257 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 
| 242   result_ = result; | 258   result_ = result; | 
| 243   message_loop_task_ = new CancelableCallbackTask( | 259   message_loop_task_ = new CancelableCallbackTask( | 
| 244       NewCallback(this, &AsyncContext::RunAsynchronousCallback)); | 260       NewCallback(this, &AsyncContext::RunAsynchronousCallback)); | 
| 245   message_loop_->PostTask(FROM_HERE, message_loop_task_); | 261   message_loop_->PostTask(FROM_HERE, message_loop_task_); | 
| 246   background_io_completed_.Signal(); | 262   background_io_completed_.Signal(); | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 267   std::swap(temp, callback_); | 283   std::swap(temp, callback_); | 
| 268   background_io_completed_.Reset(); | 284   background_io_completed_.Reset(); | 
| 269   temp->Run(result_); | 285   temp->Run(result_); | 
| 270 } | 286 } | 
| 271 | 287 | 
| 272 // FileStream ------------------------------------------------------------ | 288 // FileStream ------------------------------------------------------------ | 
| 273 | 289 | 
| 274 FileStream::FileStream() | 290 FileStream::FileStream() | 
| 275     : file_(base::kInvalidPlatformFileValue), | 291     : file_(base::kInvalidPlatformFileValue), | 
| 276       open_flags_(0), | 292       open_flags_(0), | 
| 277       auto_closed_(true) { | 293       auto_closed_(false), | 
|  | 294       record_uma_(false) { | 
| 278   DCHECK(!IsOpen()); | 295   DCHECK(!IsOpen()); | 
| 279 } | 296 } | 
| 280 | 297 | 
| 281 FileStream::FileStream(base::PlatformFile file, int flags) | 298 FileStream::FileStream(base::PlatformFile file, int flags) | 
| 282     : file_(file), | 299     : file_(file), | 
| 283       open_flags_(flags), | 300       open_flags_(flags), | 
| 284       auto_closed_(false) { | 301       auto_closed_(false), | 
|  | 302       record_uma_(false) { | 
| 285   // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to | 303   // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to | 
| 286   // make sure we will perform asynchronous File IO to it. | 304   // make sure we will perform asynchronous File IO to it. | 
| 287   if (flags & base::PLATFORM_FILE_ASYNC) { | 305   if (flags & base::PLATFORM_FILE_ASYNC) { | 
| 288     async_context_.reset(new AsyncContext()); | 306     async_context_.reset(new AsyncContext()); | 
| 289   } | 307   } | 
| 290 } | 308 } | 
| 291 | 309 | 
| 292 FileStream::~FileStream() { | 310 FileStream::~FileStream() { | 
| 293   if (auto_closed_) | 311   if (auto_closed_) | 
| 294     Close(); | 312     Close(); | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 307 } | 325 } | 
| 308 | 326 | 
| 309 int FileStream::Open(const FilePath& path, int open_flags) { | 327 int FileStream::Open(const FilePath& path, int open_flags) { | 
| 310   if (IsOpen()) { | 328   if (IsOpen()) { | 
| 311     DLOG(FATAL) << "File is already open!"; | 329     DLOG(FATAL) << "File is already open!"; | 
| 312     return ERR_UNEXPECTED; | 330     return ERR_UNEXPECTED; | 
| 313   } | 331   } | 
| 314 | 332 | 
| 315   open_flags_ = open_flags; | 333   open_flags_ = open_flags; | 
| 316   file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); | 334   file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); | 
| 317   if (file_ == base::kInvalidPlatformFileValue) { | 335   if (file_ == base::kInvalidPlatformFileValue) | 
| 318     return MapErrorCode(errno); | 336     return RecordAndMapError(errno, FILE_ERROR_SOURCE_OPEN, record_uma_); | 
| 319   } |  | 
| 320 | 337 | 
| 321   if (open_flags_ & base::PLATFORM_FILE_ASYNC) { | 338   if (open_flags_ & base::PLATFORM_FILE_ASYNC) | 
| 322     async_context_.reset(new AsyncContext()); | 339     async_context_.reset(new AsyncContext()); | 
| 323   } |  | 
| 324 | 340 | 
| 325   return OK; | 341   return OK; | 
| 326 } | 342 } | 
| 327 | 343 | 
| 328 bool FileStream::IsOpen() const { | 344 bool FileStream::IsOpen() const { | 
| 329   return file_ != base::kInvalidPlatformFileValue; | 345   return file_ != base::kInvalidPlatformFileValue; | 
| 330 } | 346 } | 
| 331 | 347 | 
| 332 int64 FileStream::Seek(Whence whence, int64 offset) { | 348 int64 FileStream::Seek(Whence whence, int64 offset) { | 
| 333   base::ThreadRestrictions::AssertIOAllowed(); | 349   base::ThreadRestrictions::AssertIOAllowed(); | 
| 334 | 350 | 
| 335   if (!IsOpen()) | 351   if (!IsOpen()) | 
| 336     return ERR_UNEXPECTED; | 352     return ERR_UNEXPECTED; | 
| 337 | 353 | 
| 338   // If we're in async, make sure we don't have a request in flight. | 354   // If we're in async, make sure we don't have a request in flight. | 
| 339   DCHECK(!async_context_.get() || !async_context_->callback()); | 355   DCHECK(!async_context_.get() || !async_context_->callback()); | 
| 340 | 356 | 
| 341   off_t res = lseek(file_, static_cast<off_t>(offset), | 357   off_t res = lseek(file_, static_cast<off_t>(offset), | 
| 342                     static_cast<int>(whence)); | 358                     static_cast<int>(whence)); | 
| 343   if (res == static_cast<off_t>(-1)) | 359   if (res == static_cast<off_t>(-1)) | 
| 344     return MapErrorCode(errno); | 360     return RecordAndMapError(errno, FILE_ERROR_SOURCE_SEEK, record_uma_); | 
| 345 | 361 | 
| 346   return res; | 362   return res; | 
| 347 } | 363 } | 
| 348 | 364 | 
| 349 int64 FileStream::Available() { | 365 int64 FileStream::Available() { | 
| 350   base::ThreadRestrictions::AssertIOAllowed(); | 366   base::ThreadRestrictions::AssertIOAllowed(); | 
| 351 | 367 | 
| 352   if (!IsOpen()) | 368   if (!IsOpen()) | 
| 353     return ERR_UNEXPECTED; | 369     return ERR_UNEXPECTED; | 
| 354 | 370 | 
| 355   int64 cur_pos = Seek(FROM_CURRENT, 0); | 371   int64 cur_pos = Seek(FROM_CURRENT, 0); | 
| 356   if (cur_pos < 0) | 372   if (cur_pos < 0) | 
| 357     return cur_pos; | 373     return cur_pos; | 
| 358 | 374 | 
| 359   struct stat info; | 375   struct stat info; | 
| 360   if (fstat(file_, &info) != 0) | 376   if (fstat(file_, &info) != 0) | 
| 361     return MapErrorCode(errno); | 377     return RecordAndMapError(errno, FILE_ERROR_SOURCE_GET_SIZE, record_uma_); | 
| 362 | 378 | 
| 363   int64 size = static_cast<int64>(info.st_size); | 379   int64 size = static_cast<int64>(info.st_size); | 
| 364   DCHECK_GT(size, cur_pos); | 380   DCHECK_GT(size, cur_pos); | 
| 365 | 381 | 
| 366   return size - cur_pos; | 382   return size - cur_pos; | 
| 367 } | 383 } | 
| 368 | 384 | 
| 369 int FileStream::Read( | 385 int FileStream::Read( | 
| 370     char* buf, int buf_len, CompletionCallback* callback) { | 386     char* buf, int buf_len, CompletionCallback* callback) { | 
| 371   if (!IsOpen()) | 387   if (!IsOpen()) | 
| 372     return ERR_UNEXPECTED; | 388     return ERR_UNEXPECTED; | 
| 373 | 389 | 
| 374   // read(..., 0) will return 0, which indicates end-of-file. | 390   // read(..., 0) will return 0, which indicates end-of-file. | 
| 375   DCHECK(buf_len > 0); | 391   DCHECK(buf_len > 0); | 
| 376   DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 392   DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 
| 377 | 393 | 
| 378   if (async_context_.get()) { | 394   if (async_context_.get()) { | 
| 379     DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 395     DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 
| 380     // If we're in async, make sure we don't have a request in flight. | 396     // If we're in async, make sure we don't have a request in flight. | 
| 381     DCHECK(!async_context_->callback()); | 397     DCHECK(!async_context_->callback()); | 
|  | 398     if (record_uma_) | 
|  | 399       async_context_->EnableErrorStatistics(); | 
| 382     async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); | 400     async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); | 
| 383     return ERR_IO_PENDING; | 401     return ERR_IO_PENDING; | 
| 384   } else { | 402   } else { | 
| 385     return ReadFile(file_, buf, buf_len); | 403     return ReadFile(file_, buf, buf_len, record_uma_); | 
| 386   } | 404   } | 
| 387 } | 405 } | 
| 388 | 406 | 
| 389 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 407 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 
| 390   int to_read = buf_len; | 408   int to_read = buf_len; | 
| 391   int bytes_total = 0; | 409   int bytes_total = 0; | 
| 392 | 410 | 
| 393   do { | 411   do { | 
| 394     int bytes_read = Read(buf, to_read, NULL); | 412     int bytes_read = Read(buf, to_read, NULL); | 
| 395     if (bytes_read <= 0) { | 413     if (bytes_read <= 0) { | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
| 412   // write(..., 0) will return 0, which indicates end-of-file. | 430   // write(..., 0) will return 0, which indicates end-of-file. | 
| 413   DCHECK_GT(buf_len, 0); | 431   DCHECK_GT(buf_len, 0); | 
| 414 | 432 | 
| 415   if (!IsOpen()) | 433   if (!IsOpen()) | 
| 416     return ERR_UNEXPECTED; | 434     return ERR_UNEXPECTED; | 
| 417 | 435 | 
| 418   if (async_context_.get()) { | 436   if (async_context_.get()) { | 
| 419     DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 437     DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 
| 420     // If we're in async, make sure we don't have a request in flight. | 438     // If we're in async, make sure we don't have a request in flight. | 
| 421     DCHECK(!async_context_->callback()); | 439     DCHECK(!async_context_->callback()); | 
|  | 440     if (record_uma_) | 
|  | 441       async_context_->EnableErrorStatistics(); | 
| 422     async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); | 442     async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); | 
| 423     return ERR_IO_PENDING; | 443     return ERR_IO_PENDING; | 
| 424   } else { | 444   } else { | 
| 425     return WriteFile(file_, buf, buf_len); | 445     return WriteFile(file_, buf, buf_len, record_uma_); | 
| 426   } | 446   } | 
| 427 } | 447 } | 
| 428 | 448 | 
| 429 int64 FileStream::Truncate(int64 bytes) { | 449 int64 FileStream::Truncate(int64 bytes) { | 
| 430   base::ThreadRestrictions::AssertIOAllowed(); | 450   base::ThreadRestrictions::AssertIOAllowed(); | 
| 431 | 451 | 
| 432   if (!IsOpen()) | 452   if (!IsOpen()) | 
| 433     return ERR_UNEXPECTED; | 453     return ERR_UNEXPECTED; | 
| 434 | 454 | 
| 435   // We better be open for reading. | 455   // We better be open for reading. | 
| 436   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 456   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 
| 437 | 457 | 
| 438   // Seek to the position to truncate from. | 458   // Seek to the position to truncate from. | 
| 439   int64 seek_position = Seek(FROM_BEGIN, bytes); | 459   int64 seek_position = Seek(FROM_BEGIN, bytes); | 
| 440   if (seek_position != bytes) | 460   if (seek_position != bytes) | 
| 441     return ERR_UNEXPECTED; | 461     return ERR_UNEXPECTED; | 
| 442 | 462 | 
| 443   // And truncate the file. | 463   // And truncate the file. | 
| 444   int result = ftruncate(file_, bytes); | 464   int result = ftruncate(file_, bytes); | 
| 445   return result == 0 ? seek_position : MapErrorCode(errno); | 465   if (result == 0) | 
|  | 466     return seek_position; | 
|  | 467 | 
|  | 468   return RecordAndMapError(errno, FILE_ERROR_SOURCE_SET_EOF, record_uma_); | 
| 446 } | 469 } | 
| 447 | 470 | 
| 448 int FileStream::Flush() { | 471 int FileStream::Flush() { | 
| 449   if (!IsOpen()) | 472   if (!IsOpen()) | 
| 450     return ERR_UNEXPECTED; | 473     return ERR_UNEXPECTED; | 
| 451 | 474 | 
| 452   return FlushFile(file_); | 475   return FlushFile(file_, record_uma_); | 
|  | 476 } | 
|  | 477 | 
|  | 478 void FileStream::EnableErrorStatistics() { | 
|  | 479   record_uma_ = true; | 
| 453 } | 480 } | 
| 454 | 481 | 
| 455 }  // namespace net | 482 }  // namespace net | 
| OLD | NEW | 
|---|