| 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/synchronization/waitable_event.h" |
| 13 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
| 14 #include "base/threading/worker_pool.h" | 15 #include "base/threading/worker_pool.h" |
| 15 #include "net/base/file_stream_metrics.h" | 16 #include "net/base/file_stream_metrics.h" |
| 16 #include "net/base/file_stream_net_log_parameters.h" | 17 #include "net/base/file_stream_net_log_parameters.h" |
| 17 #include "net/base/io_buffer.h" | 18 #include "net/base/io_buffer.h" |
| 18 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
| 19 | 20 |
| 20 namespace net { | 21 namespace net { |
| 21 | 22 |
| 22 // Ensure that we can just use our Whence values directly. | 23 // Ensure that we can just use our Whence values directly. |
| 23 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); | 24 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); |
| 24 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); | 25 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); |
| 25 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); | 26 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); |
| 26 | 27 |
| 27 static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { | 28 namespace { |
| 29 |
| 30 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { |
| 28 overlapped->Offset = offset.LowPart; | 31 overlapped->Offset = offset.LowPart; |
| 29 overlapped->OffsetHigh = offset.HighPart; | 32 overlapped->OffsetHigh = offset.HighPart; |
| 30 } | 33 } |
| 31 | 34 |
| 32 static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { | 35 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { |
| 33 LARGE_INTEGER offset; | 36 LARGE_INTEGER offset; |
| 34 offset.LowPart = overlapped->Offset; | 37 offset.LowPart = overlapped->Offset; |
| 35 offset.HighPart = overlapped->OffsetHigh; | 38 offset.HighPart = overlapped->OffsetHigh; |
| 36 offset.QuadPart += static_cast<LONGLONG>(count); | 39 offset.QuadPart += static_cast<LONGLONG>(count); |
| 37 SetOffset(overlapped, offset); | 40 SetOffset(overlapped, offset); |
| 38 } | 41 } |
| 39 | 42 |
| 40 namespace { | |
| 41 | |
| 42 int RecordAndMapError(int error, | 43 int RecordAndMapError(int error, |
| 43 FileErrorSource source, | 44 FileErrorSource source, |
| 44 bool record_uma, | 45 bool record_uma, |
| 45 const net::BoundNetLog& bound_net_log) { | 46 const net::BoundNetLog& bound_net_log) { |
| 46 net::Error net_error = MapSystemError(error); | 47 net::Error net_error = MapSystemError(error); |
| 47 | 48 |
| 48 bound_net_log.AddEvent( | 49 bound_net_log.AddEvent( |
| 49 net::NetLog::TYPE_FILE_STREAM_ERROR, | 50 net::NetLog::TYPE_FILE_STREAM_ERROR, |
| 50 make_scoped_refptr( | 51 make_scoped_refptr( |
| 51 new FileStreamErrorParameters(GetFileErrorSourceName(source), | 52 new FileStreamErrorParameters(GetFileErrorSourceName(source), |
| (...skipping 25 matching lines...) Expand all Loading... |
| 77 LOG(WARNING) << "Failed to open file: " << error; | 78 LOG(WARNING) << "Failed to open file: " << error; |
| 78 *result = RecordAndMapError(error, | 79 *result = RecordAndMapError(error, |
| 79 FILE_ERROR_SOURCE_OPEN, | 80 FILE_ERROR_SOURCE_OPEN, |
| 80 record_uma, | 81 record_uma, |
| 81 bound_net_log); | 82 bound_net_log); |
| 82 bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL); | 83 bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL); |
| 83 return; | 84 return; |
| 84 } | 85 } |
| 85 } | 86 } |
| 86 | 87 |
| 87 // Opens a file using OpenFile() and signals the completion. | |
| 88 void OpenFileAndSignal(const FilePath& path, | |
| 89 int open_flags, | |
| 90 bool record_uma, | |
| 91 base::PlatformFile* file, | |
| 92 int* result, | |
| 93 base::WaitableEvent* on_io_complete, | |
| 94 const net::BoundNetLog& bound_net_log) { | |
| 95 OpenFile(path, open_flags, record_uma, file, result, bound_net_log); | |
| 96 on_io_complete->Signal(); | |
| 97 } | |
| 98 | |
| 99 // Closes a file with some network logging. | 88 // Closes a file with some network logging. |
| 100 void CloseFile(base::PlatformFile file, | 89 void CloseFile(base::PlatformFile file, |
| 101 const net::BoundNetLog& bound_net_log) { | 90 const net::BoundNetLog& bound_net_log) { |
| 102 bound_net_log.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE, NULL); | 91 bound_net_log.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE, NULL); |
| 103 if (file == base::kInvalidPlatformFileValue) | 92 if (file == base::kInvalidPlatformFileValue) |
| 104 return; | 93 return; |
| 105 | 94 |
| 106 CancelIo(file); | 95 CancelIo(file); |
| 107 | 96 |
| 108 if (!base::ClosePlatformFile(file)) | 97 if (!base::ClosePlatformFile(file)) |
| 109 NOTREACHED(); | 98 NOTREACHED(); |
| 110 bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL); | 99 bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL); |
| 111 } | 100 } |
| 112 | 101 |
| 113 // Closes a file with CloseFile() and signals the completion. | 102 // Closes a file with CloseFile() and signals the completion. |
| 114 void CloseFileAndSignal(base::PlatformFile* file, | 103 void CloseFileAndSignal(base::PlatformFile* file, |
| 115 base::WaitableEvent* on_io_complete, | 104 base::WaitableEvent* on_io_complete, |
| 116 const net::BoundNetLog& bound_net_log) { | 105 const net::BoundNetLog& bound_net_log) { |
| 117 CloseFile(*file, bound_net_log); | 106 CloseFile(*file, bound_net_log); |
| 118 *file = base::kInvalidPlatformFileValue; | 107 *file = base::kInvalidPlatformFileValue; |
| 119 on_io_complete->Signal(); | 108 on_io_complete->Signal(); |
| 120 } | 109 } |
| 121 | 110 |
| 111 // Invokes a given closure and signals the completion. |
| 112 void InvokeAndSignal(const base::Closure& closure, |
| 113 base::WaitableEvent* on_io_complete) { |
| 114 closure.Run(); |
| 115 on_io_complete->Signal(); |
| 116 } |
| 117 |
| 122 } // namespace | 118 } // namespace |
| 123 | 119 |
| 124 // FileStreamWin::AsyncContext ---------------------------------------------- | 120 // FileStreamWin::AsyncContext ---------------------------------------------- |
| 125 | 121 |
| 126 class FileStreamWin::AsyncContext : public MessageLoopForIO::IOHandler { | 122 class FileStreamWin::AsyncContext : public MessageLoopForIO::IOHandler { |
| 127 public: | 123 public: |
| 128 explicit AsyncContext(const net::BoundNetLog& bound_net_log) | 124 explicit AsyncContext(const net::BoundNetLog& bound_net_log) |
| 129 : context_(), is_closing_(false), | 125 : context_(), is_closing_(false), |
| 130 record_uma_(false), bound_net_log_(bound_net_log), | 126 record_uma_(false), bound_net_log_(bound_net_log), |
| 131 error_source_(FILE_ERROR_SOURCE_COUNT) { | 127 error_source_(FILE_ERROR_SOURCE_COUNT) { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 } | 259 } |
| 264 } else { | 260 } else { |
| 265 CloseSync(); | 261 CloseSync(); |
| 266 } | 262 } |
| 267 } | 263 } |
| 268 | 264 |
| 269 bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL); | 265 bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL); |
| 270 } | 266 } |
| 271 | 267 |
| 272 void FileStreamWin::Close(const CompletionCallback& callback) { | 268 void FileStreamWin::Close(const CompletionCallback& callback) { |
| 273 DCHECK(callback_.is_null()); | |
| 274 callback_ = callback; | |
| 275 | |
| 276 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 269 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); |
| 277 | 270 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); |
| 278 DCHECK(!on_io_complete_.get()); | 271 DCHECK(!on_io_complete_.get()); |
| 279 on_io_complete_.reset(new base::WaitableEvent( | 272 on_io_complete_.reset(new base::WaitableEvent( |
| 280 false /* manual_reset */, false /* initially_signaled */)); | 273 false /* manual_reset */, false /* initially_signaled */)); |
| 281 | 274 |
| 282 // Passing &file_ to a thread pool looks unsafe but it's safe here as the | 275 // Passing &file_ to a thread pool looks unsafe but it's safe here as the |
| 283 // destructor ensures that the close operation is complete with | 276 // destructor ensures that the close operation is complete with |
| 284 // WaitForIOCompletion(). See also the destructor. | 277 // WaitForIOCompletion(). See also the destructor. |
| 285 const bool posted = base::WorkerPool::PostTaskAndReply( | 278 const bool posted = base::WorkerPool::PostTaskAndReply( |
| 286 FROM_HERE, | 279 FROM_HERE, |
| 287 base::Bind(&CloseFileAndSignal, &file_, on_io_complete_.get(), | 280 base::Bind(&CloseFileAndSignal, &file_, on_io_complete_.get(), |
| 288 bound_net_log_), | 281 bound_net_log_), |
| 289 base::Bind(&FileStreamWin::OnClosed, weak_ptr_factory_.GetWeakPtr()), | 282 base::Bind(&FileStreamWin::OnClosed, |
| 283 weak_ptr_factory_.GetWeakPtr(), |
| 284 callback), |
| 290 true /* task_is_slow */); | 285 true /* task_is_slow */); |
| 291 DCHECK(posted); | 286 DCHECK(posted); |
| 292 } | 287 } |
| 293 | 288 |
| 294 void FileStreamWin::CloseSync() { | 289 void FileStreamWin::CloseSync() { |
| 295 // The logic here is similar to CloseFile() but async_context_.reset() is | 290 // The logic here is similar to CloseFile() but async_context_.reset() is |
| 296 // caled in this function. | 291 // caled in this function. |
| 297 | 292 |
| 298 // Block until the in-flight open operation is complete. | 293 // Block until the in-flight open operation is complete. |
| 299 // TODO(satorux): Replace this with a DCHECK(open_flags & ASYNC) once this | 294 // TODO(satorux): Replace this with a DCHECK(open_flags & ASYNC) once this |
| (...skipping 16 matching lines...) Expand all Loading... |
| 316 } | 311 } |
| 317 } | 312 } |
| 318 | 313 |
| 319 int FileStreamWin::Open(const FilePath& path, int open_flags, | 314 int FileStreamWin::Open(const FilePath& path, int open_flags, |
| 320 const CompletionCallback& callback) { | 315 const CompletionCallback& callback) { |
| 321 if (IsOpen()) { | 316 if (IsOpen()) { |
| 322 DLOG(FATAL) << "File is already open!"; | 317 DLOG(FATAL) << "File is already open!"; |
| 323 return ERR_UNEXPECTED; | 318 return ERR_UNEXPECTED; |
| 324 } | 319 } |
| 325 | 320 |
| 326 DCHECK(callback_.is_null()); | |
| 327 callback_ = callback; | |
| 328 | |
| 329 open_flags_ = open_flags; | 321 open_flags_ = open_flags; |
| 330 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 322 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); |
| 331 | 323 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); |
| 332 DCHECK(!on_io_complete_.get()); | 324 DCHECK(!on_io_complete_.get()); |
| 333 on_io_complete_.reset(new base::WaitableEvent( | 325 on_io_complete_.reset(new base::WaitableEvent( |
| 334 false /* manual_reset */, false /* initially_signaled */)); | 326 false /* manual_reset */, false /* initially_signaled */)); |
| 335 | 327 |
| 336 // Passing &file_ to a thread pool looks unsafe but it's safe here as the | 328 // Passing &file_ to a thread pool looks unsafe but it's safe here as the |
| 337 // destructor ensures that the open operation is complete with | 329 // destructor ensures that the open operation is complete with |
| 338 // WaitForIOCompletion(). See also the destructor. | 330 // WaitForIOCompletion(). See also the destructor. |
| 339 int* result = new int(OK); | 331 int* result = new int(OK); |
| 340 const bool posted = base::WorkerPool::PostTaskAndReply( | 332 const bool posted = base::WorkerPool::PostTaskAndReply( |
| 341 FROM_HERE, | 333 FROM_HERE, |
| 342 base::Bind(&OpenFileAndSignal, | 334 base::Bind(&InvokeAndSignal, |
| 343 path, open_flags, record_uma_, &file_, result, | 335 base::Bind(&OpenFile, path, open_flags, record_uma_, &file_, |
| 344 on_io_complete_.get(), bound_net_log_), | 336 result, bound_net_log_), |
| 337 on_io_complete_.get()), |
| 345 base::Bind(&FileStreamWin::OnOpened, | 338 base::Bind(&FileStreamWin::OnOpened, |
| 346 weak_ptr_factory_.GetWeakPtr(), | 339 weak_ptr_factory_.GetWeakPtr(), |
| 347 base::Owned(result)), | 340 callback, base::Owned(result)), |
| 348 true /* task_is_slow */); | 341 true /* task_is_slow */); |
| 349 DCHECK(posted); | 342 DCHECK(posted); |
| 350 return ERR_IO_PENDING; | 343 return ERR_IO_PENDING; |
| 351 } | 344 } |
| 352 | 345 |
| 353 int FileStreamWin::OpenSync(const FilePath& path, int open_flags) { | 346 int FileStreamWin::OpenSync(const FilePath& path, int open_flags) { |
| 354 if (IsOpen()) { | 347 if (IsOpen()) { |
| 355 DLOG(FATAL) << "File is already open!"; | 348 DLOG(FATAL) << "File is already open!"; |
| 356 return ERR_UNEXPECTED; | 349 return ERR_UNEXPECTED; |
| 357 } | 350 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 373 async_context_.get()); | 366 async_context_.get()); |
| 374 } | 367 } |
| 375 | 368 |
| 376 return OK; | 369 return OK; |
| 377 } | 370 } |
| 378 | 371 |
| 379 bool FileStreamWin::IsOpen() const { | 372 bool FileStreamWin::IsOpen() const { |
| 380 return file_ != base::kInvalidPlatformFileValue; | 373 return file_ != base::kInvalidPlatformFileValue; |
| 381 } | 374 } |
| 382 | 375 |
| 383 int64 FileStreamWin::Seek(Whence whence, int64 offset) { | 376 int FileStreamWin::Seek(Whence whence, int64 offset, |
| 377 const Int64CompletionCallback& callback) { |
| 378 if (!IsOpen()) |
| 379 return ERR_UNEXPECTED; |
| 380 |
| 381 // Make sure we're async and we have no other in-flight async operations. |
| 382 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); |
| 383 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); |
| 384 DCHECK(!on_io_complete_.get()); |
| 385 |
| 386 int64* result = new int64(-1); |
| 387 on_io_complete_.reset(new base::WaitableEvent( |
| 388 false /* manual_reset */, false /* initially_signaled */)); |
| 389 |
| 390 const bool posted = base::WorkerPool::PostTaskAndReply( |
| 391 FROM_HERE, |
| 392 base::Bind(&InvokeAndSignal, |
| 393 // Unretained should be fine as we wait for a signal on |
| 394 // on_io_complete_ at the destructor. |
| 395 base::Bind(&FileStreamWin::SeekFile, base::Unretained(this), |
| 396 whence, offset, result), |
| 397 on_io_complete_.get()), |
| 398 base::Bind(&FileStreamWin::OnSeeked, |
| 399 weak_ptr_factory_.GetWeakPtr(), |
| 400 callback, base::Owned(result)), |
| 401 true /* task is slow */); |
| 402 DCHECK(posted); |
| 403 return ERR_IO_PENDING; |
| 404 } |
| 405 |
| 406 int64 FileStreamWin::SeekSync(Whence whence, int64 offset) { |
| 384 if (!IsOpen()) | 407 if (!IsOpen()) |
| 385 return ERR_UNEXPECTED; | 408 return ERR_UNEXPECTED; |
| 386 | 409 |
| 387 DCHECK(!async_context_.get() || async_context_->callback().is_null()); | 410 DCHECK(!async_context_.get() || async_context_->callback().is_null()); |
| 388 | 411 int64 result = -1; |
| 389 LARGE_INTEGER distance, result; | 412 SeekFile(whence, offset, &result); |
| 390 distance.QuadPart = offset; | 413 return result; |
| 391 DWORD move_method = static_cast<DWORD>(whence); | |
| 392 if (!SetFilePointerEx(file_, distance, &result, move_method)) { | |
| 393 DWORD error = GetLastError(); | |
| 394 LOG(WARNING) << "SetFilePointerEx failed: " << error; | |
| 395 return RecordAndMapError(error, | |
| 396 FILE_ERROR_SOURCE_SEEK, | |
| 397 record_uma_, | |
| 398 bound_net_log_); | |
| 399 } | |
| 400 if (async_context_.get()) { | |
| 401 async_context_->set_error_source(FILE_ERROR_SOURCE_SEEK); | |
| 402 SetOffset(async_context_->overlapped(), result); | |
| 403 } | |
| 404 return result.QuadPart; | |
| 405 } | 414 } |
| 406 | 415 |
| 407 int64 FileStreamWin::Available() { | 416 int64 FileStreamWin::Available() { |
| 408 base::ThreadRestrictions::AssertIOAllowed(); | 417 base::ThreadRestrictions::AssertIOAllowed(); |
| 409 | 418 |
| 410 if (!IsOpen()) | 419 if (!IsOpen()) |
| 411 return ERR_UNEXPECTED; | 420 return ERR_UNEXPECTED; |
| 412 | 421 |
| 413 int64 cur_pos = Seek(FROM_CURRENT, 0); | 422 int64 cur_pos = SeekSync(FROM_CURRENT, 0); |
| 414 if (cur_pos < 0) | 423 if (cur_pos < 0) |
| 415 return cur_pos; | 424 return cur_pos; |
| 416 | 425 |
| 417 LARGE_INTEGER file_size; | 426 LARGE_INTEGER file_size; |
| 418 if (!GetFileSizeEx(file_, &file_size)) { | 427 if (!GetFileSizeEx(file_, &file_size)) { |
| 419 DWORD error = GetLastError(); | 428 DWORD error = GetLastError(); |
| 420 LOG(WARNING) << "GetFileSizeEx failed: " << error; | 429 LOG(WARNING) << "GetFileSizeEx failed: " << error; |
| 421 return RecordAndMapError(error, | 430 return RecordAndMapError(error, |
| 422 FILE_ERROR_SOURCE_GET_SIZE, | 431 FILE_ERROR_SOURCE_GET_SIZE, |
| 423 record_uma_, | 432 record_uma_, |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 int64 FileStreamWin::Truncate(int64 bytes) { | 610 int64 FileStreamWin::Truncate(int64 bytes) { |
| 602 base::ThreadRestrictions::AssertIOAllowed(); | 611 base::ThreadRestrictions::AssertIOAllowed(); |
| 603 | 612 |
| 604 if (!IsOpen()) | 613 if (!IsOpen()) |
| 605 return ERR_UNEXPECTED; | 614 return ERR_UNEXPECTED; |
| 606 | 615 |
| 607 // We'd better be open for writing. | 616 // We'd better be open for writing. |
| 608 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 617 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 609 | 618 |
| 610 // Seek to the position to truncate from. | 619 // Seek to the position to truncate from. |
| 611 int64 seek_position = Seek(FROM_BEGIN, bytes); | 620 int64 seek_position = SeekSync(FROM_BEGIN, bytes); |
| 612 if (seek_position != bytes) | 621 if (seek_position != bytes) |
| 613 return ERR_UNEXPECTED; | 622 return ERR_UNEXPECTED; |
| 614 | 623 |
| 615 // And truncate the file. | 624 // And truncate the file. |
| 616 BOOL result = SetEndOfFile(file_); | 625 BOOL result = SetEndOfFile(file_); |
| 617 if (!result) { | 626 if (!result) { |
| 618 DWORD error = GetLastError(); | 627 DWORD error = GetLastError(); |
| 619 LOG(WARNING) << "SetEndOfFile failed: " << error; | 628 LOG(WARNING) << "SetEndOfFile failed: " << error; |
| 620 return RecordAndMapError(error, | 629 return RecordAndMapError(error, |
| 621 FILE_ERROR_SOURCE_SET_EOF, | 630 FILE_ERROR_SOURCE_SET_EOF, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 net::NetLog::TYPE_FILE_STREAM_SOURCE, | 664 net::NetLog::TYPE_FILE_STREAM_SOURCE, |
| 656 make_scoped_refptr( | 665 make_scoped_refptr( |
| 657 new net::NetLogSourceParameter("source_dependency", | 666 new net::NetLogSourceParameter("source_dependency", |
| 658 bound_net_log_.source()))); | 667 bound_net_log_.source()))); |
| 659 } | 668 } |
| 660 | 669 |
| 661 base::PlatformFile FileStreamWin::GetPlatformFileForTesting() { | 670 base::PlatformFile FileStreamWin::GetPlatformFileForTesting() { |
| 662 return file_; | 671 return file_; |
| 663 } | 672 } |
| 664 | 673 |
| 665 void FileStreamWin::OnClosed() { | 674 void FileStreamWin::OnClosed(const CompletionCallback& callback) { |
| 666 file_ = base::kInvalidPlatformFileValue; | 675 file_ = base::kInvalidPlatformFileValue; |
| 667 | 676 |
| 668 CompletionCallback temp = callback_; | 677 // Reset this before Run() as Run() may issue a new async operation. |
| 669 callback_.Reset(); | 678 ResetOnIOComplete(); |
| 670 | 679 callback.Run(OK); |
| 671 // Reset this before Run(). Run() should not issue a new async operation | |
| 672 // here, but just to keep it consistent with OnOpened(). | |
| 673 on_io_complete_.reset(); | |
| 674 temp.Run(OK); | |
| 675 } | 680 } |
| 676 | 681 |
| 677 void FileStreamWin::OnOpened(int* result) { | 682 void FileStreamWin::SeekFile(Whence whence, int64 offset, int64* result) { |
| 683 LARGE_INTEGER distance, res; |
| 684 distance.QuadPart = offset; |
| 685 DWORD move_method = static_cast<DWORD>(whence); |
| 686 if (!SetFilePointerEx(file_, distance, &res, move_method)) { |
| 687 DWORD error = GetLastError(); |
| 688 LOG(WARNING) << "SetFilePointerEx failed: " << error; |
| 689 *result = RecordAndMapError(error, |
| 690 FILE_ERROR_SOURCE_SEEK, |
| 691 record_uma_, |
| 692 bound_net_log_); |
| 693 return; |
| 694 } |
| 695 if (async_context_.get()) { |
| 696 async_context_->set_error_source(FILE_ERROR_SOURCE_SEEK); |
| 697 SetOffset(async_context_->overlapped(), res); |
| 698 } |
| 699 *result = res.QuadPart; |
| 700 } |
| 701 |
| 702 void FileStreamWin::OnOpened(const CompletionCallback& callback, int* result) { |
| 678 if (*result == OK) { | 703 if (*result == OK) { |
| 679 async_context_.reset(new AsyncContext(bound_net_log_)); | 704 async_context_.reset(new AsyncContext(bound_net_log_)); |
| 680 if (record_uma_) | 705 if (record_uma_) |
| 681 async_context_->EnableErrorStatistics(); | 706 async_context_->EnableErrorStatistics(); |
| 682 MessageLoopForIO::current()->RegisterIOHandler(file_, | 707 MessageLoopForIO::current()->RegisterIOHandler(file_, |
| 683 async_context_.get()); | 708 async_context_.get()); |
| 684 } | 709 } |
| 685 | 710 |
| 686 CompletionCallback temp = callback_; | 711 // Reset this before Run() as Run() may issue a new async operation. |
| 687 callback_.Reset(); | 712 ResetOnIOComplete(); |
| 713 callback.Run(*result); |
| 714 } |
| 688 | 715 |
| 716 void FileStreamWin::OnSeeked( |
| 717 const Int64CompletionCallback& callback, |
| 718 int64* result) { |
| 689 // Reset this before Run() as Run() may issue a new async operation. | 719 // Reset this before Run() as Run() may issue a new async operation. |
| 720 ResetOnIOComplete(); |
| 721 callback.Run(*result); |
| 722 } |
| 723 |
| 724 void FileStreamWin::ResetOnIOComplete() { |
| 690 on_io_complete_.reset(); | 725 on_io_complete_.reset(); |
| 691 temp.Run(*result); | 726 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 692 } | 727 } |
| 693 | 728 |
| 694 void FileStreamWin::WaitForIOCompletion() { | 729 void FileStreamWin::WaitForIOCompletion() { |
| 695 if (on_io_complete_.get()) { | 730 if (on_io_complete_.get()) { |
| 696 on_io_complete_->Wait(); | 731 on_io_complete_->Wait(); |
| 697 on_io_complete_.reset(); | 732 on_io_complete_.reset(); |
| 698 } | 733 } |
| 699 } | 734 } |
| 700 | 735 |
| 701 } // namespace net | 736 } // namespace net |
| OLD | NEW |