| 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 |