summaryrefslogtreecommitdiffstats
path: root/webkit/browser
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-28 02:08:07 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-28 02:08:07 +0000
commitc6f9203a46211bb08b84f73b4e1df303f1ab8c42 (patch)
treeb8774c1e80f5e37c7f31a889023962fb3eb1bb7e /webkit/browser
parentba7e19a2704f1c4772d1f1f3a45a2b2b78c0bbd7 (diff)
downloadchromium_src-c6f9203a46211bb08b84f73b4e1df303f1ab8c42.zip
chromium_src-c6f9203a46211bb08b84f73b4e1df303f1ab8c42.tar.gz
chromium_src-c6f9203a46211bb08b84f73b4e1df303f1ab8c42.tar.bz2
Move browser-specific FileAPI code from webkit/fileapi to webkit/browser/fileapi
Moving following files: - file_system_context* - file_system_operation* - file_system_url* - and all others but not in syncable/ ones BUG=239710 TBR=avi@chromium.org, tzik@chromium.org Review URL: https://codereview.chromium.org/15859007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202482 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/browser')
-rw-r--r--webkit/browser/fileapi/async_file_test_helper.cc235
-rw-r--r--webkit/browser/fileapi/async_file_test_helper.h90
-rw-r--r--webkit/browser/fileapi/async_file_util.h338
-rw-r--r--webkit/browser/fileapi/async_file_util_adapter.cc307
-rw-r--r--webkit/browser/fileapi/async_file_util_adapter.h109
-rw-r--r--webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc8
-rw-r--r--webkit/browser/fileapi/cross_operation_delegate.cc6
-rw-r--r--webkit/browser/fileapi/dump_file_system.cc205
-rw-r--r--webkit/browser/fileapi/external_mount_points.cc4
-rw-r--r--webkit/browser/fileapi/external_mount_points_unittest.cc2
-rw-r--r--webkit/browser/fileapi/file_permission_policy.cc34
-rw-r--r--webkit/browser/fileapi/file_permission_policy.h34
-rw-r--r--webkit/browser/fileapi/file_stream_writer.h72
-rw-r--r--webkit/browser/fileapi/file_system_context.cc421
-rw-r--r--webkit/browser/fileapi/file_system_context.h309
-rw-r--r--webkit/browser/fileapi/file_system_context_unittest.cc329
-rw-r--r--webkit/browser/fileapi/file_system_dir_url_request_job.cc6
-rw-r--r--webkit/browser/fileapi/file_system_dir_url_request_job.h2
-rw-r--r--webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc6
-rw-r--r--webkit/browser/fileapi/file_system_file_stream_reader.cc132
-rw-r--r--webkit/browser/fileapi/file_system_file_stream_reader.h79
-rw-r--r--webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc281
-rw-r--r--webkit/browser/fileapi/file_system_mount_point_provider.h2
-rw-r--r--webkit/browser/fileapi/file_system_operation.h278
-rw-r--r--webkit/browser/fileapi/file_system_operation_context.cc33
-rw-r--r--webkit/browser/fileapi/file_system_operation_context.h127
-rw-r--r--webkit/browser/fileapi/file_system_options.cc19
-rw-r--r--webkit/browser/fileapi/file_system_options.h53
-rw-r--r--webkit/browser/fileapi/file_system_quota_client.cc2
-rw-r--r--webkit/browser/fileapi/file_system_quota_client_unittest.cc4
-rw-r--r--webkit/browser/fileapi/file_system_url.cc188
-rw-r--r--webkit/browser/fileapi/file_system_url.h173
-rw-r--r--webkit/browser/fileapi/file_system_url_request_job.cc2
-rw-r--r--webkit/browser/fileapi/file_system_url_request_job.h2
-rw-r--r--webkit/browser/fileapi/file_system_url_request_job_unittest.cc4
-rw-r--r--webkit/browser/fileapi/file_system_url_unittest.cc195
-rw-r--r--webkit/browser/fileapi/file_writer_delegate.cc253
-rw-r--r--webkit/browser/fileapi/file_writer_delegate.h106
-rw-r--r--webkit/browser/fileapi/file_writer_delegate_unittest.cc465
-rw-r--r--webkit/browser/fileapi/isolated_context.cc2
-rw-r--r--webkit/browser/fileapi/isolated_context_unittest.cc2
-rw-r--r--webkit/browser/fileapi/isolated_file_util.cc6
-rw-r--r--webkit/browser/fileapi/isolated_file_util_unittest.cc8
-rw-r--r--webkit/browser/fileapi/isolated_mount_point_provider.cc10
-rw-r--r--webkit/browser/fileapi/local_file_stream_writer.cc230
-rw-r--r--webkit/browser/fileapi/local_file_stream_writer.h89
-rw-r--r--webkit/browser/fileapi/local_file_stream_writer_unittest.cc156
-rw-r--r--webkit/browser/fileapi/local_file_system_cross_operation_unittest.cc10
-rw-r--r--webkit/browser/fileapi/local_file_system_operation.cc12
-rw-r--r--webkit/browser/fileapi/local_file_system_operation.h6
-rw-r--r--webkit/browser/fileapi/local_file_system_operation_unittest.cc8
-rw-r--r--webkit/browser/fileapi/local_file_system_operation_write_unittest.cc6
-rw-r--r--webkit/browser/fileapi/local_file_util.cc6
-rw-r--r--webkit/browser/fileapi/local_file_util_unittest.cc6
-rw-r--r--webkit/browser/fileapi/mock_file_change_observer.h2
-rw-r--r--webkit/browser/fileapi/mock_file_system_context.cc4
-rw-r--r--webkit/browser/fileapi/mock_file_system_options.h2
-rw-r--r--webkit/browser/fileapi/native_file_util.cc2
-rw-r--r--webkit/browser/fileapi/obfuscated_file_util.cc6
-rw-r--r--webkit/browser/fileapi/obfuscated_file_util.h2
-rw-r--r--webkit/browser/fileapi/obfuscated_file_util_unittest.cc10
-rw-r--r--webkit/browser/fileapi/recursive_operation_delegate.cc4
-rw-r--r--webkit/browser/fileapi/recursive_operation_delegate.h4
-rw-r--r--webkit/browser/fileapi/remote_file_system_proxy.h150
-rw-r--r--webkit/browser/fileapi/remove_operation_delegate.cc87
-rw-r--r--webkit/browser/fileapi/remove_operation_delegate.h50
-rw-r--r--webkit/browser/fileapi/sandbox_file_stream_writer.cc6
-rw-r--r--webkit/browser/fileapi/sandbox_file_stream_writer.h4
-rw-r--r--webkit/browser/fileapi/sandbox_file_system_test_helper.cc153
-rw-r--r--webkit/browser/fileapi/sandbox_file_system_test_helper.h100
-rw-r--r--webkit/browser/fileapi/sandbox_mount_point_provider.cc10
-rw-r--r--webkit/browser/fileapi/sandbox_mount_point_provider.h2
-rw-r--r--webkit/browser/fileapi/sandbox_mount_point_provider_unittest.cc2
-rw-r--r--webkit/browser/fileapi/sandbox_quota_observer.cc2
-rw-r--r--webkit/browser/fileapi/sandbox_quota_observer.h2
-rw-r--r--webkit/browser/fileapi/test_file_set.cc76
-rw-r--r--webkit/browser/fileapi/test_file_set.h41
-rw-r--r--webkit/browser/fileapi/test_mount_point_provider.cc203
-rw-r--r--webkit/browser/fileapi/test_mount_point_provider.h104
-rw-r--r--webkit/browser/fileapi/transient_file_util.cc4
-rw-r--r--webkit/browser/fileapi/transient_file_util_unittest.cc4
-rw-r--r--webkit/browser/fileapi/upload_file_system_file_element_reader.cc115
-rw-r--r--webkit/browser/fileapi/upload_file_system_file_element_reader.h64
-rw-r--r--webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc284
-rw-r--r--webkit/browser/fileapi/webkit_browser_fileapi.gypi41
85 files changed, 6910 insertions, 102 deletions
diff --git a/webkit/browser/fileapi/async_file_test_helper.cc b/webkit/browser/fileapi/async_file_test_helper.cc
new file mode 100644
index 0000000..b71e9e5
--- /dev/null
+++ b/webkit/browser/fileapi/async_file_test_helper.cc
@@ -0,0 +1,235 @@
+// Copyright (c) 2013 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 "base/bind.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/quota/quota_manager.h"
+
+namespace fileapi {
+
+namespace {
+
+typedef FileSystemOperation::FileEntryList FileEntryList;
+
+void AssignAndQuit(base::RunLoop* run_loop,
+ base::PlatformFileError* result_out,
+ base::PlatformFileError result) {
+ *result_out = result;
+ run_loop->Quit();
+}
+
+base::Callback<void(base::PlatformFileError)>
+AssignAndQuitCallback(base::RunLoop* run_loop,
+ base::PlatformFileError* result) {
+ return base::Bind(&AssignAndQuit, run_loop, base::Unretained(result));
+}
+
+void GetMetadataCallback(base::RunLoop* run_loop,
+ base::PlatformFileError* result_out,
+ base::PlatformFileInfo* file_info_out,
+ base::FilePath* platform_path_out,
+ base::PlatformFileError result,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path) {
+ *result_out = result;
+ if (file_info_out)
+ *file_info_out = file_info;
+ if (platform_path_out)
+ *platform_path_out = platform_path;
+ run_loop->Quit();
+}
+
+void ReadDirectoryCallback(base::RunLoop* run_loop,
+ base::PlatformFileError* result_out,
+ FileEntryList* entries_out,
+ base::PlatformFileError result,
+ const FileEntryList& entries,
+ bool has_more) {
+ *result_out = result;
+ *entries_out = entries;
+ if (result != base::PLATFORM_FILE_OK || !has_more)
+ run_loop->Quit();
+}
+
+void DidGetUsageAndQuota(quota::QuotaStatusCode* status_out,
+ int64* usage_out,
+ int64* quota_out,
+ quota::QuotaStatusCode status,
+ int64 usage,
+ int64 quota) {
+ if (status_out)
+ *status_out = status;
+ if (usage_out)
+ *usage_out = usage;
+ if (quota_out)
+ *quota_out = quota;
+}
+
+} // namespace
+
+const int64 AsyncFileTestHelper::kDontCheckSize = -1;
+
+base::PlatformFileError AsyncFileTestHelper::Copy(
+ FileSystemContext* context,
+ const FileSystemURL& src,
+ const FileSystemURL& dest) {
+ DCHECK(context);
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(dest, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ base::RunLoop run_loop;
+ operation->Copy(src, dest, AssignAndQuitCallback(&run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::Move(
+ FileSystemContext* context,
+ const FileSystemURL& src,
+ const FileSystemURL& dest) {
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(dest, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ base::RunLoop run_loop;
+ operation->Move(src, dest, AssignAndQuitCallback(&run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::Remove(
+ FileSystemContext* context,
+ const FileSystemURL& url,
+ bool recursive) {
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(url, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ base::RunLoop run_loop;
+ operation->Remove(url, recursive, AssignAndQuitCallback(&run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::ReadDirectory(
+ FileSystemContext* context,
+ const FileSystemURL& url,
+ FileEntryList* entries) {
+ DCHECK(entries);
+ entries->clear();
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(url, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::RunLoop run_loop;
+ operation->ReadDirectory(
+ url, base::Bind(&ReadDirectoryCallback, &run_loop, &result, entries));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::CreateDirectory(
+ FileSystemContext* context,
+ const FileSystemURL& url) {
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(url, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ base::RunLoop run_loop;
+ operation->CreateDirectory(url,
+ false /* exclusive */,
+ false /* recursive */,
+ AssignAndQuitCallback(&run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::CreateFile(
+ FileSystemContext* context,
+ const FileSystemURL& url) {
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(url, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::RunLoop run_loop;
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ operation->CreateFile(url, false /* exclusive */,
+ AssignAndQuitCallback(&run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::TruncateFile(
+ FileSystemContext* context,
+ const FileSystemURL& url,
+ size_t size) {
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(url, NULL);
+ EXPECT_TRUE(operation != NULL);
+ base::RunLoop run_loop;
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ operation->Truncate(url, size,
+ AssignAndQuitCallback(&run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+base::PlatformFileError AsyncFileTestHelper::GetMetadata(
+ FileSystemContext* context,
+ const FileSystemURL& url,
+ base::PlatformFileInfo* file_info,
+ base::FilePath* platform_path) {
+ base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+ base::RunLoop run_loop;
+ FileSystemOperation* operation =
+ context->CreateFileSystemOperation(url, NULL);
+ EXPECT_TRUE(operation != NULL);
+ operation->GetMetadata(url, base::Bind(&GetMetadataCallback,
+ &run_loop, &result,
+ file_info, platform_path));
+ run_loop.Run();
+ return result;
+}
+
+bool AsyncFileTestHelper::FileExists(
+ FileSystemContext* context,
+ const FileSystemURL& url,
+ int64 expected_size) {
+ base::PlatformFileInfo file_info;
+ base::PlatformFileError result = GetMetadata(context, url, &file_info, NULL);
+ if (result != base::PLATFORM_FILE_OK || file_info.is_directory)
+ return false;
+ return expected_size == kDontCheckSize || file_info.size == expected_size;
+}
+
+bool AsyncFileTestHelper::DirectoryExists(
+ FileSystemContext* context,
+ const FileSystemURL& url) {
+ base::PlatformFileInfo file_info;
+ base::PlatformFileError result = GetMetadata(context, url, &file_info, NULL);
+ return (result == base::PLATFORM_FILE_OK) && file_info.is_directory;
+}
+
+quota::QuotaStatusCode AsyncFileTestHelper::GetUsageAndQuota(
+ quota::QuotaManager* quota_manager,
+ const GURL& origin,
+ FileSystemType type,
+ int64* usage,
+ int64* quota) {
+ quota::QuotaStatusCode status = quota::kQuotaStatusUnknown;
+ quota_manager->GetUsageAndQuota(
+ origin,
+ FileSystemTypeToQuotaStorageType(type),
+ base::Bind(&DidGetUsageAndQuota, &status, usage, quota));
+ base::MessageLoop::current()->RunUntilIdle();
+ return status;
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/async_file_test_helper.h b/webkit/browser/fileapi/async_file_test_helper.h
new file mode 100644
index 0000000..8e400a4
--- /dev/null
+++ b/webkit/browser/fileapi/async_file_test_helper.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 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 WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_TEST_HELPER_H_
+#define WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_TEST_HELPER_H_
+
+#include "base/basictypes.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/quota/quota_status_code.h"
+
+namespace quota {
+class QuotaManager;
+}
+
+namespace fileapi {
+
+class FileSystemContext;
+class FileSystemURL;
+
+// A helper class to perform async file operations in a synchronous way.
+class AsyncFileTestHelper {
+ public:
+ typedef FileSystemOperation::FileEntryList FileEntryList;
+
+ static const int64 kDontCheckSize;
+
+ // Performs Copy from |src| to |dest| and returns the status code.
+ static base::PlatformFileError Copy(FileSystemContext* context,
+ const FileSystemURL& src,
+ const FileSystemURL& dest);
+
+ // Performs Move from |src| to |dest| and returns the status code.
+ static base::PlatformFileError Move(FileSystemContext* context,
+ const FileSystemURL& src,
+ const FileSystemURL& dest);
+
+ // Removes the given |url|.
+ static base::PlatformFileError Remove(FileSystemContext* context,
+ const FileSystemURL& url,
+ bool recursive);
+
+ // Performs ReadDirectory on |url|.
+ static base::PlatformFileError ReadDirectory(FileSystemContext* context,
+ const FileSystemURL& url,
+ FileEntryList* entries);
+
+ // Creates a directory at |url|.
+ static base::PlatformFileError CreateDirectory(FileSystemContext* context,
+ const FileSystemURL& url);
+
+ // Creates a file at |url|.
+ static base::PlatformFileError CreateFile(FileSystemContext* context,
+ const FileSystemURL& url);
+
+ // Truncates the file |url| to |size|.
+ static base::PlatformFileError TruncateFile(FileSystemContext* context,
+ const FileSystemURL& url,
+ size_t size);
+
+ // Retrieves PlatformFileInfo for |url| and populates |file_info|.
+ static base::PlatformFileError GetMetadata(FileSystemContext* context,
+ const FileSystemURL& url,
+ base::PlatformFileInfo* file_info,
+ base::FilePath* platform_path);
+
+ // Returns true if a file exists at |url| with |size|. If |size| is
+ // kDontCheckSize it doesn't check the file size (but just check its
+ // existence).
+ static bool FileExists(FileSystemContext* context,
+ const FileSystemURL& url,
+ int64 size);
+
+ // Returns true if a directory exists at |url|.
+ static bool DirectoryExists(FileSystemContext* context,
+ const FileSystemURL& url);
+
+ // Returns usage and quota. It's valid to pass NULL to |usage| and/or |quota|.
+ static quota::QuotaStatusCode GetUsageAndQuota(
+ quota::QuotaManager* quota_manager,
+ const GURL& origin,
+ FileSystemType type,
+ int64* usage,
+ int64* quota);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_TEST_HELPER_H_
diff --git a/webkit/browser/fileapi/async_file_util.h b/webkit/browser/fileapi/async_file_util.h
new file mode 100644
index 0000000..190e69b
--- /dev/null
+++ b/webkit/browser/fileapi/async_file_util.h
@@ -0,0 +1,338 @@
+// Copyright (c) 2013 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 WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_UTIL_H_
+#define WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_UTIL_H_
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/files/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "webkit/fileapi/directory_entry.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace base {
+class Time;
+}
+
+namespace webkit_blob {
+class ShareableFileReference;
+}
+
+namespace fileapi {
+
+class FileSystemOperationContext;
+class FileSystemURL;
+
+// An interface which provides filesystem-specific file operations for
+// LocalFileSystemOperation.
+//
+// Each filesystem which needs to be dispatched from LocalFileSystemOperation
+// must implement this interface or a synchronous version of interface:
+// FileSystemFileUtil.
+//
+class WEBKIT_STORAGE_EXPORT AsyncFileUtil {
+ public:
+ typedef base::Callback<
+ void(base::PlatformFileError result)> StatusCallback;
+
+ typedef base::FileUtilProxy::CreateOrOpenCallback CreateOrOpenCallback;
+
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ bool created)> EnsureFileExistsCallback;
+
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path)> GetFileInfoCallback;
+
+ typedef std::vector<DirectoryEntry> EntryList;
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ const EntryList& file_list,
+ bool has_more)> ReadDirectoryCallback;
+
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path,
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref
+ )> CreateSnapshotFileCallback;
+
+ AsyncFileUtil() {}
+ virtual ~AsyncFileUtil() {}
+
+ // Creates or opens a file with the given flags.
+ // If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to create
+ // a new file at the given |url| and calls back with
+ // PLATFORM_FILE_ERROR_FILE_EXISTS if the |url| already exists.
+ //
+ // LocalFileSystemOperation::OpenFile calls this.
+ // This is used only by Pepper/NaCL File API.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ virtual bool CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int file_flags,
+ const CreateOrOpenCallback& callback) = 0;
+
+ // Ensures that the given |url| exist. This creates a empty new file
+ // at |url| if the |url| does not exist.
+ //
+ // LocalFileSystemOperation::CreateFile calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_OK and created==true if a file has not existed and
+ // is created at |url|.
+ // - PLATFORM_FILE_OK and created==false if the file already exists.
+ // - Other error code (with created=false) if a file hasn't existed yet
+ // and there was an error while creating a new file.
+ //
+ virtual bool EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const EnsureFileExistsCallback& callback) = 0;
+
+ // Creates directory at given url.
+ //
+ // LocalFileSystemOperation::CreateDirectory calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if the |url|'s parent directory
+ // does not exist and |recursive| is false.
+ // - PLATFORM_FILE_ERROR_EXISTS if a directory already exists at |url|
+ // and |exclusive| is true.
+ // - PLATFORM_FILE_ERROR_EXISTS if a file already exists at |url|
+ // (regardless of |exclusive| value).
+ // - Other error code if it failed to create a directory.
+ //
+ virtual bool CreateDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ bool exclusive,
+ bool recursive,
+ const StatusCallback& callback) = 0;
+
+ // Retrieves the information about a file.
+ //
+ // LocalFileSystemOperation::GetMetadata calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if the file doesn't exist.
+ // - Other error code if there was an error while retrieving the file info.
+ //
+ virtual bool GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const GetFileInfoCallback& callback) = 0;
+
+ // Reads contents of a directory at |path|.
+ //
+ // LocalFileSystemOperation::ReadDirectory calls this.
+ //
+ // Note that the |name| field of each entry in |file_list|
+ // returned by |callback| should have a base file name
+ // of the entry relative to the directory, but not an absolute path.
+ //
+ // (E.g. if ReadDirectory is called for a directory
+ // 'path/to/dir' and the directory has entries 'a' and 'b',
+ // the returned |file_list| should include entries whose names
+ // are 'a' and 'b', but not '/path/to/dir/a' and '/path/to/dir/b'.)
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if the target directory doesn't exist.
+ // - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY if an entry exists at |url| but
+ // is a file (not a directory).
+ //
+ virtual bool ReadDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const ReadDirectoryCallback& callback) = 0;
+
+ // Modifies timestamps of a file or directory at |url| with
+ // |last_access_time| and |last_modified_time|. The function DOES NOT
+ // create a file unlike 'touch' command on Linux.
+ //
+ // LocalFileSystemOperation::TouchFile calls this.
+ // This is used only by Pepper/NaCL File API.
+ //
+ // This returns false if it fails to post an async task.
+ virtual bool Touch(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) = 0;
+
+ // Truncates a file at |path| to |length|. If |length| is larger than
+ // the original file size, the file will be extended, and the extended
+ // part is filled with null bytes.
+ //
+ // LocalFileSystemOperation::Truncate calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if the file doesn't exist.
+ //
+ virtual bool Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int64 length,
+ const StatusCallback& callback) = 0;
+
+ // Copies a file from |src_url| to |dest_url|.
+ // This must be called for files that belong to the same filesystem
+ // (i.e. type() and origin() of the |src_url| and |dest_url| must match).
+ //
+ // LocalFileSystemOperation::Copy calls this for same-filesystem copy case.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url|
+ // or the parent directory of |dest_url| does not exist.
+ // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file.
+ // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
+ // is not a file.
+ // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and
+ // its parent path is a file.
+ //
+ virtual bool CopyFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) = 0;
+
+ // Moves a local file from |src_url| to |dest_url|.
+ // This must be called for files that belong to the same filesystem
+ // (i.e. type() and origin() of the |src_url| and |dest_url| must match).
+ //
+ // LocalFileSystemOperation::Move calls this for same-filesystem move case.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url|
+ // or the parent directory of |dest_url| does not exist.
+ // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file.
+ // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
+ // is not a file.
+ // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and
+ // its parent path is a file.
+ //
+ virtual bool MoveFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) = 0;
+
+ // Copies in a single file from a different filesystem.
+ //
+ // LocalFileSystemOperation::Copy or Move calls this for cross-filesystem
+ // cases.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_file_path|
+ // or the parent directory of |dest_url| does not exist.
+ // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
+ // is not a file.
+ // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and
+ // its parent path is a file.
+ //
+ virtual bool CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) = 0;
+
+ // Deletes a single file.
+ //
+ // LocalFileSystemOperation::RemoveFile calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist.
+ // - PLATFORM_FILE_ERROR_NOT_A_FILE if |url| is not a file.
+ //
+ virtual bool DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) = 0;
+
+ // Removes a single empty directory.
+ //
+ // LocalFileSystemOperation::RemoveDirectory calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist.
+ // - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY if |url| is not a directory.
+ // - PLATFORM_FILE_ERROR_NOT_EMPTY if |url| is not empty.
+ //
+ virtual bool DeleteDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) = 0;
+
+ // Creates a local snapshot file for a given |url| and returns the
+ // metadata and platform path of the snapshot file via |callback|.
+ // In regular filesystem cases the implementation may simply return
+ // the metadata of the file itself (as well as GetMetadata does),
+ // while in non-regular filesystem case the backend may create a
+ // temporary snapshot file which holds the file data and return
+ // the metadata of the temporary file.
+ //
+ // In the callback, it returns:
+ // |file_info| is the metadata of the snapshot file created.
+ // |platform_path| is the full absolute platform path to the snapshot
+ // file created. If a file is not backed by a real local file in
+ // the implementor's FileSystem, the implementor must create a
+ // local snapshot file and return the path of the created file.
+ //
+ // If implementors creates a temporary file for snapshotting and wants
+ // FileAPI backend to take care of the lifetime of the file (so that
+ // it won't get deleted while JS layer has any references to the created
+ // File/Blob object), it should return non-empty |file_ref|.
+ // Via the |file_ref| implementors can schedule a file deletion
+ // or arbitrary callbacks when the last reference of File/Blob is dropped.
+ //
+ // LocalFileSystemOperation::CreateSnapshotFile calls this.
+ //
+ // This returns false if it fails to post an async task.
+ //
+ // This reports following error code via |callback|:
+ // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist.
+ // - PLATFORM_FILE_ERROR_NOT_A_FILE if |url| exists but is a directory.
+ //
+ // The field values of |file_info| are undefined (implementation
+ // dependent) in error cases, and the caller should always
+ // check the return code.
+ virtual bool CreateSnapshotFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const CreateSnapshotFileCallback& callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncFileUtil);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_UTIL_H_
diff --git a/webkit/browser/fileapi/async_file_util_adapter.cc b/webkit/browser/fileapi/async_file_util_adapter.cc
new file mode 100644
index 0000000..5046bbe
--- /dev/null
+++ b/webkit/browser/fileapi/async_file_util_adapter.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2013 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 "webkit/browser/fileapi/async_file_util_adapter.h"
+
+#include "base/bind.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_runner_util.h"
+#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/fileapi/file_system_util.h"
+
+using base::Bind;
+using base::Callback;
+using base::Owned;
+using base::PlatformFileError;
+using base::Unretained;
+using webkit_blob::ShareableFileReference;
+
+namespace fileapi {
+
+namespace {
+
+class EnsureFileExistsHelper {
+ public:
+ EnsureFileExistsHelper() : error_(base::PLATFORM_FILE_OK), created_(false) {}
+
+ void RunWork(FileSystemFileUtil* file_util,
+ FileSystemOperationContext* context,
+ const FileSystemURL& url) {
+ error_ = file_util->EnsureFileExists(context, url, &created_);
+ }
+
+ void Reply(const AsyncFileUtil::EnsureFileExistsCallback& callback) {
+ if (!callback.is_null())
+ callback.Run(error_, created_);
+ }
+
+ private:
+ base::PlatformFileError error_;
+ bool created_;
+ DISALLOW_COPY_AND_ASSIGN(EnsureFileExistsHelper);
+};
+
+class GetFileInfoHelper {
+ public:
+ GetFileInfoHelper()
+ : error_(base::PLATFORM_FILE_OK) {}
+
+ void GetFileInfo(FileSystemFileUtil* file_util,
+ FileSystemOperationContext* context,
+ const FileSystemURL& url) {
+ error_ = file_util->GetFileInfo(context, url, &file_info_, &platform_path_);
+ }
+
+ void CreateSnapshotFile(FileSystemFileUtil* file_util,
+ FileSystemOperationContext* context,
+ const FileSystemURL& url) {
+ scoped_file_ = file_util->CreateSnapshotFile(
+ context, url, &error_, &file_info_, &platform_path_);
+ }
+
+ void ReplyFileInfo(const AsyncFileUtil::GetFileInfoCallback& callback) {
+ if (!callback.is_null())
+ callback.Run(error_, file_info_, platform_path_);
+ }
+
+ void ReplySnapshotFile(
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback) {
+ if (!callback.is_null())
+ callback.Run(error_, file_info_, platform_path_,
+ ShareableFileReference::GetOrCreate(scoped_file_.Pass()));
+ }
+
+ private:
+ base::PlatformFileError error_;
+ base::PlatformFileInfo file_info_;
+ base::FilePath platform_path_;
+ webkit_blob::ScopedFile scoped_file_;
+ DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
+};
+
+class ReadDirectoryHelper {
+ public:
+ ReadDirectoryHelper() : error_(base::PLATFORM_FILE_OK) {}
+
+ void RunWork(FileSystemFileUtil* file_util,
+ FileSystemOperationContext* context,
+ const FileSystemURL& url) {
+ base::PlatformFileInfo file_info;
+ base::FilePath platform_path;
+ PlatformFileError error = file_util->GetFileInfo(
+ context, url, &file_info, &platform_path);
+ if (error != base::PLATFORM_FILE_OK) {
+ error_ = error;
+ return;
+ }
+ if (!file_info.is_directory) {
+ error_ = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+ return;
+ }
+
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
+ file_util->CreateFileEnumerator(context, url));
+
+ base::FilePath current;
+ while (!(current = file_enum->Next()).empty()) {
+ DirectoryEntry entry;
+ entry.is_directory = file_enum->IsDirectory();
+ entry.name = VirtualPath::BaseName(current).value();
+ entry.size = file_enum->Size();
+ entry.last_modified_time = file_enum->LastModifiedTime();
+ entries_.push_back(entry);
+ }
+ error_ = base::PLATFORM_FILE_OK;
+ }
+
+ void Reply(const AsyncFileUtil::ReadDirectoryCallback& callback) {
+ if (!callback.is_null())
+ callback.Run(error_, entries_, false /* has_more */);
+ }
+
+ private:
+ base::PlatformFileError error_;
+ std::vector<DirectoryEntry> entries_;
+ DISALLOW_COPY_AND_ASSIGN(ReadDirectoryHelper);
+};
+
+} // namespace
+
+AsyncFileUtilAdapter::AsyncFileUtilAdapter(
+ FileSystemFileUtil* sync_file_util)
+ : sync_file_util_(sync_file_util) {
+ DCHECK(sync_file_util_.get());
+}
+
+AsyncFileUtilAdapter::~AsyncFileUtilAdapter() {
+}
+
+bool AsyncFileUtilAdapter::CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int file_flags,
+ const CreateOrOpenCallback& callback) {
+ return base::FileUtilProxy::RelayCreateOrOpen(
+ context->task_runner(),
+ Bind(&FileSystemFileUtil::CreateOrOpen, Unretained(sync_file_util_.get()),
+ context, url, file_flags),
+ Bind(&FileSystemFileUtil::Close, Unretained(sync_file_util_.get()),
+ context),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const EnsureFileExistsCallback& callback) {
+ EnsureFileExistsHelper* helper = new EnsureFileExistsHelper;
+ return context->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ Bind(&EnsureFileExistsHelper::RunWork, Unretained(helper),
+ sync_file_util_.get(), context, url),
+ Bind(&EnsureFileExistsHelper::Reply, Owned(helper), callback));
+}
+
+bool AsyncFileUtilAdapter::CreateDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ bool exclusive,
+ bool recursive,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::CreateDirectory,
+ Unretained(sync_file_util_.get()),
+ context, url, exclusive, recursive),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const GetFileInfoCallback& callback) {
+ GetFileInfoHelper* helper = new GetFileInfoHelper;
+ return context->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ Bind(&GetFileInfoHelper::GetFileInfo, Unretained(helper),
+ sync_file_util_.get(), context, url),
+ Bind(&GetFileInfoHelper::ReplyFileInfo, Owned(helper), callback));
+}
+
+bool AsyncFileUtilAdapter::ReadDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const ReadDirectoryCallback& callback) {
+ ReadDirectoryHelper* helper = new ReadDirectoryHelper;
+ return context->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ Bind(&ReadDirectoryHelper::RunWork, Unretained(helper),
+ sync_file_util_.get(), context, url),
+ Bind(&ReadDirectoryHelper::Reply, Owned(helper), callback));
+}
+
+bool AsyncFileUtilAdapter::Touch(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::Touch, Unretained(sync_file_util_.get()),
+ context, url, last_access_time, last_modified_time),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int64 length,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::Truncate, Unretained(sync_file_util_.get()),
+ context, url, length),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::CopyFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::CopyOrMoveFile,
+ Unretained(sync_file_util_.get()),
+ context, src_url, dest_url, true /* copy */),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::MoveFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::CopyOrMoveFile,
+ Unretained(sync_file_util_.get()),
+ context, src_url, dest_url, false /* copy */),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::CopyInForeignFile,
+ Unretained(sync_file_util_.get()),
+ context, src_file_path, dest_url),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::DeleteFile,
+ Unretained(sync_file_util_.get()), context, url),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::DeleteDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) {
+ return base::PostTaskAndReplyWithResult(
+ context->task_runner(), FROM_HERE,
+ Bind(&FileSystemFileUtil::DeleteDirectory,
+ Unretained(sync_file_util_.get()),
+ context, url),
+ callback);
+}
+
+bool AsyncFileUtilAdapter::CreateSnapshotFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const CreateSnapshotFileCallback& callback) {
+ GetFileInfoHelper* helper = new GetFileInfoHelper;
+ return context->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ Bind(&GetFileInfoHelper::CreateSnapshotFile, Unretained(helper),
+ sync_file_util_.get(), context, url),
+ Bind(&GetFileInfoHelper::ReplySnapshotFile, Owned(helper), callback));
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/async_file_util_adapter.h b/webkit/browser/fileapi/async_file_util_adapter.h
new file mode 100644
index 0000000..3a85028
--- /dev/null
+++ b/webkit/browser/fileapi/async_file_util_adapter.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2013 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 WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_UTIL_ADAPTER_H_
+#define WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_UTIL_ADAPTER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "webkit/browser/fileapi/async_file_util.h"
+
+namespace fileapi {
+
+class FileSystemFileUtil;
+
+// An adapter class for FileSystemFileUtil classes to provide asynchronous
+// interface.
+//
+// A filesystem can do either:
+// - implement a synchronous version of FileUtil by extending
+// FileSystemFileUtil and atach it to this adapter, or
+// - directly implement AsyncFileUtil.
+//
+class WEBKIT_STORAGE_EXPORT_PRIVATE AsyncFileUtilAdapter
+ : public AsyncFileUtil {
+ public:
+ // Creates a new AsyncFileUtil for |sync_file_util|. This takes the
+ // ownership of |sync_file_util|. (This doesn't take scoped_ptr<> just
+ // to save extra make_scoped_ptr; in all use cases a new fresh FileUtil is
+ // created only for this adapter.)
+ explicit AsyncFileUtilAdapter(FileSystemFileUtil* sync_file_util);
+
+ virtual ~AsyncFileUtilAdapter();
+
+ FileSystemFileUtil* sync_file_util() {
+ return sync_file_util_.get();
+ }
+
+ // AsyncFileUtil overrides.
+ virtual bool CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int file_flags,
+ const CreateOrOpenCallback& callback) OVERRIDE;
+ virtual bool EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const EnsureFileExistsCallback& callback) OVERRIDE;
+ virtual bool CreateDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ bool exclusive,
+ bool recursive,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const GetFileInfoCallback& callback) OVERRIDE;
+ virtual bool ReadDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const ReadDirectoryCallback& callback) OVERRIDE;
+ virtual bool Touch(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int64 length,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool CopyFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool MoveFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool DeleteDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool CreateSnapshotFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const CreateSnapshotFileCallback& callback) OVERRIDE;
+
+ private:
+ scoped_ptr<FileSystemFileUtil> sync_file_util_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncFileUtilAdapter);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_ASYNC_FILE_UTIL_ADAPTER_H_
diff --git a/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc b/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc
index 383b7ef..9f12178 100644
--- a/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc
+++ b/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc
@@ -8,16 +8,16 @@
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
-#include "webkit/fileapi/async_file_test_helper.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/test_mount_point_provider.h"
#include "webkit/fileapi/file_system_util.h"
-#include "webkit/fileapi/test_mount_point_provider.h"
#include "webkit/quota/mock_special_storage_policy.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/cross_operation_delegate.cc b/webkit/browser/fileapi/cross_operation_delegate.cc
index 7c1c7d6..f0b74b8 100644
--- a/webkit/browser/fileapi/cross_operation_delegate.cc
+++ b/webkit/browser/fileapi/cross_operation_delegate.cc
@@ -8,10 +8,10 @@
#include "base/files/file_path.h"
#include "webkit/blob/shareable_file_reference.h"
#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/local_file_system_operation.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/dump_file_system.cc b/webkit/browser/fileapi/dump_file_system.cc
new file mode 100644
index 0000000..452dc5f
--- /dev/null
+++ b/webkit/browser/fileapi/dump_file_system.cc
@@ -0,0 +1,205 @@
+// Copyright (c) 2013 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.
+//
+// A tool to dump HTML5 filesystem from CUI.
+//
+// Usage:
+//
+// ./out/Release/dump_file_system [options] <filesystem dir> [origin]...
+//
+// If no origin is specified, this dumps all origins in the profile dir.
+//
+// Available options:
+//
+// -t : dumps temporary files instead of persistent.
+// -s : dumps syncable files instead of persistent.
+// -l : more information will be displayed.
+//
+// The format of -l option is:
+//
+// === ORIGIN origin_name origin_dir ===
+// file_name file_id file_size file_content_path
+// ...
+//
+// where file_name has a trailing slash, file_size is the number of
+// children, and file_content_path is empty if the file is a directory.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/format_macros.h"
+#include "base/stringprintf.h"
+#include "webkit/browser/fileapi/obfuscated_file_util.h"
+#include "webkit/browser/fileapi/sandbox_directory_database.h"
+#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
+#include "webkit/browser/fileapi/sandbox_origin_database.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+
+namespace {
+
+bool g_opt_long;
+fileapi::FileSystemType g_opt_fs_type = fileapi::kFileSystemTypePersistent;
+
+void ShowMessageAndExit(const std::string& msg) {
+ fprintf(stderr, "%s\n", msg.c_str());
+ exit(EXIT_FAILURE);
+}
+
+void ShowUsageAndExit(const std::string& arg0) {
+ ShowMessageAndExit(
+ "Usage: " + arg0 +
+ " [-l] [-t] [-s] <filesystem dir> [origin]...");
+}
+
+} // namespace
+
+namespace fileapi {
+
+static void DumpDirectoryTree(const std::string& origin_name,
+ base::FilePath origin_dir) {
+ origin_dir = origin_dir.Append(
+ ObfuscatedFileUtil::GetDirectoryNameForType(g_opt_fs_type));
+
+ printf("=== ORIGIN %s %s ===\n",
+ origin_name.c_str(), FilePathToString(origin_dir).c_str());
+
+ if (!file_util::DirectoryExists(origin_dir))
+ return;
+
+ SandboxDirectoryDatabase directory_db(origin_dir);
+ SandboxDirectoryDatabase::FileId root_id;
+ if (!directory_db.GetFileWithPath(StringToFilePath("/"), &root_id))
+ return;
+
+ std::stack<std::pair<SandboxDirectoryDatabase::FileId,
+ std::string> > paths;
+ paths.push(std::make_pair(root_id, ""));
+ while (!paths.empty()) {
+ SandboxDirectoryDatabase::FileId id = paths.top().first;
+ const std::string dirname = paths.top().second;
+ paths.pop();
+
+ SandboxDirectoryDatabase::FileInfo info;
+ if (!directory_db.GetFileInfo(id, &info)) {
+ ShowMessageAndExit(base::StringPrintf("GetFileInfo failed for %"PRId64,
+ id));
+ }
+
+ const std::string name =
+ dirname + "/" + FilePathToString(base::FilePath(info.name));
+ std::vector<SandboxDirectoryDatabase::FileId> children;
+ if (info.is_directory()) {
+ if (!directory_db.ListChildren(id, &children)) {
+ ShowMessageAndExit(base::StringPrintf(
+ "ListChildren failed for %s (%"PRId64")",
+ info.name.c_str(), id));
+ }
+
+ for (size_t j = children.size(); j; j--)
+ paths.push(make_pair(children[j-1], name));
+ }
+
+ // +1 for the leading extra slash.
+ const char* display_name = name.c_str() + 1;
+ const char* directory_suffix = info.is_directory() ? "/" : "";
+ if (g_opt_long) {
+ int64 size;
+ if (info.is_directory()) {
+ size = static_cast<int64>(children.size());
+ } else {
+ file_util::GetFileSize(origin_dir.Append(info.data_path), &size);
+ }
+ // TODO(hamaji): Modification time?
+ printf("%s%s %"PRId64" %"PRId64" %s\n",
+ display_name,
+ directory_suffix,
+ id,
+ size,
+ FilePathToString(info.data_path).c_str());
+ } else {
+ printf("%s%s\n", display_name, directory_suffix);
+ }
+ }
+}
+
+static void DumpOrigin(const base::FilePath& file_system_dir,
+ const std::string& origin_name) {
+ SandboxOriginDatabase origin_db(file_system_dir);
+ base::FilePath origin_dir;
+ if (!origin_db.HasOriginPath(origin_name)) {
+ ShowMessageAndExit("Origin " + origin_name + " is not in " +
+ FilePathToString(file_system_dir));
+ }
+
+ if (!origin_db.GetPathForOrigin(origin_name, &origin_dir)) {
+ ShowMessageAndExit("Failed to get path of origin " + origin_name +
+ " in " + FilePathToString(file_system_dir));
+ }
+ DumpDirectoryTree(origin_name, file_system_dir.Append(origin_dir));
+}
+
+static void DumpFileSystem(const base::FilePath& file_system_dir) {
+ SandboxOriginDatabase origin_db(file_system_dir);
+ std::vector<SandboxOriginDatabase::OriginRecord> origins;
+ origin_db.ListAllOrigins(&origins);
+ for (size_t i = 0; i < origins.size(); i++) {
+ const SandboxOriginDatabase::OriginRecord& origin = origins[i];
+ DumpDirectoryTree(origin.origin, file_system_dir.Append(origin.path));
+ puts("");
+ }
+}
+
+} // namespace fileapi
+
+int main(int argc, char* argv[]) {
+ const char* arg0 = argv[0];
+ std::string username = "Default";
+ while (true) {
+ if (argc < 2)
+ ShowUsageAndExit(arg0);
+
+ if (std::string(argv[1]) == "-l") {
+ g_opt_long = true;
+ argc--;
+ argv++;
+ } else if (std::string(argv[1]) == "-t") {
+ g_opt_fs_type = fileapi::kFileSystemTypeTemporary;
+ argc--;
+ argv++;
+ } else if (std::string(argv[1]) == "-s") {
+ g_opt_fs_type = fileapi::kFileSystemTypeSyncable;
+ argc--;
+ argv++;
+ } else {
+ break;
+ }
+ }
+
+ if (argc < 2)
+ ShowUsageAndExit(arg0);
+
+ const base::FilePath file_system_dir = fileapi::StringToFilePath(argv[1]);
+ if (!file_util::DirectoryExists(file_system_dir)) {
+ ShowMessageAndExit(fileapi::FilePathToString(file_system_dir) +
+ " is not a filesystem directory");
+ }
+
+ if (argc == 2) {
+ fileapi::DumpFileSystem(file_system_dir);
+ } else {
+ for (int i = 2; i < argc; i++) {
+ fileapi::DumpOrigin(file_system_dir, argv[i]);
+ }
+ }
+ return 0;
+}
diff --git a/webkit/browser/fileapi/external_mount_points.cc b/webkit/browser/fileapi/external_mount_points.cc
index 5dddfe3..269c09e 100644
--- a/webkit/browser/fileapi/external_mount_points.cc
+++ b/webkit/browser/fileapi/external_mount_points.cc
@@ -8,8 +8,8 @@
#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/stl_util.h"
-#include "webkit/fileapi/file_system_url.h"
-#include "webkit/fileapi/remote_file_system_proxy.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/remote_file_system_proxy.h"
namespace {
diff --git a/webkit/browser/fileapi/external_mount_points_unittest.cc b/webkit/browser/fileapi/external_mount_points_unittest.cc
index 8dad0f7..cc2acbe 100644
--- a/webkit/browser/fileapi/external_mount_points_unittest.cc
+++ b/webkit/browser/fileapi/external_mount_points_unittest.cc
@@ -8,7 +8,7 @@
#include "base/files/file_path.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#define FPL FILE_PATH_LITERAL
diff --git a/webkit/browser/fileapi/file_permission_policy.cc b/webkit/browser/fileapi/file_permission_policy.cc
new file mode 100644
index 0000000..1645487
--- /dev/null
+++ b/webkit/browser/fileapi/file_permission_policy.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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 "webkit/browser/fileapi/file_permission_policy.h"
+
+#include "base/platform_file.h"
+
+namespace fileapi {
+
+const int kReadFilePermissions = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_EXCLUSIVE_READ |
+ base::PLATFORM_FILE_ASYNC;
+
+const int kWriteFilePermissions = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_EXCLUSIVE_WRITE |
+ base::PLATFORM_FILE_ASYNC |
+ base::PLATFORM_FILE_WRITE_ATTRIBUTES;
+
+const int kCreateFilePermissions = base::PLATFORM_FILE_CREATE;
+
+const int kOpenFilePermissions = base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_OPEN_ALWAYS |
+ base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_OPEN_TRUNCATED |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_EXCLUSIVE_WRITE |
+ base::PLATFORM_FILE_DELETE_ON_CLOSE |
+ base::PLATFORM_FILE_WRITE_ATTRIBUTES;
+
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_permission_policy.h b/webkit/browser/fileapi/file_permission_policy.h
new file mode 100644
index 0000000..baecbb1
--- /dev/null
+++ b/webkit/browser/fileapi/file_permission_policy.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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 WEBKIT_BROWSER_FILEAPI_FILE_PERMISSION_POLICY_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_PERMISSION_POLICY_H_
+
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace fileapi {
+
+WEBKIT_STORAGE_EXPORT extern const int kReadFilePermissions;
+WEBKIT_STORAGE_EXPORT extern const int kWriteFilePermissions;
+WEBKIT_STORAGE_EXPORT extern const int kCreateFilePermissions;
+WEBKIT_STORAGE_EXPORT extern const int kOpenFilePermissions;
+
+enum FilePermissionPolicy {
+ // Any access should be always denied.
+ FILE_PERMISSION_ALWAYS_DENY,
+
+ // Any access should be always allowed. (This should be used only for
+ // access to sandbox directories.)
+ FILE_PERMISSION_ALWAYS_ALLOW,
+
+ // Access should be examined by per-file permission policy.
+ FILE_PERMISSION_USE_FILE_PERMISSION,
+
+ // Access should be examined by per-filesystem permission policy.
+ FILE_PERMISSION_USE_FILESYSTEM_PERMISSION,
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_PERMISSION_POLICY_H_
diff --git a/webkit/browser/fileapi/file_stream_writer.h b/webkit/browser/fileapi/file_stream_writer.h
new file mode 100644
index 0000000..fe79a24
--- /dev/null
+++ b/webkit/browser/fileapi/file_stream_writer.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_STREAM_WRITER_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_STREAM_WRITER_H_
+
+#include "base/basictypes.h"
+#include "net/base/completion_callback.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace fileapi {
+
+// A generic interface for writing to a file-like object.
+class WEBKIT_STORAGE_EXPORT_PRIVATE FileStreamWriter {
+ public:
+ // Closes the file. If there's an in-flight operation, it is canceled (i.e.,
+ // the callback function associated with the operation is not called).
+ virtual ~FileStreamWriter() {}
+
+ // Writes to the current cursor position asynchronously.
+ //
+ // Up to buf_len bytes will be written. (In other words, partial
+ // writes are allowed.) If the write completed synchronously, it returns
+ // the number of bytes written. If the operation could not be performed, it
+ // returns an error code. Otherwise, net::ERR_IO_PENDING is returned, and the
+ // callback will be run on the thread where Write() was called when the write
+ // has completed.
+ //
+ // This errors out (either synchronously or via callback) with:
+ // net::ERR_FILE_NOT_FOUND: When the target file is not found.
+ // net::ERR_ACCESS_DENIED: When the target file is a directory or
+ // the writer has no permission on the file.
+ // net::ERR_FILE_NO_SPACE: When the write will result in out of quota
+ // or there is not enough room left on the disk.
+ //
+ // It is invalid to call Write while there is an in-flight async operation.
+ virtual int Write(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) = 0;
+
+ // Cancels an in-flight async operation.
+ //
+ // If the cancel is finished synchronously, it returns net::OK. If the
+ // cancel could not be performed, it returns an error code. Especially when
+ // there is no in-flight operation, net::ERR_UNEXPECTED is returned.
+ // Otherwise, net::ERR_IO_PENDING is returned, and the callback will be run on
+ // the thread where Cancel() was called when the cancel has completed. It is
+ // invalid to call Cancel() more than once on the same async operation.
+ //
+ // In either case, the callback function passed to the in-flight async
+ // operation is dismissed immediately when Cancel() is called, and thus
+ // will never be called.
+ virtual int Cancel(const net::CompletionCallback& callback) = 0;
+
+ // Flushes the data written so far.
+ //
+ // If the flush finished synchronously, it return net::OK. If the flush could
+ // not be performed, it returns an error code. Otherwise, net::ERR_IO_PENDING
+ // is returned, and the callback will be run on the thread where Flush() was
+ // called when the flush has completed.
+ //
+ // It is invalid to call Flush while there is an in-flight async operation.
+ virtual int Flush(const net::CompletionCallback& callback) = 0;
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_STREAM_WRITER_H_
diff --git a/webkit/browser/fileapi/file_system_context.cc b/webkit/browser/fileapi/file_system_context.cc
new file mode 100644
index 0000000..a8c42aa
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_context.cc
@@ -0,0 +1,421 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_context.h"
+
+#include "base/bind.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/blob/file_stream_reader.h"
+#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_stream_writer.h"
+#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_options.h"
+#include "webkit/browser/fileapi/file_system_quota_client.h"
+#include "webkit/browser/fileapi/file_system_task_runners.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/fileapi/isolated_mount_point_provider.h"
+#include "webkit/browser/fileapi/mount_points.h"
+#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
+#include "webkit/browser/fileapi/test_mount_point_provider.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/syncable/local_file_change_tracker.h"
+#include "webkit/fileapi/syncable/local_file_sync_context.h"
+#include "webkit/fileapi/syncable/syncable_file_system_util.h"
+#include "webkit/quota/quota_manager.h"
+#include "webkit/quota/special_storage_policy.h"
+
+#if defined(OS_CHROMEOS)
+#include "webkit/chromeos/fileapi/cros_mount_point_provider.h"
+#endif
+
+using quota::QuotaClient;
+
+namespace fileapi {
+
+namespace {
+
+QuotaClient* CreateQuotaClient(
+ FileSystemContext* context,
+ bool is_incognito) {
+ return new FileSystemQuotaClient(context, is_incognito);
+}
+
+void DidOpenFileSystem(
+ const FileSystemContext::OpenFileSystemCallback& callback,
+ const GURL& filesystem_root,
+ const std::string& filesystem_name,
+ base::PlatformFileError error) {
+ callback.Run(error, filesystem_name, filesystem_root);
+}
+
+} // namespace
+
+FileSystemContext::FileSystemContext(
+ scoped_ptr<FileSystemTaskRunners> task_runners,
+ ExternalMountPoints* external_mount_points,
+ quota::SpecialStoragePolicy* special_storage_policy,
+ quota::QuotaManagerProxy* quota_manager_proxy,
+ ScopedVector<FileSystemMountPointProvider> additional_providers,
+ const base::FilePath& partition_path,
+ const FileSystemOptions& options)
+ : task_runners_(task_runners.Pass()),
+ quota_manager_proxy_(quota_manager_proxy),
+ sandbox_provider_(
+ new SandboxMountPointProvider(
+ quota_manager_proxy,
+ task_runners_->file_task_runner(),
+ partition_path,
+ options,
+ special_storage_policy)),
+ isolated_provider_(new IsolatedMountPointProvider()),
+ additional_providers_(additional_providers.Pass()),
+ external_mount_points_(external_mount_points),
+ partition_path_(partition_path) {
+ DCHECK(task_runners_.get());
+
+ if (quota_manager_proxy) {
+ quota_manager_proxy->RegisterClient(CreateQuotaClient(
+ this, options.is_incognito()));
+ }
+
+ RegisterMountPointProvider(sandbox_provider_.get());
+ RegisterMountPointProvider(isolated_provider_.get());
+
+#if defined(OS_CHROMEOS)
+ // TODO(kinuko): Move this out of webkit/fileapi layer.
+ DCHECK(external_mount_points);
+ external_provider_.reset(
+ new chromeos::CrosMountPointProvider(
+ special_storage_policy,
+ external_mount_points,
+ ExternalMountPoints::GetSystemInstance()));
+ RegisterMountPointProvider(external_provider_.get());
+#endif
+
+ for (ScopedVector<FileSystemMountPointProvider>::const_iterator iter =
+ additional_providers_.begin();
+ iter != additional_providers_.end(); ++iter) {
+ RegisterMountPointProvider(*iter);
+ }
+
+ // Additional mount points must be added before regular system-wide
+ // mount points.
+ if (external_mount_points)
+ url_crackers_.push_back(external_mount_points);
+ url_crackers_.push_back(ExternalMountPoints::GetSystemInstance());
+ url_crackers_.push_back(IsolatedContext::GetInstance());
+}
+
+bool FileSystemContext::DeleteDataForOriginOnFileThread(
+ const GURL& origin_url) {
+ DCHECK(task_runners_->file_task_runner()->RunsTasksOnCurrentThread());
+ DCHECK(sandbox_provider());
+ DCHECK(origin_url == origin_url.GetOrigin());
+
+ // Delete temporary and persistent data.
+ return
+ (sandbox_provider()->DeleteOriginDataOnFileThread(
+ this, quota_manager_proxy(), origin_url,
+ kFileSystemTypeTemporary) ==
+ base::PLATFORM_FILE_OK) &&
+ (sandbox_provider()->DeleteOriginDataOnFileThread(
+ this, quota_manager_proxy(), origin_url,
+ kFileSystemTypePersistent) ==
+ base::PLATFORM_FILE_OK) &&
+ (sandbox_provider()->DeleteOriginDataOnFileThread(
+ this, quota_manager_proxy(), origin_url,
+ kFileSystemTypeSyncable) ==
+ base::PLATFORM_FILE_OK);
+}
+
+FileSystemQuotaUtil*
+FileSystemContext::GetQuotaUtil(FileSystemType type) const {
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ if (!mount_point_provider)
+ return NULL;
+ return mount_point_provider->GetQuotaUtil();
+}
+
+AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
+ FileSystemType type) const {
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ if (!mount_point_provider)
+ return NULL;
+ return mount_point_provider->GetAsyncFileUtil(type);
+}
+
+FileSystemFileUtil* FileSystemContext::GetFileUtil(
+ FileSystemType type) const {
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ if (!mount_point_provider)
+ return NULL;
+ return mount_point_provider->GetFileUtil(type);
+}
+
+CopyOrMoveFileValidatorFactory*
+FileSystemContext::GetCopyOrMoveFileValidatorFactory(
+ FileSystemType type, base::PlatformFileError* error_code) const {
+ DCHECK(error_code);
+ *error_code = base::PLATFORM_FILE_OK;
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ if (!mount_point_provider)
+ return NULL;
+ return mount_point_provider->GetCopyOrMoveFileValidatorFactory(
+ type, error_code);
+}
+
+FileSystemMountPointProvider* FileSystemContext::GetMountPointProvider(
+ FileSystemType type) const {
+ MountPointProviderMap::const_iterator found = provider_map_.find(type);
+ if (found != provider_map_.end())
+ return found->second;
+ NOTREACHED() << "Unknown filesystem type: " << type;
+ return NULL;
+}
+
+const UpdateObserverList* FileSystemContext::GetUpdateObservers(
+ FileSystemType type) const {
+ // Currently update observer is only available in SandboxMountPointProvider
+ // and TestMountPointProvider.
+ // TODO(kinuko): Probably GetUpdateObservers() virtual method should be
+ // added to FileSystemMountPointProvider interface and be called like
+ // other GetFoo() methods do.
+ if (SandboxMountPointProvider::IsSandboxType(type))
+ return sandbox_provider()->GetUpdateObservers(type);
+ if (type != kFileSystemTypeTest)
+ return NULL;
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ return static_cast<TestMountPointProvider*>(
+ mount_point_provider)->GetUpdateObservers(type);
+}
+
+SandboxMountPointProvider*
+FileSystemContext::sandbox_provider() const {
+ return sandbox_provider_.get();
+}
+
+ExternalFileSystemMountPointProvider*
+FileSystemContext::external_provider() const {
+ return external_provider_.get();
+}
+
+void FileSystemContext::OpenFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const OpenFileSystemCallback& callback) {
+ DCHECK(!callback.is_null());
+
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ if (!mount_point_provider) {
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, std::string(), GURL());
+ return;
+ }
+
+ GURL root_url = GetFileSystemRootURI(origin_url, type);
+ std::string name = GetFileSystemName(origin_url, type);
+
+ mount_point_provider->ValidateFileSystemRoot(
+ origin_url, type, create,
+ base::Bind(&DidOpenFileSystem, callback, root_url, name));
+}
+
+void FileSystemContext::OpenSyncableFileSystem(
+ const std::string& mount_name,
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const OpenFileSystemCallback& callback) {
+ DCHECK(!callback.is_null());
+
+ DCHECK(type == kFileSystemTypeSyncable);
+
+ GURL root_url = sync_file_system::GetSyncableFileSystemRootURI(
+ origin_url, mount_name);
+ std::string name = GetFileSystemName(origin_url, kFileSystemTypeSyncable);
+
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ DCHECK(mount_point_provider);
+ mount_point_provider->ValidateFileSystemRoot(
+ origin_url, type, create,
+ base::Bind(&DidOpenFileSystem, callback, root_url, name));
+}
+
+void FileSystemContext::DeleteFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ const DeleteFileSystemCallback& callback) {
+ DCHECK(origin_url == origin_url.GetOrigin());
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(type);
+ if (!mount_point_provider) {
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return;
+ }
+
+ mount_point_provider->DeleteFileSystem(origin_url, type, this, callback);
+}
+
+FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
+ const FileSystemURL& url, base::PlatformFileError* error_code) {
+ if (!url.is_valid()) {
+ if (error_code)
+ *error_code = base::PLATFORM_FILE_ERROR_INVALID_URL;
+ return NULL;
+ }
+
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(url.type());
+ if (!mount_point_provider) {
+ if (error_code)
+ *error_code = base::PLATFORM_FILE_ERROR_FAILED;
+ return NULL;
+ }
+
+ base::PlatformFileError fs_error = base::PLATFORM_FILE_OK;
+ FileSystemOperation* operation =
+ mount_point_provider->CreateFileSystemOperation(url, this, &fs_error);
+
+ if (error_code)
+ *error_code = fs_error;
+ return operation;
+}
+
+scoped_ptr<webkit_blob::FileStreamReader>
+FileSystemContext::CreateFileStreamReader(
+ const FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time) {
+ if (!url.is_valid())
+ return scoped_ptr<webkit_blob::FileStreamReader>();
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(url.type());
+ if (!mount_point_provider)
+ return scoped_ptr<webkit_blob::FileStreamReader>();
+ return mount_point_provider->CreateFileStreamReader(
+ url, offset, expected_modification_time, this);
+}
+
+scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(
+ const FileSystemURL& url,
+ int64 offset) {
+ if (!url.is_valid())
+ return scoped_ptr<FileStreamWriter>();
+ FileSystemMountPointProvider* mount_point_provider =
+ GetMountPointProvider(url.type());
+ if (!mount_point_provider)
+ return scoped_ptr<FileStreamWriter>();
+ return mount_point_provider->CreateFileStreamWriter(url, offset, this);
+}
+
+void FileSystemContext::SetLocalFileChangeTracker(
+ scoped_ptr<sync_file_system::LocalFileChangeTracker> tracker) {
+ DCHECK(!change_tracker_.get());
+ DCHECK(tracker.get());
+ change_tracker_ = tracker.Pass();
+ sandbox_provider_->AddSyncableFileUpdateObserver(
+ change_tracker_.get(),
+ task_runners_->file_task_runner());
+ sandbox_provider_->AddSyncableFileChangeObserver(
+ change_tracker_.get(),
+ task_runners_->file_task_runner());
+}
+
+void FileSystemContext::set_sync_context(
+ sync_file_system::LocalFileSyncContext* sync_context) {
+ sync_context_ = sync_context;
+}
+
+FileSystemURL FileSystemContext::CrackURL(const GURL& url) const {
+ return CrackFileSystemURL(FileSystemURL(url));
+}
+
+FileSystemURL FileSystemContext::CreateCrackedFileSystemURL(
+ const GURL& origin,
+ FileSystemType type,
+ const base::FilePath& path) const {
+ return CrackFileSystemURL(FileSystemURL(origin, type, path));
+}
+
+FileSystemContext::~FileSystemContext() {
+ task_runners_->file_task_runner()->DeleteSoon(
+ FROM_HERE, change_tracker_.release());
+}
+
+void FileSystemContext::DeleteOnCorrectThread() const {
+ if (!task_runners_->io_task_runner()->RunsTasksOnCurrentThread() &&
+ task_runners_->io_task_runner()->DeleteSoon(FROM_HERE, this)) {
+ return;
+ }
+ delete this;
+}
+
+FileSystemURL FileSystemContext::CrackFileSystemURL(
+ const FileSystemURL& url) const {
+ if (!url.is_valid())
+ return FileSystemURL();
+
+ // The returned value in case there is no crackers which can crack the url.
+ // This is valid situation for non isolated/external file systems.
+ FileSystemURL current = url;
+
+ // File system may be mounted multiple times (e.g., an isolated filesystem on
+ // top of an external filesystem). Hence cracking needs to be iterated.
+ for (;;) {
+ FileSystemURL cracked = current;
+ for (size_t i = 0; i < url_crackers_.size(); ++i) {
+ if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
+ continue;
+ cracked = url_crackers_[i]->CrackFileSystemURL(current);
+ if (cracked.is_valid())
+ break;
+ }
+ if (cracked == current)
+ break;
+ current = cracked;
+ }
+ return current;
+}
+
+void FileSystemContext::RegisterMountPointProvider(
+ FileSystemMountPointProvider* provider) {
+ const FileSystemType mount_types[] = {
+ kFileSystemTypeTemporary,
+ kFileSystemTypePersistent,
+ kFileSystemTypeIsolated,
+ kFileSystemTypeExternal,
+ };
+ // Register mount point providers for public mount types.
+ for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) {
+ if (provider->CanHandleType(mount_types[j])) {
+ const bool inserted = provider_map_.insert(
+ std::make_pair(mount_types[j], provider)).second;
+ DCHECK(inserted);
+ }
+ }
+ // Register mount point providers for internal types.
+ for (int t = kFileSystemInternalTypeEnumStart + 1;
+ t < kFileSystemInternalTypeEnumEnd; ++t) {
+ FileSystemType type = static_cast<FileSystemType>(t);
+ if (provider->CanHandleType(type)) {
+ const bool inserted = provider_map_.insert(
+ std::make_pair(type, provider)).second;
+ DCHECK(inserted);
+ }
+ }
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_context.h b/webkit/browser/fileapi/file_system_context.h
new file mode 100644
index 0000000..1c15e31
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_context.h
@@ -0,0 +1,309 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_CONTEXT_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_CONTEXT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/platform_file.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace chrome {
+class NativeMediaFileUtilTest;
+}
+
+namespace quota {
+class QuotaManagerProxy;
+class SpecialStoragePolicy;
+}
+
+namespace sync_file_system {
+class LocalFileChangeTracker;
+class LocalFileSyncContext;
+}
+
+namespace webkit_blob {
+class BlobURLRequestJobTest;
+class FileStreamReader;
+}
+
+namespace fileapi {
+
+class AsyncFileUtil;
+class CopyOrMoveFileValidatorFactory;
+class ExternalFileSystemMountPointProvider;
+class ExternalMountPoints;
+class FileStreamWriter;
+class FileSystemFileUtil;
+class FileSystemMountPointProvider;
+class FileSystemOperation;
+class FileSystemOptions;
+class FileSystemQuotaUtil;
+class FileSystemTaskRunners;
+class FileSystemURL;
+class IsolatedMountPointProvider;
+class MountPoints;
+class SandboxMountPointProvider;
+
+struct DefaultContextDeleter;
+
+// This class keeps and provides a file system context for FileSystem API.
+// An instance of this class is created and owned by profile.
+class WEBKIT_STORAGE_EXPORT FileSystemContext
+ : public base::RefCountedThreadSafe<FileSystemContext,
+ DefaultContextDeleter> {
+ public:
+ // task_runners->file_task_runner() is used as default TaskRunner.
+ // Unless a MountPointProvider is overridden in CreateFileSystemOperation,
+ // it is used for all file operations and file related meta operations.
+ // The code assumes that
+ // task_runners->file_task_runner()->RunsTasksOnCurrentThread()
+ // returns false if the current task is not running on the thread that allows
+ // blocking file operations (like SequencedWorkerPool implementation does).
+ //
+ // |external_mount_points| contains non-system external mount points available
+ // in the context. If not NULL, it will be used during URL cracking. On
+ // ChromeOS, it will be passed to external_mount_point_provider.
+ // |external_mount_points| may be NULL only on platforms different from
+ // ChromeOS (i.e. platforms that don't use external_mount_point_provider).
+ //
+ // |additional_providers| are added to the internal provider map
+ // to serve filesystem requests for non-regular types.
+ // If none is given, this context only handles HTML5 Sandbox FileSystem
+ // and Drag-and-drop Isolated FileSystem requests.
+ FileSystemContext(
+ scoped_ptr<FileSystemTaskRunners> task_runners,
+ ExternalMountPoints* external_mount_points,
+ quota::SpecialStoragePolicy* special_storage_policy,
+ quota::QuotaManagerProxy* quota_manager_proxy,
+ ScopedVector<FileSystemMountPointProvider> additional_providers,
+ const base::FilePath& partition_path,
+ const FileSystemOptions& options);
+
+ bool DeleteDataForOriginOnFileThread(const GURL& origin_url);
+
+ quota::QuotaManagerProxy* quota_manager_proxy() const {
+ return quota_manager_proxy_.get();
+ }
+
+ // Returns a quota util for a given filesystem type. This may
+ // return NULL if the type does not support the usage tracking or
+ // it is not a quota-managed storage.
+ FileSystemQuotaUtil* GetQuotaUtil(FileSystemType type) const;
+
+ // Returns the appropriate AsyncFileUtil instance for the given |type|.
+ AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) const;
+
+ // Returns the appropriate FileUtil instance for the given |type|.
+ // This may return NULL if it is given an invalid type or the filesystem
+ // does not support synchronous file operations.
+ FileSystemFileUtil* GetFileUtil(FileSystemType type) const;
+
+ // Returns the appropriate CopyOrMoveFileValidatorFactory for the given
+ // |type|. If |error_code| is PLATFORM_FILE_OK and the result is NULL,
+ // then no validator is required.
+ CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
+ FileSystemType type, base::PlatformFileError* error_code) const;
+
+ // Returns the mount point provider instance for the given |type|.
+ // This may return NULL if it is given an invalid or unsupported filesystem
+ // type.
+ FileSystemMountPointProvider* GetMountPointProvider(
+ FileSystemType type) const;
+
+ // Returns update observers for the given filesystem type.
+ const UpdateObserverList* GetUpdateObservers(FileSystemType type) const;
+
+ // Returns a FileSystemMountPointProvider instance for sandboxed filesystem
+ // types (e.g. TEMPORARY or PERSISTENT). This is equivalent to calling
+ // GetMountPointProvider(kFileSystemType{Temporary, Persistent}).
+ SandboxMountPointProvider* sandbox_provider() const;
+
+ // Returns a FileSystemMountPointProvider instance for external filesystem
+ // type, which is used only by chromeos for now. This is equivalent to
+ // calling GetMountPointProvider(kFileSystemTypeExternal).
+ ExternalFileSystemMountPointProvider* external_provider() const;
+
+ // Used for OpenFileSystem.
+ typedef base::Callback<void(base::PlatformFileError result,
+ const std::string& name,
+ const GURL& root)> OpenFileSystemCallback;
+
+ // Used for DeleteFileSystem.
+ typedef base::Callback<void(base::PlatformFileError result)>
+ DeleteFileSystemCallback;
+
+ // Opens the filesystem for the given |origin_url| and |type|, and dispatches
+ // |callback| on completion.
+ // If |create| is true this may actually set up a filesystem instance
+ // (e.g. by creating the root directory or initializing the database
+ // entry etc).
+ void OpenFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const OpenFileSystemCallback& callback);
+
+ // Opens a syncable filesystem for the given |origin_url|.
+ // The file system is internally mounted as an external file system at the
+ // given |mount_name|.
+ // Currently only kFileSystemTypeSyncable type is supported.
+ void OpenSyncableFileSystem(
+ const std::string& mount_name,
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const OpenFileSystemCallback& callback);
+
+ // Deletes the filesystem for the given |origin_url| and |type|. This should
+ // be called on the IO Thread.
+ void DeleteFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ const DeleteFileSystemCallback& callback);
+
+ // Creates a new FileSystemOperation instance by getting an appropriate
+ // MountPointProvider for |url| and calling the provider's corresponding
+ // CreateFileSystemOperation method.
+ // The resolved MountPointProvider could perform further specialization
+ // depending on the filesystem type pointed by the |url|.
+ FileSystemOperation* CreateFileSystemOperation(
+ const FileSystemURL& url,
+ base::PlatformFileError* error_code);
+
+ // Creates new FileStreamReader instance to read a file pointed by the given
+ // filesystem URL |url| starting from |offset|. |expected_modification_time|
+ // specifies the expected last modification if the value is non-null, the
+ // reader will check the underlying file's actual modification time to see if
+ // the file has been modified, and if it does any succeeding read operations
+ // should fail with ERR_UPLOAD_FILE_CHANGED error.
+ // This method internally cracks the |url|, get an appropriate
+ // MountPointProvider for the URL and call the provider's CreateFileReader.
+ // The resolved MountPointProvider could perform further specialization
+ // depending on the filesystem type pointed by the |url|.
+ scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+ const FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time);
+
+ // Creates new FileStreamWriter instance to write into a file pointed by
+ // |url| from |offset|.
+ scoped_ptr<FileStreamWriter> CreateFileStreamWriter(
+ const FileSystemURL& url,
+ int64 offset);
+
+ FileSystemTaskRunners* task_runners() { return task_runners_.get(); }
+
+ sync_file_system::LocalFileChangeTracker* change_tracker() {
+ return change_tracker_.get();
+ }
+ void SetLocalFileChangeTracker(
+ scoped_ptr<sync_file_system::LocalFileChangeTracker> tracker);
+
+ sync_file_system::LocalFileSyncContext* sync_context() {
+ return sync_context_.get();
+ }
+ void set_sync_context(sync_file_system::LocalFileSyncContext* sync_context);
+
+ const base::FilePath& partition_path() const { return partition_path_; }
+
+ // Same as |CrackFileSystemURL|, but cracks FileSystemURL created from |url|.
+ FileSystemURL CrackURL(const GURL& url) const;
+ // Same as |CrackFileSystemURL|, but cracks FileSystemURL created from method
+ // arguments.
+ FileSystemURL CreateCrackedFileSystemURL(const GURL& origin,
+ FileSystemType type,
+ const base::FilePath& path) const;
+
+ private:
+ typedef std::map<FileSystemType, FileSystemMountPointProvider*>
+ MountPointProviderMap;
+
+ // These classes know the target filesystem (i.e. sandbox filesystem)
+ // supports synchronous FileUtil.
+ friend class LocalFileSystemOperation;
+ friend class sync_file_system::LocalFileChangeTracker;
+ friend class sync_file_system::LocalFileSyncContext;
+
+ // Deleters.
+ friend struct DefaultContextDeleter;
+ friend class base::DeleteHelper<FileSystemContext>;
+ friend class base::RefCountedThreadSafe<FileSystemContext,
+ DefaultContextDeleter>;
+ ~FileSystemContext();
+
+ void DeleteOnCorrectThread() const;
+
+ // For non-cracked isolated and external mount points, returns a FileSystemURL
+ // created by cracking |url|. The url is cracked using MountPoints registered
+ // as |url_crackers_|. If the url cannot be cracked, returns invalid
+ // FileSystemURL.
+ //
+ // If the original url does not point to an isolated or external filesystem,
+ // returns the original url, without attempting to crack it.
+ FileSystemURL CrackFileSystemURL(const FileSystemURL& url) const;
+
+ // For initial provider_map construction. This must be called only from
+ // the constructor.
+ void RegisterMountPointProvider(FileSystemMountPointProvider* provider);
+
+ scoped_ptr<FileSystemTaskRunners> task_runners_;
+
+ scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
+
+ // Regular mount point providers.
+ scoped_ptr<SandboxMountPointProvider> sandbox_provider_;
+ scoped_ptr<IsolatedMountPointProvider> isolated_provider_;
+ scoped_ptr<ExternalFileSystemMountPointProvider> external_provider_;
+
+ // Additional mount point providers.
+ ScopedVector<FileSystemMountPointProvider> additional_providers_;
+
+ // Registered mount point providers.
+ // The map must be constructed in the constructor since it can be accessed
+ // on multiple threads.
+ // The ownership of each provider is held by mount_point_providers_.
+ MountPointProviderMap provider_map_;
+ // External mount points visible in the file system context (excluding system
+ // external mount points).
+ scoped_refptr<ExternalMountPoints> external_mount_points_;
+
+ // MountPoints used to crack FileSystemURLs. The MountPoints are ordered
+ // in order they should try to crack a FileSystemURL.
+ std::vector<MountPoints*> url_crackers_;
+
+ // The base path of the storage partition for this context.
+ const base::FilePath partition_path_;
+
+ // For syncable file systems.
+ scoped_ptr<sync_file_system::LocalFileChangeTracker> change_tracker_;
+ scoped_refptr<sync_file_system::LocalFileSyncContext> sync_context_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemContext);
+};
+
+struct DefaultContextDeleter {
+ static void Destruct(const FileSystemContext* context) {
+ context->DeleteOnCorrectThread();
+ }
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_CONTEXT_H_
diff --git a/webkit/browser/fileapi/file_system_context_unittest.cc b/webkit/browser/fileapi/file_system_context_unittest.cc
new file mode 100644
index 0000000..18ead11
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_context_unittest.cc
@@ -0,0 +1,329 @@
+// Copyright (c) 2013 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 "webkit/browser/fileapi/file_system_context.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop.h"
+#include "base/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_task_runners.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/fileapi/mock_file_system_options.h"
+#include "webkit/quota/mock_quota_manager.h"
+#include "webkit/quota/mock_special_storage_policy.h"
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+#define DRIVE FPL("C:")
+#else
+#define DRIVE
+#endif
+
+namespace fileapi {
+
+namespace {
+
+const char kTestOrigin[] = "http://chromium.org/";
+const base::FilePath::CharType kVirtualPathNoRoot[] = FPL("root/file");
+
+GURL CreateRawFileSystemURL(const std::string& type_str,
+ const std::string& fs_id) {
+ std::string url_str = base::StringPrintf(
+ "filesystem:http://chromium.org/%s/%s/root/file",
+ type_str.c_str(),
+ fs_id.c_str());
+ return GURL(url_str);
+}
+
+class FileSystemContextTest : public testing::Test {
+ public:
+ FileSystemContextTest() {}
+
+ virtual void SetUp() {
+ ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
+
+ storage_policy_ = new quota::MockSpecialStoragePolicy();
+
+ mock_quota_manager_ = new quota::MockQuotaManager(
+ false /* is_incognito */,
+ data_dir_.path(),
+ base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current(),
+ storage_policy_);
+ }
+
+ protected:
+ FileSystemContext* CreateFileSystemContextForTest(
+ ExternalMountPoints* external_mount_points) {
+ return new FileSystemContext(
+ FileSystemTaskRunners::CreateMockTaskRunners(),
+ external_mount_points,
+ storage_policy_,
+ mock_quota_manager_->proxy(),
+ ScopedVector<FileSystemMountPointProvider>(),
+ data_dir_.path(),
+ CreateAllowFileAccessOptions());
+ }
+
+ // Verifies a *valid* filesystem url has expected values.
+ void ExpectFileSystemURLMatches(const FileSystemURL& url,
+ const GURL& expect_origin,
+ FileSystemType expect_mount_type,
+ FileSystemType expect_type,
+ const base::FilePath& expect_path,
+ const base::FilePath& expect_virtual_path,
+ const std::string& expect_filesystem_id) {
+ EXPECT_TRUE(url.is_valid());
+
+ EXPECT_EQ(expect_origin, url.origin());
+ EXPECT_EQ(expect_mount_type, url.mount_type());
+ EXPECT_EQ(expect_type, url.type());
+ EXPECT_EQ(expect_path, url.path());
+ EXPECT_EQ(expect_virtual_path, url.virtual_path());
+ EXPECT_EQ(expect_filesystem_id, url.filesystem_id());
+ }
+
+ private:
+ base::ScopedTempDir data_dir_;
+ base::MessageLoop message_loop_;
+ scoped_refptr<quota::SpecialStoragePolicy> storage_policy_;
+ scoped_refptr<quota::MockQuotaManager> mock_quota_manager_;
+};
+
+// It is not valid to pass NULL ExternalMountPoints to FileSystemContext on
+// ChromeOS.
+#if !defined(OS_CHROMEOS)
+TEST_F(FileSystemContextTest, NullExternalMountPoints) {
+ scoped_refptr<FileSystemContext> file_system_context(
+ CreateFileSystemContextForTest(NULL));
+
+ // Cracking system external mount and isolated mount points should work.
+ std::string isolated_name = "root";
+ std::string isolated_id =
+ IsolatedContext::GetInstance()->RegisterFileSystemForPath(
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/isolated/root")),
+ &isolated_name);
+ // Register system external mount point.
+ ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+ "system",
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/sys/"))));
+
+ FileSystemURL cracked_isolated = file_system_context->CrackURL(
+ CreateRawFileSystemURL("isolated", isolated_id));
+
+ ExpectFileSystemURLMatches(
+ cracked_isolated,
+ GURL(kTestOrigin),
+ kFileSystemTypeIsolated,
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/isolated/root/file")).NormalizePathSeparators(),
+ base::FilePath::FromUTF8Unsafe(isolated_id).Append(FPL("root/file")).
+ NormalizePathSeparators(),
+ isolated_id);
+
+ FileSystemURL cracked_external = file_system_context->CrackURL(
+ CreateRawFileSystemURL("external", "system"));
+
+ ExpectFileSystemURLMatches(
+ cracked_external,
+ GURL(kTestOrigin),
+ kFileSystemTypeExternal,
+ kFileSystemTypeNativeLocal,
+ base::FilePath(
+ DRIVE FPL("/test/sys/root/file")).NormalizePathSeparators(),
+ base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
+ "system");
+
+
+ IsolatedContext::GetInstance()->RevokeFileSystem(isolated_id);
+ ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
+}
+#endif // !defiend(OS_CHROMEOS)
+
+TEST_F(FileSystemContextTest, FileSystemContextKeepsMountPointsAlive) {
+ scoped_refptr<ExternalMountPoints> mount_points =
+ ExternalMountPoints::CreateRefCounted();
+
+ // Register system external mount point.
+ ASSERT_TRUE(mount_points->RegisterFileSystem(
+ "system",
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/sys/"))));
+
+ scoped_refptr<FileSystemContext> file_system_context(
+ CreateFileSystemContextForTest(mount_points.get()));
+
+ // Release a MountPoints reference created in the test.
+ mount_points = NULL;
+
+ // FileSystemContext should keep a reference to the |mount_points|, so it
+ // should be able to resolve the URL.
+ FileSystemURL cracked_external = file_system_context->CrackURL(
+ CreateRawFileSystemURL("external", "system"));
+
+ ExpectFileSystemURLMatches(
+ cracked_external,
+ GURL(kTestOrigin),
+ kFileSystemTypeExternal,
+ kFileSystemTypeNativeLocal,
+ base::FilePath(
+ DRIVE FPL("/test/sys/root/file")).NormalizePathSeparators(),
+ base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
+ "system");
+
+ // No need to revoke the registered filesystem since |mount_points| lifetime
+ // is bound to this test.
+}
+
+TEST_F(FileSystemContextTest, CrackFileSystemURL) {
+ scoped_refptr<ExternalMountPoints> external_mount_points(
+ ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<FileSystemContext> file_system_context(
+ CreateFileSystemContextForTest(external_mount_points));
+
+ // Register an isolated mount point.
+ std::string isolated_file_system_name = "root";
+ const std::string kIsolatedFileSystemID =
+ IsolatedContext::GetInstance()->RegisterFileSystemForPath(
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/isolated/root")),
+ &isolated_file_system_name);
+ // Register system external mount point.
+ ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+ "system",
+ kFileSystemTypeDrive,
+ base::FilePath(DRIVE FPL("/test/sys/"))));
+ ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+ "ext",
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/ext"))));
+ // Register a system external mount point with the same name/id as the
+ // registered isolated mount point.
+ ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+ kIsolatedFileSystemID,
+ kFileSystemTypeRestrictedNativeLocal,
+ base::FilePath(DRIVE FPL("/test/system/isolated"))));
+ // Add a mount points with the same name as a system mount point to
+ // FileSystemContext's external mount points.
+ ASSERT_TRUE(external_mount_points->RegisterFileSystem(
+ "ext",
+ kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/local/ext/"))));
+
+ const GURL kTestOrigin = GURL("http://chromium.org/");
+ const base::FilePath kVirtualPathNoRoot = base::FilePath(FPL("root/file"));
+
+ struct TestCase {
+ // Test case values.
+ std::string root;
+ std::string type_str;
+
+ // Expected test results.
+ bool expect_is_valid;
+ FileSystemType expect_mount_type;
+ FileSystemType expect_type;
+ const base::FilePath::CharType* expect_path;
+ std::string expect_filesystem_id;
+ };
+
+ const TestCase kTestCases[] = {
+ // Following should not be handled by the url crackers:
+ {
+ "pers_mount", "persistent", true /* is_valid */,
+ kFileSystemTypePersistent, kFileSystemTypePersistent,
+ FPL("pers_mount/root/file"),
+ std::string() /* filesystem id */
+ },
+ {
+ "temp_mount", "temporary", true /* is_valid */,
+ kFileSystemTypeTemporary, kFileSystemTypeTemporary,
+ FPL("temp_mount/root/file"),
+ std::string() /* filesystem id */
+ },
+ // Should be cracked by isolated mount points:
+ {
+ kIsolatedFileSystemID, "isolated", true /* is_valid */,
+ kFileSystemTypeIsolated, kFileSystemTypeNativeLocal,
+ DRIVE FPL("/test/isolated/root/file"),
+ kIsolatedFileSystemID
+ },
+ // Should be cracked by system mount points:
+ {
+ "system", "external", true /* is_valid */,
+ kFileSystemTypeExternal, kFileSystemTypeDrive,
+ DRIVE FPL("/test/sys/root/file"),
+ "system"
+ },
+ {
+ kIsolatedFileSystemID, "external", true /* is_valid */,
+ kFileSystemTypeExternal, kFileSystemTypeRestrictedNativeLocal,
+ DRIVE FPL("/test/system/isolated/root/file"),
+ kIsolatedFileSystemID
+ },
+ // Should be cracked by FileSystemContext's ExternalMountPoints.
+ {
+ "ext", "external", true /* is_valid */,
+ kFileSystemTypeExternal, kFileSystemTypeNativeLocal,
+ DRIVE FPL("/test/local/ext/root/file"),
+ "ext"
+ },
+ // Test for invalid filesystem url (made invalid by adding invalid
+ // filesystem type).
+ {
+ "sytem", "external", false /* is_valid */,
+ // The rest of values will be ignored.
+ kFileSystemTypeUnknown, kFileSystemTypeUnknown, FPL(""),
+ std::string()
+ },
+ // Test for URL with non-existing filesystem id.
+ {
+ "invalid", "external", false /* is_valid */,
+ // The rest of values will be ignored.
+ kFileSystemTypeUnknown, kFileSystemTypeUnknown, FPL(""),
+ std::string()
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+ const base::FilePath virtual_path =
+ base::FilePath::FromUTF8Unsafe(kTestCases[i].root).Append(kVirtualPathNoRoot);
+
+ GURL raw_url =
+ CreateRawFileSystemURL(kTestCases[i].type_str, kTestCases[i].root);
+ FileSystemURL cracked_url = file_system_context->CrackURL(raw_url);
+
+ SCOPED_TRACE(testing::Message() << "Test case " << i << ": "
+ << "Cracking URL: " << raw_url);
+
+ EXPECT_EQ(kTestCases[i].expect_is_valid, cracked_url.is_valid());
+ if (!kTestCases[i].expect_is_valid)
+ continue;
+
+ ExpectFileSystemURLMatches(
+ cracked_url,
+ GURL(kTestOrigin),
+ kTestCases[i].expect_mount_type,
+ kTestCases[i].expect_type,
+ base::FilePath(kTestCases[i].expect_path).NormalizePathSeparators(),
+ virtual_path.NormalizePathSeparators(),
+ kTestCases[i].expect_filesystem_id);
+ }
+
+ IsolatedContext::GetInstance()->RevokeFileSystemByPath(
+ base::FilePath(DRIVE FPL("/test/isolated/root")));
+ ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
+ ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("ext");
+ ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ kIsolatedFileSystemID);
+}
+
+} // namespace
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_dir_url_request_job.cc b/webkit/browser/fileapi/file_system_dir_url_request_job.cc
index f94f99e..48a13c7 100644
--- a/webkit/browser/fileapi/file_system_dir_url_request_job.cc
+++ b/webkit/browser/fileapi/file_system_dir_url_request_job.cc
@@ -19,10 +19,10 @@
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/fileapi/directory_entry.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation.h"
-#include "webkit/fileapi/file_system_url.h"
using net::NetworkDelegate;
using net::URLRequest;
diff --git a/webkit/browser/fileapi/file_system_dir_url_request_job.h b/webkit/browser/fileapi/file_system_dir_url_request_job.h
index f3cae42..4811dd9 100644
--- a/webkit/browser/fileapi/file_system_dir_url_request_job.h
+++ b/webkit/browser/fileapi/file_system_dir_url_request_job.h
@@ -13,7 +13,7 @@
#include "base/message_loop_proxy.h"
#include "base/platform_file.h"
#include "net/url_request/url_request_job.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/storage/webkit_storage_export.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc
index 65b9492..7de553a 100644
--- a/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc
+++ b/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc
@@ -22,12 +22,12 @@
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/icu/public/i18n/unicode/regex.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/quota/mock_special_storage_policy.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/file_system_file_stream_reader.cc b/webkit/browser/fileapi/file_system_file_stream_reader.cc
new file mode 100644
index 0000000..29268a7
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_file_stream_reader.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_file_stream_reader.h"
+
+#include "base/files/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "base/single_thread_task_runner.h"
+#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "webkit/blob/local_file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_task_runners.h"
+
+using webkit_blob::LocalFileStreamReader;
+
+namespace fileapi {
+
+namespace {
+
+void ReadAdapter(base::WeakPtr<FileSystemFileStreamReader> reader,
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ if (!reader)
+ return;
+ int rv = reader->Read(buf, buf_len, callback);
+ if (rv != net::ERR_IO_PENDING)
+ callback.Run(rv);
+}
+
+void GetLengthAdapter(base::WeakPtr<FileSystemFileStreamReader> reader,
+ const net::Int64CompletionCallback& callback) {
+ if (!reader)
+ return;
+ int rv = reader->GetLength(callback);
+ if (rv != net::ERR_IO_PENDING)
+ callback.Run(rv);
+}
+
+void Int64CallbackAdapter(const net::Int64CompletionCallback& callback,
+ int value) {
+ callback.Run(value);
+}
+
+} // namespace
+
+FileSystemFileStreamReader::FileSystemFileStreamReader(
+ FileSystemContext* file_system_context,
+ const FileSystemURL& url,
+ int64 initial_offset,
+ const base::Time& expected_modification_time)
+ : file_system_context_(file_system_context),
+ url_(url),
+ initial_offset_(initial_offset),
+ expected_modification_time_(expected_modification_time),
+ has_pending_create_snapshot_(false),
+ weak_factory_(this) {
+}
+
+FileSystemFileStreamReader::~FileSystemFileStreamReader() {
+}
+
+int FileSystemFileStreamReader::Read(
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ if (local_file_reader_)
+ return local_file_reader_->Read(buf, buf_len, callback);
+ return CreateSnapshot(
+ base::Bind(&ReadAdapter, weak_factory_.GetWeakPtr(),
+ make_scoped_refptr(buf), buf_len, callback),
+ callback);
+}
+
+int64 FileSystemFileStreamReader::GetLength(
+ const net::Int64CompletionCallback& callback) {
+ if (local_file_reader_)
+ return local_file_reader_->GetLength(callback);
+ return CreateSnapshot(
+ base::Bind(&GetLengthAdapter, weak_factory_.GetWeakPtr(), callback),
+ base::Bind(&Int64CallbackAdapter, callback));
+}
+
+int FileSystemFileStreamReader::CreateSnapshot(
+ const base::Closure& callback,
+ const net::CompletionCallback& error_callback) {
+ DCHECK(!has_pending_create_snapshot_);
+ base::PlatformFileError error_code;
+ FileSystemOperation* operation =
+ file_system_context_->CreateFileSystemOperation(url_, &error_code);
+ if (error_code != base::PLATFORM_FILE_OK)
+ return net::PlatformFileErrorToNetError(error_code);
+ has_pending_create_snapshot_ = true;
+ operation->CreateSnapshotFile(
+ url_,
+ base::Bind(&FileSystemFileStreamReader::DidCreateSnapshot,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ return net::ERR_IO_PENDING;
+}
+
+void FileSystemFileStreamReader::DidCreateSnapshot(
+ const base::Closure& callback,
+ const net::CompletionCallback& error_callback,
+ base::PlatformFileError file_error,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path,
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
+ DCHECK(has_pending_create_snapshot_);
+ DCHECK(!local_file_reader_.get());
+ has_pending_create_snapshot_ = false;
+
+ if (file_error != base::PLATFORM_FILE_OK) {
+ error_callback.Run(net::PlatformFileErrorToNetError(file_error));
+ return;
+ }
+
+ // Keep the reference (if it's non-null) so that the file won't go away.
+ snapshot_ref_ = file_ref;
+
+ local_file_reader_.reset(
+ new LocalFileStreamReader(
+ file_system_context_->task_runners()->file_task_runner(),
+ platform_path, initial_offset_, expected_modification_time_));
+
+ callback.Run();
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_file_stream_reader.h b/webkit/browser/fileapi/file_system_file_stream_reader.h
new file mode 100644
index 0000000..5a2fc9a
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_file_stream_reader.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_FILE_STREAM_READER_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_FILE_STREAM_READER_H_
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/platform_file.h"
+#include "base/time.h"
+#include "webkit/blob/file_stream_reader.h"
+#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace base {
+class FilePath;
+class SequencedTaskRunner;
+}
+
+namespace webkit_blob {
+class LocalFileStreamReader;
+}
+
+namespace fileapi {
+
+class FileSystemContext;
+
+// TODO(kinaba,satorux): This generic implementation would work for any
+// filesystems but remote filesystem should implement its own reader
+// rather than relying on FileSystemOperation::GetSnapshotFile() which
+// may force downloading the entire contents for remote files.
+class WEBKIT_STORAGE_EXPORT_PRIVATE FileSystemFileStreamReader
+ : public webkit_blob::FileStreamReader {
+ public:
+ // Creates a new FileReader for a filesystem URL |url| form |initial_offset|.
+ // |expected_modification_time| specifies the expected last modification if
+ // the value is non-null, the reader will check the underlying file's actual
+ // modification time to see if the file has been modified, and if it does any
+ // succeeding read operations should fail with ERR_UPLOAD_FILE_CHANGED error.
+ FileSystemFileStreamReader(FileSystemContext* file_system_context,
+ const FileSystemURL& url,
+ int64 initial_offset,
+ const base::Time& expected_modification_time);
+ virtual ~FileSystemFileStreamReader();
+
+ // FileStreamReader overrides.
+ virtual int Read(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual int64 GetLength(
+ const net::Int64CompletionCallback& callback) OVERRIDE;
+
+ private:
+ int CreateSnapshot(const base::Closure& callback,
+ const net::CompletionCallback& error_callback);
+ void DidCreateSnapshot(
+ const base::Closure& callback,
+ const net::CompletionCallback& error_callback,
+ base::PlatformFileError file_error,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path,
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref);
+
+ scoped_refptr<FileSystemContext> file_system_context_;
+ FileSystemURL url_;
+ const int64 initial_offset_;
+ const base::Time expected_modification_time_;
+ scoped_ptr<webkit_blob::LocalFileStreamReader> local_file_reader_;
+ scoped_refptr<webkit_blob::ShareableFileReference> snapshot_ref_;
+ bool has_pending_create_snapshot_;
+ base::WeakPtrFactory<FileSystemFileStreamReader> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileSystemFileStreamReader);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_FILE_STREAM_READER_H_
diff --git a/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc b/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc
new file mode 100644
index 0000000..466acda
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_file_stream_reader.h"
+
+#include <limits>
+#include <string>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/platform_file.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/mock_file_system_context.h"
+#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
+
+namespace fileapi {
+
+namespace {
+
+const char kURLOrigin[] = "http://remote/";
+const char kTestFileName[] = "test.dat";
+const char kTestData[] = "0123456789";
+const int kTestDataSize = arraysize(kTestData) - 1;
+
+void ReadFromReader(FileSystemFileStreamReader* reader,
+ std::string* data,
+ size_t size,
+ int* result) {
+ ASSERT_TRUE(reader != NULL);
+ ASSERT_TRUE(result != NULL);
+ *result = net::OK;
+ net::TestCompletionCallback callback;
+ size_t total_bytes_read = 0;
+ while (total_bytes_read < size) {
+ scoped_refptr<net::IOBufferWithSize> buf(
+ new net::IOBufferWithSize(size - total_bytes_read));
+ int rv = reader->Read(buf, buf->size(), callback.callback());
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ if (rv < 0)
+ *result = rv;
+ if (rv <= 0)
+ break;
+ total_bytes_read += rv;
+ data->append(buf->data(), rv);
+ }
+}
+
+void NeverCalled(int unused) { ADD_FAILURE(); }
+
+} // namespace
+
+class FileSystemFileStreamReaderTest : public testing::Test {
+ public:
+ FileSystemFileStreamReaderTest()
+ : message_loop_(base::MessageLoop::TYPE_IO) {}
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ file_system_context_ = CreateFileSystemContextForTesting(
+ NULL, temp_dir_.path());
+
+ file_system_context_->sandbox_provider()->ValidateFileSystemRoot(
+ GURL(kURLOrigin), kFileSystemTypeTemporary, true, // create
+ base::Bind(&OnValidateFileSystem));
+ base::MessageLoop::current()->RunUntilIdle();
+
+ WriteFile(kTestFileName, kTestData, kTestDataSize,
+ &test_file_modification_time_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
+ protected:
+ FileSystemFileStreamReader* CreateFileReader(
+ const std::string& file_name,
+ int64 initial_offset,
+ const base::Time& expected_modification_time) {
+ return new FileSystemFileStreamReader(file_system_context_,
+ GetFileSystemURL(file_name),
+ initial_offset,
+ expected_modification_time);
+ }
+
+ base::Time test_file_modification_time() const {
+ return test_file_modification_time_;
+ }
+
+ void WriteFile(const std::string& file_name,
+ const char* buf,
+ int buf_size,
+ base::Time* modification_time) {
+ FileSystemFileUtil* file_util = file_system_context_->
+ sandbox_provider()->GetFileUtil(kFileSystemTypeTemporary);
+ FileSystemURL url = GetFileSystemURL(file_name);
+
+ FileSystemOperationContext context(file_system_context_);
+ context.set_allowed_bytes_growth(1024);
+
+ base::PlatformFile handle = base::kInvalidPlatformFileValue;
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen(
+ &context,
+ url,
+ base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
+ &handle,
+ &created));
+ EXPECT_TRUE(created);
+ ASSERT_NE(base::kInvalidPlatformFileValue, handle);
+ ASSERT_EQ(buf_size,
+ base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size));
+ base::ClosePlatformFile(handle);
+
+ base::PlatformFileInfo file_info;
+ base::FilePath platform_path;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ file_util->GetFileInfo(&context, url, &file_info,
+ &platform_path));
+ if (modification_time)
+ *modification_time = file_info.last_modified;
+ }
+
+ private:
+ static void OnValidateFileSystem(base::PlatformFileError result) {
+ ASSERT_EQ(base::PLATFORM_FILE_OK, result);
+ }
+
+ FileSystemURL GetFileSystemURL(const std::string& file_name) {
+ return file_system_context_->CreateCrackedFileSystemURL(
+ GURL(kURLOrigin),
+ kFileSystemTypeTemporary,
+ base::FilePath().AppendASCII(file_name));
+ }
+
+ base::MessageLoop message_loop_;
+ base::ScopedTempDir temp_dir_;
+ scoped_refptr<FileSystemContext> file_system_context_;
+ base::Time test_file_modification_time_;
+};
+
+TEST_F(FileSystemFileStreamReaderTest, NonExistent) {
+ const char kFileName[] = "nonexistent";
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kFileName, 0, base::Time()));
+ int result = 0;
+ std::string data;
+ ReadFromReader(reader.get(), &data, 10, &result);
+ ASSERT_EQ(net::ERR_FILE_NOT_FOUND, result);
+ ASSERT_EQ(0U, data.size());
+}
+
+TEST_F(FileSystemFileStreamReaderTest, Empty) {
+ const char kFileName[] = "empty";
+ WriteFile(kFileName, NULL, 0, NULL);
+
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kFileName, 0, base::Time()));
+ int result = 0;
+ std::string data;
+ ReadFromReader(reader.get(), &data, 10, &result);
+ ASSERT_EQ(net::OK, result);
+ ASSERT_EQ(0U, data.size());
+
+ net::TestInt64CompletionCallback callback;
+ int64 length_result = reader->GetLength(callback.callback());
+ if (length_result == net::ERR_IO_PENDING)
+ length_result = callback.WaitForResult();
+ ASSERT_EQ(0, length_result);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, GetLengthNormal) {
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 0, test_file_modification_time()));
+ net::TestInt64CompletionCallback callback;
+ int64 result = reader->GetLength(callback.callback());
+ if (result == net::ERR_IO_PENDING)
+ result = callback.WaitForResult();
+ ASSERT_EQ(kTestDataSize, result);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, GetLengthAfterModified) {
+ // Pass a fake expected modifictaion time so that the expectation fails.
+ base::Time fake_expected_modification_time =
+ test_file_modification_time() - base::TimeDelta::FromSeconds(10);
+
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 0, fake_expected_modification_time));
+ net::TestInt64CompletionCallback callback;
+ int64 result = reader->GetLength(callback.callback());
+ if (result == net::ERR_IO_PENDING)
+ result = callback.WaitForResult();
+ ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
+
+ // With NULL expected modification time this should work.
+ reader.reset(CreateFileReader(kTestFileName, 0, base::Time()));
+ result = reader->GetLength(callback.callback());
+ if (result == net::ERR_IO_PENDING)
+ result = callback.WaitForResult();
+ ASSERT_EQ(kTestDataSize, result);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, GetLengthWithOffset) {
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 3, base::Time()));
+ net::TestInt64CompletionCallback callback;
+ int64 result = reader->GetLength(callback.callback());
+ if (result == net::ERR_IO_PENDING)
+ result = callback.WaitForResult();
+ // Initial offset does not affect the result of GetLength.
+ ASSERT_EQ(kTestDataSize, result);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, ReadNormal) {
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 0, test_file_modification_time()));
+ int result = 0;
+ std::string data;
+ ReadFromReader(reader.get(), &data, kTestDataSize, &result);
+ ASSERT_EQ(net::OK, result);
+ ASSERT_EQ(kTestData, data);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, ReadAfterModified) {
+ // Pass a fake expected modifictaion time so that the expectation fails.
+ base::Time fake_expected_modification_time =
+ test_file_modification_time() - base::TimeDelta::FromSeconds(10);
+
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 0, fake_expected_modification_time));
+ int result = 0;
+ std::string data;
+ ReadFromReader(reader.get(), &data, kTestDataSize, &result);
+ ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
+ ASSERT_EQ(0U, data.size());
+
+ // With NULL expected modification time this should work.
+ data.clear();
+ reader.reset(CreateFileReader(kTestFileName, 0, base::Time()));
+ ReadFromReader(reader.get(), &data, kTestDataSize, &result);
+ ASSERT_EQ(net::OK, result);
+ ASSERT_EQ(kTestData, data);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, ReadWithOffset) {
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 3, base::Time()));
+ int result = 0;
+ std::string data;
+ ReadFromReader(reader.get(), &data, kTestDataSize, &result);
+ ASSERT_EQ(net::OK, result);
+ ASSERT_EQ(&kTestData[3], data);
+}
+
+TEST_F(FileSystemFileStreamReaderTest, DeleteWithUnfinishedRead) {
+ scoped_ptr<FileSystemFileStreamReader> reader(
+ CreateFileReader(kTestFileName, 0, base::Time()));
+
+ net::TestCompletionCallback callback;
+ scoped_refptr<net::IOBufferWithSize> buf(
+ new net::IOBufferWithSize(kTestDataSize));
+ int rv = reader->Read(buf, buf->size(), base::Bind(&NeverCalled));
+ ASSERT_TRUE(rv == net::ERR_IO_PENDING || rv >= 0);
+
+ // Delete immediately.
+ // Should not crash; nor should NeverCalled be callback.
+ reader.reset();
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_mount_point_provider.h b/webkit/browser/fileapi/file_system_mount_point_provider.h
index d8aff2b..400a041 100644
--- a/webkit/browser/fileapi/file_system_mount_point_provider.h
+++ b/webkit/browser/fileapi/file_system_mount_point_provider.h
@@ -12,7 +12,7 @@
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/platform_file.h"
-#include "webkit/fileapi/file_permission_policy.h"
+#include "webkit/browser/fileapi/file_permission_policy.h"
#include "webkit/fileapi/file_system_types.h"
#include "webkit/storage/webkit_storage_export.h"
diff --git a/webkit/browser/fileapi/file_system_operation.h b/webkit/browser/fileapi/file_system_operation.h
new file mode 100644
index 0000000..bf960cb
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_operation.h
@@ -0,0 +1,278 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/platform_file.h"
+#include "base/process.h"
+#include "webkit/fileapi/directory_entry.h"
+
+namespace base {
+class Time;
+} // namespace base
+
+namespace net {
+class URLRequestContext;
+} // namespace net
+
+namespace webkit_blob {
+class ShareableFileReference;
+}
+
+class GURL;
+
+namespace fileapi {
+
+class FileSystemURL;
+class LocalFileSystemOperation;
+
+// The interface class for FileSystemOperation implementations.
+//
+// This interface defines file system operations required to implement
+// "File API: Directories and System"
+// http://www.w3.org/TR/file-system-api/
+//
+// DESIGN NOTES
+//
+// This class is designed to
+//
+// 1) Serve one-time file system operation per instance. Only one
+// method(CreateFile, CreateDirectory, Copy, Move, DirectoryExists,
+// GetMetadata, ReadDirectory and Remove) may be called during the
+// lifetime of this object and it should be called no more than once.
+//
+// 2) Be self-destructed, or get deleted via base::Owned() after the
+// operation finishes and completion callback is called.
+//
+// 3) Deliver the results of operations to the client via the callback function
+// passed as the last parameter of the method.
+//
+class FileSystemOperation {
+ public:
+ virtual ~FileSystemOperation() {}
+
+ // Used for CreateFile(), etc. |result| is the return code of the operation.
+ typedef base::Callback<void(base::PlatformFileError result)> StatusCallback;
+
+ // Used for GetMetadata(). |result| is the return code of the operation,
+ // |file_info| is the obtained file info, and |platform_path| is the path
+ // of the file.
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path)> GetMetadataCallback;
+
+ // Used for OpenFile(). |result| is the return code of the operation.
+ // |on_close_callback| will be called after the file is closed in the child
+ // process.
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ base::PlatformFile file,
+ const base::Closure& on_close_callback,
+ base::ProcessHandle peer_handle)> OpenFileCallback;
+
+ // Used for ReadDirectoryCallback.
+ typedef std::vector<DirectoryEntry> FileEntryList;
+
+ // Used for ReadDirectory(). |result| is the return code of the operation,
+ // |file_list| is the list of files read, and |has_more| is true if some files
+ // are yet to be read.
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ const FileEntryList& file_list,
+ bool has_more)> ReadDirectoryCallback;
+
+ // Used for CreateSnapshotFile(). (Please see the comment at
+ // CreateSnapshotFile() below for how the method is called)
+ // |result| is the return code of the operation.
+ // |file_info| is the metadata of the snapshot file created.
+ // |platform_path| is the path to the snapshot file created.
+ //
+ // The snapshot file could simply be of the local file pointed by the given
+ // filesystem URL in local filesystem cases; remote filesystems
+ // may want to download the file into a temporary snapshot file and then
+ // return the metadata of the temporary file.
+ //
+ // |file_ref| is used to manage the lifetime of the returned
+ // snapshot file. It can be set to let the chromium backend take
+ // care of the life time of the snapshot file. Otherwise (if the returned
+ // file does not require any handling) the implementation can just
+ // return NULL. In a more complex case, the implementaiton can manage
+ // the lifetime of the snapshot file on its own (e.g. by its cache system)
+ // but also can be notified via the reference when the file becomes no
+ // longer necessary in the javascript world.
+ // Please see the comment for ShareableFileReference for details.
+ //
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path,
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref)>
+ SnapshotFileCallback;
+
+ // Used for Write().
+ typedef base::Callback<void(base::PlatformFileError result,
+ int64 bytes,
+ bool complete)> WriteCallback;
+
+ // Creates a file at |path|. If |exclusive| is true, an error is raised
+ // in case a file is already present at the URL.
+ virtual void CreateFile(const FileSystemURL& path,
+ bool exclusive,
+ const StatusCallback& callback) = 0;
+
+ // Creates a directory at |path|. If |exclusive| is true, an error is
+ // raised in case a directory is already present at the URL. If
+ // |recursive| is true, create parent directories as needed just like
+ // mkdir -p does.
+ virtual void CreateDirectory(const FileSystemURL& path,
+ bool exclusive,
+ bool recursive,
+ const StatusCallback& callback) = 0;
+
+ // Copies a file or directory from |src_path| to |dest_path|. If
+ // |src_path| is a directory, the contents of |src_path| are copied to
+ // |dest_path| recursively. A new file or directory is created at
+ // |dest_path| as needed.
+ virtual void Copy(const FileSystemURL& src_path,
+ const FileSystemURL& dest_path,
+ const StatusCallback& callback) = 0;
+
+ // Moves a file or directory from |src_path| to |dest_path|. A new file
+ // or directory is created at |dest_path| as needed.
+ virtual void Move(const FileSystemURL& src_path,
+ const FileSystemURL& dest_path,
+ const StatusCallback& callback) = 0;
+
+ // Checks if a directory is present at |path|.
+ virtual void DirectoryExists(const FileSystemURL& path,
+ const StatusCallback& callback) = 0;
+
+ // Checks if a file is present at |path|.
+ virtual void FileExists(const FileSystemURL& path,
+ const StatusCallback& callback) = 0;
+
+ // Gets the metadata of a file or directory at |path|.
+ virtual void GetMetadata(const FileSystemURL& path,
+ const GetMetadataCallback& callback) = 0;
+
+ // Reads contents of a directory at |path|.
+ virtual void ReadDirectory(const FileSystemURL& path,
+ const ReadDirectoryCallback& callback) = 0;
+
+ // Removes a file or directory at |path|. If |recursive| is true, remove
+ // all files and directories under the directory at |path| recursively.
+ virtual void Remove(const FileSystemURL& path, bool recursive,
+ const StatusCallback& callback) = 0;
+
+ // Writes contents of |blob_url| to |path| at |offset|.
+ // |url_request_context| is used to read contents in |blob_url|.
+ virtual void Write(const net::URLRequestContext* url_request_context,
+ const FileSystemURL& path,
+ const GURL& blob_url,
+ int64 offset,
+ const WriteCallback& callback) = 0;
+
+ // Truncates a file at |path| to |length|. If |length| is larger than
+ // the original file size, the file will be extended, and the extended
+ // part is filled with null bytes.
+ virtual void Truncate(const FileSystemURL& path, int64 length,
+ const StatusCallback& callback) = 0;
+
+ // Tries to cancel the current operation [we support cancelling write or
+ // truncate only]. Reports failure for the current operation, then reports
+ // success for the cancel operation itself via the |cancel_dispatcher|.
+ //
+ // E.g. a typical cancel implementation would look like:
+ //
+ // virtual void SomeOperationImpl::Cancel(
+ // const StatusCallback& cancel_callback) {
+ // // Abort the current inflight operation first.
+ // ...
+ //
+ // // Dispatch ABORT error for the current operation by invoking
+ // // the callback function for the ongoing operation,
+ // operation_callback.Run(base::PLATFORM_FILE_ERROR_ABORT, ...);
+ //
+ // // Dispatch 'success' for the cancel (or dispatch appropriate
+ // // error code with DidFail() if the cancel has somehow failed).
+ // cancel_callback.Run(base::PLATFORM_FILE_OK);
+ // }
+ //
+ // Note that, for reporting failure, the callback function passed to a
+ // cancellable operations are kept around with the operation instance
+ // (as |operation_callback_| in the code example).
+ virtual void Cancel(const StatusCallback& cancel_callback) = 0;
+
+ // Modifies timestamps of a file or directory at |path| with
+ // |last_access_time| and |last_modified_time|. The function DOES NOT
+ // create a file unlike 'touch' command on Linux.
+ //
+ // This function is used only by Pepper as of writing.
+ virtual void TouchFile(const FileSystemURL& path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) = 0;
+
+ // Opens a file at |path| with |file_flags|, where flags are OR'ed
+ // values of base::PlatformFileFlags.
+ //
+ // |peer_handle| is the process handle of a pepper plugin process, which
+ // is necessary for underlying IPC calls with Pepper plugins.
+ //
+ // This function is used only by Pepper as of writing.
+ virtual void OpenFile(const FileSystemURL& path,
+ int file_flags,
+ base::ProcessHandle peer_handle,
+ const OpenFileCallback& callback) = 0;
+
+ // For downcasting to FileSystemOperation.
+ // TODO(kinuko): this hack should go away once appropriate upload-stream
+ // handling based on element types is supported.
+ virtual LocalFileSystemOperation* AsLocalFileSystemOperation() = 0;
+
+ // Creates a local snapshot file for a given |path| and returns the
+ // metadata and platform path of the snapshot file via |callback|.
+ // In local filesystem cases the implementation may simply return
+ // the metadata of the file itself (as well as GetMetadata does),
+ // while in remote filesystem case the backend may want to download the file
+ // into a temporary snapshot file and return the metadata of the
+ // temporary file. Or if the implementaiton already has the local cache
+ // data for |path| it can simply return the path to the cache.
+ virtual void CreateSnapshotFile(const FileSystemURL& path,
+ const SnapshotFileCallback& callback) = 0;
+
+ protected:
+ // Used only for internal assertions.
+ enum OperationType {
+ kOperationNone,
+ kOperationCreateFile,
+ kOperationCreateDirectory,
+ kOperationCreateSnapshotFile,
+ kOperationCopy,
+ kOperationCopyInForeignFile,
+ kOperationMove,
+ kOperationDirectoryExists,
+ kOperationFileExists,
+ kOperationGetMetadata,
+ kOperationReadDirectory,
+ kOperationRemove,
+ kOperationWrite,
+ kOperationTruncate,
+ kOperationTouchFile,
+ kOperationOpenFile,
+ kOperationCloseFile,
+ kOperationGetLocalPath,
+ kOperationCancel,
+ };
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_H_
diff --git a/webkit/browser/fileapi/file_system_operation_context.cc b/webkit/browser/fileapi/file_system_operation_context.cc
new file mode 100644
index 0000000..3866bf0
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_operation_context.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_operation_context.h"
+
+#include "base/sequenced_task_runner.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_task_runners.h"
+
+namespace fileapi {
+
+FileSystemOperationContext::FileSystemOperationContext(
+ FileSystemContext* context)
+ : file_system_context_(context),
+ task_runner_(file_system_context_->task_runners()->file_task_runner()),
+ allowed_bytes_growth_(0),
+ quota_limit_type_(quota::kQuotaLimitTypeUnknown) {}
+
+FileSystemOperationContext::FileSystemOperationContext(
+ FileSystemContext* context,
+ base::SequencedTaskRunner* task_runner)
+ : file_system_context_(context),
+ task_runner_(task_runner),
+ allowed_bytes_growth_(0),
+ quota_limit_type_(quota::kQuotaLimitTypeUnknown) {}
+
+FileSystemOperationContext::~FileSystemOperationContext() {
+ DetachUserDataThread();
+ setter_thread_checker_.DetachFromThread();
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_operation_context.h b/webkit/browser/fileapi/file_system_operation_context.h
new file mode 100644
index 0000000..68c7ce5
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_operation_context.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
+
+#include "base/supports_user_data.h"
+#include "base/threading/thread_checker.h"
+#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
+#include "webkit/quota/quota_types.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace fileapi {
+
+class FileSystemContext;
+
+// A context class which is carried around by FileSystemOperation and
+// its delegated tasks. It is valid to reuse one context instance across
+// multiple operations as far as those operations are supposed to share
+// the same context (e.g. use the same task runner, share the quota etc).
+// Note that the remaining quota bytes (allowed_bytes_growth) may be
+// updated during the execution of write operations.
+class WEBKIT_STORAGE_EXPORT_PRIVATE FileSystemOperationContext
+ : public base::SupportsUserData {
+ public:
+ explicit FileSystemOperationContext(FileSystemContext* context);
+
+ // Specifies |task_runner| which the operation is performed on.
+ FileSystemOperationContext(FileSystemContext* context,
+ base::SequencedTaskRunner* task_runner);
+
+ virtual ~FileSystemOperationContext();
+
+ FileSystemContext* file_system_context() const {
+ return file_system_context_;
+ }
+
+ // Updates the current remaining quota.
+ // This can be called to update the remaining quota during the operation.
+ void set_allowed_bytes_growth(const int64& allowed_bytes_growth) {
+ allowed_bytes_growth_ = allowed_bytes_growth;
+ }
+
+ // Returns the current remaining quota.
+ int64 allowed_bytes_growth() const { return allowed_bytes_growth_; }
+
+ quota::QuotaLimitType quota_limit_type() const {
+ return quota_limit_type_;
+ }
+
+ // Returns TaskRunner which the operation is performed on.
+ base::SequencedTaskRunner* task_runner() const {
+ return task_runner_.get();
+ }
+
+ ChangeObserverList* change_observers() { return &change_observers_; }
+ AccessObserverList* access_observers() { return &access_observers_; }
+ UpdateObserverList* update_observers() { return &update_observers_; }
+
+ // Following setters should be called only on the same thread as the
+ // FileSystemOperationContext is created (i.e. are not supposed be updated
+ // after the context's passed onto other task runners).
+ void set_change_observers(const ChangeObserverList& list) {
+ DCHECK(setter_thread_checker_.CalledOnValidThread());
+ change_observers_ = list;
+ }
+ void set_access_observers(const AccessObserverList& list) {
+ DCHECK(setter_thread_checker_.CalledOnValidThread());
+ access_observers_ = list;
+ }
+ void set_update_observers(const UpdateObserverList& list) {
+ DCHECK(setter_thread_checker_.CalledOnValidThread());
+ update_observers_ = list;
+ }
+ void set_quota_limit_type(quota::QuotaLimitType limit_type) {
+ DCHECK(setter_thread_checker_.CalledOnValidThread());
+ quota_limit_type_ = limit_type;
+ }
+
+ // Gets and sets value-type (or not-owned) variable as UserData.
+ // (SetUserValue can be called only on the same thread as this context
+ // is created as well as other setters.)
+ template <typename T> T GetUserValue(const char* key) const {
+ ValueAdapter<T>* v = static_cast<ValueAdapter<T>*>(GetUserData(key));
+ return v ? v->value() : T();
+ }
+ template <typename T> void SetUserValue(const char* key, const T& value) {
+ DCHECK(setter_thread_checker_.CalledOnValidThread());
+ SetUserData(key, new ValueAdapter<T>(value));
+ }
+
+ private:
+ // An adapter for setting a value-type (or not owned) data as UserData.
+ template <typename T> class ValueAdapter
+ : public base::SupportsUserData::Data {
+ public:
+ ValueAdapter(const T& value) : value_(value) {}
+ const T& value() const { return value_; }
+ private:
+ T value_;
+ DISALLOW_COPY_AND_ASSIGN(ValueAdapter);
+ };
+
+ FileSystemContext* file_system_context_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ int64 allowed_bytes_growth_;
+ quota::QuotaLimitType quota_limit_type_;
+
+ AccessObserverList access_observers_;
+ ChangeObserverList change_observers_;
+ UpdateObserverList update_observers_;
+
+ // Used to check its setters are not called on arbitrary thread.
+ base::ThreadChecker setter_thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileSystemOperationContext);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
diff --git a/webkit/browser/fileapi/file_system_options.cc b/webkit/browser/fileapi/file_system_options.cc
new file mode 100644
index 0000000..4100b5d
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_options.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_options.h"
+
+namespace fileapi {
+
+FileSystemOptions::FileSystemOptions(
+ ProfileMode profile_mode,
+ const std::vector<std::string>& additional_allowed_schemes)
+ : profile_mode_(profile_mode),
+ additional_allowed_schemes_(additional_allowed_schemes) {
+}
+
+FileSystemOptions::~FileSystemOptions() {
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_options.h b/webkit/browser/fileapi/file_system_options.h
new file mode 100644
index 0000000..27cc9d2
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_options.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPTIONS_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPTIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace fileapi {
+
+// Provides runtime options that may change FileSystem API behavior.
+// This object is copyable.
+class WEBKIT_STORAGE_EXPORT FileSystemOptions {
+ public:
+ enum ProfileMode {
+ PROFILE_MODE_NORMAL = 0,
+ PROFILE_MODE_INCOGNITO
+ };
+
+ // |profile_mode| specifies if the profile (for this filesystem)
+ // is running in incognito mode (PROFILE_MODE_INCOGNITO) or no
+ // (PROFILE_MODE_NORMAL).
+ // |additional_allowed_schemes| specifies schemes that are allowed
+ // to access FileSystem API in addition to "http" and "https".
+ FileSystemOptions(
+ ProfileMode profile_mode,
+ const std::vector<std::string>& additional_allowed_schemes);
+
+ ~FileSystemOptions();
+
+ // Returns true if it is running in the incognito mode.
+ bool is_incognito() const { return profile_mode_ == PROFILE_MODE_INCOGNITO; }
+
+ // Returns the schemes that must be allowed to access FileSystem API
+ // in addition to standard "http" and "https".
+ // (e.g. If the --allow-file-access-from-files option is given in chrome
+ // "file" scheme will also need to be allowed).
+ const std::vector<std::string>& additional_allowed_schemes() const {
+ return additional_allowed_schemes_;
+ }
+
+ private:
+ const ProfileMode profile_mode_;
+ const std::vector<std::string> additional_allowed_schemes_;
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPTIONS_H_
diff --git a/webkit/browser/fileapi/file_system_quota_client.cc b/webkit/browser/fileapi/file_system_quota_client.cc
index 04a54fc..8a5f51b 100644
--- a/webkit/browser/fileapi/file_system_quota_client.cc
+++ b/webkit/browser/fileapi/file_system_quota_client.cc
@@ -18,11 +18,11 @@
#include "base/task_runner_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_quota_util.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/file_system_usage_cache.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
-#include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_util.h"
using quota::StorageType;
diff --git a/webkit/browser/fileapi/file_system_quota_client_unittest.cc b/webkit/browser/fileapi/file_system_quota_client_unittest.cc
index 4c719a4..7f1c728 100644
--- a/webkit/browser/fileapi/file_system_quota_client_unittest.cc
+++ b/webkit/browser/fileapi/file_system_quota_client_unittest.cc
@@ -11,13 +11,13 @@
#include "base/platform_file.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_quota_client.h"
#include "webkit/browser/fileapi/file_system_usage_cache.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/obfuscated_file_util.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/file_system_util.h"
#include "webkit/quota/quota_types.h"
diff --git a/webkit/browser/fileapi/file_system_url.cc b/webkit/browser/fileapi/file_system_url.cc
new file mode 100644
index 0000000..f4c582c
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_url.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_url.h"
+
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "net/base/escape.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+
+namespace fileapi {
+
+namespace {
+
+} // namespace
+
+FileSystemURL::FileSystemURL()
+ : is_valid_(false),
+ mount_type_(kFileSystemTypeUnknown),
+ type_(kFileSystemTypeUnknown) {
+}
+
+// static
+FileSystemURL FileSystemURL::CreateForTest(const GURL& url) {
+ return FileSystemURL(url);
+}
+
+FileSystemURL FileSystemURL::CreateForTest(const GURL& origin,
+ FileSystemType mount_type,
+ const base::FilePath& virtual_path) {
+ return FileSystemURL(origin, mount_type, virtual_path);
+}
+
+// static
+bool FileSystemURL::ParseFileSystemSchemeURL(
+ const GURL& url,
+ GURL* origin_url,
+ FileSystemType* mount_type,
+ base::FilePath* virtual_path) {
+ GURL origin;
+ FileSystemType file_system_type = kFileSystemTypeUnknown;
+
+ if (!url.is_valid() || !url.SchemeIsFileSystem())
+ return false;
+ DCHECK(url.inner_url());
+
+ std::string inner_path = url.inner_url()->path();
+
+ const struct {
+ FileSystemType type;
+ const char* dir;
+ } kValidTypes[] = {
+ { kFileSystemTypePersistent, kPersistentDir },
+ { kFileSystemTypeTemporary, kTemporaryDir },
+ { kFileSystemTypeIsolated, kIsolatedDir },
+ { kFileSystemTypeExternal, kExternalDir },
+ { kFileSystemTypeTest, kTestDir },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidTypes); ++i) {
+ if (StartsWithASCII(inner_path, kValidTypes[i].dir, true)) {
+ file_system_type = kValidTypes[i].type;
+ break;
+ }
+ }
+
+ if (file_system_type == kFileSystemTypeUnknown)
+ return false;
+
+ std::string path = net::UnescapeURLComponent(url.path(),
+ net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS |
+ net::UnescapeRule::CONTROL_CHARS);
+
+ // Ensure the path is relative.
+ while (!path.empty() && path[0] == '/')
+ path.erase(0, 1);
+
+ base::FilePath converted_path = base::FilePath::FromUTF8Unsafe(path);
+
+ // All parent references should have been resolved in the renderer.
+ if (converted_path.ReferencesParent())
+ return false;
+
+ if (origin_url)
+ *origin_url = url.GetOrigin();
+ if (mount_type)
+ *mount_type = file_system_type;
+ if (virtual_path)
+ *virtual_path = converted_path.NormalizePathSeparators().
+ StripTrailingSeparators();
+
+ return true;
+}
+
+FileSystemURL::FileSystemURL(const GURL& url)
+ : mount_type_(kFileSystemTypeUnknown),
+ type_(kFileSystemTypeUnknown) {
+ is_valid_ = ParseFileSystemSchemeURL(url, &origin_, &mount_type_,
+ &virtual_path_);
+ path_ = virtual_path_;
+ type_ = mount_type_;
+}
+
+FileSystemURL::FileSystemURL(const GURL& origin,
+ FileSystemType mount_type,
+ const base::FilePath& virtual_path)
+ : is_valid_(true),
+ origin_(origin),
+ mount_type_(mount_type),
+ virtual_path_(virtual_path.NormalizePathSeparators()),
+ type_(mount_type),
+ path_(virtual_path.NormalizePathSeparators()) {
+}
+
+FileSystemURL::FileSystemURL(const GURL& origin,
+ FileSystemType mount_type,
+ const base::FilePath& virtual_path,
+ const std::string& mount_filesystem_id,
+ FileSystemType cracked_type,
+ const base::FilePath& cracked_path,
+ const std::string& filesystem_id)
+ : is_valid_(true),
+ origin_(origin),
+ mount_type_(mount_type),
+ virtual_path_(virtual_path.NormalizePathSeparators()),
+ mount_filesystem_id_(mount_filesystem_id),
+ type_(cracked_type),
+ path_(cracked_path.NormalizePathSeparators()),
+ filesystem_id_(filesystem_id) {
+}
+
+FileSystemURL::~FileSystemURL() {}
+
+std::string FileSystemURL::DebugString() const {
+ if (!is_valid_)
+ return "invalid filesystem: URL";
+ std::ostringstream ss;
+ ss << GetFileSystemRootURI(origin_, mount_type_);
+
+ // filesystem_id_ will be non empty for (and only for) cracked URLs.
+ if (!filesystem_id_.empty()) {
+ ss << virtual_path_.value();
+ ss << " (";
+ ss << GetFileSystemTypeString(type_) << "@" << filesystem_id_ << ":";
+ ss << path_.value();
+ ss << ")";
+ } else {
+ ss << path_.value();
+ }
+ return ss.str();
+}
+
+bool FileSystemURL::IsParent(const FileSystemURL& child) const {
+ return IsInSameFileSystem(child) &&
+ path().IsParent(child.path());
+}
+
+bool FileSystemURL::IsInSameFileSystem(const FileSystemURL& other) const {
+ return origin() == other.origin() &&
+ type() == other.type() &&
+ filesystem_id() == other.filesystem_id();
+}
+
+bool FileSystemURL::operator==(const FileSystemURL& that) const {
+ return origin_ == that.origin_ &&
+ type_ == that.type_ &&
+ path_ == that.path_ &&
+ filesystem_id_ == that.filesystem_id_ &&
+ is_valid_ == that.is_valid_;
+}
+
+bool FileSystemURL::Comparator::operator()(const FileSystemURL& lhs,
+ const FileSystemURL& rhs) const {
+ DCHECK(lhs.is_valid_ && rhs.is_valid_);
+ if (lhs.origin_ != rhs.origin_)
+ return lhs.origin_ < rhs.origin_;
+ if (lhs.type_ != rhs.type_)
+ return lhs.type_ < rhs.type_;
+ if (lhs.filesystem_id_ != rhs.filesystem_id_)
+ return lhs.filesystem_id_ < rhs.filesystem_id_;
+ return lhs.path_ < rhs.path_;
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_system_url.h b/webkit/browser/fileapi/file_system_url.h
new file mode 100644
index 0000000..0b88dd4
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_url.h
@@ -0,0 +1,173 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_URL_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_URL_H_
+
+#include <set>
+#include <string>
+
+#include "base/platform_file.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace fileapi {
+
+// A class representing a filesystem URL which consists of origin URL,
+// type and an internal path used inside the filesystem.
+//
+// When a FileSystemURL instance is created for a GURL (for filesystem: scheme),
+// each accessor method would return following values:
+//
+// Example: For a URL 'filesystem:http://foo.com/temporary/foo/bar':
+// origin() returns 'http://foo.com',
+// mount_type() returns kFileSystemTypeTemporary,
+// virtual_path() returns 'foo/bar',
+// type() returns the same value as mount_type(),
+// path() returns the same value as virtual_path(),
+//
+// All other accessors return empty or invalid value.
+//
+// FileSystemURL can also be created to represent a 'cracked' filesystem URL if
+// the original URL's type/path is pointing to a mount point which can be
+// further resolved to a lower filesystem type/path.
+//
+// Example: Assume a path '/media/removable' is mounted at mount name
+// 'mount_name' with type kFileSystemTypeFoo as an external file system.
+//
+// The original URL would look like:
+// 'filesystem:http://bar.com/external/mount_name/foo/bar':
+//
+// FileSystemURL('http://bar.com',
+// kFileSystemTypeExternal,
+// 'mount_name/foo/bar'
+// 'mount_name',
+// kFileSystemTypeFoo,
+// '/media/removable/foo/bar');
+// would create a FileSystemURL whose accessors return:
+//
+// origin() returns 'http://bar.com',
+// mount_type() returns kFileSystemTypeExternal,
+// virtual_path() returns 'mount_name/foo/bar',
+// type() returns the kFileSystemTypeFoo,
+// path() returns '/media/removable/foo/bar',
+//
+// Note that in either case virtual_path() always returns the path part after
+// 'type' part in the original URL, and mount_type() always returns the 'type'
+// part in the original URL.
+//
+// Additionally, following accessors would return valid values:
+// filesystem_id() returns 'mount_name'.
+//
+// It is impossible to directly create a valid FileSystemURL instance (except by
+// using CreatedForTest methods, which should not be used in production code).
+// To get a valid FileSystemURL, one of the following methods can be used:
+// <Friend>::CrackURL, <Friend>::CreateCrackedFileSystemURL, where <Friend> is
+// one of the friended classes.
+//
+// TODO(ericu): Look into making virtual_path() [and all FileSystem API virtual
+// paths] just an std::string, to prevent platform-specific base::FilePath behavior
+// from getting invoked by accident. Currently the base::FilePath returned here needs
+// special treatment, as it may contain paths that are illegal on the current
+// platform. To avoid problems, use VirtualPath::BaseName and
+// VirtualPath::GetComponents instead of the base::FilePath methods.
+class WEBKIT_STORAGE_EXPORT FileSystemURL {
+ public:
+ FileSystemURL();
+ ~FileSystemURL();
+
+ // Methods for creating FileSystemURL without attempting to crack them.
+ // Should be used only in tests.
+ static FileSystemURL CreateForTest(const GURL& url);
+ static FileSystemURL CreateForTest(const GURL& origin,
+ FileSystemType mount_type,
+ const base::FilePath& virtual_path);
+
+ // Parses filesystem scheme |url| into uncracked FileSystemURL components.
+ static bool ParseFileSystemSchemeURL(const GURL& url,
+ GURL* origin,
+ FileSystemType* mount_type,
+ base::FilePath* virtual_path);
+
+ // Returns true if this instance represents a valid FileSystem URL.
+ bool is_valid() const { return is_valid_; }
+
+ // Returns the origin part of this URL. See the class comment for details.
+ const GURL& origin() const { return origin_; }
+
+ // Returns the type part of this URL. See the class comment for details.
+ FileSystemType type() const { return type_; }
+
+ // Returns the cracked path of this URL. See the class comment for details.
+ const base::FilePath& path() const { return path_; }
+
+ // Returns the original path part of this URL.
+ // See the class comment for details.
+ // TODO(kinuko): this must return std::string.
+ const base::FilePath& virtual_path() const { return virtual_path_; }
+
+ // Returns the filesystem ID/mount name for isolated/external filesystem URLs.
+ // See the class comment for details.
+ const std::string& filesystem_id() const { return filesystem_id_; }
+ const std::string& mount_filesystem_id() const {
+ return mount_filesystem_id_;
+ }
+
+ FileSystemType mount_type() const { return mount_type_; }
+
+ std::string DebugString() const;
+
+ // Returns true if this URL is a strict parent of the |child|.
+ bool IsParent(const FileSystemURL& child) const;
+
+ bool IsInSameFileSystem(const FileSystemURL& other) const;
+
+ bool operator==(const FileSystemURL& that) const;
+
+ struct WEBKIT_STORAGE_EXPORT Comparator {
+ bool operator() (const FileSystemURL& lhs, const FileSystemURL& rhs) const;
+ };
+
+ private:
+ friend class FileSystemContext;
+ friend class ExternalMountPoints;
+ friend class IsolatedContext;
+
+ explicit FileSystemURL(const GURL& filesystem_url);
+ FileSystemURL(const GURL& origin,
+ FileSystemType mount_type,
+ const base::FilePath& virtual_path);
+ // Creates a cracked FileSystemURL.
+ FileSystemURL(const GURL& origin,
+ FileSystemType mount_type,
+ const base::FilePath& virtual_path,
+ const std::string& mount_filesystem_id,
+ FileSystemType cracked_type,
+ const base::FilePath& cracked_path,
+ const std::string& filesystem_id);
+
+ bool is_valid_;
+
+ // Values parsed from the original URL.
+ GURL origin_;
+ FileSystemType mount_type_;
+ base::FilePath virtual_path_;
+
+ // Values obtained by cracking URLs.
+ // |mount_filesystem_id_| is retrieved from the first round of cracking,
+ // and the rest of the fields are from recursive cracking. Permission
+ // checking on the top-level mount information should be done with the former,
+ // and the low-level file operation should be implemented with the latter.
+ std::string mount_filesystem_id_;
+ FileSystemType type_;
+ base::FilePath path_;
+ std::string filesystem_id_;
+};
+
+typedef std::set<FileSystemURL, FileSystemURL::Comparator> FileSystemURLSet;
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_URL_H_
diff --git a/webkit/browser/fileapi/file_system_url_request_job.cc b/webkit/browser/fileapi/file_system_url_request_job.cc
index b6a022c..ca0e312 100644
--- a/webkit/browser/fileapi/file_system_url_request_job.cc
+++ b/webkit/browser/fileapi/file_system_url_request_job.cc
@@ -27,8 +27,8 @@
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "webkit/blob/file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/local_file_system_operation.h"
-#include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_util.h"
using net::NetworkDelegate;
diff --git a/webkit/browser/fileapi/file_system_url_request_job.h b/webkit/browser/fileapi/file_system_url_request_job.h
index 49b4dc0..c372fa8 100644
--- a/webkit/browser/fileapi/file_system_url_request_job.h
+++ b/webkit/browser/fileapi/file_system_url_request_job.h
@@ -13,7 +13,7 @@
#include "base/platform_file.h"
#include "net/http/http_byte_range.h"
#include "net/url_request/url_request_job.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/storage/webkit_storage_export.h"
class GURL;
diff --git a/webkit/browser/fileapi/file_system_url_request_job_unittest.cc b/webkit/browser/fileapi/file_system_url_request_job_unittest.cc
index 2456b78..5b4c2ec 100644
--- a/webkit/browser/fileapi/file_system_url_request_job_unittest.cc
+++ b/webkit/browser/fileapi/file_system_url_request_job_unittest.cc
@@ -28,11 +28,11 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
namespace fileapi {
namespace {
diff --git a/webkit/browser/fileapi/file_system_url_unittest.cc b/webkit/browser/fileapi/file_system_url_unittest.cc
new file mode 100644
index 0000000..90336a6
--- /dev/null
+++ b/webkit/browser/fileapi/file_system_url_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_url.h"
+
+#include "base/files/file_path.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/syncable/syncable_file_system_util.h"
+
+#define FPL FILE_PATH_LITERAL
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+#define DRIVE FPL("C:")
+#else
+#define DRIVE FPL("/a/")
+#endif
+
+namespace fileapi {
+
+namespace {
+
+FileSystemURL CreateFileSystemURL(const std::string& url_string) {
+ FileSystemURL url = FileSystemURL::CreateForTest(GURL(url_string));
+ EXPECT_TRUE(url.type() != kFileSystemTypeExternal &&
+ url.type() != kFileSystemTypeIsolated);
+ return url;
+}
+
+std::string NormalizedUTF8Path(const base::FilePath& path) {
+ return path.NormalizePathSeparators().AsUTF8Unsafe();
+}
+
+} // namespace
+
+TEST(FileSystemURLTest, ParsePersistent) {
+ FileSystemURL url = CreateFileSystemURL(
+ "filesystem:http://chromium.org/persistent/directory/file");
+ ASSERT_TRUE(url.is_valid());
+ EXPECT_EQ("http://chromium.org/", url.origin().spec());
+ EXPECT_EQ(kFileSystemTypePersistent, url.type());
+ EXPECT_EQ(FPL("file"), VirtualPath::BaseName(url.path()).value());
+ EXPECT_EQ(FPL("directory"), url.path().DirName().value());
+}
+
+TEST(FileSystemURLTest, ParseTemporary) {
+ FileSystemURL url = CreateFileSystemURL(
+ "filesystem:http://chromium.org/temporary/directory/file");
+ ASSERT_TRUE(url.is_valid());
+ EXPECT_EQ("http://chromium.org/", url.origin().spec());
+ EXPECT_EQ(kFileSystemTypeTemporary, url.type());
+ EXPECT_EQ(FPL("file"), VirtualPath::BaseName(url.path()).value());
+ EXPECT_EQ(FPL("directory"), url.path().DirName().value());
+}
+
+TEST(FileSystemURLTest, EnsureFilePathIsRelative) {
+ FileSystemURL url = CreateFileSystemURL(
+ "filesystem:http://chromium.org/temporary/////directory/file");
+ ASSERT_TRUE(url.is_valid());
+ EXPECT_EQ("http://chromium.org/", url.origin().spec());
+ EXPECT_EQ(kFileSystemTypeTemporary, url.type());
+ EXPECT_EQ(FPL("file"), VirtualPath::BaseName(url.path()).value());
+ EXPECT_EQ(FPL("directory"), url.path().DirName().value());
+ EXPECT_FALSE(url.path().IsAbsolute());
+}
+
+TEST(FileSystemURLTest, RejectBadSchemes) {
+ EXPECT_FALSE(CreateFileSystemURL("http://chromium.org/").is_valid());
+ EXPECT_FALSE(CreateFileSystemURL("https://chromium.org/").is_valid());
+ EXPECT_FALSE(CreateFileSystemURL("file:///foo/bar").is_valid());
+ EXPECT_FALSE(CreateFileSystemURL("foobar:///foo/bar").is_valid());
+}
+
+TEST(FileSystemURLTest, UnescapePath) {
+ FileSystemURL url = CreateFileSystemURL(
+ "filesystem:http://chromium.org/persistent/%7Echromium/space%20bar");
+ ASSERT_TRUE(url.is_valid());
+ EXPECT_EQ(FPL("space bar"), VirtualPath::BaseName(url.path()).value());
+ EXPECT_EQ(FPL("~chromium"), url.path().DirName().value());
+}
+
+TEST(FileSystemURLTest, RejectBadType) {
+ EXPECT_FALSE(CreateFileSystemURL(
+ "filesystem:http://c.org/foobar/file").is_valid());
+}
+
+TEST(FileSystemURLTest, RejectMalformedURL) {
+ EXPECT_FALSE(CreateFileSystemURL("filesystem:///foobar/file").is_valid());
+ EXPECT_FALSE(CreateFileSystemURL("filesystem:foobar/file").is_valid());
+}
+
+TEST(FileSystemURLTest, CompareURLs) {
+ const GURL urls[] = {
+ GURL("filesystem:http://chromium.org/temporary/dir a/file a"),
+ GURL("filesystem:http://chromium.org/temporary/dir a/file a"),
+ GURL("filesystem:http://chromium.org/temporary/dir a/file b"),
+ GURL("filesystem:http://chromium.org/temporary/dir a/file aa"),
+ GURL("filesystem:http://chromium.org/temporary/dir b/file a"),
+ GURL("filesystem:http://chromium.org/temporary/dir aa/file b"),
+ GURL("filesystem:http://chromium.com/temporary/dir a/file a"),
+ GURL("filesystem:https://chromium.org/temporary/dir a/file a")
+ };
+
+ FileSystemURL::Comparator compare;
+ for (size_t i = 0; i < arraysize(urls); ++i) {
+ for (size_t j = 0; j < arraysize(urls); ++j) {
+ SCOPED_TRACE(testing::Message() << i << " < " << j);
+ EXPECT_EQ(urls[i] < urls[j],
+ compare(FileSystemURL::CreateForTest(urls[i]),
+ FileSystemURL::CreateForTest(urls[j])));
+ }
+ }
+
+ const FileSystemURL a = CreateFileSystemURL(
+ "filesystem:http://chromium.org/temporary/dir a/file a");
+ const FileSystemURL b = CreateFileSystemURL(
+ "filesystem:http://chromium.org/persistent/dir a/file a");
+ EXPECT_EQ(a.type() < b.type(), compare(a, b));
+ EXPECT_EQ(b.type() < a.type(), compare(b, a));
+}
+
+TEST(FileSystemURLTest, IsParent) {
+ const std::string root1 = GetFileSystemRootURI(
+ GURL("http://example.com"), kFileSystemTypeTemporary).spec();
+ const std::string root2 = GetFileSystemRootURI(
+ GURL("http://example.com"), kFileSystemTypePersistent).spec();
+ const std::string root3 = GetFileSystemRootURI(
+ GURL("http://chromium.org"), kFileSystemTypeTemporary).spec();
+
+ const std::string parent("dir");
+ const std::string child("dir/child");
+ const std::string other("other");
+
+ // True cases.
+ EXPECT_TRUE(CreateFileSystemURL(root1 + parent).IsParent(
+ CreateFileSystemURL(root1 + child)));
+ EXPECT_TRUE(CreateFileSystemURL(root2 + parent).IsParent(
+ CreateFileSystemURL(root2 + child)));
+
+ // False cases: the path is not a child.
+ EXPECT_FALSE(CreateFileSystemURL(root1 + parent).IsParent(
+ CreateFileSystemURL(root1 + other)));
+ EXPECT_FALSE(CreateFileSystemURL(root1 + parent).IsParent(
+ CreateFileSystemURL(root1 + parent)));
+ EXPECT_FALSE(CreateFileSystemURL(root1 + child).IsParent(
+ CreateFileSystemURL(root1 + parent)));
+
+ // False case: different types.
+ EXPECT_FALSE(CreateFileSystemURL(root1 + parent).IsParent(
+ CreateFileSystemURL(root2 + child)));
+
+ // False case: different origins.
+ EXPECT_FALSE(CreateFileSystemURL(root1 + parent).IsParent(
+ CreateFileSystemURL(root3 + child)));
+}
+
+TEST(FileSystemURLTest, DebugString) {
+ const GURL kOrigin("http://example.com");
+ const base::FilePath kPath(FPL("dir/file"));
+
+ const FileSystemURL kURL1 = FileSystemURL::CreateForTest(
+ kOrigin, kFileSystemTypeTemporary, kPath);
+ EXPECT_EQ("filesystem:http://example.com/temporary/" +
+ NormalizedUTF8Path(kPath),
+ kURL1.DebugString());
+}
+
+TEST(FileSystemURLTest, IsInSameFileSystem) {
+ FileSystemURL url_foo_temp_a = FileSystemURL::CreateForTest(
+ GURL("http://foo"), kFileSystemTypeTemporary,
+ base::FilePath::FromUTF8Unsafe("a"));
+ FileSystemURL url_foo_temp_b = FileSystemURL::CreateForTest(
+ GURL("http://foo"), kFileSystemTypeTemporary,
+ base::FilePath::FromUTF8Unsafe("b"));
+ FileSystemURL url_foo_perm_a = FileSystemURL::CreateForTest(
+ GURL("http://foo"), kFileSystemTypePersistent,
+ base::FilePath::FromUTF8Unsafe("a"));
+ FileSystemURL url_bar_temp_a = FileSystemURL::CreateForTest(
+ GURL("http://bar"), kFileSystemTypeTemporary,
+ base::FilePath::FromUTF8Unsafe("a"));
+ FileSystemURL url_bar_perm_a = FileSystemURL::CreateForTest(
+ GURL("http://bar"), kFileSystemTypePersistent,
+ base::FilePath::FromUTF8Unsafe("a"));
+
+ EXPECT_TRUE(url_foo_temp_a.IsInSameFileSystem(url_foo_temp_a));
+ EXPECT_TRUE(url_foo_temp_a.IsInSameFileSystem(url_foo_temp_b));
+ EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_foo_perm_a));
+ EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_bar_temp_a));
+ EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_bar_perm_a));
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_writer_delegate.cc b/webkit/browser/fileapi/file_writer_delegate.cc
new file mode 100644
index 0000000..f3a2d94
--- /dev/null
+++ b/webkit/browser/fileapi/file_writer_delegate.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/file_writer_delegate.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_util_proxy.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/net_errors.h"
+#include "webkit/browser/fileapi/file_stream_writer.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+
+namespace fileapi {
+
+static const int kReadBufSize = 32768;
+
+namespace {
+
+base::PlatformFileError NetErrorToPlatformFileError(int error) {
+// TODO(kinuko): Move this static method to more convenient place.
+ switch (error) {
+ case net::OK:
+ return base::PLATFORM_FILE_OK;
+ case net::ERR_FILE_NO_SPACE:
+ return base::PLATFORM_FILE_ERROR_NO_SPACE;
+ case net::ERR_FILE_NOT_FOUND:
+ return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ case net::ERR_ACCESS_DENIED:
+ return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
+ default:
+ return base::PLATFORM_FILE_ERROR_FAILED;
+ }
+}
+
+} // namespace
+
+FileWriterDelegate::FileWriterDelegate(
+ const DelegateWriteCallback& write_callback,
+ scoped_ptr<FileStreamWriter> file_stream_writer)
+ : write_callback_(write_callback),
+ file_stream_writer_(file_stream_writer.Pass()),
+ writing_started_(false),
+ bytes_written_backlog_(0),
+ bytes_written_(0),
+ bytes_read_(0),
+ io_buffer_(new net::IOBufferWithSize(kReadBufSize)),
+ weak_factory_(this) {
+}
+
+FileWriterDelegate::~FileWriterDelegate() {
+}
+
+void FileWriterDelegate::Start(scoped_ptr<net::URLRequest> request) {
+ request_ = request.Pass();
+ request_->Start();
+}
+
+bool FileWriterDelegate::Cancel() {
+ if (request_) {
+ // This halts any callbacks on this delegate.
+ request_->set_delegate(NULL);
+ request_->Cancel();
+ }
+
+ const int status = file_stream_writer_->Cancel(
+ base::Bind(&FileWriterDelegate::OnWriteCancelled,
+ weak_factory_.GetWeakPtr()));
+ // Return true to finish immediately if we have no pending writes.
+ // Otherwise we'll do the final cleanup in the Cancel callback.
+ return (status != net::ERR_IO_PENDING);
+}
+
+void FileWriterDelegate::OnReceivedRedirect(net::URLRequest* request,
+ const GURL& new_url,
+ bool* defer_redirect) {
+ NOTREACHED();
+ OnError(base::PLATFORM_FILE_ERROR_SECURITY);
+}
+
+void FileWriterDelegate::OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) {
+ NOTREACHED();
+ OnError(base::PLATFORM_FILE_ERROR_SECURITY);
+}
+
+void FileWriterDelegate::OnCertificateRequested(
+ net::URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) {
+ NOTREACHED();
+ OnError(base::PLATFORM_FILE_ERROR_SECURITY);
+}
+
+void FileWriterDelegate::OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) {
+ NOTREACHED();
+ OnError(base::PLATFORM_FILE_ERROR_SECURITY);
+}
+
+void FileWriterDelegate::OnResponseStarted(net::URLRequest* request) {
+ DCHECK_EQ(request_.get(), request);
+ if (!request->status().is_success() || request->GetResponseCode() != 200) {
+ OnError(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+ Read();
+}
+
+void FileWriterDelegate::OnReadCompleted(net::URLRequest* request,
+ int bytes_read) {
+ DCHECK_EQ(request_.get(), request);
+ if (!request->status().is_success()) {
+ OnError(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+ OnDataReceived(bytes_read);
+}
+
+void FileWriterDelegate::Read() {
+ bytes_written_ = 0;
+ bytes_read_ = 0;
+ if (request_->Read(io_buffer_.get(), io_buffer_->size(), &bytes_read_)) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FileWriterDelegate::OnDataReceived,
+ weak_factory_.GetWeakPtr(),
+ bytes_read_));
+ } else if (!request_->status().is_io_pending()) {
+ OnError(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+}
+
+void FileWriterDelegate::OnDataReceived(int bytes_read) {
+ bytes_read_ = bytes_read;
+ if (!bytes_read_) { // We're done.
+ OnProgress(0, true);
+ } else {
+ // This could easily be optimized to rotate between a pool of buffers, so
+ // that we could read and write at the same time. It's not yet clear that
+ // it's necessary.
+ cursor_ = new net::DrainableIOBuffer(io_buffer_, bytes_read_);
+ Write();
+ }
+}
+
+void FileWriterDelegate::Write() {
+ writing_started_ = true;
+ int64 bytes_to_write = bytes_read_ - bytes_written_;
+ int write_response =
+ file_stream_writer_->Write(cursor_,
+ static_cast<int>(bytes_to_write),
+ base::Bind(&FileWriterDelegate::OnDataWritten,
+ weak_factory_.GetWeakPtr()));
+ if (write_response > 0)
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FileWriterDelegate::OnDataWritten,
+ weak_factory_.GetWeakPtr(),
+ write_response));
+ else if (net::ERR_IO_PENDING != write_response)
+ OnError(NetErrorToPlatformFileError(write_response));
+}
+
+void FileWriterDelegate::OnDataWritten(int write_response) {
+ if (write_response > 0) {
+ OnProgress(write_response, false);
+ cursor_->DidConsume(write_response);
+ bytes_written_ += write_response;
+ if (bytes_written_ == bytes_read_)
+ Read();
+ else
+ Write();
+ } else {
+ OnError(NetErrorToPlatformFileError(write_response));
+ }
+}
+
+FileWriterDelegate::WriteProgressStatus
+FileWriterDelegate::GetCompletionStatusOnError() const {
+ return writing_started_ ? ERROR_WRITE_STARTED : ERROR_WRITE_NOT_STARTED;
+}
+
+void FileWriterDelegate::OnError(base::PlatformFileError error) {
+ if (request_) {
+ request_->set_delegate(NULL);
+ request_->Cancel();
+ }
+
+ if (writing_started_)
+ FlushForCompletion(error, 0, ERROR_WRITE_STARTED);
+ else
+ write_callback_.Run(error, 0, ERROR_WRITE_NOT_STARTED);
+}
+
+void FileWriterDelegate::OnProgress(int bytes_written, bool done) {
+ DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_);
+ static const int kMinProgressDelayMS = 200;
+ base::Time currentTime = base::Time::Now();
+ if (done || last_progress_event_time_.is_null() ||
+ (currentTime - last_progress_event_time_).InMilliseconds() >
+ kMinProgressDelayMS) {
+ bytes_written += bytes_written_backlog_;
+ last_progress_event_time_ = currentTime;
+ bytes_written_backlog_ = 0;
+
+ if (done) {
+ FlushForCompletion(base::PLATFORM_FILE_OK, bytes_written,
+ SUCCESS_COMPLETED);
+ } else {
+ write_callback_.Run(base::PLATFORM_FILE_OK, bytes_written,
+ SUCCESS_IO_PENDING);
+ }
+ return;
+ }
+ bytes_written_backlog_ += bytes_written;
+}
+
+void FileWriterDelegate::OnWriteCancelled(int status) {
+ write_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT, 0,
+ GetCompletionStatusOnError());
+}
+
+void FileWriterDelegate::FlushForCompletion(
+ base::PlatformFileError error,
+ int bytes_written,
+ WriteProgressStatus progress_status) {
+ int flush_error = file_stream_writer_->Flush(
+ base::Bind(&FileWriterDelegate::OnFlushed,
+ weak_factory_.GetWeakPtr(),
+ error, bytes_written, progress_status));
+ if (flush_error != net::ERR_IO_PENDING)
+ OnFlushed(error, bytes_written, progress_status, flush_error);
+}
+
+void FileWriterDelegate::OnFlushed(base::PlatformFileError error,
+ int bytes_written,
+ WriteProgressStatus progress_status,
+ int flush_error) {
+ if (error == base::PLATFORM_FILE_OK && flush_error != net::OK) {
+ // If the Flush introduced an error, overwrite the status.
+ // Otherwise, keep the original error status.
+ error = NetErrorToPlatformFileError(flush_error);
+ progress_status = GetCompletionStatusOnError();
+ }
+ write_callback_.Run(error, bytes_written, progress_status);
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/file_writer_delegate.h b/webkit/browser/fileapi/file_writer_delegate.h
new file mode 100644
index 0000000..6fd8fab
--- /dev/null
+++ b/webkit/browser/fileapi/file_writer_delegate.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_FILE_WRITER_DELEGATE_H_
+#define WEBKIT_BROWSER_FILEAPI_FILE_WRITER_DELEGATE_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "base/time.h"
+#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/url_request/url_request.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace fileapi {
+
+class FileStreamWriter;
+class FileSystemOperationContext;
+class FileSystemQuotaUtil;
+
+class WEBKIT_STORAGE_EXPORT_PRIVATE FileWriterDelegate
+ : public net::URLRequest::Delegate {
+ public:
+ enum WriteProgressStatus {
+ SUCCESS_IO_PENDING,
+ SUCCESS_COMPLETED,
+ ERROR_WRITE_STARTED,
+ ERROR_WRITE_NOT_STARTED,
+ };
+
+ typedef base::Callback<void(base::PlatformFileError result,
+ int64 bytes,
+ WriteProgressStatus write_status)>
+ DelegateWriteCallback;
+
+ FileWriterDelegate(
+ const DelegateWriteCallback& write_callback,
+ scoped_ptr<FileStreamWriter> file_writer);
+ virtual ~FileWriterDelegate();
+
+ void Start(scoped_ptr<net::URLRequest> request);
+
+ // Cancels the current write operation. Returns true if it is ok to
+ // delete this instance immediately. Otherwise this will call
+ // |write_operation|->DidWrite() with complete=true to let the operation
+ // perform the final cleanup.
+ bool Cancel();
+
+ virtual void OnReceivedRedirect(net::URLRequest* request,
+ const GURL& new_url,
+ bool* defer_redirect) OVERRIDE;
+ virtual void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) OVERRIDE;
+ virtual void OnCertificateRequested(
+ net::URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) OVERRIDE;
+ virtual void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) OVERRIDE;
+ virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
+ virtual void OnReadCompleted(net::URLRequest* request,
+ int bytes_read) OVERRIDE;
+
+ private:
+ void OnGetFileInfoAndStartRequest(
+ scoped_ptr<net::URLRequest> request,
+ base::PlatformFileError error,
+ const base::PlatformFileInfo& file_info);
+ void Read();
+ void OnDataReceived(int bytes_read);
+ void Write();
+ void OnDataWritten(int write_response);
+ void OnError(base::PlatformFileError error);
+ void OnProgress(int bytes_read, bool done);
+ void OnWriteCancelled(int status);
+ void FlushForCompletion(base::PlatformFileError error,
+ int bytes_written,
+ WriteProgressStatus progress_status);
+ void OnFlushed(base::PlatformFileError error,
+ int bytes_written,
+ WriteProgressStatus progress_status,
+ int flush_error);
+
+ FileSystemQuotaUtil* quota_util() const;
+ WriteProgressStatus GetCompletionStatusOnError() const;
+
+ DelegateWriteCallback write_callback_;
+ scoped_ptr<FileStreamWriter> file_stream_writer_;
+ base::Time last_progress_event_time_;
+ bool writing_started_;
+ int bytes_written_backlog_;
+ int bytes_written_;
+ int bytes_read_;
+ scoped_refptr<net::IOBufferWithSize> io_buffer_;
+ scoped_refptr<net::DrainableIOBuffer> cursor_;
+ scoped_ptr<net::URLRequest> request_;
+ base::WeakPtrFactory<FileWriterDelegate> weak_factory_;
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_FILE_WRITER_DELEGATE_H_
diff --git a/webkit/browser/fileapi/file_writer_delegate_unittest.cc b/webkit/browser/fileapi/file_writer_delegate_unittest.cc
new file mode 100644
index 0000000..320fee8e
--- /dev/null
+++ b/webkit/browser/fileapi/file_writer_delegate_unittest.cc
@@ -0,0 +1,465 @@
+// Copyright (c) 2012 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 <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/io_buffer.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/platform_test.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_quota_util.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
+#include "webkit/browser/fileapi/local_file_system_operation.h"
+#include "webkit/browser/fileapi/mock_file_system_context.h"
+#include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
+
+namespace fileapi {
+
+namespace {
+
+const GURL kOrigin("http://example.com");
+const FileSystemType kFileSystemType = kFileSystemTypeTest;
+
+class Result {
+ public:
+ Result()
+ : status_(base::PLATFORM_FILE_OK),
+ bytes_written_(0),
+ write_status_(FileWriterDelegate::SUCCESS_IO_PENDING) {}
+
+ base::PlatformFileError status() const { return status_; }
+ int64 bytes_written() const { return bytes_written_; }
+ FileWriterDelegate::WriteProgressStatus write_status() const {
+ return write_status_;
+ }
+
+ void DidWrite(base::PlatformFileError status, int64 bytes,
+ FileWriterDelegate::WriteProgressStatus write_status) {
+ write_status_ = write_status;
+ if (status == base::PLATFORM_FILE_OK) {
+ bytes_written_ += bytes;
+ if (write_status_ != FileWriterDelegate::SUCCESS_IO_PENDING)
+ base::MessageLoop::current()->Quit();
+ } else {
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status_);
+ status_ = status;
+ base::MessageLoop::current()->Quit();
+ }
+ }
+
+ private:
+ // For post-operation status.
+ base::PlatformFileError status_;
+ int64 bytes_written_;
+ FileWriterDelegate::WriteProgressStatus write_status_;
+};
+
+const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
+const int kDataSize = ARRAYSIZE_UNSAFE(kData) - 1;
+
+} // namespace (anonymous)
+
+class FileWriterDelegateTest : public PlatformTest {
+ public:
+ FileWriterDelegateTest()
+ : loop_(base::MessageLoop::TYPE_IO) {}
+
+ protected:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ FileSystemFileUtil* file_util() {
+ return file_system_context_->GetFileUtil(kFileSystemType);
+ }
+
+ int64 usage() {
+ return file_system_context_->GetQuotaUtil(kFileSystemType)->
+ GetOriginUsageOnFileThread(file_system_context_,
+ kOrigin,
+ kFileSystemType);
+ }
+
+ int64 GetFileSizeOnDisk(const char* test_file_path) {
+ // There might be in-flight flush/write.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&base::DoNothing));
+ base::MessageLoop::current()->RunUntilIdle();
+
+ FileSystemURL url = GetFileSystemURL(test_file_path);
+ base::PlatformFileInfo file_info;
+ base::FilePath platform_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ file_util()->GetFileInfo(NewOperationContext().get(), url,
+ &file_info, &platform_path));
+ return file_info.size;
+ }
+
+ FileSystemURL GetFileSystemURL(const char* file_name) const {
+ return file_system_context_->CreateCrackedFileSystemURL(
+ kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
+ }
+
+ scoped_ptr<FileSystemOperationContext> NewOperationContext() {
+ FileSystemOperationContext* context =
+ new FileSystemOperationContext(file_system_context_);
+ context->set_update_observers(
+ *file_system_context_->GetUpdateObservers(kFileSystemType));
+ return make_scoped_ptr(context);
+ }
+
+ FileWriterDelegate* CreateWriterDelegate(
+ const char* test_file_path,
+ int64 offset,
+ int64 allowed_growth,
+ Result* result) {
+ SandboxFileStreamWriter* writer = new SandboxFileStreamWriter(
+ file_system_context_,
+ GetFileSystemURL(test_file_path),
+ offset,
+ *file_system_context_->GetUpdateObservers(kFileSystemType));
+ writer->set_default_quota(allowed_growth);
+ return new FileWriterDelegate(
+ base::Bind(&Result::DidWrite, base::Unretained(result)),
+ scoped_ptr<FileStreamWriter>(writer));
+ }
+
+ // Creates and sets up a FileWriterDelegate for writing the given |blob_url|,
+ // and creates a new FileWriterDelegate for the file.
+ void PrepareForWrite(const char* test_file_path,
+ const GURL& blob_url,
+ int64 offset,
+ int64 allowed_growth) {
+ result_.reset(new Result());
+ file_writer_delegate_.reset(
+ CreateWriterDelegate(test_file_path, offset, allowed_growth,
+ result_.get()));
+ request_.reset(empty_context_.CreateRequest(
+ blob_url, file_writer_delegate_.get()));
+ }
+
+ static net::URLRequest::ProtocolFactory Factory;
+
+ // This should be alive until the very end of this instance.
+ base::MessageLoop loop_;
+
+ scoped_refptr<FileSystemContext> file_system_context_;
+
+ net::URLRequestContext empty_context_;
+ scoped_ptr<FileWriterDelegate> file_writer_delegate_;
+ scoped_ptr<net::URLRequest> request_;
+ scoped_ptr<Result> result_;
+
+ base::ScopedTempDir dir_;
+
+ static const char* content_;
+};
+
+const char* FileWriterDelegateTest::content_ = NULL;
+
+namespace {
+
+static std::string g_content;
+
+class FileWriterDelegateTestJob : public net::URLRequestJob {
+ public:
+ FileWriterDelegateTestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const std::string& content)
+ : net::URLRequestJob(request, network_delegate),
+ content_(content),
+ remaining_bytes_(content.length()),
+ cursor_(0) {
+ }
+
+ virtual void Start() OVERRIDE {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
+ }
+
+ virtual bool ReadRawData(net::IOBuffer* buf,
+ int buf_size,
+ int *bytes_read) OVERRIDE {
+ if (remaining_bytes_ < buf_size)
+ buf_size = static_cast<int>(remaining_bytes_);
+
+ for (int i = 0; i < buf_size; ++i)
+ buf->data()[i] = content_[cursor_++];
+ remaining_bytes_ -= buf_size;
+
+ SetStatus(net::URLRequestStatus());
+ *bytes_read = buf_size;
+ return true;
+ }
+
+ virtual int GetResponseCode() const OVERRIDE {
+ return 200;
+ }
+
+ protected:
+ virtual ~FileWriterDelegateTestJob() {}
+
+ private:
+ std::string content_;
+ int remaining_bytes_;
+ int cursor_;
+};
+
+} // namespace (anonymous)
+
+// static
+net::URLRequestJob* FileWriterDelegateTest::Factory(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const std::string& scheme) {
+ return new FileWriterDelegateTestJob(
+ request, network_delegate, FileWriterDelegateTest::content_);
+}
+
+void FileWriterDelegateTest::SetUp() {
+ ASSERT_TRUE(dir_.CreateUniqueTempDir());
+
+ file_system_context_ = CreateFileSystemContextForTesting(
+ NULL, dir_.path());
+
+ bool created = false;
+ scoped_ptr<FileSystemOperationContext> context = NewOperationContext();
+ context->set_allowed_bytes_growth(kint64max);
+ base::PlatformFileError error = file_util()->EnsureFileExists(
+ context.get(),
+ GetFileSystemURL("test"),
+ &created);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error);
+ ASSERT_TRUE(created);
+ net::URLRequest::Deprecated::RegisterProtocolFactory("blob", &Factory);
+}
+
+void FileWriterDelegateTest::TearDown() {
+ net::URLRequest::Deprecated::RegisterProtocolFactory("blob", NULL);
+ file_system_context_ = NULL;
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
+TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) {
+ const GURL kBlobURL("blob:nolimit");
+ content_ = kData;
+
+ PrepareForWrite("test", kBlobURL, 0, kint64max);
+
+ ASSERT_EQ(0, usage());
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ ASSERT_EQ(kDataSize, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+ EXPECT_EQ(kDataSize, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+}
+
+TEST_F(FileWriterDelegateTest, WriteSuccessWithJustQuota) {
+ const GURL kBlobURL("blob:just");
+ content_ = kData;
+ const int64 kAllowedGrowth = kDataSize;
+ PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
+
+ ASSERT_EQ(0, usage());
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ ASSERT_EQ(kAllowedGrowth, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+
+ EXPECT_EQ(kAllowedGrowth, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+}
+
+TEST_F(FileWriterDelegateTest, DISABLED_WriteFailureByQuota) {
+ const GURL kBlobURL("blob:failure");
+ content_ = kData;
+ const int64 kAllowedGrowth = kDataSize - 1;
+ PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
+
+ ASSERT_EQ(0, usage());
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ ASSERT_EQ(kAllowedGrowth, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+
+ EXPECT_EQ(kAllowedGrowth, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, result_->status());
+ ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result_->write_status());
+}
+
+TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
+ const GURL kBlobURL("blob:zero");
+ content_ = "";
+ int64 kAllowedGrowth = 0;
+ PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
+
+ ASSERT_EQ(0, usage());
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ ASSERT_EQ(kAllowedGrowth, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+
+ EXPECT_EQ(kAllowedGrowth, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+}
+
+TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
+ scoped_ptr<FileWriterDelegate> file_writer_delegate2;
+ scoped_ptr<net::URLRequest> request2;
+ scoped_ptr<Result> result2;
+
+ bool created = false;
+ file_util()->EnsureFileExists(NewOperationContext().get(),
+ GetFileSystemURL("test2"),
+ &created);
+ ASSERT_TRUE(created);
+
+ const GURL kBlobURL("blob:nolimitconcurrent");
+ const GURL kBlobURL2("blob:nolimitconcurrent2");
+ content_ = kData;
+
+ PrepareForWrite("test", kBlobURL, 0, kint64max);
+
+ // Credate another FileWriterDelegate for concurrent write.
+ result2.reset(new Result());
+ file_writer_delegate2.reset(CreateWriterDelegate(
+ "test2", 0, kint64max, result2.get()));
+ request2.reset(empty_context_.CreateRequest(
+ kBlobURL2, file_writer_delegate2.get()));
+
+ ASSERT_EQ(0, usage());
+ file_writer_delegate_->Start(request_.Pass());
+ file_writer_delegate2->Start(request2.Pass());
+ base::MessageLoop::current()->Run();
+ if (result_->write_status() == FileWriterDelegate::SUCCESS_IO_PENDING ||
+ result2->write_status() == FileWriterDelegate::SUCCESS_IO_PENDING)
+ base::MessageLoop::current()->Run();
+
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result2->write_status());
+ file_writer_delegate_.reset();
+ file_writer_delegate2.reset();
+
+ ASSERT_EQ(kDataSize * 2, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test") + GetFileSizeOnDisk("test2"), usage());
+
+ EXPECT_EQ(kDataSize, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+ EXPECT_EQ(kDataSize, result2->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result2->status());
+}
+
+TEST_F(FileWriterDelegateTest, WritesWithQuotaAndOffset) {
+ const GURL kBlobURL("blob:failure-with-updated-quota");
+ content_ = kData;
+
+ // Writing kDataSize (=45) bytes data while allowed_growth is 100.
+ int64 offset = 0;
+ int64 allowed_growth = 100;
+ ASSERT_LT(kDataSize, allowed_growth);
+ PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+
+ ASSERT_EQ(0, usage());
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ ASSERT_EQ(kDataSize, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+ EXPECT_EQ(kDataSize, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+
+ // Trying to overwrite kDataSize bytes data while allowed_growth is 20.
+ offset = 0;
+ allowed_growth = 20;
+ PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ EXPECT_EQ(kDataSize, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+ EXPECT_EQ(kDataSize, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+
+ // Trying to write kDataSize bytes data from offset 25 while
+ // allowed_growth is 55.
+ offset = 25;
+ allowed_growth = 55;
+ PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ EXPECT_EQ(offset + kDataSize, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+ EXPECT_EQ(kDataSize, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+
+ // Trying to overwrite 45 bytes data while allowed_growth is -20.
+ offset = 0;
+ allowed_growth = -20;
+ PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+
+ int64 pre_write_usage = GetFileSizeOnDisk("test");
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ EXPECT_EQ(pre_write_usage, usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+ EXPECT_EQ(kDataSize, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
+
+ // Trying to overwrite 45 bytes data with offset pre_write_usage - 20,
+ // while allowed_growth is 10.
+ const int kOverlap = 20;
+ offset = pre_write_usage - kOverlap;
+ allowed_growth = 10;
+ PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+
+ file_writer_delegate_->Start(request_.Pass());
+ base::MessageLoop::current()->Run();
+ ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result_->write_status());
+ file_writer_delegate_.reset();
+
+ EXPECT_EQ(pre_write_usage + allowed_growth,
+ usage());
+ EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
+ EXPECT_EQ(kOverlap + allowed_growth, result_->bytes_written());
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, result_->status());
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/isolated_context.cc b/webkit/browser/fileapi/isolated_context.cc
index 978ca0f..38aed76 100644
--- a/webkit/browser/fileapi/isolated_context.cc
+++ b/webkit/browser/fileapi/isolated_context.cc
@@ -12,7 +12,7 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/strings/string_number_conversions.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_url.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/isolated_context_unittest.cc b/webkit/browser/fileapi/isolated_context_unittest.cc
index 17c9ab5..36073ca 100644
--- a/webkit/browser/fileapi/isolated_context_unittest.cc
+++ b/webkit/browser/fileapi/isolated_context_unittest.cc
@@ -7,8 +7,8 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/fileapi/file_system_url.h"
#define FPL(x) FILE_PATH_LITERAL(x)
diff --git a/webkit/browser/fileapi/isolated_file_util.cc b/webkit/browser/fileapi/isolated_file_util.cc
index f8812ce..4ed1f8c 100644
--- a/webkit/browser/fileapi/isolated_file_util.cc
+++ b/webkit/browser/fileapi/isolated_file_util.cc
@@ -9,11 +9,11 @@
#include "base/file_util.h"
#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/native_file_util.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/file_system_url.h"
using base::PlatformFileError;
using base::PlatformFileInfo;
diff --git a/webkit/browser/fileapi/isolated_file_util_unittest.cc b/webkit/browser/fileapi/isolated_file_util_unittest.cc
index c6d8f81..dfedabd 100644
--- a/webkit/browser/fileapi/isolated_file_util_unittest.cc
+++ b/webkit/browser/fileapi/isolated_file_util_unittest.cc
@@ -15,6 +15,9 @@
#include "base/message_loop_proxy.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/isolated_file_util.h"
@@ -22,10 +25,7 @@
#include "webkit/browser/fileapi/local_file_util.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/native_file_util.h"
-#include "webkit/fileapi/async_file_test_helper.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/test_file_set.h"
+#include "webkit/browser/fileapi/test_file_set.h"
using file_util::FileEnumerator;
diff --git a/webkit/browser/fileapi/isolated_mount_point_provider.cc b/webkit/browser/fileapi/isolated_mount_point_provider.cc
index 60a3aee..0cec867 100644
--- a/webkit/browser/fileapi/isolated_mount_point_provider.cc
+++ b/webkit/browser/fileapi/isolated_mount_point_provider.cc
@@ -14,20 +14,20 @@
#include "base/platform_file.h"
#include "base/sequenced_task_runner.h"
#include "webkit/blob/local_file_stream_reader.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.h"
#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/isolated_file_util.h"
+#include "webkit/browser/fileapi/local_file_stream_writer.h"
#include "webkit/browser/fileapi/local_file_system_operation.h"
#include "webkit/browser/fileapi/native_file_util.h"
#include "webkit/browser/fileapi/transient_file_util.h"
-#include "webkit/fileapi/async_file_util_adapter.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_file_stream_reader.h"
-#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/file_system_util.h"
-#include "webkit/fileapi/local_file_stream_writer.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/local_file_stream_writer.cc b/webkit/browser/fileapi/local_file_stream_writer.cc
new file mode 100644
index 0000000..a34f803
--- /dev/null
+++ b/webkit/browser/fileapi/local_file_stream_writer.cc
@@ -0,0 +1,230 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/local_file_stream_writer.h"
+
+#include "base/callback.h"
+#include "base/message_loop.h"
+#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace fileapi {
+
+namespace {
+
+const int kOpenFlagsForWrite = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC;
+
+} // namespace
+
+LocalFileStreamWriter::LocalFileStreamWriter(const base::FilePath& file_path,
+ int64 initial_offset)
+ : file_path_(file_path),
+ initial_offset_(initial_offset),
+ has_pending_operation_(false),
+ weak_factory_(this) {}
+
+LocalFileStreamWriter::~LocalFileStreamWriter() {
+ // Invalidate weak pointers so that we won't receive any callbacks from
+ // in-flight stream operations, which might be triggered during the file close
+ // in the FileStream destructor.
+ weak_factory_.InvalidateWeakPtrs();
+
+ // FileStream's destructor closes the file safely, since we opened the file
+ // by its Open() method.
+}
+
+int LocalFileStreamWriter::Write(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ DCHECK(!has_pending_operation_);
+ DCHECK(cancel_callback_.is_null());
+
+ has_pending_operation_ = true;
+ if (stream_impl_) {
+ int result = InitiateWrite(buf, buf_len, callback);
+ if (result != net::ERR_IO_PENDING)
+ has_pending_operation_ = false;
+ return result;
+ }
+ return InitiateOpen(callback,
+ base::Bind(&LocalFileStreamWriter::ReadyToWrite,
+ weak_factory_.GetWeakPtr(),
+ make_scoped_refptr(buf), buf_len, callback));
+}
+
+int LocalFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
+ if (!has_pending_operation_)
+ return net::ERR_UNEXPECTED;
+
+ DCHECK(!callback.is_null());
+ cancel_callback_ = callback;
+ return net::ERR_IO_PENDING;
+}
+
+int LocalFileStreamWriter::Flush(const net::CompletionCallback& callback) {
+ DCHECK(!has_pending_operation_);
+ DCHECK(cancel_callback_.is_null());
+
+ // Write() is not called yet, so there's nothing to flush.
+ if (!stream_impl_)
+ return net::OK;
+
+ has_pending_operation_ = true;
+ int result = InitiateFlush(callback);
+ if (result != net::ERR_IO_PENDING)
+ has_pending_operation_ = false;
+ return result;
+}
+
+int LocalFileStreamWriter::InitiateOpen(
+ const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation) {
+ DCHECK(has_pending_operation_);
+ DCHECK(!stream_impl_.get());
+
+ stream_impl_.reset(new net::FileStream(NULL));
+ return stream_impl_->Open(file_path_,
+ kOpenFlagsForWrite,
+ base::Bind(&LocalFileStreamWriter::DidOpen,
+ weak_factory_.GetWeakPtr(),
+ error_callback,
+ main_operation));
+}
+
+void LocalFileStreamWriter::DidOpen(
+ const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation,
+ int result) {
+ DCHECK(has_pending_operation_);
+ DCHECK(stream_impl_.get());
+
+ if (CancelIfRequested())
+ return;
+
+ if (result != net::OK) {
+ has_pending_operation_ = false;
+ stream_impl_.reset(NULL);
+ error_callback.Run(result);
+ return;
+ }
+
+ InitiateSeek(error_callback, main_operation);
+}
+
+void LocalFileStreamWriter::InitiateSeek(
+ const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation) {
+ DCHECK(has_pending_operation_);
+ DCHECK(stream_impl_.get());
+
+ if (initial_offset_ == 0) {
+ // No need to seek.
+ main_operation.Run();
+ return;
+ }
+
+ int result = stream_impl_->Seek(net::FROM_BEGIN, initial_offset_,
+ base::Bind(&LocalFileStreamWriter::DidSeek,
+ weak_factory_.GetWeakPtr(),
+ error_callback,
+ main_operation));
+ if (result != net::ERR_IO_PENDING) {
+ has_pending_operation_ = false;
+ error_callback.Run(result);
+ }
+}
+
+void LocalFileStreamWriter::DidSeek(
+ const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation,
+ int64 result) {
+ DCHECK(has_pending_operation_);
+
+ if (CancelIfRequested())
+ return;
+
+ if (result != initial_offset_) {
+ // TODO(kinaba) add a more specific error code.
+ result = net::ERR_FAILED;
+ }
+
+ if (result < 0) {
+ has_pending_operation_ = false;
+ error_callback.Run(static_cast<int>(result));
+ return;
+ }
+
+ main_operation.Run();
+}
+
+void LocalFileStreamWriter::ReadyToWrite(
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ DCHECK(has_pending_operation_);
+
+ int result = InitiateWrite(buf, buf_len, callback);
+ if (result != net::ERR_IO_PENDING) {
+ has_pending_operation_ = false;
+ callback.Run(result);
+ }
+}
+
+int LocalFileStreamWriter::InitiateWrite(
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ DCHECK(has_pending_operation_);
+ DCHECK(stream_impl_.get());
+
+ return stream_impl_->Write(buf, buf_len,
+ base::Bind(&LocalFileStreamWriter::DidWrite,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void LocalFileStreamWriter::DidWrite(const net::CompletionCallback& callback,
+ int result) {
+ DCHECK(has_pending_operation_);
+
+ if (CancelIfRequested())
+ return;
+ has_pending_operation_ = false;
+ callback.Run(result);
+}
+
+int LocalFileStreamWriter::InitiateFlush(
+ const net::CompletionCallback& callback) {
+ DCHECK(has_pending_operation_);
+ DCHECK(stream_impl_.get());
+
+ return stream_impl_->Flush(base::Bind(&LocalFileStreamWriter::DidFlush,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void LocalFileStreamWriter::DidFlush(const net::CompletionCallback& callback,
+ int result) {
+ DCHECK(has_pending_operation_);
+
+ if (CancelIfRequested())
+ return;
+ has_pending_operation_ = false;
+ callback.Run(result);
+}
+
+bool LocalFileStreamWriter::CancelIfRequested() {
+ DCHECK(has_pending_operation_);
+
+ if (cancel_callback_.is_null())
+ return false;
+
+ net::CompletionCallback pending_cancel = cancel_callback_;
+ has_pending_operation_ = false;
+ cancel_callback_.Reset();
+ pending_cancel.Run(net::OK);
+ return true;
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/local_file_stream_writer.h b/webkit/browser/fileapi/local_file_stream_writer.h
new file mode 100644
index 0000000..ed3ee68
--- /dev/null
+++ b/webkit/browser/fileapi/local_file_stream_writer.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_LOCAL_FILE_STREAM_WRITER_H_
+#define WEBKIT_BROWSER_FILEAPI_LOCAL_FILE_STREAM_WRITER_H_
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "webkit/browser/fileapi/file_stream_writer.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace net {
+class FileStream;
+}
+
+namespace fileapi {
+
+// This class is a thin wrapper around net::FileStream for writing local files.
+class WEBKIT_STORAGE_EXPORT_PRIVATE LocalFileStreamWriter
+ : public FileStreamWriter {
+ public:
+ // Create a writer for the existing file in the path |file_path| starting from
+ // |initial_offset|.
+ LocalFileStreamWriter(const base::FilePath& file_path, int64 initial_offset);
+ virtual ~LocalFileStreamWriter();
+
+ // FileStreamWriter overrides.
+ virtual int Write(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual int Cancel(const net::CompletionCallback& callback) OVERRIDE;
+ virtual int Flush(const net::CompletionCallback& callback) OVERRIDE;
+
+ private:
+ // Opens |file_path_| and if it succeeds, proceeds to InitiateSeek().
+ // If failed, the error code is returned by calling |error_callback|.
+ int InitiateOpen(const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation);
+ void DidOpen(const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation,
+ int result);
+
+ // Seeks to |initial_offset_| and proceeds to |main_operation| if it succeeds.
+ // If failed, the error code is returned by calling |error_callback|.
+ void InitiateSeek(const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation);
+ void DidSeek(const net::CompletionCallback& error_callback,
+ const base::Closure& main_operation,
+ int64 result);
+
+ // Passed as the |main_operation| of InitiateOpen() function.
+ void ReadyToWrite(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback);
+
+ // Writes asynchronously to the file.
+ int InitiateWrite(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback);
+ void DidWrite(const net::CompletionCallback& callback, int result);
+
+ // Flushes asynchronously to the file.
+ int InitiateFlush(const net::CompletionCallback& callback);
+ void DidFlush(const net::CompletionCallback& callback, int result);
+
+ // Stops the in-flight operation and calls |cancel_callback_| if it has been
+ // set by Cancel() for the current operation.
+ bool CancelIfRequested();
+
+ // Initialization parameters.
+ const base::FilePath file_path_;
+ const int64 initial_offset_;
+
+ // Current states of the operation.
+ bool has_pending_operation_;
+ scoped_ptr<net::FileStream> stream_impl_;
+ net::CompletionCallback cancel_callback_;
+
+ base::WeakPtrFactory<LocalFileStreamWriter> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(LocalFileStreamWriter);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_LOCAL_FILE_STREAM_WRITER_H_
diff --git a/webkit/browser/fileapi/local_file_stream_writer_unittest.cc b/webkit/browser/fileapi/local_file_stream_writer_unittest.cc
new file mode 100644
index 0000000..984a114
--- /dev/null
+++ b/webkit/browser/fileapi/local_file_stream_writer_unittest.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/local_file_stream_writer.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using fileapi::LocalFileStreamWriter;
+
+class LocalFileStreamWriterTest : public testing::Test {
+ public:
+ LocalFileStreamWriterTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ }
+
+ protected:
+ base::FilePath Path(const std::string& name) {
+ return temp_dir_.path().AppendASCII(name);
+ }
+
+ int WriteStringToWriter(LocalFileStreamWriter* writer,
+ const std::string& data) {
+ scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(data));
+ scoped_refptr<net::DrainableIOBuffer> drainable(
+ new net::DrainableIOBuffer(buffer, buffer->size()));
+
+ while (drainable->BytesRemaining() > 0) {
+ net::TestCompletionCallback callback;
+ int result = writer->Write(drainable, drainable->BytesRemaining(),
+ callback.callback());
+ if (result == net::ERR_IO_PENDING)
+ result = callback.WaitForResult();
+ if (result <= 0)
+ return result;
+ drainable->DidConsume(result);
+ }
+ return net::OK;
+ }
+
+ std::string GetFileContent(const base::FilePath& path) {
+ std::string content;
+ file_util::ReadFileToString(path, &content);
+ return content;
+ }
+
+ base::FilePath CreateFileWithContent(const std::string& name,
+ const std::string& data) {
+ base::FilePath path = Path(name);
+ file_util::WriteFile(path, data.c_str(), data.size());
+ return path;
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ base::ScopedTempDir temp_dir_;
+};
+
+void NeverCalled(int unused) {
+ ADD_FAILURE();
+}
+
+} // namespace
+
+TEST_F(LocalFileStreamWriterTest, Write) {
+ base::FilePath path = CreateFileWithContent("file_a", std::string());
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 0));
+ EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo"));
+ EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "bar"));
+ writer.reset();
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(file_util::PathExists(path));
+ EXPECT_EQ("foobar", GetFileContent(path));
+}
+
+TEST_F(LocalFileStreamWriterTest, WriteMiddle) {
+ base::FilePath path = CreateFileWithContent("file_a", "foobar");
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 2));
+ EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
+ writer.reset();
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(file_util::PathExists(path));
+ EXPECT_EQ("foxxxr", GetFileContent(path));
+}
+
+TEST_F(LocalFileStreamWriterTest, WriteEnd) {
+ base::FilePath path = CreateFileWithContent("file_a", "foobar");
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 6));
+ EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
+ writer.reset();
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(file_util::PathExists(path));
+ EXPECT_EQ("foobarxxx", GetFileContent(path));
+}
+
+TEST_F(LocalFileStreamWriterTest, WriteFailForNonexistingFile) {
+ base::FilePath path = Path("file_a");
+ ASSERT_FALSE(file_util::PathExists(path));
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 0));
+ EXPECT_EQ(net::ERR_FILE_NOT_FOUND, WriteStringToWriter(writer.get(), "foo"));
+ writer.reset();
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_FALSE(file_util::PathExists(path));
+}
+
+TEST_F(LocalFileStreamWriterTest, CancelBeforeOperation) {
+ base::FilePath path = Path("file_a");
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 0));
+ // Cancel immediately fails when there's no in-flight operation.
+ int cancel_result = writer->Cancel(base::Bind(&NeverCalled));
+ EXPECT_EQ(net::ERR_UNEXPECTED, cancel_result);
+}
+
+TEST_F(LocalFileStreamWriterTest, CancelAfterFinishedOperation) {
+ base::FilePath path = CreateFileWithContent("file_a", std::string());
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 0));
+ EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo"));
+
+ // Cancel immediately fails when there's no in-flight operation.
+ int cancel_result = writer->Cancel(base::Bind(&NeverCalled));
+ EXPECT_EQ(net::ERR_UNEXPECTED, cancel_result);
+
+ writer.reset();
+ base::MessageLoop::current()->RunUntilIdle();
+ // Write operation is already completed.
+ EXPECT_TRUE(file_util::PathExists(path));
+ EXPECT_EQ("foo", GetFileContent(path));
+}
+
+TEST_F(LocalFileStreamWriterTest, CancelWrite) {
+ base::FilePath path = CreateFileWithContent("file_a", "foobar");
+ scoped_ptr<LocalFileStreamWriter> writer(new LocalFileStreamWriter(path, 0));
+
+ scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer("xxx"));
+ int result = writer->Write(buffer, buffer->size(), base::Bind(&NeverCalled));
+ ASSERT_EQ(net::ERR_IO_PENDING, result);
+
+ net::TestCompletionCallback callback;
+ writer->Cancel(callback.callback());
+ int cancel_result = callback.WaitForResult();
+ EXPECT_EQ(net::OK, cancel_result);
+}
diff --git a/webkit/browser/fileapi/local_file_system_cross_operation_unittest.cc b/webkit/browser/fileapi/local_file_system_cross_operation_unittest.cc
index 13a3f39..1b600d9 100644
--- a/webkit/browser/fileapi/local_file_system_cross_operation_unittest.cc
+++ b/webkit/browser/fileapi/local_file_system_cross_operation_unittest.cc
@@ -12,14 +12,14 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
-#include "webkit/fileapi/async_file_test_helper.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/test_file_set.h"
#include "webkit/fileapi/file_system_util.h"
-#include "webkit/fileapi/test_file_set.h"
#include "webkit/quota/mock_quota_manager.h"
#include "webkit/quota/quota_manager.h"
diff --git a/webkit/browser/fileapi/local_file_system_operation.cc b/webkit/browser/fileapi/local_file_system_operation.cc
index 4a10db9..f278cf2 100644
--- a/webkit/browser/fileapi/local_file_system_operation.cc
+++ b/webkit/browser/fileapi/local_file_system_operation.cc
@@ -11,20 +11,20 @@
#include "net/base/escape.h"
#include "net/url_request/url_request_context.h"
#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/browser/fileapi/async_file_util.h"
#include "webkit/browser/fileapi/cross_operation_delegate.h"
#include "webkit/browser/fileapi/file_observers.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
+#include "webkit/browser/fileapi/remove_operation_delegate.h"
#include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
-#include "webkit/fileapi/async_file_util.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_types.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
-#include "webkit/fileapi/file_writer_delegate.h"
-#include "webkit/fileapi/remove_operation_delegate.h"
#include "webkit/quota/quota_manager.h"
#include "webkit/quota/quota_types.h"
diff --git a/webkit/browser/fileapi/local_file_system_operation.h b/webkit/browser/fileapi/local_file_system_operation.h
index bc951d0..bca7834 100644
--- a/webkit/browser/fileapi/local_file_system_operation.h
+++ b/webkit/browser/fileapi/local_file_system_operation.h
@@ -10,9 +10,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "webkit/blob/scoped_file.h"
-#include "webkit/fileapi/file_system_operation.h"
-#include "webkit/fileapi/file_system_url.h"
-#include "webkit/fileapi/file_writer_delegate.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
#include "webkit/quota/quota_types.h"
#include "webkit/storage/webkit_storage_export.h"
diff --git a/webkit/browser/fileapi/local_file_system_operation_unittest.cc b/webkit/browser/fileapi/local_file_system_operation_unittest.cc
index b5a81ab..cbbd0f7 100644
--- a/webkit/browser/fileapi/local_file_system_operation_unittest.cc
+++ b/webkit/browser/fileapi/local_file_system_operation_unittest.cc
@@ -15,13 +15,13 @@
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/mock_file_change_observer.h"
-#include "webkit/fileapi/async_file_test_helper.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/sandbox_file_system_test_helper.h"
#include "webkit/fileapi/file_system_util.h"
-#include "webkit/fileapi/sandbox_file_system_test_helper.h"
#include "webkit/quota/mock_quota_manager.h"
#include "webkit/quota/quota_manager.h"
diff --git a/webkit/browser/fileapi/local_file_system_operation_write_unittest.cc b/webkit/browser/fileapi/local_file_system_operation_write_unittest.cc
index 15ca130..ba72758 100644
--- a/webkit/browser/fileapi/local_file_system_operation_write_unittest.cc
+++ b/webkit/browser/fileapi/local_file_system_operation_write_unittest.cc
@@ -19,14 +19,14 @@
#include "webkit/blob/blob_storage_controller.h"
#include "webkit/blob/blob_url_request_job.h"
#include "webkit/blob/mock_blob_url_request_context.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/local_file_system_operation.h"
#include "webkit/browser/fileapi/local_file_util.h"
#include "webkit/browser/fileapi/mock_file_change_observer.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation.h"
-#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_util.h"
#include "webkit/quota/mock_quota_manager.h"
diff --git a/webkit/browser/fileapi/local_file_util.cc b/webkit/browser/fileapi/local_file_util.cc
index 7302170..8dcd277 100644
--- a/webkit/browser/fileapi/local_file_util.cc
+++ b/webkit/browser/fileapi/local_file_util.cc
@@ -7,12 +7,12 @@
#include "base/file_util.h"
#include "base/files/file_util_proxy.h"
#include "googleurl/src/gurl.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/native_file_util.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_types.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/local_file_util_unittest.cc b/webkit/browser/fileapi/local_file_util_unittest.cc
index efc8da96..4ca052f 100644
--- a/webkit/browser/fileapi/local_file_util_unittest.cc
+++ b/webkit/browser/fileapi/local_file_util_unittest.cc
@@ -13,13 +13,13 @@
#include "base/strings/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/local_file_util.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/native_file_util.h"
-#include "webkit/fileapi/async_file_test_helper.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_types.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/mock_file_change_observer.h b/webkit/browser/fileapi/mock_file_change_observer.h
index 36ff3ae..3835323d 100644
--- a/webkit/browser/fileapi/mock_file_change_observer.h
+++ b/webkit/browser/fileapi/mock_file_change_observer.h
@@ -8,8 +8,8 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "webkit/browser/fileapi/file_observers.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
-#include "webkit/fileapi/file_system_url.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/mock_file_system_context.cc b/webkit/browser/fileapi/mock_file_system_context.cc
index 2fda4e9..f6c930a 100644
--- a/webkit/browser/fileapi/mock_file_system_context.cc
+++ b/webkit/browser/fileapi/mock_file_system_context.cc
@@ -6,11 +6,11 @@
#include "base/memory/scoped_vector.h"
#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/mock_file_system_options.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/test_mount_point_provider.h"
+#include "webkit/browser/fileapi/test_mount_point_provider.h"
#include "webkit/quota/mock_special_storage_policy.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/mock_file_system_options.h b/webkit/browser/fileapi/mock_file_system_options.h
index 32ebd74..f46f635 100644
--- a/webkit/browser/fileapi/mock_file_system_options.h
+++ b/webkit/browser/fileapi/mock_file_system_options.h
@@ -5,7 +5,7 @@
#ifndef WEBKIT_BROWSER_FILEAPI_MOCK_FILE_SYSTEM_OPTIONS_H_
#define WEBKIT_BROWSER_FILEAPI_MOCK_FILE_SYSTEM_OPTIONS_H_
-#include "webkit/fileapi/file_system_options.h"
+#include "webkit/browser/fileapi/file_system_options.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/native_file_util.cc b/webkit/browser/fileapi/native_file_util.cc
index e3a9519..3900244 100644
--- a/webkit/browser/fileapi/native_file_util.cc
+++ b/webkit/browser/fileapi/native_file_util.cc
@@ -6,7 +6,7 @@
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
-#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/obfuscated_file_util.cc b/webkit/browser/fileapi/obfuscated_file_util.cc
index 5d9d377..668ec37 100644
--- a/webkit/browser/fileapi/obfuscated_file_util.cc
+++ b/webkit/browser/fileapi/obfuscated_file_util.cc
@@ -20,11 +20,11 @@
#include "googleurl/src/gurl.h"
#include "webkit/base/origin_url_conversions.h"
#include "webkit/browser/fileapi/file_observers.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/native_file_util.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
#include "webkit/fileapi/syncable/syncable_file_system_util.h"
#include "webkit/quota/quota_manager.h"
diff --git a/webkit/browser/fileapi/obfuscated_file_util.h b/webkit/browser/fileapi/obfuscated_file_util.h
index e4915a3..24cd246 100644
--- a/webkit/browser/fileapi/obfuscated_file_util.h
+++ b/webkit/browser/fileapi/obfuscated_file_util.h
@@ -15,10 +15,10 @@
#include "base/timer.h"
#include "webkit/blob/shareable_file_reference.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/sandbox_directory_database.h"
#include "webkit/browser/fileapi/sandbox_origin_database.h"
#include "webkit/fileapi/file_system_types.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/storage/webkit_storage_export.h"
namespace base {
diff --git a/webkit/browser/fileapi/obfuscated_file_util_unittest.cc b/webkit/browser/fileapi/obfuscated_file_util_unittest.cc
index 1b42186..a0e788d 100644
--- a/webkit/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/webkit/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -14,18 +14,18 @@
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/file_system_usage_cache.h"
#include "webkit/browser/fileapi/mock_file_change_observer.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/fileapi/async_file_test_helper.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/sandbox_file_system_test_helper.h"
-#include "webkit/fileapi/test_file_set.h"
+#include "webkit/browser/fileapi/sandbox_file_system_test_helper.h"
+#include "webkit/browser/fileapi/test_file_set.h"
#include "webkit/quota/mock_special_storage_policy.h"
#include "webkit/quota/quota_manager.h"
#include "webkit/quota/quota_types.h"
diff --git a/webkit/browser/fileapi/recursive_operation_delegate.cc b/webkit/browser/fileapi/recursive_operation_delegate.cc
index a358c21..80d7c14 100644
--- a/webkit/browser/fileapi/recursive_operation_delegate.cc
+++ b/webkit/browser/fileapi/recursive_operation_delegate.cc
@@ -5,9 +5,9 @@
#include "webkit/browser/fileapi/recursive_operation_delegate.h"
#include "base/bind.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/local_file_system_operation.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/recursive_operation_delegate.h b/webkit/browser/fileapi/recursive_operation_delegate.h
index 23e0735..ba8c81e 100644
--- a/webkit/browser/fileapi/recursive_operation_delegate.h
+++ b/webkit/browser/fileapi/recursive_operation_delegate.h
@@ -10,8 +10,8 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
-#include "webkit/fileapi/file_system_operation.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_url.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/remote_file_system_proxy.h b/webkit/browser/fileapi/remote_file_system_proxy.h
new file mode 100644
index 0000000..0b59a73
--- /dev/null
+++ b/webkit/browser/fileapi/remote_file_system_proxy.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_REMOTE_FILE_SYSTEM_PROXY_H_
+#define WEBKIT_BROWSER_FILEAPI_REMOTE_FILE_SYSTEM_PROXY_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+
+namespace base {
+class SequencedTaskRunner;
+} // namespace base
+
+namespace webkit_blob {
+class FileStreamReader;
+} // namespace webkit_blob
+
+namespace fileapi {
+
+typedef base::Callback<
+ void(base::PlatformFileError result,
+ const base::FilePath& platform_path,
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref)>
+ WritableSnapshotFile;
+
+// The interface class for remote file system proxy.
+class RemoteFileSystemProxyInterface :
+ public base::RefCountedThreadSafe<RemoteFileSystemProxyInterface> {
+ public:
+ // Used for OpenFile(). |result| is the return code of the operation.
+ typedef base::Callback<
+ void(base::PlatformFileError result,
+ base::PlatformFile file,
+ base::ProcessHandle peer_handle)> OpenFileCallback;
+
+
+ // Gets the file or directory info for given|path|.
+ virtual void GetFileInfo(const FileSystemURL& url,
+ const FileSystemOperation::GetMetadataCallback& callback) = 0;
+
+ // Copies a file or directory from |src_url| to |dest_url|. If
+ // |src_url| is a directory, the contents of |src_url| are copied to
+ // |dest_url| recursively. A new file or directory is created at
+ // |dest_url| as needed.
+ virtual void Copy(
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Moves a file or directory from |src_url| to |dest_url|. A new file
+ // or directory is created at |dest_url| as needed.
+ virtual void Move(
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Reads contents of a directory at |url|.
+ virtual void ReadDirectory(const FileSystemURL& url,
+ const FileSystemOperation::ReadDirectoryCallback& callback) = 0;
+
+ // Removes a file or directory at |url|. If |recursive| is true, remove
+ // all files and directories under the directory at |url| recursively.
+ virtual void Remove(const FileSystemURL& url, bool recursive,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Creates a directory at |url|. If |exclusive| is true, an error is
+ // raised in case a directory is already present at the URL. If
+ // |recursive| is true, create parent directories as needed just like
+ // mkdir -p does.
+ virtual void CreateDirectory(
+ const FileSystemURL& url,
+ bool exclusive,
+ bool recursive,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Creates a file at |url|. If the flag |is_exclusive| is true, an
+ // error is raised when a file already exists at the path. It is
+ // an error if a directory or a hosted document is already present at the
+ // path, or the parent directory of the path is not present yet.
+ virtual void CreateFile(
+ const FileSystemURL& url,
+ bool exclusive,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Changes the length of an existing file at |url| to |length|. If |length|
+ // is negative, an error is raised. If |length| is more than the current size
+ // of the file, zero is padded for the extended part.
+ virtual void Truncate(
+ const FileSystemURL& url,
+ int64 length,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Creates a local snapshot file for a given |url| and returns the
+ // metadata and platform path of the snapshot file via |callback|.
+ // See also FileSystemOperation::CreateSnapshotFile().
+ virtual void CreateSnapshotFile(
+ const FileSystemURL& url,
+ const FileSystemOperation::SnapshotFileCallback& callback) = 0;
+
+ // Creates a local snapshot file for a given |url| and marks it for
+ // modification. A webkit_blob::ShareableFileReference is passed to
+ // |callback|, and when the reference is released, modification to the
+ // snapshot is marked for uploading to the remote file system.
+ virtual void CreateWritableSnapshotFile(
+ const FileSystemURL& url,
+ const WritableSnapshotFile& callback) = 0;
+
+ // Opens file for a given |url| with specified |flags| (see
+ // base::PlatformFileFlags for details).
+ virtual void OpenFile(
+ const FileSystemURL& url,
+ int flags,
+ base::ProcessHandle peer_handle,
+ const OpenFileCallback& callback) = 0;
+
+ // Notifies that a file opened by OpenFile (at |path|) is closed.
+ virtual void NotifyCloseFile(const FileSystemURL& url) = 0;
+
+ // Modifies the timestamp of a given |url| to |last_access_time| and
+ // |last_modified_time|. Note that unlike 'touch' command of Linux, it
+ // does not create a new file.
+ virtual void TouchFile(
+ const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const FileSystemOperation::StatusCallback& callback) = 0;
+
+ // Creates a new file stream reader for the file at |url| with an |offset|.
+ // |expected_modification_time| specifies the expected last modification
+ // if it isn't null, and the reader will return ERR_UPLOAD_FILE_CHANGED error
+ // if the file has been modified.
+ // The error will be notified via error code of FileStreamReader's methods,
+ // and this method itself doesn't check if the file exists and is a regular
+ // file.
+ virtual scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+ base::SequencedTaskRunner* file_task_runner,
+ const FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<RemoteFileSystemProxyInterface>;
+ virtual ~RemoteFileSystemProxyInterface() {}
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_REMOTE_FILE_SYSTEM_PROXY_H_
diff --git a/webkit/browser/fileapi/remove_operation_delegate.cc b/webkit/browser/fileapi/remove_operation_delegate.cc
new file mode 100644
index 0000000..f7238c8
--- /dev/null
+++ b/webkit/browser/fileapi/remove_operation_delegate.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2013 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 "webkit/browser/fileapi/remove_operation_delegate.h"
+
+#include "base/bind.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/local_file_system_operation.h"
+
+namespace fileapi {
+
+RemoveOperationDelegate::RemoveOperationDelegate(
+ FileSystemContext* file_system_context,
+ LocalFileSystemOperation* operation,
+ const FileSystemURL& url,
+ const StatusCallback& callback)
+ : RecursiveOperationDelegate(file_system_context, operation),
+ url_(url),
+ callback_(callback) {
+}
+
+RemoveOperationDelegate::~RemoveOperationDelegate() {}
+
+void RemoveOperationDelegate::Run() {
+ NewNestedOperation()->RemoveFile(url_, base::Bind(
+ &RemoveOperationDelegate::DidTryRemoveFile, AsWeakPtr()));
+}
+
+void RemoveOperationDelegate::RunRecursively() {
+ StartRecursiveOperation(
+ url_,
+ base::Bind(&RemoveOperationDelegate::RemoveNextDirectory, AsWeakPtr()));
+}
+
+void RemoveOperationDelegate::ProcessFile(const FileSystemURL& url,
+ const StatusCallback& callback) {
+ if (to_remove_directories_.size() == 1u &&
+ to_remove_directories_.top() == url) {
+ // We seem to have been re-directed from ProcessDirectory.
+ to_remove_directories_.pop();
+ }
+ NewNestedOperation()->RemoveFile(url, base::Bind(
+ &RemoveOperationDelegate::DidRemoveFile, AsWeakPtr(), callback));
+}
+
+void RemoveOperationDelegate::ProcessDirectory(const FileSystemURL& url,
+ const StatusCallback& callback) {
+ to_remove_directories_.push(url);
+ callback.Run(base::PLATFORM_FILE_OK);
+}
+
+void RemoveOperationDelegate::DidTryRemoveFile(
+ base::PlatformFileError error) {
+ if (error == base::PLATFORM_FILE_OK ||
+ error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) {
+ callback_.Run(error);
+ return;
+ }
+ NewNestedOperation()->RemoveDirectory(url_, callback_);
+}
+
+void RemoveOperationDelegate::DidRemoveFile(const StatusCallback& callback,
+ base::PlatformFileError error) {
+ if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
+ callback.Run(base::PLATFORM_FILE_OK);
+ return;
+ }
+ callback.Run(error);
+}
+
+void RemoveOperationDelegate::RemoveNextDirectory(
+ base::PlatformFileError error) {
+ if (error != base::PLATFORM_FILE_OK ||
+ to_remove_directories_.empty()) {
+ callback_.Run(error);
+ return;
+ }
+ FileSystemURL url = to_remove_directories_.top();
+ to_remove_directories_.pop();
+ NewNestedOperation()->RemoveDirectory(url, base::Bind(
+ &RemoveOperationDelegate::RemoveNextDirectory,
+ AsWeakPtr()));
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/remove_operation_delegate.h b/webkit/browser/fileapi/remove_operation_delegate.h
new file mode 100644
index 0000000..2fa4b68
--- /dev/null
+++ b/webkit/browser/fileapi/remove_operation_delegate.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2013 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 WEBKIT_BROWSER_FILEAPI_REMOVE_OPERATION_DELEGATE_H_
+#define WEBKIT_BROWSER_FILEAPI_REMOVE_OPERATION_DELEGATE_H_
+
+#include <stack>
+
+#include "webkit/browser/fileapi/recursive_operation_delegate.h"
+
+namespace fileapi {
+
+class RemoveOperationDelegate
+ : public RecursiveOperationDelegate,
+ public base::SupportsWeakPtr<RemoveOperationDelegate> {
+ public:
+ RemoveOperationDelegate(FileSystemContext* file_system_context,
+ LocalFileSystemOperation* operation,
+ const FileSystemURL& url,
+ const StatusCallback& callback);
+ virtual ~RemoveOperationDelegate();
+
+ // RecursiveOperationDelegate overrides:
+ virtual void Run() OVERRIDE;
+ virtual void RunRecursively() OVERRIDE;
+ virtual void ProcessFile(const FileSystemURL& url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual void ProcessDirectory(const FileSystemURL& url,
+ const StatusCallback& callback) OVERRIDE;
+
+ using base::SupportsWeakPtr<RemoveOperationDelegate>::AsWeakPtr;
+
+ private:
+ void DidTryRemoveFile(base::PlatformFileError error);
+ void DidRemoveFile(const StatusCallback& callback,
+ base::PlatformFileError error);
+ void RemoveNextDirectory(base::PlatformFileError error);
+
+ FileSystemURL url_;
+ StatusCallback callback_;
+
+ std::stack<FileSystemURL> to_remove_directories_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveOperationDelegate);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_REMOVE_OPERATION_DELEGATE_H_
diff --git a/webkit/browser/fileapi/sandbox_file_stream_writer.cc b/webkit/browser/fileapi/sandbox_file_stream_writer.cc
index 490d62b..a937476 100644
--- a/webkit/browser/fileapi/sandbox_file_stream_writer.cc
+++ b/webkit/browser/fileapi/sandbox_file_stream_writer.cc
@@ -11,10 +11,10 @@
#include "net/base/net_errors.h"
#include "webkit/blob/local_file_stream_reader.h"
#include "webkit/browser/fileapi/file_observers.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/local_file_stream_writer.h"
#include "webkit/fileapi/file_system_util.h"
-#include "webkit/fileapi/local_file_stream_writer.h"
#include "webkit/quota/quota_manager.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/sandbox_file_stream_writer.h b/webkit/browser/fileapi/sandbox_file_stream_writer.h
index 19fc7bf..3de8d0d 100644
--- a/webkit/browser/fileapi/sandbox_file_stream_writer.h
+++ b/webkit/browser/fileapi/sandbox_file_stream_writer.h
@@ -9,10 +9,10 @@
#include "base/memory/scoped_ptr.h"
#include "base/platform_file.h"
#include "googleurl/src/gurl.h"
+#include "webkit/browser/fileapi/file_stream_writer.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
-#include "webkit/fileapi/file_stream_writer.h"
#include "webkit/fileapi/file_system_types.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/quota/quota_types.h"
#include "webkit/storage/webkit_storage_export.h"
diff --git a/webkit/browser/fileapi/sandbox_file_system_test_helper.cc b/webkit/browser/fileapi/sandbox_file_system_test_helper.cc
new file mode 100644
index 0000000..01a0a27
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_file_system_test_helper.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/sandbox_file_system_test_helper.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_task_runners.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_usage_cache.h"
+#include "webkit/browser/fileapi/local_file_system_operation.h"
+#include "webkit/browser/fileapi/mock_file_system_context.h"
+#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/quota/mock_special_storage_policy.h"
+
+namespace fileapi {
+
+SandboxFileSystemTestHelper::SandboxFileSystemTestHelper(
+ const GURL& origin, FileSystemType type)
+ : origin_(origin), type_(type), file_util_(NULL) {
+}
+
+SandboxFileSystemTestHelper::SandboxFileSystemTestHelper()
+ : origin_(GURL("http://foo.com")),
+ type_(kFileSystemTypeTemporary),
+ file_util_(NULL) {
+}
+
+SandboxFileSystemTestHelper::~SandboxFileSystemTestHelper() {
+}
+
+void SandboxFileSystemTestHelper::SetUp(const base::FilePath& base_dir) {
+ SetUp(base_dir, NULL);
+}
+
+void SandboxFileSystemTestHelper::SetUp(
+ FileSystemContext* file_system_context) {
+ file_system_context_ = file_system_context;
+
+ SetUpFileSystem();
+}
+
+void SandboxFileSystemTestHelper::SetUp(
+ const base::FilePath& base_dir,
+ quota::QuotaManagerProxy* quota_manager_proxy) {
+ file_system_context_ = CreateFileSystemContextForTesting(
+ quota_manager_proxy, base_dir);
+
+ SetUpFileSystem();
+}
+
+void SandboxFileSystemTestHelper::TearDown() {
+ file_system_context_ = NULL;
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
+base::FilePath SandboxFileSystemTestHelper::GetOriginRootPath() const {
+ return file_system_context_->sandbox_provider()->
+ GetBaseDirectoryForOriginAndType(origin_, type_, false);
+}
+
+base::FilePath SandboxFileSystemTestHelper::GetLocalPath(
+ const base::FilePath& path) {
+ DCHECK(file_util_);
+ base::FilePath local_path;
+ scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
+ file_util_->GetLocalFilePath(context.get(), CreateURL(path), &local_path);
+ return local_path;
+}
+
+base::FilePath SandboxFileSystemTestHelper::GetLocalPathFromASCII(
+ const std::string& path) {
+ return GetLocalPath(base::FilePath().AppendASCII(path));
+}
+
+base::FilePath SandboxFileSystemTestHelper::GetUsageCachePath() const {
+ return file_system_context_->
+ sandbox_provider()->GetUsageCachePathForOriginAndType(origin_, type_);
+}
+
+FileSystemURL SandboxFileSystemTestHelper::CreateURL(
+ const base::FilePath& path) const {
+ return file_system_context_->CreateCrackedFileSystemURL(origin_, type_, path);
+}
+
+int64 SandboxFileSystemTestHelper::GetCachedOriginUsage() const {
+ return file_system_context_->GetQuotaUtil(type_)->GetOriginUsageOnFileThread(
+ file_system_context_, origin_, type_);
+}
+
+int64 SandboxFileSystemTestHelper::ComputeCurrentOriginUsage() {
+ usage_cache()->CloseCacheFiles();
+ int64 size = file_util::ComputeDirectorySize(GetOriginRootPath());
+ if (file_util::PathExists(GetUsageCachePath()))
+ size -= FileSystemUsageCache::kUsageFileSize;
+ return size;
+}
+
+int64
+SandboxFileSystemTestHelper::ComputeCurrentDirectoryDatabaseUsage() const {
+ return file_util::ComputeDirectorySize(
+ GetOriginRootPath().AppendASCII("Paths"));
+}
+
+LocalFileSystemOperation* SandboxFileSystemTestHelper::NewOperation() {
+ DCHECK(file_system_context_.get());
+ DCHECK(file_util_);
+ LocalFileSystemOperation* operation = static_cast<LocalFileSystemOperation*>(
+ file_system_context_->CreateFileSystemOperation(
+ CreateURL(base::FilePath()), NULL));
+ return operation;
+}
+
+FileSystemOperationContext*
+SandboxFileSystemTestHelper::NewOperationContext() {
+ DCHECK(file_system_context_.get());
+ FileSystemOperationContext* context =
+ new FileSystemOperationContext(file_system_context_.get());
+ context->set_update_observers(
+ *file_system_context_->GetUpdateObservers(type_));
+ return context;
+}
+
+FileSystemUsageCache* SandboxFileSystemTestHelper::usage_cache() {
+ return file_system_context()->sandbox_provider()->usage_cache();
+}
+
+void SandboxFileSystemTestHelper::SetUpFileSystem() {
+ DCHECK(file_system_context_);
+ DCHECK(file_system_context_->sandbox_provider()->CanHandleType(type_));
+
+ file_util_ = file_system_context_->GetFileUtil(type_);
+ DCHECK(file_util_);
+
+ // Prepare the origin's root directory.
+ file_system_context_->sandbox_provider()->
+ GetFileSystemRootPathOnFileThread(CreateURL(base::FilePath()),
+ true /* create */);
+
+ // Initialize the usage cache file.
+ base::FilePath usage_cache_path = GetUsageCachePath();
+ if (!usage_cache_path.empty())
+ usage_cache()->UpdateUsage(usage_cache_path, 0);
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_file_system_test_helper.h b/webkit/browser/fileapi/sandbox_file_system_test_helper.h
new file mode 100644
index 0000000..13abe17
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_file_system_test_helper.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_TEST_HELPER_H_
+#define WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_TEST_HELPER_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_usage_cache.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/quota/quota_types.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace quota {
+class QuotaManagerProxy;
+}
+
+namespace fileapi {
+
+class FileSystemContext;
+class FileSystemFileUtil;
+class FileSystemOperationContext;
+class LocalFileSystemOperation;
+
+// Filesystem test helper class that encapsulates test environment for
+// a given {origin, type} pair. This helper only works for sandboxed
+// file systems (Temporary or Persistent).
+class SandboxFileSystemTestHelper {
+ public:
+ SandboxFileSystemTestHelper(const GURL& origin, FileSystemType type);
+ SandboxFileSystemTestHelper();
+ ~SandboxFileSystemTestHelper();
+
+ void SetUp(const base::FilePath& base_dir);
+ // If you want to use more than one SandboxFileSystemTestHelper in
+ // a single base directory, they have to share a context, so that they don't
+ // have multiple databases fighting over the lock to the origin directory
+ // [deep down inside ObfuscatedFileUtil].
+ void SetUp(FileSystemContext* file_system_context);
+ void SetUp(const base::FilePath& base_dir,
+ quota::QuotaManagerProxy* quota_manager_proxy);
+ void TearDown();
+
+ base::FilePath GetOriginRootPath() const;
+ base::FilePath GetLocalPath(const base::FilePath& path);
+ base::FilePath GetLocalPathFromASCII(const std::string& path);
+
+ // Returns empty path if filesystem type is neither temporary nor persistent.
+ base::FilePath GetUsageCachePath() const;
+
+ FileSystemURL CreateURL(const base::FilePath& path) const;
+ FileSystemURL CreateURLFromUTF8(const std::string& utf8) const {
+ return CreateURL(base::FilePath::FromUTF8Unsafe(utf8));
+ }
+
+ // This returns cached usage size returned by QuotaUtil.
+ int64 GetCachedOriginUsage() const;
+
+ // This doesn't work with OFSFU.
+ int64 ComputeCurrentOriginUsage();
+
+ int64 ComputeCurrentDirectoryDatabaseUsage() const;
+
+ LocalFileSystemOperation* NewOperation();
+ FileSystemOperationContext* NewOperationContext();
+
+ FileSystemContext* file_system_context() const {
+ return file_system_context_.get();
+ }
+
+ const GURL& origin() const { return origin_; }
+ FileSystemType type() const { return type_; }
+ quota::StorageType storage_type() const {
+ return FileSystemTypeToQuotaStorageType(type_);
+ }
+ FileSystemFileUtil* file_util() const { return file_util_; }
+ FileSystemUsageCache* usage_cache();
+
+ private:
+ void SetUpFileSystem();
+
+ scoped_refptr<FileSystemContext> file_system_context_;
+
+ const GURL origin_;
+ const FileSystemType type_;
+ FileSystemFileUtil* file_util_;
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_TEST_HELPER_H_
diff --git a/webkit/browser/fileapi/sandbox_mount_point_provider.cc b/webkit/browser/fileapi/sandbox_mount_point_provider.cc
index d701d9f..23c7cee 100644
--- a/webkit/browser/fileapi/sandbox_mount_point_provider.cc
+++ b/webkit/browser/fileapi/sandbox_mount_point_provider.cc
@@ -14,18 +14,18 @@
#include "base/task_runner_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.h"
#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_options.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/file_system_usage_cache.h"
#include "webkit/browser/fileapi/local_file_system_operation.h"
#include "webkit/browser/fileapi/obfuscated_file_util.h"
#include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
#include "webkit/browser/fileapi/sandbox_quota_observer.h"
-#include "webkit/fileapi/async_file_util_adapter.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_file_stream_reader.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/file_system_options.h"
#include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/file_system_util.h"
#include "webkit/fileapi/syncable/syncable_file_system_operation.h"
diff --git a/webkit/browser/fileapi/sandbox_mount_point_provider.h b/webkit/browser/fileapi/sandbox_mount_point_provider.h
index 0b779c1..763a5af 100644
--- a/webkit/browser/fileapi/sandbox_mount_point_provider.h
+++ b/webkit/browser/fileapi/sandbox_mount_point_provider.h
@@ -16,9 +16,9 @@
#include "base/memory/weak_ptr.h"
#include "googleurl/src/gurl.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_options.h"
#include "webkit/browser/fileapi/file_system_quota_util.h"
#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
-#include "webkit/fileapi/file_system_options.h"
#include "webkit/quota/special_storage_policy.h"
#include "webkit/storage/webkit_storage_export.h"
diff --git a/webkit/browser/fileapi/sandbox_mount_point_provider_unittest.cc b/webkit/browser/fileapi/sandbox_mount_point_provider_unittest.cc
index 3f40f34..9a6e152 100644
--- a/webkit/browser/fileapi/sandbox_mount_point_provider_unittest.cc
+++ b/webkit/browser/fileapi/sandbox_mount_point_provider_unittest.cc
@@ -15,8 +15,8 @@
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/mock_file_system_options.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
// PS stands for path separator.
diff --git a/webkit/browser/fileapi/sandbox_quota_observer.cc b/webkit/browser/fileapi/sandbox_quota_observer.cc
index e6e9422..3dca091 100644
--- a/webkit/browser/fileapi/sandbox_quota_observer.cc
+++ b/webkit/browser/fileapi/sandbox_quota_observer.cc
@@ -5,9 +5,9 @@
#include "webkit/browser/fileapi/sandbox_quota_observer.h"
#include "base/sequenced_task_runner.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/file_system_usage_cache.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
-#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
#include "webkit/quota/quota_client.h"
#include "webkit/quota/quota_manager.h"
diff --git a/webkit/browser/fileapi/sandbox_quota_observer.h b/webkit/browser/fileapi/sandbox_quota_observer.h
index 788899d..908e2b2 100644
--- a/webkit/browser/fileapi/sandbox_quota_observer.h
+++ b/webkit/browser/fileapi/sandbox_quota_observer.h
@@ -14,7 +14,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "webkit/browser/fileapi/file_observers.h"
-#include "webkit/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_url.h"
namespace base {
class SequencedTaskRunner;
diff --git a/webkit/browser/fileapi/test_file_set.cc b/webkit/browser/fileapi/test_file_set.cc
new file mode 100644
index 0000000..7b0b0f0
--- /dev/null
+++ b/webkit/browser/fileapi/test_file_set.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/test_file_set.h"
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/platform_file.h"
+#include "base/rand_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace fileapi {
+
+namespace test {
+
+const TestCaseRecord kRegularTestCases[] = {
+ {true, FILE_PATH_LITERAL("dir a"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir A"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir f"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir h"), 0},
+ {true, FILE_PATH_LITERAL("dir b"), 0},
+ {true, FILE_PATH_LITERAL("dir b/dir a"), 0},
+ {true, FILE_PATH_LITERAL("dir c"), 0},
+ {false, FILE_PATH_LITERAL("file 0"), 38},
+ {false, FILE_PATH_LITERAL("file 2"), 60},
+ {false, FILE_PATH_LITERAL("file 3"), 0},
+ {false, FILE_PATH_LITERAL("dir a/file 0"), 39},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 0"), 40},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 1"), 41},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 2"), 42},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 3"), 50},
+};
+
+const size_t kRegularTestCaseSize = arraysize(kRegularTestCases);
+
+void SetUpOneTestCase(const base::FilePath& root_path,
+ const TestCaseRecord& test_case) {
+ base::FilePath path = root_path.Append(test_case.path);
+ if (test_case.is_directory) {
+ ASSERT_TRUE(file_util::CreateDirectory(path));
+ return;
+ }
+ base::PlatformFileError error_code;
+ bool created = false;
+ int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE;
+ base::PlatformFile file_handle =
+ base::CreatePlatformFile(path, file_flags, &created, &error_code);
+ EXPECT_TRUE(created);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error_code);
+ ASSERT_NE(base::kInvalidPlatformFileValue, file_handle);
+ EXPECT_TRUE(base::ClosePlatformFile(file_handle));
+ if (test_case.data_file_size > 0U) {
+ std::string content = base::RandBytesAsString(test_case.data_file_size);
+ ASSERT_EQ(static_cast<int>(content.size()),
+ file_util::WriteFile(path, content.data(), content.size()));
+ }
+}
+
+
+void SetUpRegularTestCases(const base::FilePath& root_path) {
+ for (size_t i = 0; i < arraysize(kRegularTestCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Creating kRegularTestCases " << i);
+ SetUpOneTestCase(root_path, kRegularTestCases[i]);
+ }
+}
+
+} // namespace test
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/test_file_set.h b/webkit/browser/fileapi/test_file_set.h
new file mode 100644
index 0000000..59e90ab
--- /dev/null
+++ b/webkit/browser/fileapi/test_file_set.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_TEST_FILE_SET_H_
+#define WEBKIT_BROWSER_FILEAPI_TEST_FILE_SET_H_
+
+#include <set>
+
+#include "base/files/file_path.h"
+
+// Common test data structures and test cases.
+
+namespace fileapi {
+
+class FileSystemFileUtil;
+
+namespace test {
+
+struct TestCaseRecord {
+ bool is_directory;
+ const base::FilePath::CharType path[64];
+ int64 data_file_size;
+};
+
+extern const TestCaseRecord kRegularTestCases[];
+extern const size_t kRegularTestCaseSize;
+
+size_t GetRegularTestCaseSize();
+
+// Creates one file or directory specified by |record|.
+void SetUpOneTestCase(const base::FilePath& root_path, const TestCaseRecord& record);
+
+// Creates the files and directories specified in kRegularTestCases.
+void SetUpRegularTestCases(const base::FilePath& root_path);
+
+} // namespace test
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_TEST_FILE_SET_H_
diff --git a/webkit/browser/fileapi/test_mount_point_provider.cc b/webkit/browser/fileapi/test_mount_point_provider.cc
new file mode 100644
index 0000000..e0caaa4
--- /dev/null
+++ b/webkit/browser/fileapi/test_mount_point_provider.cc
@@ -0,0 +1,203 @@
+// Copyright (c) 2012 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 "webkit/browser/fileapi/test_mount_point_provider.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/sequenced_task_runner.h"
+#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "webkit/browser/fileapi/file_observers.h"
+#include "webkit/browser/fileapi/file_system_file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_quota_util.h"
+#include "webkit/browser/fileapi/local_file_system_operation.h"
+#include "webkit/browser/fileapi/local_file_util.h"
+#include "webkit/browser/fileapi/native_file_util.h"
+#include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/quota/quota_manager.h"
+
+namespace fileapi {
+
+// This only supports single origin.
+class TestMountPointProvider::QuotaUtil
+ : public FileSystemQuotaUtil,
+ public FileUpdateObserver {
+ public:
+ QuotaUtil() : usage_(0) {}
+ virtual ~QuotaUtil() {}
+
+ // FileSystemQuotaUtil overrides.
+ virtual void GetOriginsForTypeOnFileThread(
+ FileSystemType type,
+ std::set<GURL>* origins) OVERRIDE {
+ NOTREACHED();
+ }
+ virtual void GetOriginsForHostOnFileThread(
+ FileSystemType type,
+ const std::string& host,
+ std::set<GURL>* origins) OVERRIDE {
+ NOTREACHED();
+ }
+ virtual int64 GetOriginUsageOnFileThread(
+ FileSystemContext* context,
+ const GURL& origin_url,
+ FileSystemType type) OVERRIDE {
+ return usage_;
+ }
+ virtual void InvalidateUsageCache(const GURL& origin_url,
+ FileSystemType type) OVERRIDE {
+ // Do nothing.
+ }
+ virtual void StickyInvalidateUsageCache(
+ const GURL& origin,
+ FileSystemType type) OVERRIDE {
+ // Do nothing.
+ }
+
+ // FileUpdateObserver overrides.
+ virtual void OnStartUpdate(const FileSystemURL& url) OVERRIDE {}
+ virtual void OnUpdate(const FileSystemURL& url, int64 delta) OVERRIDE {
+ usage_ += delta;
+ }
+ virtual void OnEndUpdate(const FileSystemURL& url) OVERRIDE {}
+
+ private:
+ int64 usage_;
+};
+
+TestMountPointProvider::TestMountPointProvider(
+ base::SequencedTaskRunner* task_runner,
+ const base::FilePath& base_path)
+ : base_path_(base_path),
+ task_runner_(task_runner),
+ local_file_util_(new AsyncFileUtilAdapter(new LocalFileUtil())),
+ quota_util_(new QuotaUtil),
+ require_copy_or_move_validator_(false) {
+ UpdateObserverList::Source source;
+ source.AddObserver(quota_util_.get(), task_runner_);
+ observers_ = UpdateObserverList(source);
+}
+
+TestMountPointProvider::~TestMountPointProvider() {
+}
+
+bool TestMountPointProvider::CanHandleType(FileSystemType type) const {
+ return (type == kFileSystemTypeTest);
+}
+
+void TestMountPointProvider::ValidateFileSystemRoot(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const ValidateFileSystemCallback& callback) {
+ // This won't be called unless we add test code that opens a test
+ // filesystem by OpenFileSystem.
+ NOTREACHED();
+}
+
+base::FilePath TestMountPointProvider::GetFileSystemRootPathOnFileThread(
+ const FileSystemURL& url,
+ bool create) {
+ DCHECK_EQ(kFileSystemTypeTest, url.type());
+ bool success = true;
+ if (create)
+ success = file_util::CreateDirectory(base_path_);
+ else
+ success = file_util::DirectoryExists(base_path_);
+ return success ? base_path_ : base::FilePath();
+}
+
+FileSystemFileUtil* TestMountPointProvider::GetFileUtil(FileSystemType type) {
+ DCHECK(local_file_util_.get());
+ return local_file_util_->sync_file_util();
+}
+
+AsyncFileUtil* TestMountPointProvider::GetAsyncFileUtil(FileSystemType type) {
+ return local_file_util_.get();
+}
+
+CopyOrMoveFileValidatorFactory*
+TestMountPointProvider::GetCopyOrMoveFileValidatorFactory(
+ FileSystemType type, base::PlatformFileError* error_code) {
+ DCHECK(error_code);
+ *error_code = base::PLATFORM_FILE_OK;
+ if (require_copy_or_move_validator_) {
+ if (!copy_or_move_file_validator_factory_)
+ *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
+ return copy_or_move_file_validator_factory_.get();
+ }
+ return NULL;
+}
+
+void TestMountPointProvider::InitializeCopyOrMoveFileValidatorFactory(
+ FileSystemType type, scoped_ptr<CopyOrMoveFileValidatorFactory> factory) {
+ if (!require_copy_or_move_validator_) {
+ DCHECK(!factory);
+ return;
+ }
+ if (!copy_or_move_file_validator_factory_)
+ copy_or_move_file_validator_factory_ = factory.Pass();
+}
+
+FilePermissionPolicy TestMountPointProvider::GetPermissionPolicy(
+ const FileSystemURL& url, int permissions) const {
+ return FILE_PERMISSION_ALWAYS_DENY;
+}
+
+FileSystemOperation* TestMountPointProvider::CreateFileSystemOperation(
+ const FileSystemURL& url,
+ FileSystemContext* context,
+ base::PlatformFileError* error_code) const {
+ scoped_ptr<FileSystemOperationContext> operation_context(
+ new FileSystemOperationContext(context));
+ operation_context->set_update_observers(observers_);
+ return new LocalFileSystemOperation(context, operation_context.Pass());
+}
+
+scoped_ptr<webkit_blob::FileStreamReader>
+TestMountPointProvider::CreateFileStreamReader(
+ const FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time,
+ FileSystemContext* context) const {
+ return scoped_ptr<webkit_blob::FileStreamReader>(
+ new FileSystemFileStreamReader(
+ context, url, offset, expected_modification_time));
+}
+
+scoped_ptr<fileapi::FileStreamWriter>
+TestMountPointProvider::CreateFileStreamWriter(
+ const FileSystemURL& url,
+ int64 offset,
+ FileSystemContext* context) const {
+ return scoped_ptr<fileapi::FileStreamWriter>(
+ new SandboxFileStreamWriter(context, url, offset, observers_));
+}
+
+FileSystemQuotaUtil* TestMountPointProvider::GetQuotaUtil() {
+ return quota_util_.get();
+}
+
+void TestMountPointProvider::DeleteFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ FileSystemContext* context,
+ const DeleteFileSystemCallback& callback) {
+ // This won't be called unless we add test code that opens a test
+ // filesystem by OpenFileSystem.
+ NOTREACHED();
+ callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+}
+
+const UpdateObserverList* TestMountPointProvider::GetUpdateObservers(
+ FileSystemType type) const {
+ return &observers_;
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/test_mount_point_provider.h b/webkit/browser/fileapi/test_mount_point_provider.h
new file mode 100644
index 0000000..2dddb3c
--- /dev/null
+++ b/webkit/browser/fileapi/test_mount_point_provider.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 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 WEBKIT_BROWSER_FILEAPI_TEST_MOUNT_POINT_PROVIDER_H_
+#define WEBKIT_BROWSER_FILEAPI_TEST_MOUNT_POINT_PROVIDER_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.h"
+#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace fileapi {
+
+class AsyncFileUtilAdapter;
+class FileSystemQuotaUtil;
+
+// This should be only used for testing.
+// This mount point provider uses LocalFileUtil and stores data file
+// under the given directory.
+class WEBKIT_STORAGE_EXPORT_PRIVATE TestMountPointProvider
+ : public FileSystemMountPointProvider {
+ public:
+ TestMountPointProvider(
+ base::SequencedTaskRunner* task_runner,
+ const base::FilePath& base_path);
+ virtual ~TestMountPointProvider();
+
+ // FileSystemMountPointProvider implementation.
+ virtual bool CanHandleType(FileSystemType type) const OVERRIDE;
+ virtual void ValidateFileSystemRoot(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const ValidateFileSystemCallback& callback) OVERRIDE;
+ virtual base::FilePath GetFileSystemRootPathOnFileThread(
+ const FileSystemURL& url,
+ bool create) OVERRIDE;
+ virtual FileSystemFileUtil* GetFileUtil(FileSystemType type) OVERRIDE;
+ virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE;
+ virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
+ FileSystemType type,
+ base::PlatformFileError* error_code) OVERRIDE;
+ virtual void InitializeCopyOrMoveFileValidatorFactory(
+ FileSystemType type,
+ scoped_ptr<CopyOrMoveFileValidatorFactory> factory) OVERRIDE;
+ virtual FilePermissionPolicy GetPermissionPolicy(
+ const FileSystemURL& url,
+ int permissions) const OVERRIDE;
+ virtual FileSystemOperation* CreateFileSystemOperation(
+ const FileSystemURL& url,
+ FileSystemContext* context,
+ base::PlatformFileError* error_code) const OVERRIDE;
+ virtual scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+ const FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time,
+ FileSystemContext* context) const OVERRIDE;
+ virtual scoped_ptr<FileStreamWriter> CreateFileStreamWriter(
+ const FileSystemURL& url,
+ int64 offset,
+ FileSystemContext* context) const OVERRIDE;
+ virtual FileSystemQuotaUtil* GetQuotaUtil() OVERRIDE;
+ virtual void DeleteFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ FileSystemContext* context,
+ const DeleteFileSystemCallback& callback) OVERRIDE;
+
+ const UpdateObserverList* GetUpdateObservers(FileSystemType type) const;
+
+ // For CopyOrMoveFileValidatorFactory testing. Once it's set to true
+ // GetCopyOrMoveFileValidatorFactory will start returning security
+ // error if validator is not initialized.
+ void set_require_copy_or_move_validator(bool flag) {
+ require_copy_or_move_validator_ = flag;
+ }
+
+ private:
+ class QuotaUtil;
+
+ base::FilePath base_path_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_ptr<AsyncFileUtilAdapter> local_file_util_;
+ scoped_ptr<QuotaUtil> quota_util_;
+ UpdateObserverList observers_;
+
+ bool require_copy_or_move_validator_;
+ scoped_ptr<CopyOrMoveFileValidatorFactory>
+ copy_or_move_file_validator_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMountPointProvider);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_TEST_MOUNT_POINT_PROVIDER_H_
diff --git a/webkit/browser/fileapi/transient_file_util.cc b/webkit/browser/fileapi/transient_file_util.cc
index d9ee207..74c2dbea 100644
--- a/webkit/browser/fileapi/transient_file_util.cc
+++ b/webkit/browser/fileapi/transient_file_util.cc
@@ -8,9 +8,9 @@
#include "base/bind.h"
#include "base/files/file_path.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
-#include "webkit/fileapi/file_system_url.h"
using webkit_blob::ScopedFile;
diff --git a/webkit/browser/fileapi/transient_file_util_unittest.cc b/webkit/browser/fileapi/transient_file_util_unittest.cc
index 47d50c5..2b774f5 100644
--- a/webkit/browser/fileapi/transient_file_util_unittest.cc
+++ b/webkit/browser/fileapi/transient_file_util_unittest.cc
@@ -11,11 +11,11 @@
#include "base/platform_file.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/blob/scoped_file.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
#include "webkit/browser/fileapi/transient_file_util.h"
-#include "webkit/fileapi/file_system_context.h"
-#include "webkit/fileapi/file_system_operation_context.h"
namespace fileapi {
diff --git a/webkit/browser/fileapi/upload_file_system_file_element_reader.cc b/webkit/browser/fileapi/upload_file_system_file_element_reader.cc
new file mode 100644
index 0000000..f5d47f9
--- /dev/null
+++ b/webkit/browser/fileapi/upload_file_system_file_element_reader.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2013 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 "webkit/browser/fileapi/upload_file_system_file_element_reader.h"
+
+#include "base/bind.h"
+#include "net/base/net_errors.h"
+#include "webkit/blob/file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+
+namespace fileapi {
+
+UploadFileSystemFileElementReader::UploadFileSystemFileElementReader(
+ FileSystemContext* file_system_context,
+ const GURL& url,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time)
+ : file_system_context_(file_system_context),
+ url_(url),
+ range_offset_(range_offset),
+ range_length_(range_length),
+ expected_modification_time_(expected_modification_time),
+ stream_length_(0),
+ position_(0),
+ weak_ptr_factory_(this) {
+}
+
+UploadFileSystemFileElementReader::~UploadFileSystemFileElementReader() {
+}
+
+int UploadFileSystemFileElementReader::Init(
+ const net::CompletionCallback& callback) {
+ // Reset states.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ stream_length_ = 0;
+ position_ = 0;
+
+ // Initialize the stream reader and the length.
+ stream_reader_ =
+ file_system_context_->CreateFileStreamReader(
+ file_system_context_->CrackURL(url_),
+ range_offset_,
+ expected_modification_time_);
+ DCHECK(stream_reader_);
+
+ const int64 result = stream_reader_->GetLength(
+ base::Bind(&UploadFileSystemFileElementReader::OnGetLength,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ if (result >= 0) {
+ stream_length_ = result;
+ return net::OK;
+ }
+
+ // The error code can be casted to int.
+ return static_cast<int>(result);
+}
+
+uint64 UploadFileSystemFileElementReader::GetContentLength() const {
+ return std::min(stream_length_, range_length_);
+}
+
+uint64 UploadFileSystemFileElementReader::BytesRemaining() const {
+ return GetContentLength() - position_;
+}
+
+int UploadFileSystemFileElementReader::Read(
+ net::IOBuffer* buf,
+ int buf_length,
+ const net::CompletionCallback& callback) {
+ DCHECK_LT(0, buf_length);
+ DCHECK(stream_reader_);
+
+ const uint64 num_bytes_to_read =
+ std::min(BytesRemaining(), static_cast<uint64>(buf_length));
+
+ if (num_bytes_to_read == 0)
+ return 0;
+
+ const int result = stream_reader_->Read(
+ buf, num_bytes_to_read,
+ base::Bind(&UploadFileSystemFileElementReader::OnRead,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ if (result >= 0)
+ OnRead(net::CompletionCallback(), result);
+ return result;
+}
+
+void UploadFileSystemFileElementReader::OnGetLength(
+ const net::CompletionCallback& callback,
+ int64 result) {
+ if (result >= 0) {
+ stream_length_ = result;
+ callback.Run(net::OK);
+ return;
+ }
+ callback.Run(result);
+}
+
+void UploadFileSystemFileElementReader::OnRead(
+ const net::CompletionCallback& callback,
+ int result) {
+ if (result > 0) {
+ position_ += result;
+ DCHECK_LE(position_, GetContentLength());
+ }
+ if (!callback.is_null())
+ callback.Run(result);
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/upload_file_system_file_element_reader.h b/webkit/browser/fileapi/upload_file_system_file_element_reader.h
new file mode 100644
index 0000000..525dc00
--- /dev/null
+++ b/webkit/browser/fileapi/upload_file_system_file_element_reader.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 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 WEBKIT_BROWSER_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
+#define WEBKIT_BROWSER_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/upload_element_reader.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace webkit_blob {
+class FileStreamReader;
+}
+
+namespace fileapi {
+
+class FileSystemContext;
+
+// An UploadElementReader implementation for filesystem file.
+class WEBKIT_STORAGE_EXPORT UploadFileSystemFileElementReader
+ : public net::UploadElementReader {
+ public:
+ UploadFileSystemFileElementReader(
+ FileSystemContext* file_system_context,
+ const GURL& url,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time);
+ virtual ~UploadFileSystemFileElementReader();
+
+ // UploadElementReader overrides:
+ virtual int Init(const net::CompletionCallback& callback) OVERRIDE;
+ virtual uint64 GetContentLength() const OVERRIDE;
+ virtual uint64 BytesRemaining() const OVERRIDE;
+ virtual int Read(net::IOBuffer* buf,
+ int buf_length,
+ const net::CompletionCallback& callback) OVERRIDE;
+
+ private:
+ void OnGetLength(const net::CompletionCallback& callback, int64 result);
+ void OnRead(const net::CompletionCallback& callback, int result);
+
+ scoped_refptr<FileSystemContext> file_system_context_;
+ const GURL url_;
+ const uint64 range_offset_;
+ const uint64 range_length_;
+ const base::Time expected_modification_time_;
+
+ scoped_ptr<webkit_blob::FileStreamReader> stream_reader_;
+
+ uint64 stream_length_;
+ uint64 position_;
+
+ base::WeakPtrFactory<UploadFileSystemFileElementReader> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadFileSystemFileElementReader);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_BROWSER_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
diff --git a/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc b/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
new file mode 100644
index 0000000..fb993c8
--- /dev/null
+++ b/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
@@ -0,0 +1,284 @@
+// Copyright (c) 2013 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 "webkit/browser/fileapi/upload_file_system_file_element_reader.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_util.h"
+#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/mock_file_system_context.h"
+
+namespace fileapi {
+
+namespace {
+
+const char kFileSystemURLOrigin[] = "http://remote";
+const fileapi::FileSystemType kFileSystemType =
+ fileapi::kFileSystemTypeTemporary;
+
+} // namespace
+
+class UploadFileSystemFileElementReaderTest : public testing::Test {
+ public:
+ UploadFileSystemFileElementReaderTest()
+ : message_loop_(base::MessageLoop::TYPE_IO) {}
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ file_system_context_ = fileapi::CreateFileSystemContextForTesting(
+ NULL, temp_dir_.path());
+
+ file_system_context_->OpenFileSystem(
+ GURL(kFileSystemURLOrigin),
+ kFileSystemType,
+ true, // create
+ base::Bind(&UploadFileSystemFileElementReaderTest::OnValidateFileSystem,
+ base::Unretained(this)));
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_TRUE(file_system_root_url_.is_valid());
+
+ // Prepare a file on file system.
+ const char kTestData[] = "abcdefghijklmnop0123456789";
+ file_data_.assign(kTestData, kTestData + arraysize(kTestData) - 1);
+ const char kFilename[] = "File.dat";
+ file_url_ = GetFileSystemURL(kFilename);
+ WriteFileSystemFile(kFilename, &file_data_[0], file_data_.size(),
+ &file_modification_time_);
+
+ // Create and initialize a reader.
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, file_url_, 0, kuint64max,
+ file_modification_time_));
+ net::TestCompletionCallback callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(callback.callback()));
+ EXPECT_EQ(net::OK, callback.WaitForResult());
+ EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
+ EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
+ EXPECT_FALSE(reader_->IsInMemory());
+ }
+
+ protected:
+ GURL GetFileSystemURL(const std::string& filename) {
+ return GURL(file_system_root_url_.spec() + filename);
+ }
+
+ void WriteFileSystemFile(const std::string& filename,
+ const char* buf,
+ int buf_size,
+ base::Time* modification_time) {
+ fileapi::FileSystemURL url =
+ file_system_context_->CreateCrackedFileSystemURL(
+ GURL(kFileSystemURLOrigin),
+ kFileSystemType,
+ base::FilePath().AppendASCII(filename));
+
+ fileapi::FileSystemFileUtil* file_util =
+ file_system_context_->GetFileUtil(kFileSystemType);
+
+ fileapi::FileSystemOperationContext context(file_system_context_);
+ context.set_allowed_bytes_growth(1024);
+
+ base::PlatformFile handle = base::kInvalidPlatformFileValue;
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen(
+ &context,
+ url,
+ base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
+ &handle,
+ &created));
+ EXPECT_TRUE(created);
+ ASSERT_NE(base::kInvalidPlatformFileValue, handle);
+ ASSERT_EQ(buf_size,
+ base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size));
+ base::ClosePlatformFile(handle);
+
+ base::PlatformFileInfo file_info;
+ base::FilePath platform_path;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ file_util->GetFileInfo(&context, url, &file_info,
+ &platform_path));
+ *modification_time = file_info.last_modified;
+ }
+
+ void OnValidateFileSystem(base::PlatformFileError result,
+ const std::string& name,
+ const GURL& root) {
+ ASSERT_EQ(base::PLATFORM_FILE_OK, result);
+ ASSERT_TRUE(root.is_valid());
+ file_system_root_url_ = root;
+ }
+
+ base::MessageLoop message_loop_;
+ base::ScopedTempDir temp_dir_;
+ scoped_refptr<FileSystemContext> file_system_context_;
+ GURL file_system_root_url_;
+ std::vector<char> file_data_;
+ GURL file_url_;
+ base::Time file_modification_time_;
+ scoped_ptr<UploadFileSystemFileElementReader> reader_;
+};
+
+TEST_F(UploadFileSystemFileElementReaderTest, ReadAll) {
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(file_data_.size());
+ net::TestCompletionCallback read_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback.callback()));
+ EXPECT_EQ(buf->size(), read_callback.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+ // Try to read again.
+ EXPECT_EQ(0, reader_->Read(buf, buf->size(), read_callback.callback()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, ReadPartially) {
+ const size_t kHalfSize = file_data_.size() / 2;
+ ASSERT_EQ(file_data_.size(), kHalfSize * 2);
+
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(kHalfSize);
+
+ net::TestCompletionCallback read_callback1;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback1.callback()));
+ EXPECT_EQ(buf->size(), read_callback1.WaitForResult());
+ EXPECT_EQ(file_data_.size() - buf->size(), reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.begin() + kHalfSize,
+ buf->data()));
+
+ net::TestCompletionCallback read_callback2;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback2.callback()));
+ EXPECT_EQ(buf->size(), read_callback2.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin() + kHalfSize, file_data_.end(),
+ buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, ReadTooMuch) {
+ const size_t kTooLargeSize = file_data_.size() * 2;
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(kTooLargeSize);
+ net::TestCompletionCallback read_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback.callback()));
+ EXPECT_EQ(static_cast<int>(file_data_.size()), read_callback.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, MultipleInit) {
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(file_data_.size());
+
+ // Read all.
+ net::TestCompletionCallback read_callback1;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback1.callback()));
+ EXPECT_EQ(buf->size(), read_callback1.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+
+ // Call Init() again to reset the state.
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::OK, init_callback.WaitForResult());
+ EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
+ EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
+
+ // Read again.
+ net::TestCompletionCallback read_callback2;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback2.callback()));
+ EXPECT_EQ(buf->size(), read_callback2.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, InitDuringAsyncOperation) {
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(file_data_.size());
+
+ // Start reading all.
+ net::TestCompletionCallback read_callback1;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback1.callback()));
+
+ // Call Init to cancel the previous read.
+ net::TestCompletionCallback init_callback1;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback1.callback()));
+
+ // Call Init again to cancel the previous init.
+ net::TestCompletionCallback init_callback2;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback2.callback()));
+ EXPECT_EQ(net::OK, init_callback2.WaitForResult());
+ EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
+ EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
+
+ // Read half.
+ scoped_refptr<net::IOBufferWithSize> buf2 =
+ new net::IOBufferWithSize(file_data_.size() / 2);
+ net::TestCompletionCallback read_callback2;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Read(buf2, buf2->size(),
+ read_callback2.callback()));
+ EXPECT_EQ(buf2->size(), read_callback2.WaitForResult());
+ EXPECT_EQ(file_data_.size() - buf2->size(), reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.begin() + buf2->size(),
+ buf2->data()));
+
+ // Make sure callbacks are not called for cancelled operations.
+ EXPECT_FALSE(read_callback1.have_result());
+ EXPECT_FALSE(init_callback1.have_result());
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, Range) {
+ const int kOffset = 2;
+ const int kLength = file_data_.size() - kOffset * 3;
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, file_url_, kOffset, kLength, base::Time()));
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::OK, init_callback.WaitForResult());
+ EXPECT_EQ(static_cast<uint64>(kLength), reader_->GetContentLength());
+ EXPECT_EQ(static_cast<uint64>(kLength), reader_->BytesRemaining());
+ scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kLength);
+ net::TestCompletionCallback read_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback.callback()));
+ EXPECT_EQ(kLength, read_callback.WaitForResult());
+ EXPECT_TRUE(std::equal(file_data_.begin() + kOffset,
+ file_data_.begin() + kOffset + kLength,
+ buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, FileChanged) {
+ // Expect one second before the actual modification time to simulate change.
+ const base::Time expected_modification_time =
+ file_modification_time_ - base::TimeDelta::FromSeconds(1);
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, file_url_, 0, kuint64max,
+ expected_modification_time));
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, init_callback.WaitForResult());
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, WrongURL) {
+ const GURL wrong_url = GetFileSystemURL("wrong_file_name.dat");
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, wrong_url, 0, kuint64max, base::Time()));
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
+}
+
+} // namespace fileapi
diff --git a/webkit/browser/fileapi/webkit_browser_fileapi.gypi b/webkit/browser/fileapi/webkit_browser_fileapi.gypi
index 70f5f7d..333a71d 100644
--- a/webkit/browser/fileapi/webkit_browser_fileapi.gypi
+++ b/webkit/browser/fileapi/webkit_browser_fileapi.gypi
@@ -5,34 +5,55 @@
{
'variables': {
'webkit_browser_fileapi_sources': [
+ '../browser/fileapi/async_file_util.h',
+ '../browser/fileapi/async_file_util_adapter.cc',
+ '../browser/fileapi/async_file_util_adapter.h',
'../browser/fileapi/copy_or_move_file_validator.h',
'../browser/fileapi/cross_operation_delegate.cc',
'../browser/fileapi/cross_operation_delegate.h',
'../browser/fileapi/external_mount_points.cc',
'../browser/fileapi/external_mount_points.h',
'../browser/fileapi/file_observers.h',
+ '../browser/fileapi/file_permission_policy.cc',
+ '../browser/fileapi/file_permission_policy.h',
+ '../browser/fileapi/file_stream_writer.h',
+ '../browser/fileapi/file_system_context.cc',
+ '../browser/fileapi/file_system_context.h',
'../browser/fileapi/file_system_dir_url_request_job.cc',
'../browser/fileapi/file_system_dir_url_request_job.h',
+ '../browser/fileapi/file_system_file_stream_reader.cc',
+ '../browser/fileapi/file_system_file_stream_reader.h',
'../browser/fileapi/file_system_file_util.cc',
'../browser/fileapi/file_system_file_util.h',
'../browser/fileapi/file_system_mount_point_provider.h',
+ '../browser/fileapi/file_system_operation.h',
+ '../browser/fileapi/file_system_operation_context.cc',
+ '../browser/fileapi/file_system_operation_context.h',
+ '../browser/fileapi/file_system_options.cc',
+ '../browser/fileapi/file_system_options.h',
'../browser/fileapi/file_system_quota_client.cc',
'../browser/fileapi/file_system_quota_client.h',
'../browser/fileapi/file_system_quota_util.h',
'../browser/fileapi/file_system_task_runners.cc',
'../browser/fileapi/file_system_task_runners.h',
+ '../browser/fileapi/file_system_url.cc',
+ '../browser/fileapi/file_system_url.h',
'../browser/fileapi/file_system_url_request_job.cc',
'../browser/fileapi/file_system_url_request_job.h',
'../browser/fileapi/file_system_url_request_job_factory.cc',
'../browser/fileapi/file_system_url_request_job_factory.h',
'../browser/fileapi/file_system_usage_cache.cc',
'../browser/fileapi/file_system_usage_cache.h',
+ '../browser/fileapi/file_writer_delegate.cc',
+ '../browser/fileapi/file_writer_delegate.h',
'../browser/fileapi/isolated_context.cc',
'../browser/fileapi/isolated_context.h',
'../browser/fileapi/isolated_file_util.cc',
'../browser/fileapi/isolated_file_util.h',
'../browser/fileapi/isolated_mount_point_provider.cc',
'../browser/fileapi/isolated_mount_point_provider.h',
+ '../browser/fileapi/local_file_stream_writer.cc',
+ '../browser/fileapi/local_file_stream_writer.h',
'../browser/fileapi/local_file_system_operation.cc',
'../browser/fileapi/local_file_system_operation.h',
'../browser/fileapi/local_file_util.cc',
@@ -45,6 +66,9 @@
'../browser/fileapi/obfuscated_file_util.h',
'../browser/fileapi/recursive_operation_delegate.cc',
'../browser/fileapi/recursive_operation_delegate.h',
+ '../browser/fileapi/remote_file_system_proxy.h',
+ '../browser/fileapi/remove_operation_delegate.cc',
+ '../browser/fileapi/remove_operation_delegate.h',
'../browser/fileapi/sandbox_directory_database.cc',
'../browser/fileapi/sandbox_directory_database.h',
'../browser/fileapi/sandbox_file_stream_writer.cc',
@@ -56,8 +80,25 @@
'../browser/fileapi/sandbox_quota_observer.cc',
'../browser/fileapi/sandbox_quota_observer.h',
'../browser/fileapi/task_runner_bound_observer_list.h',
+ '../browser/fileapi/test_mount_point_provider.cc',
+ '../browser/fileapi/test_mount_point_provider.h',
'../browser/fileapi/transient_file_util.cc',
'../browser/fileapi/transient_file_util.h',
+ '../browser/fileapi/upload_file_system_file_element_reader.cc',
+ '../browser/fileapi/upload_file_system_file_element_reader.h',
],
},
+ 'targets': [
+ {
+ 'target_name': 'dump_file_system',
+ 'type': 'executable',
+ 'sources': [
+ 'dump_file_system.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '../support/webkit_support.gyp:webkit_storage',
+ ],
+ },
+ ],
}