 Chromium Code Reviews
 Chromium Code Reviews Issue 7583049:
  Record UMA statistics for file_stream operations.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 7583049:
  Record UMA statistics for file_stream operations.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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> | 
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 case EACCES: | 55 case EACCES: | 
| 56 return ERR_ACCESS_DENIED; | 56 return ERR_ACCESS_DENIED; | 
| 57 default: | 57 default: | 
| 58 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 58 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 
| 59 return ERR_FAILED; | 59 return ERR_FAILED; | 
| 60 } | 60 } | 
| 61 } | 61 } | 
| 62 | 62 | 
| 63 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 63 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 
| 64 // calls MapErrorCode() to map errno to net error codes. | 64 // calls MapErrorCode() to map errno to net error codes. | 
| 65 int ReadFile(base::PlatformFile file, char* buf, int buf_len) { | 65 int ReadFile(base::PlatformFile file, char* buf, int buf_len, int class_flags) { | 
| 66 base::ThreadRestrictions::AssertIOAllowed(); | 66 base::ThreadRestrictions::AssertIOAllowed(); | 
| 67 // read(..., 0) returns 0 to indicate end-of-file. | 67 // read(..., 0) returns 0 to indicate end-of-file. | 
| 68 | 68 | 
| 69 // Loop in the case of getting interrupted by a signal. | 69 // 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))); | 70 ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); | 
| 71 if (res == static_cast<ssize_t>(-1)) | 71 if (res == static_cast<ssize_t>(-1)) { | 
| 72 return MapErrorCode(errno); | 72 int error = errno; | 
| 73 RecordFileError(error, FILE_ERROR_TYPES_READ, class_flags); | |
| 74 return MapErrorCode(error); | |
| 75 } | |
| 73 return static_cast<int>(res); | 76 return static_cast<int>(res); | 
| 74 } | 77 } | 
| 75 | 78 | 
| 76 void ReadFileTask(base::PlatformFile file, | 79 void ReadFileTask(base::PlatformFile file, | 
| 77 char* buf, | 80 char* buf, | 
| 78 int buf_len, | 81 int buf_len, | 
| 82 int class_flags, | |
| 79 CompletionCallback* callback) { | 83 CompletionCallback* callback) { | 
| 80 callback->Run(ReadFile(file, buf, buf_len)); | 84 callback->Run(ReadFile(file, buf, buf_len, class_flags)); | 
| 81 } | 85 } | 
| 82 | 86 | 
| 83 // WriteFile() is a simple wrapper around write() that handles EINTR signals and | 87 // 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 | 88 // calls MapErrorCode() to map errno to net error codes. It tries to write to | 
| 85 // completion. | 89 // completion. | 
| 86 int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { | 90 int WriteFile(base::PlatformFile file, const char* buf, int buf_len, | 
| 91 int class_flags) { | |
| 87 base::ThreadRestrictions::AssertIOAllowed(); | 92 base::ThreadRestrictions::AssertIOAllowed(); | 
| 88 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 93 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 
| 89 if (res == -1) | 94 if (res == -1) { | 
| 90 return MapErrorCode(errno); | 95 int error = errno; | 
| 96 RecordFileError(error, FILE_ERROR_TYPES_WRITE, class_flags); | |
| 97 return MapErrorCode(error); | |
| 98 } | |
| 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, int class_flags, | 
| 97 CompletionCallback* callback) { | 105 CompletionCallback* callback) { | 
| 98 callback->Run(WriteFile(file, buf, buf_len)); | 106 callback->Run(WriteFile(file, buf, buf_len, class_flags)); | 
| 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, int class_flags) { | 
| 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 int error = errno; | 
| 117 RecordFileError(error, FILE_ERROR_TYPES_FLUSH, class_flags); | |
| 118 return MapErrorCode(error); | |
| 119 } | |
| 109 return res; | 120 return res; | 
| 110 } | 121 } | 
| 111 | 122 | 
| 112 } // namespace | 123 } // namespace | 
| 113 | 124 | 
| 114 // CancelableCallbackTask takes ownership of the Callback. This task gets | 125 // CancelableCallbackTask takes ownership of the Callback. This task gets | 
| 115 // posted to the MessageLoopForIO instance. | 126 // posted to the MessageLoopForIO instance. | 
| 116 class CancelableCallbackTask : public CancelableTask { | 127 class CancelableCallbackTask : public CancelableTask { | 
| 117 public: | 128 public: | 
| 118 explicit CancelableCallbackTask(Callback0::Type* callback) | 129 explicit CancelableCallbackTask(Callback0::Type* callback) | 
| (...skipping 15 matching lines...) Expand all Loading... | |
| 134 | 145 | 
| 135 // FileStream::AsyncContext ---------------------------------------------- | 146 // FileStream::AsyncContext ---------------------------------------------- | 
| 136 | 147 | 
| 137 class FileStream::AsyncContext { | 148 class FileStream::AsyncContext { | 
| 138 public: | 149 public: | 
| 139 AsyncContext(); | 150 AsyncContext(); | 
| 140 ~AsyncContext(); | 151 ~AsyncContext(); | 
| 141 | 152 | 
| 142 // These methods post synchronous read() and write() calls to a WorkerThread. | 153 // These methods post synchronous read() and write() calls to a WorkerThread. | 
| 143 void InitiateAsyncRead( | 154 void InitiateAsyncRead( | 
| 144 base::PlatformFile file, char* buf, int buf_len, | 155 base::PlatformFile file, char* buf, int buf_len, int class_flags, | 
| 145 CompletionCallback* callback); | 156 CompletionCallback* callback); | 
| 146 void InitiateAsyncWrite( | 157 void InitiateAsyncWrite( | 
| 147 base::PlatformFile file, const char* buf, int buf_len, | 158 base::PlatformFile file, const char* buf, int buf_len, int class_flags, | 
| 148 CompletionCallback* callback); | 159 CompletionCallback* callback); | 
| 149 | 160 | 
| 150 CompletionCallback* callback() const { return callback_; } | 161 CompletionCallback* callback() const { return callback_; } | 
| 151 | 162 | 
| 152 // Called by the WorkerPool thread executing the IO after the IO completes. | 163 // Called by the WorkerPool thread executing the IO after the IO completes. | 
| 153 // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 164 // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 
| 154 // |background_io_completed_callback_|, in case the destructor is waiting. In | 165 // |background_io_completed_callback_|, in case the destructor is waiting. In | 
| 155 // that case, the destructor will call RunAsynchronousCallback() instead, and | 166 // that case, the destructor will call RunAsynchronousCallback() instead, and | 
| 156 // cancel |message_loop_task_|. | 167 // cancel |message_loop_task_|. | 
| 157 // |result| is the result of the Read/Write task. | 168 // |result| is the result of the Read/Write task. | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 RunAsynchronousCallback(); | 215 RunAsynchronousCallback(); | 
| 205 if (need_to_wait) { | 216 if (need_to_wait) { | 
| 206 // We want to see if we block the message loop for too long. | 217 // We want to see if we block the message loop for too long. | 
| 207 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 218 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 
| 208 base::TimeTicks::Now() - start); | 219 base::TimeTicks::Now() - start); | 
| 209 } | 220 } | 
| 210 } | 221 } | 
| 211 } | 222 } | 
| 212 | 223 | 
| 213 void FileStream::AsyncContext::InitiateAsyncRead( | 224 void FileStream::AsyncContext::InitiateAsyncRead( | 
| 214 base::PlatformFile file, char* buf, int buf_len, | 225 base::PlatformFile file, char* buf, int buf_len, int class_flags, | 
| 215 CompletionCallback* callback) { | 226 CompletionCallback* callback) { | 
| 216 DCHECK(!callback_); | 227 DCHECK(!callback_); | 
| 217 callback_ = callback; | 228 callback_ = callback; | 
| 218 | 229 | 
| 219 base::WorkerPool::PostTask(FROM_HERE, | 230 base::WorkerPool::PostTask(FROM_HERE, | 
| 220 NewRunnableFunction( | 231 NewRunnableFunction( | 
| 221 &ReadFileTask, | 232 &ReadFileTask, | 
| 222 file, buf, buf_len, | 233 file, buf, buf_len, class_flags, | 
| 223 &background_io_completed_callback_), | 234 &background_io_completed_callback_), | 
| 224 true /* task_is_slow */); | 235 true /* task_is_slow */); | 
| 225 } | 236 } | 
| 226 | 237 | 
| 227 void FileStream::AsyncContext::InitiateAsyncWrite( | 238 void FileStream::AsyncContext::InitiateAsyncWrite( | 
| 228 base::PlatformFile file, const char* buf, int buf_len, | 239 base::PlatformFile file, const char* buf, int buf_len, int class_flags, | 
| 229 CompletionCallback* callback) { | 240 CompletionCallback* callback) { | 
| 230 DCHECK(!callback_); | 241 DCHECK(!callback_); | 
| 231 callback_ = callback; | 242 callback_ = callback; | 
| 232 | 243 | 
| 233 base::WorkerPool::PostTask(FROM_HERE, | 244 base::WorkerPool::PostTask(FROM_HERE, | 
| 234 NewRunnableFunction( | 245 NewRunnableFunction( | 
| 235 &WriteFileTask, | 246 &WriteFileTask, | 
| 236 file, buf, buf_len, | 247 file, buf, buf_len, class_flags, | 
| 237 &background_io_completed_callback_), | 248 &background_io_completed_callback_), | 
| 238 true /* task_is_slow */); | 249 true /* task_is_slow */); | 
| 239 } | 250 } | 
| 240 | 251 | 
| 241 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 252 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 
| 242 result_ = result; | 253 result_ = result; | 
| 243 message_loop_task_ = new CancelableCallbackTask( | 254 message_loop_task_ = new CancelableCallbackTask( | 
| 244 NewCallback(this, &AsyncContext::RunAsynchronousCallback)); | 255 NewCallback(this, &AsyncContext::RunAsynchronousCallback)); | 
| 245 message_loop_->PostTask(FROM_HERE, message_loop_task_); | 256 message_loop_->PostTask(FROM_HERE, message_loop_task_); | 
| 246 background_io_completed_.Signal(); | 257 background_io_completed_.Signal(); | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 267 std::swap(temp, callback_); | 278 std::swap(temp, callback_); | 
| 268 background_io_completed_.Reset(); | 279 background_io_completed_.Reset(); | 
| 269 temp->Run(result_); | 280 temp->Run(result_); | 
| 270 } | 281 } | 
| 271 | 282 | 
| 272 // FileStream ------------------------------------------------------------ | 283 // FileStream ------------------------------------------------------------ | 
| 273 | 284 | 
| 274 FileStream::FileStream() | 285 FileStream::FileStream() | 
| 275 : file_(base::kInvalidPlatformFileValue), | 286 : file_(base::kInvalidPlatformFileValue), | 
| 276 open_flags_(0), | 287 open_flags_(0), | 
| 277 auto_closed_(true) { | 288 auto_closed_(true) { | 
| 
cbentzel
2011/08/15 19:49:11
class_flags_ needs to be initialized.
 
ahendrickson
2011/08/15 23:42:26
Done.
 | |
| 278 DCHECK(!IsOpen()); | 289 DCHECK(!IsOpen()); | 
| 279 } | 290 } | 
| 280 | 291 | 
| 292 FileStream::FileStream(int class_flags) | |
| 293 : file_(base::kInvalidPlatformFileValue), | |
| 294 open_flags_(0), | |
| 295 auto_closed_(true), | |
| 296 class_flags_(class_flags) { | |
| 297 DCHECK(!IsOpen()); | |
| 298 } | |
| 299 | |
| 281 FileStream::FileStream(base::PlatformFile file, int flags) | 300 FileStream::FileStream(base::PlatformFile file, int flags) | 
| 282 : file_(file), | 301 : file_(file), | 
| 283 open_flags_(flags), | 302 open_flags_(flags), | 
| 284 auto_closed_(false) { | 303 auto_closed_(false) { | 
| 
cbentzel
2011/08/15 19:49:11
class_flags_ needs to be initialized.
 
ahendrickson
2011/08/15 23:42:26
Done.
 | |
| 285 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to | 304 // 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. | 305 // make sure we will perform asynchronous File IO to it. | 
| 287 if (flags & base::PLATFORM_FILE_ASYNC) { | 306 if (flags & base::PLATFORM_FILE_ASYNC) { | 
| 288 async_context_.reset(new AsyncContext()); | 307 async_context_.reset(new AsyncContext()); | 
| 289 } | 308 } | 
| 290 } | 309 } | 
| 291 | 310 | 
| 311 FileStream::FileStream(base::PlatformFile file, int flags, int class_flags) | |
| 312 : file_(file), | |
| 313 open_flags_(flags), | |
| 314 auto_closed_(false), | |
| 315 class_flags_(class_flags) { | |
| 316 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to | |
| 317 // make sure we will perform asynchronous File IO to it. | |
| 318 if (flags & base::PLATFORM_FILE_ASYNC) { | |
| 319 async_context_.reset(new AsyncContext()); | |
| 320 } | |
| 321 } | |
| 322 | |
| 292 FileStream::~FileStream() { | 323 FileStream::~FileStream() { | 
| 293 if (auto_closed_) | 324 if (auto_closed_) | 
| 294 Close(); | 325 Close(); | 
| 295 } | 326 } | 
| 296 | 327 | 
| 297 void FileStream::Close() { | 328 void FileStream::Close() { | 
| 298 // Abort any existing asynchronous operations. | 329 // Abort any existing asynchronous operations. | 
| 299 async_context_.reset(); | 330 async_context_.reset(); | 
| 300 | 331 | 
| 301 if (file_ != base::kInvalidPlatformFileValue) { | 332 if (file_ != base::kInvalidPlatformFileValue) { | 
| 302 if (close(file_) != 0) { | 333 if (close(file_) != 0) { | 
| 303 NOTREACHED(); | 334 NOTREACHED(); | 
| 304 } | 335 } | 
| 305 file_ = base::kInvalidPlatformFileValue; | 336 file_ = base::kInvalidPlatformFileValue; | 
| 306 } | 337 } | 
| 307 } | 338 } | 
| 308 | 339 | 
| 309 int FileStream::Open(const FilePath& path, int open_flags) { | 340 int FileStream::Open(const FilePath& path, int open_flags) { | 
| 310 if (IsOpen()) { | 341 if (IsOpen()) { | 
| 311 DLOG(FATAL) << "File is already open!"; | 342 DLOG(FATAL) << "File is already open!"; | 
| 312 return ERR_UNEXPECTED; | 343 return ERR_UNEXPECTED; | 
| 313 } | 344 } | 
| 314 | 345 | 
| 315 open_flags_ = open_flags; | 346 open_flags_ = open_flags; | 
| 316 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); | 347 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); | 
| 317 if (file_ == base::kInvalidPlatformFileValue) { | 348 if (file_ == base::kInvalidPlatformFileValue) { | 
| 318 return MapErrorCode(errno); | 349 int error = errno; | 
| 350 RecordFileError(error, FILE_ERROR_TYPES_OPEN, class_flags_); | |
| 351 return MapErrorCode(error); | |
| 319 } | 352 } | 
| 320 | 353 | 
| 321 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { | 354 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { | 
| 322 async_context_.reset(new AsyncContext()); | 355 async_context_.reset(new AsyncContext()); | 
| 323 } | 356 } | 
| 324 | 357 | 
| 325 return OK; | 358 return OK; | 
| 326 } | 359 } | 
| 327 | 360 | 
| 328 bool FileStream::IsOpen() const { | 361 bool FileStream::IsOpen() const { | 
| 329 return file_ != base::kInvalidPlatformFileValue; | 362 return file_ != base::kInvalidPlatformFileValue; | 
| 330 } | 363 } | 
| 331 | 364 | 
| 332 int64 FileStream::Seek(Whence whence, int64 offset) { | 365 int64 FileStream::Seek(Whence whence, int64 offset) { | 
| 333 base::ThreadRestrictions::AssertIOAllowed(); | 366 base::ThreadRestrictions::AssertIOAllowed(); | 
| 334 | 367 | 
| 335 if (!IsOpen()) | 368 if (!IsOpen()) { | 
| 369 RecordFileError(EINVAL, FILE_ERROR_TYPES_IS_NOT_OPEN, class_flags_); | |
| 336 return ERR_UNEXPECTED; | 370 return ERR_UNEXPECTED; | 
| 371 } | |
| 337 | 372 | 
| 338 // If we're in async, make sure we don't have a request in flight. | 373 // If we're in async, make sure we don't have a request in flight. | 
| 339 DCHECK(!async_context_.get() || !async_context_->callback()); | 374 DCHECK(!async_context_.get() || !async_context_->callback()); | 
| 340 | 375 | 
| 341 off_t res = lseek(file_, static_cast<off_t>(offset), | 376 off_t res = lseek(file_, static_cast<off_t>(offset), | 
| 342 static_cast<int>(whence)); | 377 static_cast<int>(whence)); | 
| 343 if (res == static_cast<off_t>(-1)) | 378 if (res == static_cast<off_t>(-1)) { | 
| 344 return MapErrorCode(errno); | 379 int error = errno; | 
| 380 RecordFileError(error, FILE_ERROR_TYPES_SEEK, class_flags_); | |
| 381 return MapErrorCode(error); | |
| 382 } | |
| 345 | 383 | 
| 346 return res; | 384 return res; | 
| 347 } | 385 } | 
| 348 | 386 | 
| 349 int64 FileStream::Available() { | 387 int64 FileStream::Available() { | 
| 350 base::ThreadRestrictions::AssertIOAllowed(); | 388 base::ThreadRestrictions::AssertIOAllowed(); | 
| 351 | 389 | 
| 352 if (!IsOpen()) | 390 if (!IsOpen()) { | 
| 391 RecordFileError(EINVAL, FILE_ERROR_TYPES_IS_NOT_OPEN, class_flags_); | |
| 353 return ERR_UNEXPECTED; | 392 return ERR_UNEXPECTED; | 
| 393 } | |
| 354 | 394 | 
| 355 int64 cur_pos = Seek(FROM_CURRENT, 0); | 395 int64 cur_pos = Seek(FROM_CURRENT, 0); | 
| 356 if (cur_pos < 0) | 396 if (cur_pos < 0) | 
| 357 return cur_pos; | 397 return cur_pos; | 
| 358 | 398 | 
| 359 struct stat info; | 399 struct stat info; | 
| 360 if (fstat(file_, &info) != 0) | 400 if (fstat(file_, &info) != 0) { | 
| 361 return MapErrorCode(errno); | 401 int error = errno; | 
| 362 | 402 RecordFileError(error, FILE_ERROR_TYPES_GET_SIZE, class_flags_); | 
| 403 return MapErrorCode(error); | |
| 404 } | |
| 363 int64 size = static_cast<int64>(info.st_size); | 405 int64 size = static_cast<int64>(info.st_size); | 
| 364 DCHECK_GT(size, cur_pos); | 406 DCHECK_GT(size, cur_pos); | 
| 365 | 407 | 
| 366 return size - cur_pos; | 408 return size - cur_pos; | 
| 367 } | 409 } | 
| 368 | 410 | 
| 369 int FileStream::Read( | 411 int FileStream::Read( | 
| 370 char* buf, int buf_len, CompletionCallback* callback) { | 412 char* buf, int buf_len, CompletionCallback* callback) { | 
| 371 if (!IsOpen()) | 413 if (!IsOpen()) { | 
| 414 RecordFileError(EINVAL, FILE_ERROR_TYPES_IS_NOT_OPEN, class_flags_); | |
| 372 return ERR_UNEXPECTED; | 415 return ERR_UNEXPECTED; | 
| 416 } | |
| 373 | 417 | 
| 374 // read(..., 0) will return 0, which indicates end-of-file. | 418 // read(..., 0) will return 0, which indicates end-of-file. | 
| 375 DCHECK(buf_len > 0); | 419 DCHECK(buf_len > 0); | 
| 376 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 420 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 
| 377 | 421 | 
| 378 if (async_context_.get()) { | 422 if (async_context_.get()) { | 
| 379 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 423 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 
| 380 // If we're in async, make sure we don't have a request in flight. | 424 // If we're in async, make sure we don't have a request in flight. | 
| 381 DCHECK(!async_context_->callback()); | 425 DCHECK(!async_context_->callback()); | 
| 382 async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); | 426 async_context_->InitiateAsyncRead(file_, buf, buf_len, class_flags_, | 
| 427 callback); | |
| 383 return ERR_IO_PENDING; | 428 return ERR_IO_PENDING; | 
| 384 } else { | 429 } else { | 
| 385 return ReadFile(file_, buf, buf_len); | 430 return ReadFile(file_, buf, buf_len, class_flags_); | 
| 386 } | 431 } | 
| 387 } | 432 } | 
| 388 | 433 | 
| 389 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 434 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 
| 390 int to_read = buf_len; | 435 int to_read = buf_len; | 
| 391 int bytes_total = 0; | 436 int bytes_total = 0; | 
| 392 | 437 | 
| 393 do { | 438 do { | 
| 394 int bytes_read = Read(buf, to_read, NULL); | 439 int bytes_read = Read(buf, to_read, NULL); | 
| 395 if (bytes_read <= 0) { | 440 if (bytes_read <= 0) { | 
| 396 if (bytes_total == 0) | 441 if (bytes_total == 0) | 
| 397 return bytes_read; | 442 return bytes_read; | 
| 398 | 443 | 
| 399 return bytes_total; | 444 return bytes_total; | 
| 400 } | 445 } | 
| 401 | 446 | 
| 402 bytes_total += bytes_read; | 447 bytes_total += bytes_read; | 
| 403 buf += bytes_read; | 448 buf += bytes_read; | 
| 404 to_read -= bytes_read; | 449 to_read -= bytes_read; | 
| 405 } while (bytes_total < buf_len); | 450 } while (bytes_total < buf_len); | 
| 406 | 451 | 
| 407 return bytes_total; | 452 return bytes_total; | 
| 408 } | 453 } | 
| 409 | 454 | 
| 410 int FileStream::Write( | 455 int FileStream::Write( | 
| 411 const char* buf, int buf_len, CompletionCallback* callback) { | 456 const char* buf, int buf_len, CompletionCallback* callback) { | 
| 412 // write(..., 0) will return 0, which indicates end-of-file. | 457 // write(..., 0) will return 0, which indicates end-of-file. | 
| 413 DCHECK_GT(buf_len, 0); | 458 DCHECK_GT(buf_len, 0); | 
| 414 | 459 | 
| 415 if (!IsOpen()) | 460 if (!IsOpen()) { | 
| 461 RecordFileError(EINVAL, FILE_ERROR_TYPES_IS_NOT_OPEN, class_flags_); | |
| 416 return ERR_UNEXPECTED; | 462 return ERR_UNEXPECTED; | 
| 463 } | |
| 417 | 464 | 
| 418 if (async_context_.get()) { | 465 if (async_context_.get()) { | 
| 419 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 466 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 
| 420 // If we're in async, make sure we don't have a request in flight. | 467 // If we're in async, make sure we don't have a request in flight. | 
| 421 DCHECK(!async_context_->callback()); | 468 DCHECK(!async_context_->callback()); | 
| 422 async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); | 469 async_context_->InitiateAsyncWrite(file_, buf, buf_len, class_flags_, | 
| 470 callback); | |
| 423 return ERR_IO_PENDING; | 471 return ERR_IO_PENDING; | 
| 424 } else { | 472 } else { | 
| 425 return WriteFile(file_, buf, buf_len); | 473 return WriteFile(file_, buf, buf_len, class_flags_); | 
| 426 } | 474 } | 
| 427 } | 475 } | 
| 428 | 476 | 
| 429 int64 FileStream::Truncate(int64 bytes) { | 477 int64 FileStream::Truncate(int64 bytes) { | 
| 430 base::ThreadRestrictions::AssertIOAllowed(); | 478 base::ThreadRestrictions::AssertIOAllowed(); | 
| 431 | 479 | 
| 432 if (!IsOpen()) | 480 if (!IsOpen()) { | 
| 481 RecordFileError(EINVAL, FILE_ERROR_TYPES_IS_NOT_OPEN, class_flags_); | |
| 433 return ERR_UNEXPECTED; | 482 return ERR_UNEXPECTED; | 
| 483 } | |
| 434 | 484 | 
| 435 // We better be open for reading. | 485 // We better be open for reading. | 
| 436 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 486 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 
| 437 | 487 | 
| 438 // Seek to the position to truncate from. | 488 // Seek to the position to truncate from. | 
| 439 int64 seek_position = Seek(FROM_BEGIN, bytes); | 489 int64 seek_position = Seek(FROM_BEGIN, bytes); | 
| 440 if (seek_position != bytes) | 490 if (seek_position != bytes) | 
| 441 return ERR_UNEXPECTED; | 491 return ERR_UNEXPECTED; | 
| 442 | 492 | 
| 443 // And truncate the file. | 493 // And truncate the file. | 
| 444 int result = ftruncate(file_, bytes); | 494 int result = ftruncate(file_, bytes); | 
| 445 return result == 0 ? seek_position : MapErrorCode(errno); | 495 if (result == 0) | 
| 496 return seek_position; | |
| 497 | |
| 498 int error = errno; | |
| 499 RecordFileError(error, FILE_ERROR_TYPES_SET_EOF, class_flags_); | |
| 500 return MapErrorCode(error); | |
| 446 } | 501 } | 
| 447 | 502 | 
| 448 int FileStream::Flush() { | 503 int FileStream::Flush() { | 
| 449 if (!IsOpen()) | 504 if (!IsOpen()) { | 
| 505 RecordFileError(EINVAL, FILE_ERROR_TYPES_IS_NOT_OPEN, class_flags_); | |
| 450 return ERR_UNEXPECTED; | 506 return ERR_UNEXPECTED; | 
| 507 } | |
| 451 | 508 | 
| 452 return FlushFile(file_); | 509 return FlushFile(file_, class_flags_); | 
| 510 } | |
| 511 | |
| 512 void FileStream::EnableRecording(bool enable, int class_flags) { | |
| 513 if (enable) | |
| 514 class_flags_ |= class_flags; | |
| 515 else | |
| 516 class_flags_ &= ~class_flags; | |
| 453 } | 517 } | 
| 454 | 518 | 
| 455 } // namespace net | 519 } // namespace net | 
| OLD | NEW |