diff options
17 files changed, 655 insertions, 14 deletions
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc index 9bb2312..c615cae 100644 --- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc +++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc @@ -189,4 +189,25 @@ bool FileSystemProviderInternalCloseFileRequestedErrorFunction::RunWhenValid() { return true; } +bool +FileSystemProviderInternalReadFileRequestedSuccessFunction::RunWhenValid() { + using api::file_system_provider_internal::ReadFileRequestedSuccess::Params; + scoped_ptr<Params> params(Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + const bool has_next = params->has_next; + FulfillRequest(RequestValue::CreateForReadFileSuccess(params.Pass()), + has_next); + return true; +} + +bool FileSystemProviderInternalReadFileRequestedErrorFunction::RunWhenValid() { + using api::file_system_provider_internal::ReadFileRequestedError::Params; + const scoped_ptr<Params> params(Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + RejectRequest(ProviderErrorToFileError(params->error)); + return true; +} + } // namespace extensions diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h index d91b79e..c4c94fd 100644 --- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h +++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h @@ -150,6 +150,30 @@ class FileSystemProviderInternalCloseFileRequestedErrorFunction virtual bool RunWhenValid() OVERRIDE; }; +class FileSystemProviderInternalReadFileRequestedSuccessFunction + : public FileSystemProviderInternalFunction { + public: + DECLARE_EXTENSION_FUNCTION( + "fileSystemProviderInternal.readFileRequestedSuccess", + FILESYSTEMPROVIDERINTERNAL_READFILEREQUESTEDSUCCESS) + + protected: + virtual ~FileSystemProviderInternalReadFileRequestedSuccessFunction() {} + virtual bool RunWhenValid() OVERRIDE; +}; + +class FileSystemProviderInternalReadFileRequestedErrorFunction + : public FileSystemProviderInternalFunction { + public: + DECLARE_EXTENSION_FUNCTION( + "fileSystemProviderInternal.readFileRequestedError", + FILESYSTEMPROVIDERINTERNAL_READFILEREQUESTEDERROR) + + protected: + virtual ~FileSystemProviderInternalReadFileRequestedErrorFunction() {} + virtual bool RunWhenValid() OVERRIDE; +}; + } // namespace extensions #endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_SYSTEM_PROVIDER_FILE_SYSTEM_PROVIDER_API_H_ diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc index 1d297cd..f8fd16e 100644 --- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc +++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc @@ -9,6 +9,7 @@ #include "base/files/file.h" #include "base/message_loop/message_loop_proxy.h" #include "extensions/browser/event_router.h" +#include "net/base/io_buffer.h" namespace chromeos { namespace file_system_provider { @@ -129,6 +130,7 @@ void FakeProvidedFileSystem::OpenFile(const base::FilePath& file_path, } const int file_handle = ++last_file_handle_; + opened_files_.insert(file_handle); callback.Run(file_handle, base::File::FILE_OK); } @@ -138,12 +140,29 @@ void FakeProvidedFileSystem::CloseFile( const std::set<int>::iterator opened_file_it = opened_files_.find(file_handle); if (opened_file_it == opened_files_.end()) { - callback.Run(base::File::FILE_ERROR_NOT_FOUND); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND)); return; } opened_files_.erase(opened_file_it); - callback.Run(base::File::FILE_OK); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(callback, base::File::FILE_OK)); +} + +void FakeProvidedFileSystem::ReadFile( + int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback) { + // TODO(mtomasz): Implement together with the FileStreamReader. + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, + base::Bind(callback, + 0 /* chunk_length */, + false /* has_next */, + base::File::FILE_ERROR_SECURITY)); } const ProvidedFileSystemInfo& FakeProvidedFileSystem::GetFileSystemInfo() diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h index be83e63..3401dc0 100644 --- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h +++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h @@ -10,6 +10,10 @@ #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" +namespace net { +class IOBuffer; +} // namespace net + namespace extensions { class EventRouter; } // namespace extensions @@ -43,6 +47,11 @@ class FakeProvidedFileSystem : public ProvidedFileSystemInterface { virtual void CloseFile( int file_handle, const fileapi::AsyncFileUtil::StatusCallback& callback) OVERRIDE; + virtual void ReadFile(int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ReadChunkReceivedCallback& callback) OVERRIDE; virtual const ProvidedFileSystemInfo& GetFileSystemInfo() const OVERRIDE; virtual RequestManager* GetRequestManager() OVERRIDE; diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_file.cc b/chrome/browser/chromeos/file_system_provider/operations/read_file.cc new file mode 100644 index 0000000..55ba7b0 --- /dev/null +++ b/chrome/browser/chromeos/file_system_provider/operations/read_file.cc @@ -0,0 +1,93 @@ +// 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/operations/read_file.h" + +#include <limits> +#include <string> + +#include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_internal.h" + +namespace chromeos { +namespace file_system_provider { +namespace operations { +namespace { + +// Convert |value| into |output|. If parsing fails, then returns a negative +// value. Otherwise returns number of bytes written to the buffer. +int CopyRequestValueToBuffer(scoped_ptr<RequestValue> value, + net::IOBuffer* buffer, + int buffer_offset, + int buffer_length) { + using extensions::api::file_system_provider_internal:: + ReadFileRequestedSuccess::Params; + + const Params* params = value->read_file_success_params(); + if (!params) + return -1; + + const size_t chunk_size = params->data.length(); + + // Check for overflows. + if (chunk_size > static_cast<size_t>(buffer_length) - buffer_offset) + return -1; + + memcpy(buffer->data() + buffer_offset, params->data.c_str(), chunk_size); + + return chunk_size; +} + +} // namespace + +ReadFile::ReadFile( + extensions::EventRouter* event_router, + const ProvidedFileSystemInfo& file_system_info, + int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback) + : Operation(event_router, file_system_info), + file_handle_(file_handle), + buffer_(buffer), + offset_(offset), + length_(length), + current_offset_(offset), + callback_(callback) { +} + +ReadFile::~ReadFile() { +} + +bool ReadFile::Execute(int request_id) { + scoped_ptr<base::ListValue> values(new base::ListValue); + values->AppendInteger(file_handle_); + values->AppendDouble(offset_); + values->AppendInteger(length_); + return SendEvent( + request_id, + extensions::api::file_system_provider::OnReadFileRequested::kEventName, + values.Pass()); +} + +void ReadFile::OnSuccess(int /* request_id */, + scoped_ptr<RequestValue> result, + bool has_next) { + const int copy_result = CopyRequestValueToBuffer( + result.Pass(), buffer_, current_offset_, length_); + DCHECK_LE(0, copy_result); + DCHECK(!has_next || copy_result > 0); + if (copy_result > 0) + current_offset_ += copy_result; + callback_.Run(copy_result, has_next, base::File::FILE_OK); +} + +void ReadFile::OnError(int /* request_id */, base::File::Error error) { + callback_.Run(0 /* chunk_length */, false /* has_next */, error); +} + +} // namespace operations +} // namespace file_system_provider +} // namespace chromeos diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_file.h b/chrome/browser/chromeos/file_system_provider/operations/read_file.h new file mode 100644 index 0000000..f3cccae --- /dev/null +++ b/chrome/browser/chromeos/file_system_provider/operations/read_file.h @@ -0,0 +1,65 @@ +// 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. + +#ifndef CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_OPERATIONS_READ_FILE_H_ +#define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_OPERATIONS_READ_FILE_H_ + +#include "base/files/file.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/chromeos/file_system_provider/operations/operation.h" +#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" +#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" +#include "chrome/browser/chromeos/file_system_provider/request_value.h" +#include "net/base/io_buffer.h" +#include "webkit/browser/fileapi/async_file_util.h" + +namespace base { +class FilePath; +} // namespace base + +namespace extensions { +class EventRouter; +} // namespace extensions + +namespace chromeos { +namespace file_system_provider { +namespace operations { + +// Bridge between fileapi read file and providing extension's read fil request. +// Created per request. +class ReadFile : public Operation { + public: + ReadFile( + extensions::EventRouter* event_router, + const ProvidedFileSystemInfo& file_system_info, + int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback); + virtual ~ReadFile(); + + // Operation overrides. + virtual bool Execute(int request_id) OVERRIDE; + virtual void OnSuccess(int request_id, + scoped_ptr<RequestValue> result, + bool has_next) OVERRIDE; + virtual void OnError(int request_id, base::File::Error error) OVERRIDE; + + private: + int file_handle_; + net::IOBuffer* buffer_; + int64 offset_; + int length_; + int64 current_offset_; + const ProvidedFileSystemInterface::ReadChunkReceivedCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(ReadFile); +}; + +} // namespace operations +} // namespace file_system_provider +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_OPERATIONS_READ_FILE_H_ diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc new file mode 100644 index 0000000..3f39e4a --- /dev/null +++ b/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc @@ -0,0 +1,272 @@ +// 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 <string> + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/json/json_reader.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "chrome/browser/chromeos/file_system_provider/operations/read_file.h" +#include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_internal.h" +#include "extensions/browser/event_router.h" +#include "net/base/io_buffer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/async_file_util.h" + +namespace chromeos { +namespace file_system_provider { +namespace operations { +namespace { + +const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj"; +const int kFileSystemId = 1; +const int kRequestId = 2; +const int kFileHandle = 3; +const int kOffset = 10; +const int kLength = 5; + +// Fake event dispatcher implementation with extra logging capability. Acts as +// a providing extension end-point. +class LoggingDispatchEventImpl { + public: + explicit LoggingDispatchEventImpl(bool dispatch_reply) + : dispatch_reply_(dispatch_reply) {} + virtual ~LoggingDispatchEventImpl() {} + + bool OnDispatchEventImpl(scoped_ptr<extensions::Event> event) { + events_.push_back(event->DeepCopy()); + return dispatch_reply_; + } + + ScopedVector<extensions::Event>& events() { return events_; } + + private: + ScopedVector<extensions::Event> events_; + bool dispatch_reply_; + + DISALLOW_COPY_AND_ASSIGN(LoggingDispatchEventImpl); +}; + +// Callback invocation logger. Acts as a fileapi end-point. +class CallbackLogger { + public: + class Event { + public: + Event(int chunk_length, bool has_next, base::File::Error result) + : chunk_length_(chunk_length), has_next_(has_next), result_(result) {} + virtual ~Event() {} + + int chunk_length() const { return chunk_length_; } + bool has_next() const { return has_next_; } + base::File::Error result() const { return result_; } + + private: + int chunk_length_; + bool has_next_; + base::File::Error result_; + + DISALLOW_COPY_AND_ASSIGN(Event); + }; + + CallbackLogger() : weak_ptr_factory_(this) {} + virtual ~CallbackLogger() {} + + void OnReadFile(int chunk_length, bool has_next, base::File::Error result) { + events_.push_back(new Event(chunk_length, has_next, result)); + } + + ScopedVector<Event>& events() { return events_; } + + base::WeakPtr<CallbackLogger> GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + + private: + ScopedVector<Event> events_; + bool dispatch_reply_; + base::WeakPtrFactory<CallbackLogger> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CallbackLogger); +}; + +} // namespace + +class FileSystemProviderOperationsReadFileTest : public testing::Test { + protected: + FileSystemProviderOperationsReadFileTest() {} + virtual ~FileSystemProviderOperationsReadFileTest() {} + + virtual void SetUp() OVERRIDE { + file_system_info_ = + ProvidedFileSystemInfo(kExtensionId, + kFileSystemId, + "" /* file_system_name */, + base::FilePath() /* mount_path */); + io_buffer_ = make_scoped_refptr(new net::IOBuffer(kOffset + kLength)); + } + + ProvidedFileSystemInfo file_system_info_; + scoped_refptr<net::IOBuffer> io_buffer_; +}; + +TEST_F(FileSystemProviderOperationsReadFileTest, Execute) { + LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); + CallbackLogger callback_logger; + + ReadFile read_file( + NULL, + file_system_info_, + kFileHandle, + io_buffer_.get(), + kOffset, + kLength, + base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); + read_file.SetDispatchEventImplForTesting( + base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, + base::Unretained(&dispatcher))); + + EXPECT_TRUE(read_file.Execute(kRequestId)); + + ASSERT_EQ(1u, dispatcher.events().size()); + extensions::Event* event = dispatcher.events()[0]; + EXPECT_EQ( + extensions::api::file_system_provider::OnReadFileRequested::kEventName, + event->event_name); + base::ListValue* event_args = event->event_args.get(); + ASSERT_EQ(5u, event_args->GetSize()); + + int event_file_system_id = -1; + EXPECT_TRUE(event_args->GetInteger(0, &event_file_system_id)); + EXPECT_EQ(kFileSystemId, event_file_system_id); + + int event_request_id = -1; + EXPECT_TRUE(event_args->GetInteger(1, &event_request_id)); + EXPECT_EQ(kRequestId, event_request_id); + + int event_file_handle = -1; + EXPECT_TRUE(event_args->GetInteger(2, &event_file_handle)); + EXPECT_EQ(kFileHandle, event_file_handle); + + double event_offset = -1; + EXPECT_TRUE(event_args->GetDouble(3, &event_offset)); + EXPECT_EQ(kOffset, static_cast<double>(event_offset)); + + int event_length = -1; + EXPECT_TRUE(event_args->GetInteger(4, &event_length)); + EXPECT_EQ(kLength, event_length); +} + +TEST_F(FileSystemProviderOperationsReadFileTest, Execute_NoListener) { + LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */); + CallbackLogger callback_logger; + + ReadFile read_file( + NULL, + file_system_info_, + kFileHandle, + io_buffer_.get(), + kOffset, + kLength, + base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); + read_file.SetDispatchEventImplForTesting( + base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, + base::Unretained(&dispatcher))); + + EXPECT_FALSE(read_file.Execute(kRequestId)); +} + +TEST_F(FileSystemProviderOperationsReadFileTest, OnSuccess) { + using extensions::api::file_system_provider::EntryMetadata; + using extensions::api::file_system_provider_internal:: + ReadFileRequestedSuccess::Params; + + LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); + CallbackLogger callback_logger; + + ReadFile read_file( + NULL, + file_system_info_, + kFileHandle, + io_buffer_.get(), + kOffset, + kLength, + base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); + read_file.SetDispatchEventImplForTesting( + base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, + base::Unretained(&dispatcher))); + + EXPECT_TRUE(read_file.Execute(kRequestId)); + + // Sample input as JSON. Keep in sync with file_system_provider_api.idl. + // As for now, it is impossible to create *::Params class directly, not from + // base::Value. + const std::string input = + "[\n" + " 1,\n" // kFileSystemId + " 2,\n" // kRequestId + " \"ABCDE\",\n" // 5 bytes + " false\n" // has_next + "]\n"; + + int json_error_code; + std::string json_error_msg; + scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( + input, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg)); + ASSERT_TRUE(value.get()) << json_error_msg; + + base::ListValue* value_as_list; + ASSERT_TRUE(value->GetAsList(&value_as_list)); + scoped_ptr<Params> params(Params::Create(*value_as_list)); + ASSERT_TRUE(params.get()); + scoped_ptr<RequestValue> request_value( + RequestValue::CreateForReadFileSuccess(params.Pass())); + ASSERT_TRUE(request_value.get()); + + const bool has_next = false; + read_file.OnSuccess(kRequestId, request_value.Pass(), has_next); + + ASSERT_EQ(1u, callback_logger.events().size()); + CallbackLogger::Event* event = callback_logger.events()[0]; + EXPECT_EQ(kLength, event->chunk_length()); + EXPECT_FALSE(event->has_next()); + EXPECT_EQ("ABCDE", std::string(io_buffer_->data() + kOffset, kLength)); + EXPECT_EQ(base::File::FILE_OK, event->result()); +} + +TEST_F(FileSystemProviderOperationsReadFileTest, OnError) { + using extensions::api::file_system_provider::EntryMetadata; + using extensions::api::file_system_provider_internal::ReadFileRequestedError:: + Params; + + LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); + CallbackLogger callback_logger; + + ReadFile read_file( + NULL, + file_system_info_, + kFileHandle, + io_buffer_.get(), + kOffset, + kLength, + base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); + read_file.SetDispatchEventImplForTesting( + base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, + base::Unretained(&dispatcher))); + + EXPECT_TRUE(read_file.Execute(kRequestId)); + + read_file.OnError(kRequestId, base::File::FILE_ERROR_TOO_MANY_OPENED); + + ASSERT_EQ(1u, callback_logger.events().size()); + CallbackLogger::Event* event = callback_logger.events()[0]; + EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, event->result()); +} + +} // namespace operations +} // namespace file_system_provider +} // namespace chromeos diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc index 8e807ad..b619e4e 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc @@ -9,6 +9,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h" #include "chrome/browser/chromeos/file_system_provider/operations/open_file.h" #include "chrome/browser/chromeos/file_system_provider/operations/read_directory.h" +#include "chrome/browser/chromeos/file_system_provider/operations/read_file.h" #include "chrome/browser/chromeos/file_system_provider/operations/unmount.h" #include "chrome/browser/chromeos/file_system_provider/request_manager.h" #include "chrome/common/extensions/api/file_system_provider.h" @@ -16,9 +17,6 @@ namespace chromeos { namespace file_system_provider { -namespace { - -} // namespace ProvidedFileSystem::ProvidedFileSystem( extensions::EventRouter* event_router, @@ -60,6 +58,26 @@ void ProvidedFileSystem::ReadDirectory( } } +void ProvidedFileSystem::ReadFile(int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ReadChunkReceivedCallback& callback) { + if (!request_manager_.CreateRequest( + make_scoped_ptr<RequestManager::HandlerInterface>( + new operations::ReadFile(event_router_, + file_system_info_, + file_handle, + buffer, + offset, + length, + callback)))) { + callback.Run(0 /* chunk_length */, + false /* has_more */, + base::File::FILE_ERROR_SECURITY); + } +} + void ProvidedFileSystem::OpenFile(const base::FilePath& file_path, OpenFileMode mode, bool create, diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system.h b/chrome/browser/chromeos/file_system_provider/provided_file_system.h index 1d20f26..dffc73e 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system.h +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.h @@ -10,6 +10,10 @@ #include "chrome/browser/chromeos/file_system_provider/request_manager.h" #include "webkit/browser/fileapi/async_file_util.h" +namespace net { +class IOBuffer; +} // namespace net + namespace base { class FilePath; } // namespace base @@ -45,6 +49,11 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface { virtual void CloseFile( int file_handle, const fileapi::AsyncFileUtil::StatusCallback& callback) OVERRIDE; + virtual void ReadFile(int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ReadChunkReceivedCallback& callback) OVERRIDE; virtual const ProvidedFileSystemInfo& GetFileSystemInfo() const OVERRIDE; virtual RequestManager* GetRequestManager() OVERRIDE; diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h b/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h index 1da8059..b78b2a4 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h @@ -5,13 +5,16 @@ #ifndef CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_PROVIDED_FILE_SYSTEM_INTERFACE_H_ #define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_PROVIDED_FILE_SYSTEM_INTERFACE_H_ +#include "base/callback.h" +#include "base/files/file.h" +#include "base/files/file_path.h" #include "webkit/browser/fileapi/async_file_util.h" class EventRouter; -namespace base { -class FilePath; -} // namespace base +namespace net { +class IOBuffer; +} // namespace net namespace chromeos { namespace file_system_provider { @@ -27,6 +30,10 @@ class ProvidedFileSystemInterface { typedef base::Callback<void(int file_handle, base::File::Error result)> OpenFileCallback; + typedef base::Callback< + void(int chunk_length, bool has_next, base::File::Error result)> + ReadChunkReceivedCallback; + // Mode of opening a file. Used by OpenFile(). enum OpenFileMode { OPEN_FILE_MODE_READ, OPEN_FILE_MODE_WRITE }; @@ -44,8 +51,7 @@ class ProvidedFileSystemInterface { const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) = 0; // Requests enumerating entries from the passed |directory_path|. The callback - // can be called multiple times until either an error is returned or the - // has_more field is set to false. + // can be called multiple times until |has_more| is set to false. virtual void ReadDirectory( const base::FilePath& directory_path, const fileapi::AsyncFileUtil::ReadDirectoryCallback& callback) = 0; @@ -63,6 +69,16 @@ class ProvidedFileSystemInterface { int file_handle, const fileapi::AsyncFileUtil::StatusCallback& callback) = 0; + // Requests reading a file previously opened with |file_handle|. The callback + // can be called multiple times until |has_more| is set to false. On success + // it should return |length| bytes starting from |offset| in total. It can + // return less only in case EOF is encountered. + virtual void ReadFile(int file_handle, + net::IOBuffer* buffer, + int64 offset, + int length, + const ReadChunkReceivedCallback& callback) = 0; + // Returns a provided file system info for this file system. virtual const ProvidedFileSystemInfo& GetFileSystemInfo() const = 0; diff --git a/chrome/browser/chromeos/file_system_provider/request_value.cc b/chrome/browser/chromeos/file_system_provider/request_value.cc index ac85e66..53744d2 100644 --- a/chrome/browser/chromeos/file_system_provider/request_value.cc +++ b/chrome/browser/chromeos/file_system_provider/request_value.cc @@ -37,6 +37,14 @@ scoped_ptr<RequestValue> RequestValue::CreateForReadDirectorySuccess( return result.Pass(); } +scoped_ptr<RequestValue> RequestValue::CreateForReadFileSuccess( + scoped_ptr<extensions::api::file_system_provider_internal:: + ReadFileRequestedSuccess::Params> params) { + scoped_ptr<RequestValue> result(new RequestValue); + result->read_file_success_params_ = params.Pass(); + return result.Pass(); +} + scoped_ptr<RequestValue> RequestValue::CreateForTesting( const std::string& params) { scoped_ptr<RequestValue> result(new RequestValue); diff --git a/chrome/browser/chromeos/file_system_provider/request_value.h b/chrome/browser/chromeos/file_system_provider/request_value.h index 2519473..3920afb 100644 --- a/chrome/browser/chromeos/file_system_provider/request_value.h +++ b/chrome/browser/chromeos/file_system_provider/request_value.h @@ -31,10 +31,15 @@ class RequestValue { static scoped_ptr<RequestValue> CreateForGetMetadataSuccess( scoped_ptr<extensions::api::file_system_provider_internal:: GetMetadataRequestedSuccess::Params> params); + static scoped_ptr<RequestValue> CreateForReadDirectorySuccess( scoped_ptr<extensions::api::file_system_provider_internal:: ReadDirectoryRequestedSuccess::Params> params); + static scoped_ptr<RequestValue> CreateForReadFileSuccess( + scoped_ptr<extensions::api::file_system_provider_internal:: + ReadFileRequestedSuccess::Params> params); + static scoped_ptr<RequestValue> CreateForTesting(const std::string& params); const extensions::api::file_system_provider_internal:: @@ -55,6 +60,12 @@ class RequestValue { return read_directory_success_params_.get(); } + const extensions::api::file_system_provider_internal:: + ReadFileRequestedSuccess::Params* + read_file_success_params() const { + return read_file_success_params_.get(); + } + const std::string* testing_params() const { return testing_params_.get(); } private: @@ -66,6 +77,8 @@ class RequestValue { scoped_ptr<extensions::api::file_system_provider_internal:: ReadDirectoryRequestedSuccess::Params> read_directory_success_params_; + scoped_ptr<extensions::api::file_system_provider_internal:: + ReadFileRequestedSuccess::Params> read_file_success_params_; scoped_ptr<std::string> testing_params_; DISALLOW_COPY_AND_ASSIGN(RequestValue); diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 2177b06..f9aa402 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -391,6 +391,8 @@ 'browser/chromeos/file_system_provider/operations/operation.h', 'browser/chromeos/file_system_provider/operations/read_directory.cc', 'browser/chromeos/file_system_provider/operations/read_directory.h', + 'browser/chromeos/file_system_provider/operations/read_file.cc', + 'browser/chromeos/file_system_provider/operations/read_file.h', 'browser/chromeos/file_system_provider/operations/unmount.cc', 'browser/chromeos/file_system_provider/operations/unmount.h', 'browser/chromeos/file_system_provider/provided_file_system.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 892d5d8..c02925a 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -715,6 +715,7 @@ 'browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc', 'browser/chromeos/file_system_provider/operations/open_file_unittest.cc', 'browser/chromeos/file_system_provider/operations/read_directory_unittest.cc', + 'browser/chromeos/file_system_provider/operations/read_file_unittest.cc', 'browser/chromeos/file_system_provider/provided_file_system_unittest.cc', 'browser/chromeos/file_system_provider/request_manager_unittest.cc', 'browser/chromeos/file_system_provider/service_unittest.cc', diff --git a/chrome/common/extensions/api/file_system_provider.idl b/chrome/common/extensions/api/file_system_provider.idl index cadaccb..8b02cff 100644 --- a/chrome/common/extensions/api/file_system_provider.idl +++ b/chrome/common/extensions/api/file_system_provider.idl @@ -75,12 +75,18 @@ namespace fileSystemProvider { // Success callback for the <code>onGetMetadataRequested</code> event. callback MetadataCallback = void(EntryMetadata metadata); - // Success callback for the <code>onDirectoryRequested</code> event. If more - // entries will be returned, then <code>hasNext</code> must be true, and it - // has to be called again with additional entries. If no more entries are + // Success callback for the <code>onReadDirectoryRequested</code> event. If + // more entries will be returned, then <code>hasNext</code> must be true, and + // it has to be called again with additional entries. If no more entries are // available, then <code>hasNext</code> must be set to false. callback EntriesCallback = void(ResourceEntry[] entries, bool hasNext); + // Success callback for the <code>onReadFileRequested</code> event. If more + // data will be returned, then <code>hasNext</code> must be true, and it + // has to be called again with additional entries. If no more data is + // available, then <code>hasNext</code> must be set to false. + callback FileDataCallback = void(DOMString data, bool hasNext); + interface Functions { // Mounts a file system with the given <code>displayName</code>. // <code>displayName</code> will be shown in the left panel of @@ -152,6 +158,18 @@ namespace fileSystemProvider { long openRequestId, ProviderSuccessCallback successCallback, ProviderErrorCallback errorCallback); + + // Raised when contents of a file opened previously with <code>openRequestId + // </code>. The results should be returned in chunks by calling <code> + // successCallback</code> several times. In case of an error, <code> + // errorCallback</code> must be called. + [maxListeners=1] static void onReadFileRequested( + long fileSystemId, + long openRequestId, + double offset, + double length, + FileDataCallback successCallback, + ProviderErrorCallback errorCallback); }; }; diff --git a/chrome/common/extensions/api/file_system_provider_internal.idl b/chrome/common/extensions/api/file_system_provider_internal.idl index 582bc7d..f63cc0e 100644 --- a/chrome/common/extensions/api/file_system_provider_internal.idl +++ b/chrome/common/extensions/api/file_system_provider_internal.idl @@ -74,6 +74,21 @@ namespace fileSystemProviderInternal { long fileSystemId, long requestId, fileSystemProvider.ProviderError error); + + // Internal. Success callback of the <code>onReadFileRequested</code> + // event. Can be called multiple times per request. + static void readFileRequestedSuccess( + long fileSystemId, + long requestId, + DOMString data, + boolean hasNext); + + // Internal. Error callback of the <code>onReadFileRequested</code> + // event. Must be called when reading a file fails. + static void readFileRequestedError( + long fileSystemId, + long requestId, + fileSystemProvider.ProviderError error); }; }; diff --git a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js index 9ea4a01..cb06cda 100644 --- a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js @@ -177,7 +177,45 @@ eventBindings.registerArgumentMassager( fileSystemProviderInternal.openFileRequestedError( fileSystemId, requestId, error); } - dispatch([fileSystemId, filePath, mode, create, onSuccessCallback, + dispatch([fileSystemId, requestId, filePath, mode, create, + onSuccessCallback, onErrorCallback]); + }); + +eventBindings.registerArgumentMassager( + 'fileSystemProvider.onCloseFileRequested', + function(args, dispatch) { + var fileSystemId = args[0]; + var requestId = args[1]; + var openRequestId = args[2]; + var onSuccessCallback = function() { + fileSystemProviderInternal.closeFileRequestedSuccess( + fileSystemId, requestId); + }; + var onErrorCallback = function(error) { + fileSystemProviderInternal.closeFileRequestedError( + fileSystemId, requestId, error); + } + dispatch([fileSystemId, openRequestId, openRequestId, onSuccessCallback, + onErrorCallback]); + }); + +eventBindings.registerArgumentMassager( + 'fileSystemProvider.onReadFileRequested', + function(args, dispatch) { + var fileSystemId = args[0]; + var requestId = args[1]; + var openRequestId = args[2]; + var offset = args[3]; + var length = args[4]; + var onSuccessCallback = function(data, hasNext) { + fileSystemProviderInternal.readFileRequestedSuccess( + fileSystemId, requestId, data, hasNext); + }; + var onErrorCallback = function(error) { + fileSystemProviderInternal.readFileRequestedError( + fileSystemId, requestId, error); + } + dispatch([fileSystemId, openRequestId, offset, length, onSuccessCallback, onErrorCallback]); }); |