summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc91
-rw-r--r--chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h24
-rw-r--r--chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc6
-rw-r--r--chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc26
-rw-r--r--chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h5
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc36
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc92
-rw-r--r--chrome/browser/chromeos/file_system_provider/mount_path_util.cc7
-rw-r--r--chrome/browser/chromeos/file_system_provider/mount_path_util.h7
-rw-r--r--chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc11
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc85
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/get_metadata.h55
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc256
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system.cc12
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system.h3
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h6
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc2
-rw-r--r--chrome/browser/chromeos/file_system_provider/request_value.cc8
-rw-r--r--chrome/browser/chromeos/file_system_provider/request_value.h17
-rw-r--r--chrome/browser/chromeos/fileapi/file_system_backend.cc4
-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.idl38
-rw-r--r--chrome/common/extensions/api/file_system_provider_internal.idl14
-rw-r--r--chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js19
-rw-r--r--chrome/test/data/extensions/api_test/file_system_provider/get_metadata/manifest.json18
-rw-r--r--chrome/test/data/extensions/api_test/file_system_provider/get_metadata/test.js166
-rw-r--r--extensions/browser/extension_function_histogram_value.h2
-rw-r--r--tools/metrics/histograms/histograms.xml4
29 files changed, 946 insertions, 71 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 1bbd5c5..4aadc26 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
@@ -107,6 +107,8 @@ bool FileSystemProviderMountFunction::RunSync() {
Service* service = Service::Get(GetProfile());
DCHECK(service);
+ if (!service)
+ return false;
int file_system_id =
service->MountFileSystem(extension_id(), params->display_name);
@@ -132,11 +134,13 @@ bool FileSystemProviderMountFunction::RunSync() {
bool FileSystemProviderUnmountFunction::RunSync() {
using api::file_system_provider::Unmount::Params;
- const scoped_ptr<Params> params(Params::Create(*args_));
+ scoped_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
Service* service = Service::Get(GetProfile());
DCHECK(service);
+ if (!service)
+ return false;
if (!service->UnmountFileSystem(extension_id(), params->file_system_id)) {
// TODO(mtomasz): Pass more detailed errors, rather than just a bool.
@@ -158,6 +162,8 @@ bool FileSystemProviderInternalUnmountRequestedSuccessFunction::RunSync() {
Service* service = Service::Get(GetProfile());
DCHECK(service);
+ if (!service)
+ return false;
ProvidedFileSystemInterface* file_system =
service->GetProvidedFileSystem(extension_id(), params->file_system_id);
@@ -197,6 +203,89 @@ bool FileSystemProviderInternalUnmountRequestedErrorFunction::RunSync() {
Service* service = Service::Get(GetProfile());
DCHECK(service);
+ if (!service)
+ return false;
+
+ ProvidedFileSystemInterface* file_system =
+ service->GetProvidedFileSystem(extension_id(), params->file_system_id);
+ if (!file_system) {
+ base::ListValue* result = new base::ListValue();
+ result->Append(
+ CreateError(kNotFoundErrorName, kResponseFailedErrorMessage));
+ SetResult(result);
+ return false;
+ }
+
+ RequestManager* request_manager = file_system->GetRequestManager();
+ DCHECK(request_manager);
+
+ if (!request_manager->RejectRequest(
+ params->request_id, ProviderErrorToFileError(params->error))) {
+ // TODO(mtomasz): Pass more detailed errors, rather than just a bool.
+ base::ListValue* result = new base::ListValue();
+ result->Append(
+ CreateError(kSecurityErrorName, kResponseFailedErrorMessage));
+ SetResult(result);
+ return false;
+ }
+
+ base::ListValue* result = new base::ListValue();
+ SetResult(result);
+ return true;
+}
+
+bool FileSystemProviderInternalGetMetadataRequestedSuccessFunction::RunSync() {
+ // TODO(mtomasz): Create a common class for these internal functions so
+ // most of the code could be easily reused.
+ using api::file_system_provider_internal::GetMetadataRequestedSuccess::Params;
+ scoped_ptr<Params> params(Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ Service* service = Service::Get(GetProfile());
+ DCHECK(service);
+ if (!service)
+ return false;
+
+ ProvidedFileSystemInterface* file_system =
+ service->GetProvidedFileSystem(extension_id(), params->file_system_id);
+ if (!file_system) {
+ base::ListValue* result = new base::ListValue();
+ result->Append(
+ CreateError(kNotFoundErrorName, kResponseFailedErrorMessage));
+ SetResult(result);
+ return false;
+ }
+
+ RequestManager* request_manager = file_system->GetRequestManager();
+ DCHECK(request_manager);
+
+ const int request_id = params->request_id;
+ if (!request_manager->FulfillRequest(
+ request_id,
+ RequestValue::CreateForGetMetadataSuccess(params.Pass()),
+ false /* has_more */)) {
+ // TODO(mtomasz): Pass more detailed errors, rather than just a bool.
+ base::ListValue* result = new base::ListValue();
+ result->Append(
+ CreateError(kSecurityErrorName, kResponseFailedErrorMessage));
+ SetResult(result);
+ return false;
+ }
+
+ base::ListValue* result = new base::ListValue();
+ SetResult(result);
+ return true;
+}
+
+bool FileSystemProviderInternalGetMetadataRequestedErrorFunction::RunSync() {
+ using api::file_system_provider_internal::UnmountRequestedError::Params;
+ const scoped_ptr<Params> params(Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ Service* service = Service::Get(GetProfile());
+ DCHECK(service);
+ if (!service)
+ return false;
ProvidedFileSystemInterface* file_system =
service->GetProvidedFileSystem(extension_id(), params->file_system_id);
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 d5c945d..7e7deb2 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
@@ -53,6 +53,30 @@ class FileSystemProviderInternalUnmountRequestedErrorFunction
virtual bool RunSync() OVERRIDE;
};
+class FileSystemProviderInternalGetMetadataRequestedSuccessFunction
+ : public ChromeSyncExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION(
+ "fileSystemProviderInternal.getMetadataRequestedSuccess",
+ FILESYSTEMPROVIDERINTERNAL_GETMETADATAREQUESTEDSUCCESS)
+
+ protected:
+ virtual ~FileSystemProviderInternalGetMetadataRequestedSuccessFunction() {}
+ virtual bool RunSync() OVERRIDE;
+};
+
+class FileSystemProviderInternalGetMetadataRequestedErrorFunction
+ : public ChromeSyncExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION(
+ "fileSystemProviderInternal.getMetadataRequestedError",
+ FILESYSTEMPROVIDERINTERNAL_GETMETADATAREQUESTEDERROR)
+
+ protected:
+ virtual ~FileSystemProviderInternalGetMetadataRequestedErrorFunction() {}
+ virtual bool RunSync() OVERRIDE;
+};
+
} // namespace extensions
#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_SYSTEM_PROVIDER_FILE_SYSTEM_PROVIDER_API_H_
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
index c1317e0..bef565d 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -29,4 +29,10 @@ IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Unmount) {
<< message_;
}
+IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, GetMetadata) {
+ ASSERT_TRUE(RunPlatformAppTestWithFlags("file_system_provider/get_metadata",
+ kFlagLoadAsComponent))
+ << message_;
+}
+
} // namespace extensions
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 68a424d..8e54dd0 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
@@ -24,6 +24,32 @@ void FakeProvidedFileSystem::RequestUnmount(
FROM_HERE, base::Bind(callback, base::File::FILE_OK));
}
+void FakeProvidedFileSystem::GetMetadata(
+ const base::FilePath& entry_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) {
+ // Return fake metadata for the root directory only.
+ if (entry_path.AsUTF8Unsafe() != "/") {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ callback, base::File::FILE_ERROR_NOT_FOUND, base::File::Info()));
+ return;
+ }
+
+ base::File::Info file_info;
+ file_info.size = 0;
+ file_info.is_directory = true;
+ file_info.is_symbolic_link = false;
+ base::Time last_modified_time;
+ const bool result = base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014",
+ &last_modified_time);
+ DCHECK(result);
+ file_info.last_modified = last_modified_time;
+
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(callback, base::File::FILE_OK, file_info));
+}
+
const ProvidedFileSystemInfo& FakeProvidedFileSystem::GetFileSystemInfo()
const {
return file_system_info_;
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 60a9f63..0d37332 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
@@ -5,8 +5,6 @@
#ifndef CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FAKE_PROVIDED_FILE_SYSTEM_H_
#define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FAKE_PROVIDED_FILE_SYSTEM_H_
-#include <string>
-
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
@@ -30,6 +28,9 @@ class FakeProvidedFileSystem : public ProvidedFileSystemInterface {
// ProvidedFileSystemInterface overrides.
virtual void RequestUnmount(
const fileapi::AsyncFileUtil::StatusCallback& callback) OVERRIDE;
+ virtual void GetMetadata(
+ const base::FilePath& entry_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) OVERRIDE;
virtual const ProvidedFileSystemInfo& GetFileSystemInfo() const OVERRIDE;
virtual RequestManager* GetRequestManager() OVERRIDE;
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc
index b4a5cce..3ec9952 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc
@@ -5,9 +5,12 @@
#include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
#include "base/callback.h"
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/platform_file.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 "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_url.h"
@@ -18,6 +21,31 @@ using content::BrowserThread;
namespace chromeos {
namespace file_system_provider {
namespace internal {
+namespace {
+
+// Executes GetFileInfo on the UI thread.
+void GetFileInfoOnUIThread(
+ scoped_ptr<fileapi::FileSystemOperationContext> context,
+ const fileapi::FileSystemURL& url,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) {
+ util::FileSystemURLParser parser(url);
+ if (!parser.Parse()) {
+ callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
+ return;
+ }
+
+ parser.file_system()->GetMetadata(parser.file_path(), callback);
+}
+
+// Routes the response of GetFileInfo back to the IO thread.
+void OnGetFileInfo(const fileapi::AsyncFileUtil::GetFileInfoCallback& callback,
+ base::File::Error result,
+ const base::File::Info& file_info) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE, base::Bind(callback, result, file_info));
+}
+
+} // namespace
ProviderAsyncFileUtil::ProviderAsyncFileUtil() {}
@@ -69,8 +97,12 @@ void ProviderAsyncFileUtil::GetFileInfo(
const fileapi::FileSystemURL& url,
const GetFileInfoCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- NOTIMPLEMENTED();
- callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&GetFileInfoOnUIThread,
+ base::Passed(&context),
+ url,
+ base::Bind(&OnGetFileInfo, callback)));
}
void ProviderAsyncFileUtil::ReadDirectory(
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc
index 8b18bb8..2fe8f48 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc
@@ -11,11 +11,17 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.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/service.h"
+#include "chrome/browser/chromeos/file_system_provider/service_factory.h"
+#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_file_system_context.h"
+#include "extensions/browser/extension_registry.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/fileapi/async_file_util.h"
#include "webkit/browser/fileapi/external_mount_points.h"
@@ -28,7 +34,6 @@ namespace file_system_provider {
namespace {
const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
-const int kFileSystemId = 1;
// Logs callbacks invocations on the tested operations.
// TODO(mtomasz): Store and verify more arguments, once the operations return
@@ -86,42 +91,6 @@ class EventLogger {
DISALLOW_COPY_AND_ASSIGN(EventLogger);
};
-// Registers an external mount point, and removes it once the object gets out
-// of scope. To ensure that creating the mount point succeeded, call is_valid().
-class ScopedExternalMountPoint {
- public:
- ScopedExternalMountPoint(const std::string& mount_point_name,
- const base::FilePath& mount_path,
- fileapi::FileSystemType type)
- : mount_point_name_(mount_point_name) {
- fileapi::ExternalMountPoints* const mount_points =
- fileapi::ExternalMountPoints::GetSystemInstance();
- DCHECK(mount_points);
- is_valid_ =
- mount_points->RegisterFileSystem(mount_point_name,
- fileapi::kFileSystemTypeProvided,
- fileapi::FileSystemMountOption(),
- mount_path);
- }
-
- virtual ~ScopedExternalMountPoint() {
- if (!is_valid_)
- return;
-
- // If successfully registered in the constructor, then unregister.
- fileapi::ExternalMountPoints* const mount_points =
- fileapi::ExternalMountPoints::GetSystemInstance();
- DCHECK(mount_points);
- mount_points->RevokeFileSystem(mount_point_name_);
- }
-
- bool is_valid() { return is_valid_; }
-
- private:
- const std::string mount_point_name_;
- bool is_valid_;
-};
-
// Creates a cracked FileSystemURL for tests.
fileapi::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name,
const base::FilePath& file_path) {
@@ -134,6 +103,13 @@ fileapi::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name,
base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
}
+// Creates a Service instance. Used to be able to destroy the service in
+// TearDown().
+KeyedService* CreateService(content::BrowserContext* context) {
+ return new Service(Profile::FromBrowserContext(context),
+ extensions::ExtensionRegistry::Get(context));
+}
+
} // namespace
// Tests in this file are very lightweight and just test integration between
@@ -148,17 +124,28 @@ class FileSystemProviderProviderAsyncFileUtilTest : public testing::Test {
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
- profile_.reset(new TestingProfile);
+ profile_manager_.reset(
+ new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
+ ASSERT_TRUE(profile_manager_->SetUp());
+ profile_ = profile_manager_->CreateTestingProfile("testing-profile");
async_file_util_.reset(new internal::ProviderAsyncFileUtil);
- const base::FilePath mount_path =
- util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
+
file_system_context_ =
content::CreateFileSystemContextForTesting(NULL, data_dir_.path());
- const std::string mount_point_name = mount_path.BaseName().AsUTF8Unsafe();
- mount_point_.reset(new ScopedExternalMountPoint(
- mount_point_name, mount_path, fileapi::kFileSystemTypeProvided));
- ASSERT_TRUE(mount_point_->is_valid());
+ ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
+ Service* service = Service::Get(profile_); // Owned by its factory.
+ service->SetFileSystemFactoryForTests(
+ base::Bind(&FakeProvidedFileSystem::Create));
+
+ const int file_system_id =
+ service->MountFileSystem(kExtensionId, "testing-file-system");
+ ASSERT_LT(0, file_system_id);
+ const ProvidedFileSystemInfo& file_system_info =
+ service->GetProvidedFileSystem(kExtensionId, file_system_id)
+ ->GetFileSystemInfo();
+ const std::string mount_point_name =
+ file_system_info.mount_path().BaseName().AsUTF8Unsafe();
file_url_ = CreateFileSystemURL(
mount_point_name, base::FilePath::FromUTF8Unsafe("hello/world.txt"));
@@ -170,6 +157,12 @@ class FileSystemProviderProviderAsyncFileUtilTest : public testing::Test {
ASSERT_TRUE(root_url_.is_valid());
}
+ virtual void TearDown() OVERRIDE {
+ // Setting the testing factory to NULL will destroy the created service
+ // associated with the testing profile.
+ ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
+ }
+
scoped_ptr<fileapi::FileSystemOperationContext> CreateOperationContext() {
return make_scoped_ptr(
new fileapi::FileSystemOperationContext(file_system_context_.get()));
@@ -177,10 +170,10 @@ class FileSystemProviderProviderAsyncFileUtilTest : public testing::Test {
content::TestBrowserThreadBundle thread_bundle_;
base::ScopedTempDir data_dir_;
- scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<TestingProfileManager> profile_manager_;
+ TestingProfile* profile_; // Owned by TestingProfileManager.
scoped_ptr<fileapi::AsyncFileUtil> async_file_util_;
scoped_refptr<fileapi::FileSystemContext> file_system_context_;
- scoped_ptr<ScopedExternalMountPoint> mount_point_;
fileapi::FileSystemURL file_url_;
fileapi::FileSystemURL directory_url_;
fileapi::FileSystemURL root_url_;
@@ -283,11 +276,12 @@ TEST_F(FileSystemProviderProviderAsyncFileUtilTest, GetFileInfo) {
async_file_util_->GetFileInfo(
CreateOperationContext(),
- file_url_,
+ root_url_,
base::Bind(&EventLogger::OnGetFileInfo, logger.GetWeakPtr()));
+ base::RunLoop().RunUntilIdle();
ASSERT_TRUE(logger.error());
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, *logger.error());
+ EXPECT_EQ(base::File::FILE_OK, *logger.error());
}
TEST_F(FileSystemProviderProviderAsyncFileUtilTest, ReadDirectory) {
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util.cc
index ed7016d..a7a351d 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util.cc
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util.cc
@@ -16,6 +16,9 @@
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
namespace chromeos {
namespace file_system_provider {
@@ -50,6 +53,8 @@ FileSystemURLParser::~FileSystemURLParser() {
}
bool FileSystemURLParser::Parse() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
if (url_.type() != fileapi::kFileSystemTypeProvided)
return false;
@@ -80,7 +85,7 @@ bool FileSystemURLParser::Parse() {
std::vector<base::FilePath::StringType> components;
url_.virtual_path().GetComponents(&components);
DCHECK_LT(0u, components.size());
- file_path_ = base::FilePath();
+ file_path_ = base::FilePath::FromUTF8Unsafe("/");
for (size_t i = 1; i < components.size(); ++i) {
// TODO(mtomasz): This could be optimized, to avoid unnecessary copies.
file_path_ = file_path_.Append(components[i]);
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util.h b/chrome/browser/chromeos/file_system_provider/mount_path_util.h
index 25f6129..91f91e9 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util.h
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util.h
@@ -25,16 +25,15 @@ base::FilePath GetMountPath(Profile* profile,
int file_system_id);
// Finds file system, which is responsible for handling the specified |url| by
-// analysing the mount path.
-// Also, extract the file path from the virtual path to be used by the file
-// system operations.
+// analysing the mount path. Also, extract the file path from the virtual path
+// to be used by the file system operations.
class FileSystemURLParser {
public:
explicit FileSystemURLParser(const fileapi::FileSystemURL& url);
virtual ~FileSystemURLParser();
// Parses the |url| passed to the constructor. If parsing succeeds, then
- // returns true. Otherwise, false.
+ // returns true. Otherwise, false. Must be called on UI thread.
bool Parse();
ProvidedFileSystemInterface* file_system() const { return file_system_; }
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
index f4f843b..80fb16a 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
@@ -43,10 +43,12 @@ fileapi::FileSystemURL CreateFileSystemURL(Profile* profile,
const fileapi::ExternalMountPoints* const mount_points =
fileapi::ExternalMountPoints::GetSystemInstance();
DCHECK(mount_points);
+ DCHECK(file_path.IsAbsolute());
+ base::FilePath relative_path(file_path.value().substr(1));
return mount_points->CreateCrackedFileSystemURL(
GURL(origin),
fileapi::kFileSystemTypeExternal,
- base::FilePath(mount_path.BaseName().Append(file_path)));
+ base::FilePath(mount_path.BaseName().Append(relative_path)));
}
// Creates a Service instance. Used to be able to destroy the service in
@@ -105,7 +107,8 @@ TEST_F(FileSystemProviderMountPathUtilTest, Parser) {
kExtensionId, kFileSystemName);
EXPECT_LT(0, file_system_id);
- const base::FilePath kFilePath = base::FilePath("hello/world.txt");
+ const base::FilePath kFilePath =
+ base::FilePath::FromUTF8Unsafe("/hello/world.txt");
const fileapi::FileSystemURL url =
CreateFileSystemURL(profile_, kExtensionId, file_system_id, kFilePath);
EXPECT_TRUE(url.is_valid());
@@ -124,7 +127,7 @@ TEST_F(FileSystemProviderMountPathUtilTest, Parser_RootPath) {
kExtensionId, kFileSystemName);
EXPECT_LT(0, file_system_id);
- const base::FilePath kFilePath = base::FilePath();
+ const base::FilePath kFilePath = base::FilePath::FromUTF8Unsafe("/");
const fileapi::FileSystemURL url =
CreateFileSystemURL(profile_, kExtensionId, file_system_id, kFilePath);
EXPECT_TRUE(url.is_valid());
@@ -143,7 +146,7 @@ TEST_F(FileSystemProviderMountPathUtilTest, Parser_WrongUrl) {
kExtensionId, kFileSystemName);
EXPECT_LT(0, file_system_id);
- const base::FilePath kFilePath = base::FilePath("hello");
+ const base::FilePath kFilePath = base::FilePath::FromUTF8Unsafe("/hello");
const fileapi::FileSystemURL url = CreateFileSystemURL(
profile_, kExtensionId, file_system_id + 1, kFilePath);
// It is impossible to create a cracked URL for a mount point which doesn't
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
new file mode 100644
index 0000000..809351a
--- /dev/null
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
@@ -0,0 +1,85 @@
+// 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/get_metadata.h"
+
+#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 false.
+bool ConvertRequestValueToFileInfo(scoped_ptr<RequestValue> value,
+ base::File::Info* output) {
+ using extensions::api::file_system_provider::EntryMetadata;
+ using extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params;
+
+ const Params* params = value->get_metadata_success_params();
+ if (!params)
+ return false;
+
+ output->is_directory = params->metadata.is_directory;
+ output->size = static_cast<int64>(params->metadata.size);
+ output->is_symbolic_link = false; // Not supported.
+
+ std::string input_modification_time;
+ if (!params->metadata.modification_time.additional_properties.GetString(
+ "value", &input_modification_time)) {
+ return false;
+ }
+ if (!base::Time::FromString(input_modification_time.c_str(),
+ &output->last_modified)) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+GetMetadata::GetMetadata(
+ extensions::EventRouter* event_router,
+ const ProvidedFileSystemInfo& file_system_info,
+ const base::FilePath& directory_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback)
+ : Operation(event_router, file_system_info),
+ directory_path_(directory_path),
+ callback_(callback) {
+}
+
+GetMetadata::~GetMetadata() {
+}
+
+bool GetMetadata::Execute(int request_id) {
+ scoped_ptr<base::ListValue> values(new base::ListValue);
+ values->AppendString(directory_path_.AsUTF8Unsafe());
+ return SendEvent(
+ request_id,
+ extensions::api::file_system_provider::OnGetMetadataRequested::kEventName,
+ values.Pass());
+}
+
+void GetMetadata::OnSuccess(int /* request_id */,
+ scoped_ptr<RequestValue> result,
+ bool has_next) {
+ base::File::Info file_info;
+ const bool convert_result =
+ ConvertRequestValueToFileInfo(result.Pass(), &file_info);
+ DCHECK(convert_result);
+ callback_.Run(base::File::FILE_OK, file_info);
+}
+
+void GetMetadata::OnError(int /* request_id */, base::File::Error error) {
+ callback_.Run(error, base::File::Info());
+}
+
+} // namespace operations
+} // namespace file_system_provider
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h
new file mode 100644
index 0000000..804bc3e
--- /dev/null
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h
@@ -0,0 +1,55 @@
+// 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_GET_METADATA_H_
+#define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_OPERATIONS_GET_METADATA_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/request_value.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 directory operation and providing extension's
+// read directory request. Created per request.
+class GetMetadata : public Operation {
+ public:
+ GetMetadata(extensions::EventRouter* event_router,
+ const ProvidedFileSystemInfo& file_system_info,
+ const base::FilePath& directory_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback);
+ virtual ~GetMetadata();
+
+ // 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:
+ base::FilePath directory_path_;
+ const fileapi::AsyncFileUtil::GetFileInfoCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetMetadata);
+};
+
+} // namespace operations
+} // namespace file_system_provider
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_OPERATIONS_GET_METADATA_H_
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
new file mode 100644
index 0000000..4b091ac
--- /dev/null
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
@@ -0,0 +1,256 @@
+// 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/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.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 "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 base::FilePath::CharType kDirectoryPath[] = "/directory";
+
+// 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(base::File::Error result, const base::File::Info& file_info)
+ : result_(result), file_info_(file_info) {}
+ virtual ~Event() {}
+
+ base::File::Error result() { return result_; }
+ const base::File::Info& file_info() { return file_info_; }
+
+ private:
+ base::File::Error result_;
+ base::File::Info file_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(Event);
+ };
+
+ CallbackLogger() : weak_ptr_factory_(this) {}
+ virtual ~CallbackLogger() {}
+
+ void OnGetMetadata(base::File::Error result,
+ const base::File::Info& file_info) {
+ events_.push_back(new Event(result, file_info));
+ }
+
+ 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 FileSystemProviderOperationsGetMetadataTest : public testing::Test {
+ protected:
+ FileSystemProviderOperationsGetMetadataTest() {}
+ virtual ~FileSystemProviderOperationsGetMetadataTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ file_system_info_ =
+ ProvidedFileSystemInfo(kExtensionId,
+ kFileSystemId,
+ "" /* file_system_name */,
+ base::FilePath() /* mount_path */);
+ }
+
+ ProvidedFileSystemInfo file_system_info_;
+};
+
+TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute) {
+ LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
+ CallbackLogger callback_logger;
+
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&CallbackLogger::OnGetMetadata, callback_logger.GetWeakPtr()));
+ get_metadata.SetDispatchEventImplForTesting(
+ base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl,
+ base::Unretained(&dispatcher)));
+
+ EXPECT_TRUE(get_metadata.Execute(kRequestId));
+
+ ASSERT_EQ(1u, dispatcher.events().size());
+ extensions::Event* event = dispatcher.events()[0];
+ EXPECT_EQ(
+ extensions::api::file_system_provider::OnGetMetadataRequested::kEventName,
+ event->event_name);
+ base::ListValue* event_args = event->event_args.get();
+ ASSERT_EQ(3u, 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);
+
+ std::string event_directory_path;
+ EXPECT_TRUE(event_args->GetString(2, &event_directory_path));
+ EXPECT_EQ(kDirectoryPath, event_directory_path);
+}
+
+TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute_NoListener) {
+ LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */);
+ CallbackLogger callback_logger;
+
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&CallbackLogger::OnGetMetadata, callback_logger.GetWeakPtr()));
+ get_metadata.SetDispatchEventImplForTesting(
+ base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl,
+ base::Unretained(&dispatcher)));
+
+ EXPECT_FALSE(get_metadata.Execute(kRequestId));
+}
+
+TEST_F(FileSystemProviderOperationsGetMetadataTest, OnSuccess) {
+ using extensions::api::file_system_provider::EntryMetadata;
+ using extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params;
+
+ LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
+ CallbackLogger callback_logger;
+
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&CallbackLogger::OnGetMetadata, callback_logger.GetWeakPtr()));
+ get_metadata.SetDispatchEventImplForTesting(
+ base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl,
+ base::Unretained(&dispatcher)));
+
+ EXPECT_TRUE(get_metadata.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
+ " {\n"
+ " \"isDirectory\": false,\n"
+ " \"name\": \"blueberries.txt\",\n"
+ " \"size\": 4096,\n"
+ " \"modificationTime\": {\n"
+ " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
+ " }\n"
+ " }\n"
+ "]\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::CreateForGetMetadataSuccess(params.Pass()));
+ ASSERT_TRUE(request_value.get());
+
+ const bool has_next = false;
+ get_metadata.OnSuccess(kRequestId, request_value.Pass(), has_next);
+
+ ASSERT_EQ(1u, callback_logger.events().size());
+ CallbackLogger::Event* event = callback_logger.events()[0];
+ EXPECT_EQ(base::File::FILE_OK, event->result());
+
+ const base::File::Info& file_info = event->file_info();
+ EXPECT_FALSE(file_info.is_directory);
+ EXPECT_EQ(4096, file_info.size);
+ base::Time expected_time;
+ EXPECT_TRUE(
+ base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014", &expected_time));
+ EXPECT_EQ(expected_time, file_info.last_modified);
+}
+
+TEST_F(FileSystemProviderOperationsGetMetadataTest, OnError) {
+ using extensions::api::file_system_provider::EntryMetadata;
+ using extensions::api::file_system_provider_internal::
+ GetMetadataRequestedError::Params;
+
+ LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
+ CallbackLogger callback_logger;
+
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&CallbackLogger::OnGetMetadata, callback_logger.GetWeakPtr()));
+ get_metadata.SetDispatchEventImplForTesting(
+ base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl,
+ base::Unretained(&dispatcher)));
+
+ EXPECT_TRUE(get_metadata.Execute(kRequestId));
+
+ get_metadata.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 5b39f33..88c5c30 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/file_system_provider/provided_file_system.h"
#include "base/files/file.h"
+#include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.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"
@@ -34,6 +35,17 @@ void ProvidedFileSystem::RequestUnmount(
}
}
+void ProvidedFileSystem::GetMetadata(
+ const base::FilePath& entry_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) {
+ if (!request_manager_.CreateRequest(
+ make_scoped_ptr<RequestManager::HandlerInterface>(
+ new operations::GetMetadata(
+ event_router_, file_system_info_, entry_path, callback)))) {
+ callback.Run(base::File::FILE_ERROR_SECURITY, base::File::Info());
+ }
+}
+
const ProvidedFileSystemInfo& ProvidedFileSystem::GetFileSystemInfo() const {
return file_system_info_;
}
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 90bfcea..551d2c0 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system.h
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.h
@@ -32,6 +32,9 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface {
// ProvidedFileSystemInterface overrides.
virtual void RequestUnmount(
const fileapi::AsyncFileUtil::StatusCallback& callback) OVERRIDE;
+ virtual void GetMetadata(
+ const base::FilePath& entry_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& 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 2af2430..7cf174d 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
@@ -31,6 +31,12 @@ class ProvidedFileSystemInterface {
virtual void RequestUnmount(
const fileapi::AsyncFileUtil::StatusCallback& callback) = 0;
+ // Requests metadata of the passed |entry_path|. It can be either a file
+ // or a directory.
+ virtual void GetMetadata(
+ const base::FilePath& entry_path,
+ const fileapi::AsyncFileUtil::GetFileInfoCallback& 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/provided_file_system_unittest.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
index 7adf76c..ba72300 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(mtomasz): Move these test cases to operations/unmount_unittest.cc.
+
#include <string>
#include <vector>
diff --git a/chrome/browser/chromeos/file_system_provider/request_value.cc b/chrome/browser/chromeos/file_system_provider/request_value.cc
index 105e6b0..5bc8e42 100644
--- a/chrome/browser/chromeos/file_system_provider/request_value.cc
+++ b/chrome/browser/chromeos/file_system_provider/request_value.cc
@@ -21,6 +21,14 @@ scoped_ptr<RequestValue> RequestValue::CreateForUnmountSuccess(
return result.Pass();
}
+scoped_ptr<RequestValue> RequestValue::CreateForGetMetadataSuccess(
+ scoped_ptr<extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params> params) {
+ scoped_ptr<RequestValue> result(new RequestValue);
+ result->get_metadata_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 33872b0c..8928733 100644
--- a/chrome/browser/chromeos/file_system_provider/request_value.h
+++ b/chrome/browser/chromeos/file_system_provider/request_value.h
@@ -28,9 +28,11 @@ class RequestValue {
scoped_ptr<extensions::api::file_system_provider_internal::
UnmountRequestedSuccess::Params> params);
- static scoped_ptr<RequestValue> CreateForTesting(const std::string& params);
+ static scoped_ptr<RequestValue> CreateForGetMetadataSuccess(
+ scoped_ptr<extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params> params);
- const std::string* testing_params() const { return testing_params_.get(); }
+ static scoped_ptr<RequestValue> CreateForTesting(const std::string& params);
const extensions::api::file_system_provider_internal::
UnmountRequestedSuccess::Params*
@@ -38,9 +40,20 @@ class RequestValue {
return unmount_success_params_.get();
}
+ const extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params*
+ get_metadata_success_params() const {
+ return get_metadata_success_params_.get();
+ }
+
+ const std::string* testing_params() const { return testing_params_.get(); }
+
private:
scoped_ptr<extensions::api::file_system_provider_internal::
UnmountRequestedSuccess::Params> unmount_success_params_;
+ scoped_ptr<extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params>
+ get_metadata_success_params_;
scoped_ptr<std::string> testing_params_;
DISALLOW_COPY_AND_ASSIGN(RequestValue);
diff --git a/chrome/browser/chromeos/fileapi/file_system_backend.cc b/chrome/browser/chromeos/fileapi/file_system_backend.cc
index 5b793c4..a040fc7 100644
--- a/chrome/browser/chromeos/fileapi/file_system_backend.cc
+++ b/chrome/browser/chromeos/fileapi/file_system_backend.cc
@@ -81,6 +81,7 @@ bool FileSystemBackend::CanHandleType(fileapi::FileSystemType type) const {
case fileapi::kFileSystemTypeNativeLocal:
case fileapi::kFileSystemTypeNativeForPlatformApp:
case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
+ case fileapi::kFileSystemTypeProvided:
return true;
default:
return false;
@@ -267,7 +268,8 @@ fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
- url.type() == fileapi::kFileSystemTypeDrive);
+ url.type() == fileapi::kFileSystemTypeDrive ||
+ url.type() == fileapi::kFileSystemTypeProvided);
return fileapi::FileSystemOperation::Create(
url, context,
make_scoped_ptr(new fileapi::FileSystemOperationContext(context)));
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index a16601a..d5d3bae 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -381,6 +381,8 @@
'browser/chromeos/file_system_provider/mount_path_util.cc',
'browser/chromeos/file_system_provider/mount_path_util.h',
'browser/chromeos/file_system_provider/observer.h',
+ 'browser/chromeos/file_system_provider/operations/get_metadata.cc',
+ 'browser/chromeos/file_system_provider/operations/get_metadata.h',
'browser/chromeos/file_system_provider/operations/operation.cc',
'browser/chromeos/file_system_provider/operations/operation.h',
'browser/chromeos/file_system_provider/operations/unmount.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index e15e05a..118b8e6 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -714,6 +714,7 @@
'browser/chromeos/file_system_provider/fake_provided_file_system.h',
'browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc',
'browser/chromeos/file_system_provider/mount_path_util_unittest.cc',
+ 'browser/chromeos/file_system_provider/operations/get_metadata_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 e10cb8c..d8f8619 100644
--- a/chrome/common/extensions/api/file_system_provider.idl
+++ b/chrome/common/extensions/api/file_system_provider.idl
@@ -29,6 +29,21 @@ namespace fileSystemProvider {
IO
};
+ // Represents metadata of a file or a directory.
+ dictionary EntryMetadata {
+ // True if it is a directory.
+ boolean isDirectory;
+
+ // Name of this entry (not full path name).
+ DOMString name;
+
+ // File size in bytes.
+ double size;
+
+ // The last modified time of this entry.
+ [instanceOf=Date] object modificationTime;
+ };
+
// Callback to receive the result of mount() function.
// <code>fileSystemID</code> will be a unique ID for the file system just
// mounted. The ID is used to distinguish multiple file systems mounted
@@ -51,6 +66,9 @@ namespace fileSystemProvider {
// Callback to handle an error raised from the browser.
[nocompile] callback ErrorCallback = void([instanceOf=DOMError] object error);
+ // Success callback for the <code>onGetMetadataRequested</code> event.
+ callback MetadataCallback = void(EntryMetadata metadata);
+
interface Functions {
// Mounts a file system with the given <code>displayName</code>.
// <code>displayName</code> will be shown in the left panel of
@@ -74,15 +92,25 @@ namespace fileSystemProvider {
};
interface Events {
- // Raised, when the user requests unmounting of the file system with the
- // <code>fileSystemId</code> identifier in the Files.app UI. In response,
- // the <code>unmount</code> API method should be called. If unmounting is
- // not possible (eg. due to pending operation), then <code>errorCallback
- // </code> should be called, and <code>unmount</code> should not be called.
+ // Raised when unmounting for the file system with the <code>fileSystemId
+ // </code> identifier is requested. In response, the <code>unmount</code>
+ // API method should be called together with <code>successCallback</code>.
+ // If unmounting is not possible (eg. due to a pending operation), then
+ // <code>errorCallback</code> must be called.
[maxListeners=1] static void onUnmountRequested(
long fileSystemId,
ProviderSuccessCallback successCallback,
ProviderErrorCallback errorCallback);
+
+ // Raised, when metadata of a file or a directory at <code>entryPath</code>
+ // is requested. The metadata should be returned with the <code>
+ // successCallback</code> call. In case of an error, <code>errorCallback
+ // </code> must be called.
+ [maxListeners=1] static void onGetMetadataRequested(
+ long fileSystemId,
+ DOMString entryPath,
+ MetadataCallback successCallback,
+ ErrorCallback errorCallback);
};
};
diff --git a/chrome/common/extensions/api/file_system_provider_internal.idl b/chrome/common/extensions/api/file_system_provider_internal.idl
index 80757bd..30ebbc7 100644
--- a/chrome/common/extensions/api/file_system_provider_internal.idl
+++ b/chrome/common/extensions/api/file_system_provider_internal.idl
@@ -19,6 +19,20 @@ namespace fileSystemProviderInternal {
long fileSystemId,
long requestId,
fileSystemProvider.ProviderError error);
+
+ // Internal. Success callback of the <code>onGetMetadataRequested</code>
+ // event. Must be called if metadata is available.
+ static void getMetadataRequestedSuccess(
+ long fileSystemId,
+ long requestId,
+ fileSystemProvider.EntryMetadata metadata);
+
+ // Internal. Error callback of the <code>onGetMetadataRequested</code>
+ // event. Must be called when obtaining metadata fails.
+ static void getMetadataRequestedError(
+ 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 b896138..37fb8ee 100644
--- a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
@@ -97,4 +97,23 @@ eventBindings.registerArgumentMassager(
dispatch([fileSystemId, onSuccessCallback, onErrorCallback]);
});
+eventBindings.registerArgumentMassager(
+ 'fileSystemProvider.onGetMetadataRequested',
+ function(args, dispatch) {
+ var fileSystemId = args[0];
+ var requestId = args[1];
+ var entryPath = args[2];
+ var onSuccessCallback = function(metadata) {
+ // Serialize the Date as a string.
+ metadata.modificationTime.value = metadata.modificationTime.toString();
+ fileSystemProviderInternal.getMetadataRequestedSuccess(
+ fileSystemId, requestId, metadata);
+ };
+ var onErrorCallback = function(error) {
+ fileSystemProviderInternal.getMetadataRequestedError(
+ fileSystemId, requestId, error);
+ }
+ dispatch([fileSystemId, entryPath, onSuccessCallback, onErrorCallback]);
+ });
+
exports.binding = binding.generate();
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/get_metadata/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/get_metadata/manifest.json
new file mode 100644
index 0000000..8d1ef3c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/get_metadata/manifest.json
@@ -0,0 +1,18 @@
+{
+ "key": "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDOuXEIuoK1kAkBe0SKiJn/N9oNn3oUxGa4dwj40MnJqPn+w0aR2vuyocm0R4Drp67aYwtLjOVPF4CICRq6ICP6eU07gGwQxGdZ7HJASXV8hm0tab5I70oJmRLfFJyVAMCeWlFaOGq05v2i6EbifZM0qO5xALKNGQt+yjXi5INM5wIBIw==",
+ "name": "chrome.fileSystemProvider.onGetMetadataRequested",
+ "version": "0.1",
+ "manifest_version": 2,
+ "description":
+ "Test for chrome.fileSystemProvider.onGetMetadataRequested().",
+ "permissions": [
+ "fileSystemProvider",
+ "fileBrowserPrivate",
+ "fileBrowserHandler"
+ ],
+ "app": {
+ "background": {
+ "scripts": ["test.js"]
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/get_metadata/test.js b/chrome/test/data/extensions/api_test/file_system_provider/get_metadata/test.js
new file mode 100644
index 0000000..a93a323
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/get_metadata/test.js
@@ -0,0 +1,166 @@
+// 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.
+
+'use strict';
+
+var fileSystemId;
+var fileSystem;
+
+/**
+ * @type {Object}
+ * @const
+ */
+var TESTING_ROOT = Object.freeze({
+ isDirectory: true,
+ name: '',
+ size: 0,
+ modificationTime: new Date(2013, 3, 27, 9, 38, 14)
+});
+
+/**
+ * @type {Object}
+ * @const
+ */
+var TESTING_FILE = Object.freeze({
+ isDirectory: false,
+ name: 'tiramisu.txt',
+ size: 4096,
+ modificationTime: new Date(2014, 4, 28, 10, 39, 15)
+});
+
+/**
+ * Returns metadata for a requested entry.
+ *
+ * @param {number} inFileSystemId ID of the file system.
+ * @param {string} entryPath Path of the requested entry.
+ * @param {function(Object)} onSuccess Success callback with metadata passed
+ * an argument.
+ * @param {function(string}} onError Error callback with an error code.
+ */
+function onGetMetadataRequested(
+ inFileSystemId, entryPath, onSuccess, onError) {
+ if (inFileSystemId != fileSystemId) {
+ onError('SECURITY_ERROR'); // enum ProviderError.
+ return;
+ }
+
+ if (entryPath == '/') {
+ onSuccess(TESTING_ROOT);
+ return;
+ }
+
+ if (entryPath == '/' + TESTING_FILE.name) {
+ onSuccess(TESTING_FILE);
+ return;
+ }
+
+ onError('NOT_FOUND'); // enum ProviderError.
+}
+
+/**
+ * Sets up the tests. Called once per all test cases. In case of a failure,
+ * the callback is not called.
+ *
+ * @param {function()} callback Success callback.
+ */
+function setUp(callback) {
+ chrome.fileSystemProvider.mount('chocolate.zip', function(id) {
+ fileSystemId = id;
+ chrome.fileSystemProvider.onGetMetadataRequested.addListener(
+ onGetMetadataRequested);
+ var volumeId =
+ 'provided:' + chrome.runtime.id + '-' + fileSystemId + '-user';
+
+ chrome.fileBrowserPrivate.requestFileSystem(
+ volumeId,
+ function(inFileSystem) {
+ chrome.test.assertTrue(!!inFileSystem);
+
+ fileSystem = inFileSystem;
+ callback();
+ });
+ }, function() {
+ chrome.test.fail();
+ });
+}
+
+/**
+ * Runs all of the test cases, one by one.
+ */
+function runTests() {
+ chrome.test.runTests([
+ // Read metadata of the root.
+ function getFileMetadataSuccess() {
+ var onSuccess = chrome.test.callbackPass(function() {});
+ fileSystem.root.getMetadata(
+ function(metadata) {
+ chrome.test.assertEq(TESTING_ROOT.size, metadata.size);
+ chrome.test.assertEq(
+ TESTING_ROOT.modificationTime.toString(),
+ metadata.modificationTime.toString());
+ onSuccess();
+ }, function(error) {
+ chrome.test.fail(error.name);
+ });
+ },
+ // Read metadata of an existing testing file.
+ function getFileMetadataSuccess() {
+ var onSuccess = chrome.test.callbackPass(function() {});
+ fileSystem.root.getFile(
+ TESTING_FILE.name,
+ {create: false},
+ function(fileEntry) {
+ chrome.test.assertEq(TESTING_FILE.name, fileEntry.name);
+ chrome.test.assertEq(
+ TESTING_FILE.isDirectory, fileEntry.isDirectory);
+ fileEntry.getMetadata(function(metadata) {
+ chrome.test.assertEq(TESTING_FILE.size, metadata.size);
+ chrome.test.assertEq(
+ TESTING_FILE.modificationTime.toString(),
+ metadata.modificationTime.toString());
+ onSuccess();
+ }, function(error) {
+ chrome.test.fail(error.name);
+ });
+ },
+ function(error) {
+ chrome.test.fail(error.name);
+ });
+ },
+ // Read metadata of a directory which does not exist, what should return an
+ // error. DirectoryEntry.getDirectory() causes fetching metadata.
+ function getFileMetadataNotFound() {
+ var onSuccess = chrome.test.callbackPass(function() {});
+ fileSystem.root.getDirectory(
+ 'cranberries',
+ {create: false},
+ function(dirEntry) {
+ chrome.test.fail();
+ },
+ function(error) {
+ chrome.test.assertEq('NotFoundError', error.name);
+ onSuccess();
+ });
+ },
+ // Read metadata of a file using getDirectory(). An error should be returned
+ // because of type mismatching. DirectoryEntry.getDirectory() causes
+ // fetching metadata.
+ function getFileMetadataWrongType() {
+ var onSuccess = chrome.test.callbackPass(function() {});
+ fileSystem.root.getDirectory(
+ TESTING_FILE.name,
+ {create: false},
+ function(fileEntry) {
+ chrome.test.fail();
+ },
+ function(error) {
+ chrome.test.assertEq('TypeMismatchError', error.name);
+ onSuccess();
+ });
+ }
+ ]);
+}
+
+// Setup and run all of the test cases.
+setUp(runTests);
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 5486d77..90f8d7f 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -808,6 +808,8 @@ enum HistogramValue {
BLUETOOTHSOCKET_GETSOCKETS,
WEBSTOREPRIVATE_SIGNINFUNCTION,
SHELL_CREATEWINDOW,
+ FILESYSTEMPROVIDERINTERNAL_GETMETADATAREQUESTEDSUCCESS,
+ FILESYSTEMPROVIDERINTERNAL_GETMETADATAREQUESTEDERROR,
// Last entry: Add new entries above and ensure to update
// tools/metrics/histograms/histograms/histograms.xml.
ENUM_BOUNDARY
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 54b82f0..cb68f98 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -33765,6 +33765,10 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="747" label="BLUETOOTHSOCKET_GETSOCKETS"/>
<int value="748" label="WEBSTOREPRIVATE_SIGNINFUNCTION"/>
<int value="749" label="SHELL_CREATEWINDOW"/>
+ <int value="750"
+ label="FILESYSTEMPROVIDERINTERNAL_GETMETADATAREQUESTEDSUCCESS"/>
+ <int value="751"
+ label="FILESYSTEMPROVIDERINTERNAL_GETMETADATAREQUESTEDERROR"/>
</enum>
<enum name="ExtensionInstallCause" type="int">