summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc21
-rw-r--r--chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h24
-rw-r--r--chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc23
-rw-r--r--chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h9
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/read_file.cc93
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/read_file.h65
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc272
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system.cc24
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system.h9
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h26
-rw-r--r--chrome/browser/chromeos/file_system_provider/request_value.cc8
-rw-r--r--chrome/browser/chromeos/file_system_provider/request_value.h13
-rw-r--r--chrome/chrome_browser_chromeos.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/common/extensions/api/file_system_provider.idl24
-rw-r--r--chrome/common/extensions/api/file_system_provider_internal.idl15
-rw-r--r--chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js40
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]);
});