Chromium Code Reviews| Index: chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc |
| diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc |
| index b15314a4ccec694c6f3b5a39965a491b41e2a2b3..84a1288c35c852b080517b41d4cea9cdd94aba83 100644 |
| --- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc |
| +++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc |
| @@ -30,50 +30,48 @@ void Int64ToIntCompletionCallback(net::CompletionCallback callback, |
| callback.Run(static_cast<int>(result)); |
| } |
| -// Opens a file for reading and calls the completion callback. Must be called |
| -// on UI thread. |
| -void OpenFileOnUIThread( |
| - const fileapi::FileSystemURL& url, |
| - const FileStreamReader::OpenFileCompletedCallback& callback) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| +} // namespace |
| - util::FileSystemURLParser parser(url); |
| - if (!parser.Parse()) { |
| - callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(), |
| - base::FilePath(), |
| - 0 /* file_handle */, |
| - base::File::FILE_ERROR_SECURITY); |
| - return; |
| +class FileStreamReader::OperationRunner |
| + : public base::RefCountedThreadSafe<FileStreamReader::OperationRunner> { |
| + public: |
| + OperationRunner() : file_handle_(-1) {} |
| + |
| + // Opens a file for reading and calls the completion callback. Must be called |
| + // on UI thread. |
| + void OpenFileOnUIThread( |
| + const fileapi::FileSystemURL& url, |
| + const fileapi::AsyncFileUtil::StatusCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + util::FileSystemURLParser parser(url); |
| + if (!parser.Parse()) { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(callback, base::File::FILE_ERROR_SECURITY)); |
| + return; |
| + } |
| + |
| + file_system_ = parser.file_system()->GetWeakPtr(); |
| + file_path_ = parser.file_path(); |
| + abort_callback_ = parser.file_system()->OpenFile( |
| + file_path_, |
| + ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, |
| + base::Bind( |
| + &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback)); |
| } |
| - parser.file_system()->OpenFile( |
| - parser.file_path(), |
| - ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, |
| - base::Bind( |
| - callback, parser.file_system()->GetWeakPtr(), parser.file_path())); |
| -} |
| - |
| -// Forwards results of calling OpenFileOnUIThread back to the IO thread. |
| -void OnOpenFileCompletedOnUIThread( |
| - const FileStreamReader::OpenFileCompletedCallback& callback, |
| - base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| - const base::FilePath& file_path, |
| - int file_handle, |
| - base::File::Error result) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - BrowserThread::PostTask( |
| - BrowserThread::IO, |
| - FROM_HERE, |
| - base::Bind(callback, file_system, file_path, file_handle, result)); |
| -} |
| - |
| // Closes a file. Ignores result, since it is called from a constructor. |
| // Must be called on UI thread. |
| -void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| - int file_handle) { |
| + void CloseFileOnUIThread() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
|
hirono
2014/08/22 05:43:47
The indent is wrong from here?
mtomasz
2014/08/22 06:09:50
Done.
|
| - if (file_system.get()) |
| - file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback)); |
| + if (file_system_.get() && file_handle_ != -1) { |
| + file_system_->CloseFile(file_handle_, base::Bind(&EmptyStatusCallback)); |
| + // Closing a file must not be aborted, since we could end up on files which |
| + // are never closed. |
| + abort_callback_ = ProvidedFileSystemInterface::AbortCallback(); |
| + } |
| } |
| // Requests reading contents of a file. In case of either success or a failure |
| @@ -81,8 +79,6 @@ void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| // to false. This function guarantees that it will succeed only if the file has |
| // not been changed while reading. Must be called on UI thread. |
| void ReadFileOnUIThread( |
| - base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| - int file_handle, |
| scoped_refptr<net::IOBuffer> buffer, |
| int64 offset, |
| int length, |
| @@ -90,56 +86,123 @@ void ReadFileOnUIThread( |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| // If the file system got unmounted, then abort the reading operation. |
| - if (!file_system.get()) { |
| - callback.Run(0, false /* has_more */, base::File::FILE_ERROR_ABORT); |
| + if (!file_system_.get()) { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind( |
| + callback, 0, false /* has_more */, base::File::FILE_ERROR_ABORT)); |
| return; |
| } |
| - file_system->ReadFile(file_handle, buffer, offset, length, callback); |
| -} |
| - |
| -// Forward the completion callback to IO thread. |
| -void OnReadChunkReceivedOnUIThread( |
| - const ProvidedFileSystemInterface::ReadChunkReceivedCallback& |
| - chunk_received_callback, |
| - int chunk_length, |
| - bool has_more, |
| - base::File::Error result) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - BrowserThread::PostTask( |
| - BrowserThread::IO, |
| - FROM_HERE, |
| - base::Bind(chunk_received_callback, chunk_length, has_more, result)); |
| + abort_callback_ = file_system_->ReadFile( |
| + file_handle_, |
| + buffer, |
| + offset, |
| + length, |
| + base::Bind( |
| + &OperationRunner::OnReadFileCompletedOnUIThread, this, callback)); |
| } |
| // Requests metadata of a file. In case of either succes or a failure, |
| // |callback is executed. Must be called on UI thread. |
| void GetMetadataOnUIThread( |
| - base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| - const base::FilePath& file_path, |
| const ProvidedFileSystemInterface::GetMetadataCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| // If the file system got unmounted, then abort the get length operation. |
| - if (!file_system.get()) { |
| - callback.Run(EntryMetadata(), base::File::FILE_ERROR_ABORT); |
| + if (!file_system_.get()) { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(callback, EntryMetadata(), base::File::FILE_ERROR_ABORT)); |
| return; |
| } |
| - file_system->GetMetadata(file_path, callback); |
| + abort_callback_ = file_system_->GetMetadata( |
| + file_path_, |
| + base::Bind( |
| + &OperationRunner::OnGetMetadataCompletedOnUIThread, this, callback)); |
| } |
| -// Forward the completion callback to IO thread. |
| -void OnGetMetadataReceivedOnUIThread( |
| - const ProvidedFileSystemInterface::GetMetadataCallback& callback, |
| - const EntryMetadata& metadata, |
| +// Aborts the most recent operation (if exists), and calls the callback. |
| +void AbortOnUIThread(const fileapi::AsyncFileUtil::StatusCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + if (abort_callback_.is_null()) { |
| + // No operation to be cancelled. At most a callback call, which will be |
| + // discarded. |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(callback, base::File::FILE_OK)); |
| + return; |
| + } |
| + |
| + const ProvidedFileSystemInterface::AbortCallback abort_callback = |
| + abort_callback_; |
| + abort_callback_ = ProvidedFileSystemInterface::AbortCallback(); |
| + abort_callback.Run( |
| + base::Bind(&OperationRunner::OnAbortCompletedOnUIThread, this, callback)); |
| +} |
| + |
| +private: |
| +friend class base::RefCountedThreadSafe<OperationRunner>; |
| + |
| +virtual ~OperationRunner() {} |
| + |
| +// Remembers a file handle for further operations and forwards the result to |
| +// the IO thread. |
| +void OnOpenFileCompletedOnUIThread( |
| + const fileapi::AsyncFileUtil::StatusCallback& callback, |
| + int file_handle, |
| base::File::Error result) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + file_handle_ = file_handle; |
| BrowserThread::PostTask( |
| - BrowserThread::IO, FROM_HERE, base::Bind(callback, metadata, result)); |
| -} |
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| + } |
| -} // namespace |
| + // Forwards a metadata to the IO thread. |
| + void OnGetMetadataCompletedOnUIThread( |
| + const ProvidedFileSystemInterface::GetMetadataCallback& callback, |
| + const EntryMetadata& metadata, |
| + base::File::Error result) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, metadata, result)); |
| + } |
| + |
| + // Forwards a response of reading from a file to the IO thread. |
| + void OnReadFileCompletedOnUIThread( |
| + const ProvidedFileSystemInterface::ReadChunkReceivedCallback& |
| + chunk_received_callback, |
| + int chunk_length, |
| + bool has_more, |
| + base::File::Error result) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(chunk_received_callback, chunk_length, has_more, result)); |
| + } |
| + |
| + // Forwards a response of aborting an operation to the IO thread. |
| + void OnAbortCompletedOnUIThread( |
| + const fileapi::AsyncFileUtil::StatusCallback& callback, |
| + base::File::Error result) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| + } |
| + |
| + ProvidedFileSystemInterface::AbortCallback abort_callback_; |
| + base::WeakPtr<ProvidedFileSystemInterface> file_system_; |
| + base::FilePath file_path_; |
| + int file_handle_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(OperationRunner); |
| +}; |
| FileStreamReader::FileStreamReader(fileapi::FileSystemContext* context, |
| const fileapi::FileSystemURL& url, |
| @@ -149,16 +212,24 @@ FileStreamReader::FileStreamReader(fileapi::FileSystemContext* context, |
| current_offset_(initial_offset), |
| current_length_(0), |
| expected_modification_time_(expected_modification_time), |
| + runner_(new OperationRunner), |
| state_(NOT_INITIALIZED), |
| - file_handle_(0), |
| weak_ptr_factory_(this) { |
| } |
| FileStreamReader::~FileStreamReader() { |
| + // FileStreamReader doesn't have a Cancel() method like in FileStreamWriter. |
| + // Therefore, aborting is done from the destructor. |
| + BrowserThread::PostTask(BrowserThread::UI, |
| + FROM_HERE, |
| + base::Bind(&OperationRunner::AbortOnUIThread, |
| + runner_, |
| + base::Bind(&EmptyStatusCallback))); |
| + |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| - base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); |
| + base::Bind(&OperationRunner::CloseFileOnUIThread, runner_)); |
| } |
| void FileStreamReader::Initialize( |
| @@ -170,21 +241,18 @@ void FileStreamReader::Initialize( |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| - base::Bind(&OpenFileOnUIThread, |
| + base::Bind(&OperationRunner::OpenFileOnUIThread, |
| + runner_, |
| url_, |
| - base::Bind(&OnOpenFileCompletedOnUIThread, |
| - base::Bind(&FileStreamReader::OnOpenFileCompleted, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - pending_closure, |
| - error_callback)))); |
| + base::Bind(&FileStreamReader::OnOpenFileCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + pending_closure, |
| + error_callback))); |
| } |
| void FileStreamReader::OnOpenFileCompleted( |
| const base::Closure& pending_closure, |
| const net::Int64CompletionCallback& error_callback, |
| - base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| - const base::FilePath& file_path, |
| - int file_handle, |
| base::File::Error result) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| DCHECK_EQ(INITIALIZING, state_); |
| @@ -197,23 +265,18 @@ void FileStreamReader::OnOpenFileCompleted( |
| return; |
| } |
| - file_system_ = file_system; |
| - file_path_ = file_path; |
| - file_handle_ = file_handle; |
| - DCHECK_LT(0, file_handle); |
| + DCHECK_EQ(base::File::FILE_OK, result); |
| // Verify the last modification time. |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| - base::Bind(&GetMetadataOnUIThread, |
| - file_system_, |
| - file_path_, |
| - base::Bind(&OnGetMetadataReceivedOnUIThread, |
| - base::Bind(&FileStreamReader::OnInitializeCompleted, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - pending_closure, |
| - error_callback)))); |
| + base::Bind(&OperationRunner::GetMetadataOnUIThread, |
| + runner_, |
| + base::Bind(&FileStreamReader::OnInitializeCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + pending_closure, |
| + error_callback))); |
| } |
| void FileStreamReader::OnInitializeCompleted( |
| @@ -341,16 +404,14 @@ void FileStreamReader::ReadAfterInitialized( |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| - base::Bind(&ReadFileOnUIThread, |
| - file_system_, |
| - file_handle_, |
| + base::Bind(&OperationRunner::ReadFileOnUIThread, |
| + runner_, |
| buffer, |
| current_offset_, |
| buffer_length, |
| - base::Bind(&OnReadChunkReceivedOnUIThread, |
| - base::Bind(&FileStreamReader::OnReadChunkReceived, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - callback)))); |
| + base::Bind(&FileStreamReader::OnReadChunkReceived, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback))); |
| } |
| void FileStreamReader::GetLengthAfterInitialized( |
| @@ -362,14 +423,11 @@ void FileStreamReader::GetLengthAfterInitialized( |
| BrowserThread::UI, |
| FROM_HERE, |
| base::Bind( |
| - &GetMetadataOnUIThread, |
| - file_system_, |
| - file_path_, |
| - base::Bind( |
| - &OnGetMetadataReceivedOnUIThread, |
| - base::Bind(&FileStreamReader::OnGetMetadataForGetLengthReceived, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - callback)))); |
| + &OperationRunner::GetMetadataOnUIThread, |
| + runner_, |
| + base::Bind(&FileStreamReader::OnGetMetadataForGetLengthReceived, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback))); |
| } |
| void FileStreamReader::OnReadChunkReceived( |