| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "net/base/file_stream.h" | 5 #include "net/base/file_stream.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 14 #include "net/base/file_stream_metrics.h" | 14 #include "net/base/file_stream_metrics.h" |
| 15 #include "net/base/file_stream_net_log_parameters.h" | 15 #include "net/base/file_stream_net_log_parameters.h" |
| 16 #include "net/base/io_buffer.h" |
| 16 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 20 // Ensure that we can just use our Whence values directly. | 21 // Ensure that we can just use our Whence values directly. |
| 21 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); | 22 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); |
| 22 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); | 23 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); |
| 23 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); | 24 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); |
| 24 | 25 |
| 25 static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { | 26 static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { | 63 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { |
| 63 public: | 64 public: |
| 64 explicit AsyncContext(const net::BoundNetLog& bound_net_log) | 65 explicit AsyncContext(const net::BoundNetLog& bound_net_log) |
| 65 : context_(), is_closing_(false), | 66 : context_(), is_closing_(false), |
| 66 record_uma_(false), bound_net_log_(bound_net_log), | 67 record_uma_(false), bound_net_log_(bound_net_log), |
| 67 error_source_(FILE_ERROR_SOURCE_COUNT) { | 68 error_source_(FILE_ERROR_SOURCE_COUNT) { |
| 68 context_.handler = this; | 69 context_.handler = this; |
| 69 } | 70 } |
| 70 ~AsyncContext(); | 71 ~AsyncContext(); |
| 71 | 72 |
| 72 void IOCompletionIsPending(const CompletionCallback& callback); | 73 void IOCompletionIsPending(const CompletionCallback& callback, |
| 74 IOBuffer* buf); |
| 73 | 75 |
| 74 OVERLAPPED* overlapped() { return &context_.overlapped; } | 76 OVERLAPPED* overlapped() { return &context_.overlapped; } |
| 75 const CompletionCallback& callback() const { return callback_; } | 77 const CompletionCallback& callback() const { return callback_; } |
| 76 | 78 |
| 77 void set_error_source(FileErrorSource source) { error_source_ = source; } | 79 void set_error_source(FileErrorSource source) { error_source_ = source; } |
| 78 | 80 |
| 79 void EnableErrorStatistics() { | 81 void EnableErrorStatistics() { |
| 80 record_uma_ = true; | 82 record_uma_ = true; |
| 81 } | 83 } |
| 82 | 84 |
| 83 private: | 85 private: |
| 84 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, | 86 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, |
| 85 DWORD bytes_read, DWORD error) OVERRIDE; | 87 DWORD bytes_read, DWORD error) OVERRIDE; |
| 86 | 88 |
| 87 MessageLoopForIO::IOContext context_; | 89 MessageLoopForIO::IOContext context_; |
| 88 CompletionCallback callback_; | 90 CompletionCallback callback_; |
| 91 scoped_refptr<IOBuffer> in_flight_buf_; |
| 89 bool is_closing_; | 92 bool is_closing_; |
| 90 bool record_uma_; | 93 bool record_uma_; |
| 91 const net::BoundNetLog bound_net_log_; | 94 const net::BoundNetLog bound_net_log_; |
| 92 FileErrorSource error_source_; | 95 FileErrorSource error_source_; |
| 93 }; | 96 }; |
| 94 | 97 |
| 95 FileStream::AsyncContext::~AsyncContext() { | 98 FileStream::AsyncContext::~AsyncContext() { |
| 96 is_closing_ = true; | 99 is_closing_ = true; |
| 97 bool waited = false; | 100 bool waited = false; |
| 98 base::TimeTicks start = base::TimeTicks::Now(); | 101 base::TimeTicks start = base::TimeTicks::Now(); |
| 99 while (!callback_.is_null()) { | 102 while (!callback_.is_null()) { |
| 100 waited = true; | 103 waited = true; |
| 101 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); | 104 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); |
| 102 } | 105 } |
| 103 if (waited) { | 106 if (waited) { |
| 104 // We want to see if we block the message loop for too long. | 107 // We want to see if we block the message loop for too long. |
| 105 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 108 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", |
| 106 base::TimeTicks::Now() - start); | 109 base::TimeTicks::Now() - start); |
| 107 } | 110 } |
| 108 } | 111 } |
| 109 | 112 |
| 110 void FileStream::AsyncContext::IOCompletionIsPending( | 113 void FileStream::AsyncContext::IOCompletionIsPending( |
| 111 const CompletionCallback& callback) { | 114 const CompletionCallback& callback, |
| 115 IOBuffer* buf) { |
| 112 DCHECK(callback_.is_null()); | 116 DCHECK(callback_.is_null()); |
| 113 callback_ = callback; | 117 callback_ = callback; |
| 118 in_flight_buf_ = buf; // Hold until the async operation ends. |
| 114 } | 119 } |
| 115 | 120 |
| 116 void FileStream::AsyncContext::OnIOCompleted( | 121 void FileStream::AsyncContext::OnIOCompleted( |
| 117 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) { | 122 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) { |
| 118 DCHECK_EQ(&context_, context); | 123 DCHECK_EQ(&context_, context); |
| 119 DCHECK(!callback_.is_null()); | 124 DCHECK(!callback_.is_null()); |
| 120 | 125 |
| 121 if (is_closing_) { | 126 if (is_closing_) { |
| 122 callback_.Reset(); | 127 callback_.Reset(); |
| 128 in_flight_buf_ = NULL; |
| 123 return; | 129 return; |
| 124 } | 130 } |
| 125 | 131 |
| 126 int result = static_cast<int>(bytes_read); | 132 int result = static_cast<int>(bytes_read); |
| 127 if (error && error != ERROR_HANDLE_EOF) { | 133 if (error && error != ERROR_HANDLE_EOF) { |
| 128 result = RecordAndMapError(error, error_source_, record_uma_, | 134 result = RecordAndMapError(error, error_source_, record_uma_, |
| 129 bound_net_log_); | 135 bound_net_log_); |
| 130 } | 136 } |
| 131 | 137 |
| 132 if (bytes_read) | 138 if (bytes_read) |
| 133 IncrementOffset(&context->overlapped, bytes_read); | 139 IncrementOffset(&context->overlapped, bytes_read); |
| 134 | 140 |
| 135 CompletionCallback temp; | 141 CompletionCallback temp_callback = callback_; |
| 136 std::swap(temp, callback_); | 142 callback_.Reset(); |
| 137 temp.Run(result); | 143 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_; |
| 144 in_flight_buf_ = NULL; |
| 145 temp_callback.Run(result); |
| 138 } | 146 } |
| 139 | 147 |
| 140 // FileStream ------------------------------------------------------------ | 148 // FileStream ------------------------------------------------------------ |
| 141 | 149 |
| 142 FileStream::FileStream(net::NetLog* net_log) | 150 FileStream::FileStream(net::NetLog* net_log) |
| 143 : file_(base::kInvalidPlatformFileValue), | 151 : file_(base::kInvalidPlatformFileValue), |
| 144 open_flags_(0), | 152 open_flags_(0), |
| 145 auto_closed_(true), | 153 auto_closed_(true), |
| 146 record_uma_(false), | 154 record_uma_(false), |
| 147 bound_net_log_(net::BoundNetLog::Make(net_log, | 155 bound_net_log_(net::BoundNetLog::Make(net_log, |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 return RecordAndMapError(error, | 278 return RecordAndMapError(error, |
| 271 FILE_ERROR_SOURCE_GET_SIZE, | 279 FILE_ERROR_SOURCE_GET_SIZE, |
| 272 record_uma_, | 280 record_uma_, |
| 273 bound_net_log_); | 281 bound_net_log_); |
| 274 } | 282 } |
| 275 | 283 |
| 276 return file_size.QuadPart - cur_pos; | 284 return file_size.QuadPart - cur_pos; |
| 277 } | 285 } |
| 278 | 286 |
| 279 int FileStream::Read( | 287 int FileStream::Read( |
| 280 char* buf, int buf_len, const CompletionCallback& callback) { | 288 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
| 281 DCHECK(async_context_.get()); | 289 DCHECK(async_context_.get()); |
| 282 return ReadInternal(buf, buf_len, callback); | |
| 283 } | |
| 284 | 290 |
| 285 int FileStream::ReadSync(char* buf, int buf_len) { | |
| 286 DCHECK(!async_context_.get()); | |
| 287 return ReadInternal(buf, buf_len, CompletionCallback()); | |
| 288 } | |
| 289 | |
| 290 int FileStream::ReadInternal( | |
| 291 char* buf, int buf_len, const CompletionCallback& callback) { | |
| 292 if (!IsOpen()) | 291 if (!IsOpen()) |
| 293 return ERR_UNEXPECTED; | 292 return ERR_UNEXPECTED; |
| 294 | 293 |
| 295 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 294 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); |
| 296 | 295 |
| 297 OVERLAPPED* overlapped = NULL; | 296 OVERLAPPED* overlapped = NULL; |
| 298 if (async_context_.get()) { | 297 DCHECK(!callback.is_null()); |
| 299 DCHECK(!callback.is_null()); | 298 DCHECK(async_context_->callback().is_null()); |
| 300 DCHECK(async_context_->callback().is_null()); | 299 overlapped = async_context_->overlapped(); |
| 301 overlapped = async_context_->overlapped(); | 300 async_context_->set_error_source(FILE_ERROR_SOURCE_READ); |
| 302 async_context_->set_error_source(FILE_ERROR_SOURCE_READ); | |
| 303 } else { | |
| 304 DCHECK(callback.is_null()); | |
| 305 base::ThreadRestrictions::AssertIOAllowed(); | |
| 306 } | |
| 307 | 301 |
| 308 int rv; | 302 int rv = 0; |
| 309 | 303 |
| 310 DWORD bytes_read; | 304 DWORD bytes_read; |
| 311 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) { | 305 if (!ReadFile(file_, buf->data(), buf_len, &bytes_read, overlapped)) { |
| 312 DWORD error = GetLastError(); | 306 DWORD error = GetLastError(); |
| 313 if (async_context_.get() && error == ERROR_IO_PENDING) { | 307 if (error == ERROR_IO_PENDING) { |
| 314 async_context_->IOCompletionIsPending(callback); | 308 async_context_->IOCompletionIsPending(callback, buf); |
| 315 rv = ERR_IO_PENDING; | 309 rv = ERR_IO_PENDING; |
| 316 } else if (error == ERROR_HANDLE_EOF) { | 310 } else if (error == ERROR_HANDLE_EOF) { |
| 317 rv = 0; // Report EOF by returning 0 bytes read. | 311 rv = 0; // Report EOF by returning 0 bytes read. |
| 318 } else { | 312 } else { |
| 319 LOG(WARNING) << "ReadFile failed: " << error; | 313 LOG(WARNING) << "ReadFile failed: " << error; |
| 320 rv = RecordAndMapError(error, | 314 rv = RecordAndMapError(error, |
| 321 FILE_ERROR_SOURCE_READ, | 315 FILE_ERROR_SOURCE_READ, |
| 322 record_uma_, | 316 record_uma_, |
| 323 bound_net_log_); | 317 bound_net_log_); |
| 324 } | 318 } |
| 325 } else if (overlapped) { | 319 } else if (overlapped) { |
| 326 async_context_->IOCompletionIsPending(callback); | 320 async_context_->IOCompletionIsPending(callback, buf); |
| 327 rv = ERR_IO_PENDING; | 321 rv = ERR_IO_PENDING; |
| 328 } else { | 322 } else { |
| 329 rv = static_cast<int>(bytes_read); | 323 rv = static_cast<int>(bytes_read); |
| 330 } | 324 } |
| 331 return rv; | 325 return rv; |
| 332 } | 326 } |
| 333 | 327 |
| 328 int FileStream::ReadSync(char* buf, int buf_len) { |
| 329 DCHECK(!async_context_.get()); |
| 330 base::ThreadRestrictions::AssertIOAllowed(); |
| 331 |
| 332 if (!IsOpen()) |
| 333 return ERR_UNEXPECTED; |
| 334 |
| 335 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); |
| 336 |
| 337 int rv = 0; |
| 338 |
| 339 DWORD bytes_read; |
| 340 if (!ReadFile(file_, buf, buf_len, &bytes_read, NULL)) { |
| 341 DWORD error = GetLastError(); |
| 342 if (error == ERROR_HANDLE_EOF) { |
| 343 rv = 0; // Report EOF by returning 0 bytes read. |
| 344 } else { |
| 345 LOG(WARNING) << "ReadFile failed: " << error; |
| 346 rv = RecordAndMapError(error, |
| 347 FILE_ERROR_SOURCE_READ, |
| 348 record_uma_, |
| 349 bound_net_log_); |
| 350 } |
| 351 } else { |
| 352 rv = static_cast<int>(bytes_read); |
| 353 } |
| 354 return rv; |
| 355 } |
| 356 |
| 334 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 357 int FileStream::ReadUntilComplete(char *buf, int buf_len) { |
| 335 int to_read = buf_len; | 358 int to_read = buf_len; |
| 336 int bytes_total = 0; | 359 int bytes_total = 0; |
| 337 | 360 |
| 338 do { | 361 do { |
| 339 int bytes_read = ReadSync(buf, to_read); | 362 int bytes_read = ReadSync(buf, to_read); |
| 340 if (bytes_read <= 0) { | 363 if (bytes_read <= 0) { |
| 341 if (bytes_total == 0) | 364 if (bytes_total == 0) |
| 342 return bytes_read; | 365 return bytes_read; |
| 343 | 366 |
| 344 return bytes_total; | 367 return bytes_total; |
| 345 } | 368 } |
| 346 | 369 |
| 347 bytes_total += bytes_read; | 370 bytes_total += bytes_read; |
| 348 buf += bytes_read; | 371 buf += bytes_read; |
| 349 to_read -= bytes_read; | 372 to_read -= bytes_read; |
| 350 } while (bytes_total < buf_len); | 373 } while (bytes_total < buf_len); |
| 351 | 374 |
| 352 return bytes_total; | 375 return bytes_total; |
| 353 } | 376 } |
| 354 | 377 |
| 355 int FileStream::Write( | 378 int FileStream::Write( |
| 356 const char* buf, int buf_len, const CompletionCallback& callback) { | 379 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
| 357 DCHECK(async_context_.get()); | 380 DCHECK(async_context_.get()); |
| 358 return WriteInternal(buf, buf_len, callback); | |
| 359 } | |
| 360 | 381 |
| 361 int FileStream::WriteSync( | |
| 362 const char* buf, int buf_len) { | |
| 363 DCHECK(!async_context_.get()); | |
| 364 return WriteInternal(buf, buf_len, CompletionCallback()); | |
| 365 } | |
| 366 | |
| 367 int FileStream::WriteInternal( | |
| 368 const char* buf, int buf_len, const CompletionCallback& callback) { | |
| 369 if (!IsOpen()) | 382 if (!IsOpen()) |
| 370 return ERR_UNEXPECTED; | 383 return ERR_UNEXPECTED; |
| 371 | 384 |
| 372 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 385 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 373 | 386 |
| 374 OVERLAPPED* overlapped = NULL; | 387 OVERLAPPED* overlapped = NULL; |
| 375 if (async_context_.get()) { | 388 DCHECK(!callback.is_null()); |
| 376 DCHECK(!callback.is_null()); | 389 DCHECK(async_context_->callback().is_null()); |
| 377 DCHECK(async_context_->callback().is_null()); | 390 overlapped = async_context_->overlapped(); |
| 378 overlapped = async_context_->overlapped(); | 391 async_context_->set_error_source(FILE_ERROR_SOURCE_WRITE); |
| 379 async_context_->set_error_source(FILE_ERROR_SOURCE_WRITE); | |
| 380 } else { | |
| 381 DCHECK(callback.is_null()); | |
| 382 base::ThreadRestrictions::AssertIOAllowed(); | |
| 383 } | |
| 384 | 392 |
| 385 int rv; | 393 int rv = 0; |
| 386 DWORD bytes_written; | 394 DWORD bytes_written = 0; |
| 387 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) { | 395 if (!WriteFile(file_, buf->data(), buf_len, &bytes_written, overlapped)) { |
| 388 DWORD error = GetLastError(); | 396 DWORD error = GetLastError(); |
| 389 if (async_context_.get() && error == ERROR_IO_PENDING) { | 397 if (error == ERROR_IO_PENDING) { |
| 390 async_context_->IOCompletionIsPending(callback); | 398 async_context_->IOCompletionIsPending(callback, buf); |
| 391 rv = ERR_IO_PENDING; | 399 rv = ERR_IO_PENDING; |
| 392 } else { | 400 } else { |
| 393 LOG(WARNING) << "WriteFile failed: " << error; | 401 LOG(WARNING) << "WriteFile failed: " << error; |
| 394 rv = RecordAndMapError(error, | 402 rv = RecordAndMapError(error, |
| 395 FILE_ERROR_SOURCE_WRITE, | 403 FILE_ERROR_SOURCE_WRITE, |
| 396 record_uma_, | 404 record_uma_, |
| 397 bound_net_log_); | 405 bound_net_log_); |
| 398 } | 406 } |
| 399 } else if (overlapped) { | 407 } else if (overlapped) { |
| 400 async_context_->IOCompletionIsPending(callback); | 408 async_context_->IOCompletionIsPending(callback, buf); |
| 401 rv = ERR_IO_PENDING; | 409 rv = ERR_IO_PENDING; |
| 402 } else { | 410 } else { |
| 403 rv = static_cast<int>(bytes_written); | 411 rv = static_cast<int>(bytes_written); |
| 404 } | 412 } |
| 405 return rv; | 413 return rv; |
| 406 } | 414 } |
| 407 | 415 |
| 416 int FileStream::WriteSync( |
| 417 const char* buf, int buf_len) { |
| 418 DCHECK(!async_context_.get()); |
| 419 base::ThreadRestrictions::AssertIOAllowed(); |
| 420 |
| 421 if (!IsOpen()) |
| 422 return ERR_UNEXPECTED; |
| 423 |
| 424 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 425 |
| 426 int rv = 0; |
| 427 DWORD bytes_written = 0; |
| 428 if (!WriteFile(file_, buf, buf_len, &bytes_written, NULL)) { |
| 429 DWORD error = GetLastError(); |
| 430 LOG(WARNING) << "WriteFile failed: " << error; |
| 431 rv = RecordAndMapError(error, |
| 432 FILE_ERROR_SOURCE_WRITE, |
| 433 record_uma_, |
| 434 bound_net_log_); |
| 435 } else { |
| 436 rv = static_cast<int>(bytes_written); |
| 437 } |
| 438 return rv; |
| 439 } |
| 440 |
| 408 int FileStream::Flush() { | 441 int FileStream::Flush() { |
| 409 base::ThreadRestrictions::AssertIOAllowed(); | 442 base::ThreadRestrictions::AssertIOAllowed(); |
| 410 | 443 |
| 411 if (!IsOpen()) | 444 if (!IsOpen()) |
| 412 return ERR_UNEXPECTED; | 445 return ERR_UNEXPECTED; |
| 413 | 446 |
| 414 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 447 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 415 if (FlushFileBuffers(file_)) { | 448 if (FlushFileBuffers(file_)) { |
| 416 return OK; | 449 return OK; |
| 417 } | 450 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 owner_bound_net_log.source()))); | 509 owner_bound_net_log.source()))); |
| 477 | 510 |
| 478 owner_bound_net_log.AddEvent( | 511 owner_bound_net_log.AddEvent( |
| 479 net::NetLog::TYPE_FILE_STREAM_SOURCE, | 512 net::NetLog::TYPE_FILE_STREAM_SOURCE, |
| 480 make_scoped_refptr( | 513 make_scoped_refptr( |
| 481 new net::NetLogSourceParameter("source_dependency", | 514 new net::NetLogSourceParameter("source_dependency", |
| 482 bound_net_log_.source()))); | 515 bound_net_log_.source()))); |
| 483 } | 516 } |
| 484 | 517 |
| 485 } // namespace net | 518 } // namespace net |
| OLD | NEW |