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