Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Unified Diff: chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc

Issue 288113004: [fsp] Add FileStreamReader for the reading operation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed tests. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
new file mode 100644
index 0000000000000000000000000000000000000000..c7a5aec20861d765f9c8827f83d2435e5719c61c
--- /dev/null
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc
@@ -0,0 +1,330 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h"
+
+#include "base/files/file.h"
+#include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
+#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_errors.h"
+
+using content::BrowserThread;
+
+namespace chromeos {
+namespace file_system_provider {
+namespace {
+
+// Dicards the callback from CloseFile().
+void EmptyStatusCallback(base::File::Error /* result */) {
+}
+
+// Converts net::CompletionCallback to net::Int64CompletionCallback.
+void Int64ToIntCompletionCallback(net::CompletionCallback callback,
+ int64 result) {
+ 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::InitializeCompletedCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // TODO(mtomasz): Check if the modification time of the file is as expected.
+ util::FileSystemURLParser parser(url);
+ if (!parser.Parse()) {
+ callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(),
+ base::FilePath(),
+ 0 /* file_handle */,
+ base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ parser.file_system()->OpenFile(
+ parser.file_path(),
+ ProvidedFileSystemInterface::OPEN_FILE_MODE_READ,
+ false /* create */,
+ base::Bind(
+ callback, parser.file_system()->GetWeakPtr(), parser.file_path()));
+}
+
+// Forwards results of calling OpenFileOnUIThread back to the IO thread.
+void OnOpenFileCompletedOnUIThread(
+ const FileStreamReader::InitializeCompletedCallback& 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) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (file_system.get())
+ file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback));
+}
+
+// Requests reading contents of a file. In case of either success or a failure
+// |callback| is executed. It can be called many times, until |has_next| is set
+// 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,
+ net::IOBuffer* buffer,
+ int64 offset,
+ int length,
+ const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback) {
+ 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_next */, 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_next,
+ base::File::Error result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(chunk_received_callback, chunk_length, has_next, result));
+}
+
+// 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 fileapi::AsyncFileUtil::GetFileInfoCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // If the file system got unmounted, then abort the get length operation.
+ if (!file_system.get()) {
+ callback.Run(base::File::FILE_ERROR_ABORT, base::File::Info());
+ return;
+ }
+
+ file_system->GetMetadata(file_path, callback);
+}
+
+// Forward the completion callback to IO thread.
+void OnGetMetadataReceivedOnUIThread(
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback,
+ base::File::Error result,
+ const base::File::Info& file_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE, base::Bind(callback, result, file_info));
+}
+
+} // namespace
+
+FileStreamReader::FileStreamReader(fileapi::FileSystemContext* context,
+ const fileapi::FileSystemURL& url,
+ int64 initial_offset,
+ const base::Time& expected_modification_time)
+ : url_(url),
+ current_offset_(initial_offset),
+ current_length_(0),
+ expected_modification_time_(expected_modification_time),
+ file_handle_(0),
+ weak_ptr_factory_(this) {
+}
+
+FileStreamReader::~FileStreamReader() {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&CloseFileOnUIThread, file_system_, file_handle_));
+}
+
+void FileStreamReader::Initialize(
+ const base::Closure& pending_closure,
+ const net::Int64CompletionCallback& error_callback) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&OpenFileOnUIThread,
+ url_,
+ base::Bind(&OnOpenFileCompletedOnUIThread,
+ base::Bind(&FileStreamReader::OnInitializeCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ pending_closure,
+ error_callback))));
+}
+
+void FileStreamReader::OnInitializeCompleted(
+ 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);
+
+ // In case of an error, return immediately using the |error_callback| of the
+ // Read() or GetLength() pending request.
+ if (result != base::File::FILE_OK) {
+ error_callback.Run(net::FileErrorToNetError(result));
+ return;
+ }
+
+ file_system_ = file_system;
+ file_path_ = file_path;
+ file_handle_ = file_handle;
+ DCHECK_LT(0, file_handle);
+
+ // Run the task waiting for the initialization to be completed.
+ pending_closure.Run();
+}
+
+int FileStreamReader::Read(net::IOBuffer* buffer,
+ int buffer_length,
+ const net::CompletionCallback& callback) {
+ // Lazily initialize with the first call to Read().
+ if (!file_handle_) {
+ Initialize(base::Bind(&FileStreamReader::ReadAfterInitialized,
+ weak_ptr_factory_.GetWeakPtr(),
+ buffer,
+ buffer_length,
+ callback),
+ base::Bind(&Int64ToIntCompletionCallback, callback));
+ return net::ERR_IO_PENDING;
+ }
+
+ ReadAfterInitialized(buffer, buffer_length, callback);
+ return net::ERR_IO_PENDING;
+}
+
+int64 FileStreamReader::GetLength(
+ const net::Int64CompletionCallback& callback) {
+ // Lazily initialize with the first call to GetLength().
+ if (!file_handle_) {
+ Initialize(base::Bind(&FileStreamReader::GetLengthAfterInitialized,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ callback);
+ return net::ERR_IO_PENDING;
+ }
+
+ GetLengthAfterInitialized(callback);
+ return net::ERR_IO_PENDING;
+}
+
+void FileStreamReader::ReadAfterInitialized(
+ net::IOBuffer* buffer,
+ int buffer_length,
+ const net::CompletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // If the file system got unmounted, then abort the reading operation.
+ if (!file_handle_) {
+ callback.Run(net::ERR_ABORTED);
+ return;
+ }
+
+ current_length_ = 0;
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ReadFileOnUIThread,
+ file_system_,
+ file_handle_,
+ buffer,
+ current_offset_,
+ buffer_length,
+ base::Bind(&OnReadChunkReceivedOnUIThread,
+ base::Bind(&FileStreamReader::OnReadChunkReceived,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback))));
+}
+
+void FileStreamReader::GetLengthAfterInitialized(
+ const net::Int64CompletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // If the file system got unmounted, then abort the length fetching operation.
+ if (!file_handle_) {
+ callback.Run(net::ERR_ABORTED);
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &GetMetadataOnUIThread,
+ file_system_,
+ file_path_,
+ base::Bind(
+ &OnGetMetadataReceivedOnUIThread,
+ base::Bind(&FileStreamReader::OnGetMetadataForGetLengthReceived,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback))));
+}
+
+void FileStreamReader::OnReadChunkReceived(
+ const net::CompletionCallback& callback,
+ int chunk_length,
+ bool has_next,
+ base::File::Error result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ current_length_ += chunk_length;
+
+ // If this is the last chunk with a success, then finalize.
+ if (!has_next && result == base::File::FILE_OK) {
+ current_offset_ += current_length_;
+ callback.Run(current_length_);
+ return;
+ }
+
+ // In case of an error, abort.
+ if (result != base::File::FILE_OK) {
+ DCHECK(!has_next);
+ callback.Run(net::FileErrorToNetError(result));
+ return;
+ }
+
+ // More data is about to come, so do not call the callback yet.
+ DCHECK(has_next);
+}
+
+void FileStreamReader::OnGetMetadataForGetLengthReceived(
+ const net::Int64CompletionCallback& callback,
+ base::File::Error result,
+ const base::File::Info& file_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // In case of an error, abort.
+ if (result != base::File::FILE_OK) {
+ callback.Run(net::FileErrorToNetError(result));
+ return;
+ }
+
+ DCHECK_EQ(result, base::File::FILE_OK);
+ callback.Run(file_info.size);
+}
+
+} // namespace file_system_provider
+} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698