From 1deb7321b0a90fb08acb64aa4e02ded84d203fcf Mon Sep 17 00:00:00 2001
From: "kinuko@chromium.org"
 <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue, 28 May 2013 12:09:03 +0000
Subject: Move webkit/chromeos into webkit/browser/chromeos

As all of the code are browser-specific.

BUG=239710
R=kinaba@chromium.org

Review URL: https://codereview.chromium.org/16010006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202542 0039d316-1c4b-4281-b951-d872f2087c98
---
 webkit/browser/chromeos/DEPS                       |   3 +
 webkit/browser/chromeos/OWNERS                     |   2 +
 .../browser/chromeos/fileapi/async_file_stream.h   |  56 ++++
 .../chromeos/fileapi/cros_mount_point_provider.cc  | 358 +++++++++++++++++++++
 .../chromeos/fileapi/cros_mount_point_provider.h   | 144 +++++++++
 .../fileapi/cros_mount_point_provider_unittest.cc  | 304 +++++++++++++++++
 .../chromeos/fileapi/file_access_permissions.cc    |  58 ++++
 .../chromeos/fileapi/file_access_permissions.h     |  42 +++
 .../fileapi/file_access_permissions_unittest.cc    |  67 ++++
 .../chromeos/fileapi/remote_file_stream_writer.cc  | 119 +++++++
 .../chromeos/fileapi/remote_file_stream_writer.h   |  75 +++++
 .../fileapi/remote_file_system_operation.cc        | 321 ++++++++++++++++++
 .../fileapi/remote_file_system_operation.h         | 135 ++++++++
 webkit/browser/fileapi/file_system_context.cc      |   2 +-
 webkit/browser/fileapi/webkit_browser_fileapi.gypi |  12 +
 15 files changed, 1697 insertions(+), 1 deletion(-)
 create mode 100644 webkit/browser/chromeos/DEPS
 create mode 100644 webkit/browser/chromeos/OWNERS
 create mode 100644 webkit/browser/chromeos/fileapi/async_file_stream.h
 create mode 100644 webkit/browser/chromeos/fileapi/cros_mount_point_provider.cc
 create mode 100644 webkit/browser/chromeos/fileapi/cros_mount_point_provider.h
 create mode 100644 webkit/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc
 create mode 100644 webkit/browser/chromeos/fileapi/file_access_permissions.cc
 create mode 100644 webkit/browser/chromeos/fileapi/file_access_permissions.h
 create mode 100644 webkit/browser/chromeos/fileapi/file_access_permissions_unittest.cc
 create mode 100644 webkit/browser/chromeos/fileapi/remote_file_stream_writer.cc
 create mode 100644 webkit/browser/chromeos/fileapi/remote_file_stream_writer.h
 create mode 100644 webkit/browser/chromeos/fileapi/remote_file_system_operation.cc
 create mode 100644 webkit/browser/chromeos/fileapi/remote_file_system_operation.h

(limited to 'webkit/browser')

diff --git a/webkit/browser/chromeos/DEPS b/webkit/browser/chromeos/DEPS
new file mode 100644
index 0000000..79b8e8b
--- /dev/null
+++ b/webkit/browser/chromeos/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+chromeos",
+]
diff --git a/webkit/browser/chromeos/OWNERS b/webkit/browser/chromeos/OWNERS
new file mode 100644
index 0000000..d4a1d71
--- /dev/null
+++ b/webkit/browser/chromeos/OWNERS
@@ -0,0 +1,2 @@
+satorux@chromium.org
+zelidrag@chromium.org
diff --git a/webkit/browser/chromeos/fileapi/async_file_stream.h b/webkit/browser/chromeos/fileapi/async_file_stream.h
new file mode 100644
index 0000000..386101a
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/async_file_stream.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 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_CHROMEOS_FILEAPI_ASYNC_FILE_STREAM_H_
+#define WEBKIT_BROWSER_CHROMEOS_FILEAPI_ASYNC_FILE_STREAM_H_
+
+#include "base/callback.h"
+#include "base/platform_file.h"
+
+namespace fileapi {
+
+using base::PlatformFileError;
+
+// This class is used for implementing Open() in FileUtilAsync. This class
+// is similar to net::FileStream, but supporting only the asynchronous
+// operations and not necessarily relying on PlatformFile.
+class AsyncFileStream {
+ public:
+  // Used for Read() and Write(). |result| is the return code of the
+  // operation, and |length| is the length of data read or written.
+  typedef base::Callback<void(PlatformFileError result,
+                              int64 length)> ReadWriteCallback;
+
+  // Used for Seek(). |result| is the return code of the operation.
+  typedef base::Callback<void(PlatformFileError)> SeekCallback;
+
+  virtual ~AsyncFileStream() {};
+
+  // Reads data from the current stream position. Up to |length| bytes
+  // will be read from |buffer|. The memory pointed to by |buffer| must
+  // remain valid until the callback is called. On success,
+  // PLATFORM_FILE_OK is passed to |callback| with the number of bytes
+  // read. On failure, an error code is passed instead.
+  virtual void Read(char* buffer,
+                    int64 length,
+                    const ReadWriteCallback& callback) = 0;
+
+  // Writes data at the current stream position. Up to |length| bytes will
+  // be written from |buffer|. The memory pointed to by |buffer| must
+  // remain valid until the callback is called. On success,
+  // PLATFORM_FILE_OK is passed to |callback| with the number of bytes
+  // written. On failure, an error code is passed instead.
+  virtual void Write(const char* buffer,
+                     int64 length,
+                     const ReadWriteCallback& callback) = 0;
+
+  // Moves the stream position. On success, PLATFORM_FILE_OK is passed to
+  // |callback|. On error, an error code is passed instead.
+  virtual void Seek(int64 offset,
+                    const SeekCallback& callback) = 0;
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_BROWSER_CHROMEOS_FILEAPI_ASYNC_FILE_STREAM_H_
diff --git a/webkit/browser/chromeos/fileapi/cros_mount_point_provider.cc b/webkit/browser/chromeos/fileapi/cros_mount_point_provider.cc
new file mode 100644
index 0000000..c9270d5
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/cros_mount_point_provider.cc
@@ -0,0 +1,358 @@
+// 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/chromeos/fileapi/cros_mount_point_provider.h"
+
+#include "base/chromeos/chromeos_version.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/utf_string_conversions.h"
+#include "chromeos/dbus/cros_disks_client.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebFileSystem.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
+#include "webkit/browser/chromeos/fileapi/file_access_permissions.h"
+#include "webkit/browser/chromeos/fileapi/remote_file_stream_writer.h"
+#include "webkit/browser/chromeos/fileapi/remote_file_system_operation.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.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_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/file_system_url.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/glue/webkit_glue.h"
+
+namespace {
+
+const char kChromeUIScheme[] = "chrome";
+
+}  // namespace
+
+namespace chromeos {
+
+// static
+bool CrosMountPointProvider::CanHandleURL(const fileapi::FileSystemURL& url) {
+  if (!url.is_valid())
+    return false;
+  return url.type() == fileapi::kFileSystemTypeNativeLocal ||
+         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
+         url.type() == fileapi::kFileSystemTypeDrive;
+}
+
+CrosMountPointProvider::CrosMountPointProvider(
+    scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
+    scoped_refptr<fileapi::ExternalMountPoints> mount_points,
+    fileapi::ExternalMountPoints* system_mount_points)
+    : special_storage_policy_(special_storage_policy),
+      file_access_permissions_(new FileAccessPermissions()),
+      local_file_util_(new fileapi::AsyncFileUtilAdapter(
+          new fileapi::IsolatedFileUtil())),
+      mount_points_(mount_points),
+      system_mount_points_(system_mount_points) {
+  // Add default system mount points.
+  system_mount_points_->RegisterFileSystem(
+      "archive",
+      fileapi::kFileSystemTypeNativeLocal,
+      chromeos::CrosDisksClient::GetArchiveMountPoint());
+  system_mount_points_->RegisterFileSystem(
+      "removable",
+      fileapi::kFileSystemTypeNativeLocal,
+      chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
+  system_mount_points_->RegisterFileSystem(
+      "oem",
+      fileapi::kFileSystemTypeRestrictedNativeLocal,
+      base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
+}
+
+CrosMountPointProvider::~CrosMountPointProvider() {
+}
+
+bool CrosMountPointProvider::CanHandleType(fileapi::FileSystemType type) const {
+  switch (type) {
+    case fileapi::kFileSystemTypeExternal:
+    case fileapi::kFileSystemTypeDrive:
+    case fileapi::kFileSystemTypeRestrictedNativeLocal:
+    case fileapi::kFileSystemTypeNativeLocal:
+    case fileapi::kFileSystemTypeNativeForPlatformApp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+void CrosMountPointProvider::ValidateFileSystemRoot(
+    const GURL& origin_url,
+    fileapi::FileSystemType type,
+    bool create,
+    const ValidateFileSystemCallback& callback) {
+  DCHECK(fileapi::IsolatedContext::IsIsolatedType(type));
+  // Nothing to validate for external filesystem.
+  callback.Run(base::PLATFORM_FILE_OK);
+}
+
+base::FilePath CrosMountPointProvider::GetFileSystemRootPathOnFileThread(
+    const fileapi::FileSystemURL& url,
+    bool create) {
+  DCHECK(fileapi::IsolatedContext::IsIsolatedType(url.mount_type()));
+  if (!url.is_valid())
+    return base::FilePath();
+
+  base::FilePath root_path;
+  std::string mount_name = url.filesystem_id();
+  if (!mount_points_->GetRegisteredPath(mount_name, &root_path) &&
+      !system_mount_points_->GetRegisteredPath(mount_name, &root_path)) {
+    return base::FilePath();
+  }
+
+  return root_path.DirName();
+}
+
+fileapi::FileSystemQuotaUtil* CrosMountPointProvider::GetQuotaUtil() {
+  // No quota support.
+  return NULL;
+}
+
+void CrosMountPointProvider::DeleteFileSystem(
+    const GURL& origin_url,
+    fileapi::FileSystemType type,
+    fileapi::FileSystemContext* context,
+    const DeleteFileSystemCallback& callback) {
+  NOTREACHED();
+  callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+}
+
+bool CrosMountPointProvider::IsAccessAllowed(
+    const fileapi::FileSystemURL& url) const {
+  if (!url.is_valid())
+    return false;
+
+  // Permit access to mount points from internal WebUI.
+  const GURL& origin_url = url.origin();
+  if (origin_url.SchemeIs(kChromeUIScheme))
+    return true;
+
+  // No extra check is needed for isolated file systems.
+  if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
+    return true;
+
+  if (!CanHandleURL(url))
+    return false;
+
+  std::string extension_id = origin_url.host();
+  // Check first to make sure this extension has fileBrowserHander permissions.
+  if (!special_storage_policy_->IsFileHandler(extension_id))
+    return false;
+
+  return file_access_permissions_->HasAccessPermission(extension_id,
+                                                       url.virtual_path());
+}
+
+void CrosMountPointProvider::GrantFullAccessToExtension(
+    const std::string& extension_id) {
+  DCHECK(special_storage_policy_->IsFileHandler(extension_id));
+  if (!special_storage_policy_->IsFileHandler(extension_id))
+    return;
+
+  std::vector<fileapi::MountPoints::MountPointInfo> files;
+  mount_points_->AddMountPointInfosTo(&files);
+  system_mount_points_->AddMountPointInfosTo(&files);
+
+  for (size_t i = 0; i < files.size(); ++i) {
+    file_access_permissions_->GrantAccessPermission(
+        extension_id,
+        base::FilePath::FromUTF8Unsafe(files[i].name));
+  }
+}
+
+void CrosMountPointProvider::GrantFileAccessToExtension(
+    const std::string& extension_id, const base::FilePath& virtual_path) {
+  // All we care about here is access from extensions for now.
+  DCHECK(special_storage_policy_->IsFileHandler(extension_id));
+  if (!special_storage_policy_->IsFileHandler(extension_id))
+    return;
+
+  std::string id;
+  fileapi::FileSystemType type;
+  base::FilePath path;
+  if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &path) &&
+      !system_mount_points_->CrackVirtualPath(virtual_path,
+                                              &id, &type, &path)) {
+    return;
+  }
+
+  if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
+    LOG(ERROR) << "Can't grant access for restricted mount point";
+    return;
+  }
+
+  file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
+}
+
+void CrosMountPointProvider::RevokeAccessForExtension(
+      const std::string& extension_id) {
+  file_access_permissions_->RevokePermissions(extension_id);
+}
+
+std::vector<base::FilePath> CrosMountPointProvider::GetRootDirectories() const {
+  std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
+  mount_points_->AddMountPointInfosTo(&mount_points);
+  system_mount_points_->AddMountPointInfosTo(&mount_points);
+
+  std::vector<base::FilePath> root_dirs;
+  for (size_t i = 0; i < mount_points.size(); ++i)
+    root_dirs.push_back(mount_points[i].path);
+  return root_dirs;
+}
+
+fileapi::FileSystemFileUtil* CrosMountPointProvider::GetFileUtil(
+    fileapi::FileSystemType type) {
+  DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
+         type == fileapi::kFileSystemTypeRestrictedNativeLocal);
+  return local_file_util_->sync_file_util();
+}
+
+fileapi::AsyncFileUtil* CrosMountPointProvider::GetAsyncFileUtil(
+    fileapi::FileSystemType type) {
+  DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
+         type == fileapi::kFileSystemTypeRestrictedNativeLocal);
+  return local_file_util_.get();
+}
+
+fileapi::CopyOrMoveFileValidatorFactory*
+CrosMountPointProvider::GetCopyOrMoveFileValidatorFactory(
+    fileapi::FileSystemType type, base::PlatformFileError* error_code) {
+  DCHECK(error_code);
+  *error_code = base::PLATFORM_FILE_OK;
+  return NULL;
+}
+
+void CrosMountPointProvider::InitializeCopyOrMoveFileValidatorFactory(
+    fileapi::FileSystemType type,
+    scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory) {
+  DCHECK(!factory);
+}
+
+fileapi::FilePermissionPolicy CrosMountPointProvider::GetPermissionPolicy(
+    const fileapi::FileSystemURL& url, int permissions) const {
+  if (url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal &&
+      (permissions & ~fileapi::kReadFilePermissions)) {
+    // Restricted file system is read-only.
+    return fileapi::FILE_PERMISSION_ALWAYS_DENY;
+  }
+
+  if (!IsAccessAllowed(url))
+    return fileapi::FILE_PERMISSION_ALWAYS_DENY;
+
+  // Permit access to mount points from internal WebUI.
+  const GURL& origin_url = url.origin();
+  if (origin_url.SchemeIs(kChromeUIScheme))
+    return fileapi::FILE_PERMISSION_ALWAYS_ALLOW;
+
+  if (url.mount_type() == fileapi::kFileSystemTypeIsolated) {
+    // Permissions in isolated filesystems should be examined with
+    // FileSystem permission.
+    return fileapi::FILE_PERMISSION_USE_FILESYSTEM_PERMISSION;
+  }
+
+  // Also apply system's file permission by default.
+  return fileapi::FILE_PERMISSION_USE_FILE_PERMISSION;
+}
+
+fileapi::FileSystemOperation* CrosMountPointProvider::CreateFileSystemOperation(
+    const fileapi::FileSystemURL& url,
+    fileapi::FileSystemContext* context,
+    base::PlatformFileError* error_code) const {
+  DCHECK(url.is_valid());
+
+  if (url.type() == fileapi::kFileSystemTypeDrive) {
+    fileapi::RemoteFileSystemProxyInterface* remote_proxy =
+        GetRemoteProxy(url.filesystem_id());
+    if (!remote_proxy) {
+      *error_code = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+      return NULL;
+    }
+    return new chromeos::RemoteFileSystemOperation(remote_proxy);
+  }
+
+  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
+         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal);
+  scoped_ptr<fileapi::FileSystemOperationContext> operation_context(
+      new fileapi::FileSystemOperationContext(context));
+  return new fileapi::LocalFileSystemOperation(context,
+                                               operation_context.Pass());
+}
+
+scoped_ptr<webkit_blob::FileStreamReader>
+CrosMountPointProvider::CreateFileStreamReader(
+    const fileapi::FileSystemURL& url,
+    int64 offset,
+    const base::Time& expected_modification_time,
+    fileapi::FileSystemContext* context) const {
+  DCHECK(url.is_valid());
+
+  if (url.type() == fileapi::kFileSystemTypeDrive) {
+    fileapi::RemoteFileSystemProxyInterface* remote_proxy =
+        GetRemoteProxy(url.filesystem_id());
+    if (!remote_proxy)
+      return scoped_ptr<webkit_blob::FileStreamReader>();
+    return remote_proxy->CreateFileStreamReader(
+        context->task_runners()->file_task_runner(),
+        url, offset, expected_modification_time);
+  }
+
+  return scoped_ptr<webkit_blob::FileStreamReader>(
+      new fileapi::FileSystemFileStreamReader(
+          context, url, offset, expected_modification_time));
+}
+
+scoped_ptr<fileapi::FileStreamWriter>
+CrosMountPointProvider::CreateFileStreamWriter(
+    const fileapi::FileSystemURL& url,
+    int64 offset,
+    fileapi::FileSystemContext* context) const {
+  DCHECK(url.is_valid());
+
+  if (url.type() == fileapi::kFileSystemTypeDrive) {
+    fileapi::RemoteFileSystemProxyInterface* remote_proxy =
+        GetRemoteProxy(url.filesystem_id());
+    if (!remote_proxy)
+      return scoped_ptr<fileapi::FileStreamWriter>();
+    return scoped_ptr<fileapi::FileStreamWriter>(
+        new fileapi::RemoteFileStreamWriter(remote_proxy, url, offset));
+  }
+
+  if (url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal)
+    return scoped_ptr<fileapi::FileStreamWriter>();
+
+  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal);
+  return scoped_ptr<fileapi::FileStreamWriter>(
+      new fileapi::LocalFileStreamWriter(url.path(), offset));
+}
+
+bool CrosMountPointProvider::GetVirtualPath(
+    const base::FilePath& filesystem_path,
+    base::FilePath* virtual_path) {
+  return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
+         system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
+}
+
+fileapi::RemoteFileSystemProxyInterface* CrosMountPointProvider::GetRemoteProxy(
+    const std::string& mount_name) const {
+  fileapi::RemoteFileSystemProxyInterface* proxy =
+      mount_points_->GetRemoteFileSystemProxy(mount_name);
+  if (proxy)
+    return proxy;
+  return system_mount_points_->GetRemoteFileSystemProxy(mount_name);
+}
+
+}  // namespace chromeos
diff --git a/webkit/browser/chromeos/fileapi/cros_mount_point_provider.h b/webkit/browser/chromeos/fileapi/cros_mount_point_provider.h
new file mode 100644
index 0000000..6298078
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/cros_mount_point_provider.h
@@ -0,0 +1,144 @@
+// 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_CHROMEOS_FILEAPI_CROS_MOUNT_POINT_PROVIDER_H_
+#define WEBKIT_BROWSER_CHROMEOS_FILEAPI_CROS_MOUNT_POINT_PROVIDER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/common/fileapi/file_system_types.h"
+#include "webkit/quota/special_storage_policy.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace fileapi {
+class AsyncFileUtilAdapter;
+class CopyOrMoveFileValidatorFactory;
+class ExternalMountPoints;
+class FileSystemFileUtil;
+class FileSystemURL;
+class IsolatedContext;
+}
+
+namespace chromeos {
+
+class FileAccessPermissions;
+
+// An interface to provide local filesystem paths.
+class WEBKIT_STORAGE_EXPORT CrosMountPointProvider
+    : public fileapi::ExternalFileSystemMountPointProvider {
+ public:
+  using fileapi::FileSystemMountPointProvider::ValidateFileSystemCallback;
+  using fileapi::FileSystemMountPointProvider::DeleteFileSystemCallback;
+
+  // CrosMountPointProvider will take an ownership of a |mount_points|
+  // reference. On the other hand, |system_mount_points| will be kept as a raw
+  // pointer and it should outlive CrosMountPointProvider instance.
+  CrosMountPointProvider(
+      scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
+      scoped_refptr<fileapi::ExternalMountPoints> mount_points,
+      fileapi::ExternalMountPoints* system_mount_points);
+  virtual ~CrosMountPointProvider();
+
+  // Returns true if CrosMountpointProvider can handle |url|, i.e. its
+  // file system type matches with what this provider supports.
+  // This could be called on any threads.
+  static bool CanHandleURL(const fileapi::FileSystemURL& url);
+
+  // fileapi::FileSystemMountPointProvider overrides.
+  virtual bool CanHandleType(fileapi::FileSystemType type) const OVERRIDE;
+  virtual void ValidateFileSystemRoot(
+      const GURL& origin_url,
+      fileapi::FileSystemType type,
+      bool create,
+      const ValidateFileSystemCallback& callback) OVERRIDE;
+  virtual base::FilePath GetFileSystemRootPathOnFileThread(
+      const fileapi::FileSystemURL& url,
+      bool create) OVERRIDE;
+  virtual fileapi::FileSystemFileUtil* GetFileUtil(
+      fileapi::FileSystemType type) OVERRIDE;
+  virtual fileapi::AsyncFileUtil* GetAsyncFileUtil(
+      fileapi::FileSystemType type) OVERRIDE;
+  virtual fileapi::CopyOrMoveFileValidatorFactory*
+      GetCopyOrMoveFileValidatorFactory(
+          fileapi::FileSystemType type,
+          base::PlatformFileError* error_code) OVERRIDE;
+  virtual void InitializeCopyOrMoveFileValidatorFactory(
+      fileapi::FileSystemType type,
+      scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory) OVERRIDE;
+  virtual fileapi::FilePermissionPolicy GetPermissionPolicy(
+      const fileapi::FileSystemURL& url,
+      int permissions) const OVERRIDE;
+  virtual fileapi::FileSystemOperation* CreateFileSystemOperation(
+      const fileapi::FileSystemURL& url,
+      fileapi::FileSystemContext* context,
+      base::PlatformFileError* error_code) const OVERRIDE;
+  virtual scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+      const fileapi::FileSystemURL& path,
+      int64 offset,
+      const base::Time& expected_modification_time,
+      fileapi::FileSystemContext* context) const OVERRIDE;
+  virtual scoped_ptr<fileapi::FileStreamWriter> CreateFileStreamWriter(
+      const fileapi::FileSystemURL& url,
+      int64 offset,
+      fileapi::FileSystemContext* context) const OVERRIDE;
+  virtual fileapi::FileSystemQuotaUtil* GetQuotaUtil() OVERRIDE;
+  virtual void DeleteFileSystem(
+      const GURL& origin_url,
+      fileapi::FileSystemType type,
+      fileapi::FileSystemContext* context,
+      const DeleteFileSystemCallback& callback) OVERRIDE;
+
+  // fileapi::ExternalFileSystemMountPointProvider overrides.
+  virtual bool IsAccessAllowed(const fileapi::FileSystemURL& url)
+      const OVERRIDE;
+  virtual std::vector<base::FilePath> GetRootDirectories() const OVERRIDE;
+  virtual void GrantFullAccessToExtension(
+      const std::string& extension_id) OVERRIDE;
+  virtual void GrantFileAccessToExtension(
+      const std::string& extension_id,
+      const base::FilePath& virtual_path) OVERRIDE;
+  virtual void RevokeAccessForExtension(
+      const std::string& extension_id) OVERRIDE;
+  virtual bool GetVirtualPath(const base::FilePath& filesystem_path,
+                              base::FilePath* virtual_path) OVERRIDE;
+
+ private:
+  fileapi::RemoteFileSystemProxyInterface* GetRemoteProxy(
+      const std::string& mount_name) const;
+
+  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+  scoped_ptr<FileAccessPermissions> file_access_permissions_;
+  scoped_ptr<fileapi::AsyncFileUtilAdapter> local_file_util_;
+
+  // Mount points specific to the owning context.
+  //
+  // Add/Remove MountPoints will affect only these mount points.
+  //
+  // It is legal to have mount points with the same name as in
+  // system_mount_points_. Also, mount point paths may overlap with mount point
+  // paths in system_mount_points_. In both cases mount points in
+  // |mount_points_| will have a priority.
+  // E.g. if |mount_points_| map 'foo1' to '/foo/foo1' and
+  // |file_system_mount_points_| map 'xxx' to '/foo/foo1/xxx', |GetVirtualPaths|
+  // will resolve '/foo/foo1/xxx/yyy' as 'foo1/xxx/yyy' (i.e. the mapping from
+  // |mount_points_| will be used).
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points_;
+
+  // Globally visible mount points. System MountPonts instance should outlive
+  // all CrosMountPointProvider instances, so raw pointer is safe.
+  fileapi::ExternalMountPoints* system_mount_points_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrosMountPointProvider);
+};
+
+}  // namespace chromeos
+
+#endif  // WEBKIT_BROWSER_CHROMEOS_FILEAPI_CROS_MOUNT_POINT_PROVIDER_H_
diff --git a/webkit/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc b/webkit/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc
new file mode 100644
index 0000000..9eadd7c
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc
@@ -0,0 +1,304 @@
+// 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/chromeos/fileapi/cros_mount_point_provider.h"
+
+#include <set>
+
+#include "base/files/file_path.h"
+#include "chromeos/dbus/cros_disks_client.h"
+#include "googleurl/src/url_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_permission_policy.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/quota/mock_special_storage_policy.h"
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+using fileapi::ExternalMountPoints;
+using fileapi::FileSystemURL;
+
+namespace {
+
+FileSystemURL CreateFileSystemURL(const std::string& extension,
+                                  const char* path,
+                                  ExternalMountPoints* mount_points) {
+  return mount_points->CreateCrackedFileSystemURL(
+      GURL("chrome-extension://" + extension + "/"),
+      fileapi::kFileSystemTypeExternal,
+      base::FilePath::FromUTF8Unsafe(path));
+}
+
+TEST(CrosMountPointProviderTest, DefaultMountPoints) {
+  scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  chromeos::CrosMountPointProvider provider(
+      storage_policy,
+      mount_points.get(),
+      fileapi::ExternalMountPoints::GetSystemInstance());
+  std::vector<base::FilePath> root_dirs = provider.GetRootDirectories();
+  std::set<base::FilePath> root_dirs_set(root_dirs.begin(), root_dirs.end());
+
+  // By default there should be 3 mount points (in system mount points):
+  EXPECT_EQ(3u, root_dirs.size());
+  EXPECT_TRUE(root_dirs_set.count(
+      chromeos::CrosDisksClient::GetRemovableDiskMountPoint()));
+  EXPECT_TRUE(root_dirs_set.count(
+      chromeos::CrosDisksClient::GetArchiveMountPoint()));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/usr/share/oem"))));
+}
+
+TEST(CrosMountPointProviderTest, GetRootDirectories) {
+  scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+
+  scoped_refptr<fileapi::ExternalMountPoints> system_mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+
+  chromeos::CrosMountPointProvider provider(
+      storage_policy,
+      mount_points.get(),
+      system_mount_points.get());
+
+  const size_t initial_root_dirs_size = provider.GetRootDirectories().size();
+
+  // Register 'local' test mount points.
+  mount_points->RegisterFileSystem("c",
+                                   fileapi::kFileSystemTypeNativeLocal,
+                                   base::FilePath(FPL("/a/b/c")));
+  mount_points->RegisterFileSystem("d",
+                                   fileapi::kFileSystemTypeNativeLocal,
+                                   base::FilePath(FPL("/b/c/d")));
+
+  // Register system test mount points.
+  system_mount_points->RegisterFileSystem("d",
+                                          fileapi::kFileSystemTypeNativeLocal,
+                                          base::FilePath(FPL("/g/c/d")));
+  system_mount_points->RegisterFileSystem("e",
+                                          fileapi::kFileSystemTypeNativeLocal,
+                                          base::FilePath(FPL("/g/d/e")));
+
+  std::vector<base::FilePath> root_dirs = provider.GetRootDirectories();
+  std::set<base::FilePath> root_dirs_set(root_dirs.begin(), root_dirs.end());
+  EXPECT_EQ(initial_root_dirs_size + 4, root_dirs.size());
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/a/b/c"))));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/b/c/d"))));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/g/c/d"))));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/g/d/e"))));
+}
+
+TEST(CrosMountPointProviderTest, AccessPermissions) {
+  const int kPermission = fileapi::kReadFilePermissions;
+
+  url_util::AddStandardScheme("chrome-extension");
+
+  scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  scoped_refptr<fileapi::ExternalMountPoints> system_mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  chromeos::CrosMountPointProvider provider(
+      storage_policy,
+      mount_points.get(),
+      system_mount_points.get());
+
+  std::string extension("ddammdhioacbehjngdmkjcjbnfginlla");
+
+  storage_policy->AddFileHandler(extension);
+
+  // Initialize mount points.
+  ASSERT_TRUE(system_mount_points->RegisterFileSystem(
+      "system",
+      fileapi::kFileSystemTypeNativeLocal,
+      base::FilePath(FPL("/g/system"))));
+  ASSERT_TRUE(mount_points->RegisterFileSystem(
+      "removable",
+      fileapi::kFileSystemTypeNativeLocal,
+      base::FilePath(FPL("/media/removable"))));
+  ASSERT_TRUE(mount_points->RegisterFileSystem(
+      "oem",
+      fileapi::kFileSystemTypeRestrictedNativeLocal,
+      base::FilePath(FPL("/usr/share/oem"))));
+
+  // Provider specific mount point access.
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "removable/foo", mount_points.get()),
+          kPermission));
+
+  provider.GrantFileAccessToExtension(extension,
+                                      base::FilePath(FPL("removable/foo")));
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_USE_FILE_PERMISSION,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "removable/foo", mount_points.get()),
+          kPermission));
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "removable/foo1", mount_points.get()),
+          kPermission));
+
+  // System mount point access.
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "system/foo",
+                              system_mount_points.get()),
+          kPermission));
+
+  provider.GrantFileAccessToExtension(extension,
+                                      base::FilePath(FPL("system/foo")));
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_USE_FILE_PERMISSION,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "system/foo",
+                              system_mount_points.get()),
+          kPermission));
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "system/foo1",
+                              system_mount_points.get()),
+          kPermission));
+
+  // oem is restricted file system.
+  provider.GrantFileAccessToExtension(
+      extension, base::FilePath(FPL("oem/foo")));
+  // The extension should not be able to access the file even if
+  // GrantFileAccessToExtension was called.
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "oem/foo", mount_points.get()),
+          kPermission));
+
+  provider.GrantFullAccessToExtension(extension);
+  // The extension should be able to access restricted file system after it was
+  // granted full access.
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_USE_FILE_PERMISSION,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "oem/foo", mount_points.get()),
+          kPermission));
+  // The extension which was granted full access should be able to access any
+  // path on current file systems.
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_USE_FILE_PERMISSION,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "removable/foo1", mount_points.get()),
+          kPermission));
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_USE_FILE_PERMISSION,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "system/foo1",
+                              system_mount_points.get()),
+          kPermission));
+
+  // The extension cannot access new mount points.
+  // TODO(tbarzic): This should probably be changed.
+  ASSERT_TRUE(mount_points->RegisterFileSystem(
+      "test",
+      fileapi::kFileSystemTypeNativeLocal,
+      base::FilePath(FPL("/foo/test"))));
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "test_/foo", mount_points.get()),
+          kPermission));
+
+  provider.RevokeAccessForExtension(extension);
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_DENY,
+      provider.GetPermissionPolicy(
+          CreateFileSystemURL(extension, "removable/foo", mount_points.get()),
+          kPermission));
+
+  fileapi::FileSystemURL internal_url = FileSystemURL::CreateForTest(
+      GURL("chrome://foo"),
+      fileapi::kFileSystemTypeExternal,
+      base::FilePath(FPL("removable/")));
+  // Internal WebUI should have full access.
+  EXPECT_EQ(
+      fileapi::FILE_PERMISSION_ALWAYS_ALLOW,
+      provider.GetPermissionPolicy(internal_url, kPermission));
+}
+
+TEST(CrosMountPointProvider, GetVirtualPathConflictWithSystemPoints) {
+  scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  scoped_refptr<fileapi::ExternalMountPoints> system_mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  chromeos::CrosMountPointProvider provider(storage_policy,
+      mount_points.get(),
+      system_mount_points.get());
+
+  const fileapi::FileSystemType type = fileapi::kFileSystemTypeNativeLocal;
+
+  // Provider specific mount points.
+  ASSERT_TRUE(
+      mount_points->RegisterFileSystem("b", type, base::FilePath(FPL("/a/b"))));
+  ASSERT_TRUE(
+      mount_points->RegisterFileSystem("y", type, base::FilePath(FPL("/z/y"))));
+  ASSERT_TRUE(
+      mount_points->RegisterFileSystem("n", type, base::FilePath(FPL("/m/n"))));
+
+  // System mount points
+  ASSERT_TRUE(system_mount_points->RegisterFileSystem(
+      "gb", type, base::FilePath(FPL("/a/b"))));
+  ASSERT_TRUE(
+      system_mount_points->RegisterFileSystem(
+          "gz", type, base::FilePath(FPL("/z"))));
+  ASSERT_TRUE(system_mount_points->RegisterFileSystem(
+       "gp", type, base::FilePath(FPL("/m/n/o/p"))));
+
+  struct TestCase {
+    const base::FilePath::CharType* const local_path;
+    bool success;
+    const base::FilePath::CharType* const virtual_path;
+  };
+
+  const TestCase kTestCases[] = {
+    // Same paths in both mount points.
+    { FPL("/a/b/c/d"), true, FPL("b/c/d") },
+    // System mount points path more specific.
+    { FPL("/m/n/o/p/r/s"), true, FPL("n/o/p/r/s") },
+    // System mount points path less specific.
+    { FPL("/z/y/x"), true, FPL("y/x") },
+    // Only system mount points path matches.
+    { FPL("/z/q/r/s"), true, FPL("gz/q/r/s") },
+    // No match.
+    { FPL("/foo/xxx"), false, FPL("") },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+    // Initialize virtual path with a value.
+    base::FilePath virtual_path(FPL("/mount"));
+    base::FilePath local_path(kTestCases[i].local_path);
+    EXPECT_EQ(kTestCases[i].success,
+              provider.GetVirtualPath(local_path, &virtual_path))
+        << "Resolving " << kTestCases[i].local_path;
+
+    // There are no guarantees for |virtual_path| value if |GetVirtualPath|
+    // fails.
+    if (!kTestCases[i].success)
+      continue;
+
+    base::FilePath expected_virtual_path(kTestCases[i].virtual_path);
+    EXPECT_EQ(expected_virtual_path, virtual_path)
+        << "Resolving " << kTestCases[i].local_path;
+  }
+}
+
+}  // namespace
diff --git a/webkit/browser/chromeos/fileapi/file_access_permissions.cc b/webkit/browser/chromeos/fileapi/file_access_permissions.cc
new file mode 100644
index 0000000..db6d50a
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/file_access_permissions.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 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/chromeos/fileapi/file_access_permissions.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+
+namespace chromeos {
+
+FileAccessPermissions::FileAccessPermissions() {}
+
+FileAccessPermissions::~FileAccessPermissions() {}
+
+
+void FileAccessPermissions::GrantAccessPermission(
+    const std::string& extension_id, const base::FilePath& path) {
+  base::AutoLock locker(lock_);
+  PathAccessMap::iterator path_map_iter = path_map_.find(extension_id);
+  if (path_map_iter == path_map_.end()) {
+    PathSet path_set;
+    path_set.insert(path);
+    path_map_.insert(PathAccessMap::value_type(extension_id, path_set));
+  } else {
+    if (path_map_iter->second.find(path) != path_map_iter->second.end())
+      return;
+    path_map_iter->second.insert(path);
+  }
+}
+
+bool FileAccessPermissions::HasAccessPermission(
+    const std::string& extension_id, const base::FilePath& path) const {
+  base::AutoLock locker(lock_);
+  PathAccessMap::const_iterator path_map_iter = path_map_.find(extension_id);
+  if (path_map_iter == path_map_.end())
+    return false;
+
+  // Check this file and walk up its directory tree to find if this extension
+  // has access to it.
+  base::FilePath current_path = path.StripTrailingSeparators();
+  base::FilePath last_path;
+  while (current_path != last_path) {
+    if (path_map_iter->second.find(current_path) != path_map_iter->second.end())
+      return true;
+    last_path = current_path;
+    current_path = current_path.DirName();
+  }
+  return false;
+}
+
+void FileAccessPermissions::RevokePermissions(
+    const std::string& extension_id) {
+  base::AutoLock locker(lock_);
+  path_map_.erase(extension_id);
+}
+
+}
diff --git a/webkit/browser/chromeos/fileapi/file_access_permissions.h b/webkit/browser/chromeos/fileapi/file_access_permissions.h
new file mode 100644
index 0000000..31cf195
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/file_access_permissions.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 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_CHROMEOS_FILEAPI_FILE_ACCESS_PERMISSIONS_H_
+#define WEBKIT_BROWSER_CHROMEOS_FILEAPI_FILE_ACCESS_PERMISSIONS_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace chromeos {
+
+class WEBKIT_STORAGE_EXPORT FileAccessPermissions {
+ public:
+  FileAccessPermissions();
+  virtual ~FileAccessPermissions();
+
+  // Grants |extension_id| access to |path|.
+  void GrantAccessPermission(const std::string& extension_id,
+                             const base::FilePath& path);
+  // Checks id |extension_id| has permission to access to |path|.
+  bool HasAccessPermission(const std::string& extension_id,
+                           const base::FilePath& path) const;
+  // Revokes all file permissions for |extension_id|.
+  void RevokePermissions(const std::string& extension_id);
+
+ private:
+  typedef std::set<base::FilePath> PathSet;
+  typedef std::map<std::string, PathSet> PathAccessMap;
+
+  mutable base::Lock lock_;  // Synchronize all access to path_map_.
+  PathAccessMap path_map_;
+};
+
+}  // namespace chromeos
+
+#endif  // WEBKIT_BROWSER_CHROMEOS_FILEAPI_FILE_ACCESS_PERMISSIONS_H_
diff --git a/webkit/browser/chromeos/fileapi/file_access_permissions_unittest.cc b/webkit/browser/chromeos/fileapi/file_access_permissions_unittest.cc
new file mode 100644
index 0000000..3b6875d
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/file_access_permissions_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/chromeos/fileapi/file_access_permissions.h"
+
+
+class FileAccessPermissionsTest : public testing::Test {
+};
+
+TEST_F(FileAccessPermissionsTest, FileAccessChecks) {
+#if defined(OS_WIN)
+  base::FilePath good_dir(FILE_PATH_LITERAL("c:\\root\\dir"));
+  base::FilePath bad_dir(FILE_PATH_LITERAL("c:\\root"));
+  base::FilePath good_file(FILE_PATH_LITERAL("c:\\root\\dir\\good_file.txt"));
+  base::FilePath bad_file(FILE_PATH_LITERAL("c:\\root\\dir\\bad_file.txt"));
+#elif defined(OS_POSIX)
+  base::FilePath good_dir(FILE_PATH_LITERAL("/root/dir"));
+  base::FilePath bad_dir(FILE_PATH_LITERAL("/root"));
+  base::FilePath good_file(FILE_PATH_LITERAL("/root/dir/good_file.txt"));
+  base::FilePath bad_file(FILE_PATH_LITERAL("/root/dir/bad_file.txt"));
+#endif
+  std::string extension1("ddammdhioacbehjngdmkjcjbnfginlla");
+  std::string extension2("jkhdjkhkhsdkfhsdkhrterwmtermeter");
+
+  chromeos::FileAccessPermissions permissions;
+  // By default extension have no access to any local file.
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, bad_file));
+
+  // After granting file access to the handler extension for a given file, it
+  // can only access that file an nothing else.
+  permissions.GrantAccessPermission(extension1, good_file);
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, bad_file));
+
+
+  // After granting file access to the handler extension for a given directory,
+  // it can access that directory and all files within it.
+  permissions.GrantAccessPermission(extension2, good_dir);
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension2, bad_file));
+
+  // After revoking rights for extensions, they should not be able to access
+  // any file system element anymore.
+  permissions.RevokePermissions(extension1);
+  permissions.RevokePermissions(extension2);
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, bad_file));
+}
diff --git a/webkit/browser/chromeos/fileapi/remote_file_stream_writer.cc b/webkit/browser/chromeos/fileapi/remote_file_stream_writer.cc
new file mode 100644
index 0000000..55b807e
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/remote_file_stream_writer.cc
@@ -0,0 +1,119 @@
+// 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/chromeos/fileapi/remote_file_stream_writer.h"
+
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "webkit/blob/local_file_stream_reader.h"
+#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/browser/fileapi/local_file_stream_writer.h"
+#include "webkit/browser/fileapi/remote_file_system_proxy.h"
+
+namespace fileapi {
+
+RemoteFileStreamWriter::RemoteFileStreamWriter(
+    const scoped_refptr<RemoteFileSystemProxyInterface>& remote_filesystem,
+    const FileSystemURL& url,
+    int64 offset)
+    : remote_filesystem_(remote_filesystem),
+      url_(url),
+      initial_offset_(offset),
+      has_pending_create_snapshot_(false),
+      weak_factory_(this) {
+}
+
+RemoteFileStreamWriter::~RemoteFileStreamWriter() {
+}
+
+int RemoteFileStreamWriter::Write(net::IOBuffer* buf,
+                                  int buf_len,
+                                  const net::CompletionCallback& callback) {
+  DCHECK(!has_pending_create_snapshot_);
+  DCHECK(pending_cancel_callback_.is_null());
+
+  if (!local_file_writer_) {
+    has_pending_create_snapshot_ = true;
+    // In this RemoteFileStreamWriter, we only create snapshot file and don't
+    // have explicit close operation. This is ok, because close is automatically
+    // triggered by a refcounted |file_ref_| passed to OnFileOpened, from the
+    // destructor of RemoteFileStreamWriter.
+    remote_filesystem_->CreateWritableSnapshotFile(
+        url_,
+        base::Bind(&RemoteFileStreamWriter::OnFileOpened,
+                   weak_factory_.GetWeakPtr(),
+                   make_scoped_refptr(buf),
+                   buf_len,
+                   callback));
+    return net::ERR_IO_PENDING;
+  }
+  return local_file_writer_->Write(buf, buf_len, callback);
+}
+
+void RemoteFileStreamWriter::OnFileOpened(
+    net::IOBuffer* buf,
+    int buf_len,
+    const net::CompletionCallback& callback,
+    base::PlatformFileError open_result,
+    const base::FilePath& local_path,
+    const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
+  has_pending_create_snapshot_ = false;
+  if (!pending_cancel_callback_.is_null()) {
+    InvokePendingCancelCallback(net::OK);
+    return;
+  }
+
+  if (open_result != base::PLATFORM_FILE_OK) {
+    callback.Run(net::PlatformFileErrorToNetError(open_result));
+    return;
+  }
+
+  // Hold the reference to the file. Releasing the reference notifies the file
+  // system about to close file.
+  file_ref_ = file_ref;
+
+  DCHECK(!local_file_writer_.get());
+  local_file_writer_.reset(new fileapi::LocalFileStreamWriter(local_path,
+                                                              initial_offset_));
+  int result = local_file_writer_->Write(buf, buf_len, callback);
+  if (result != net::ERR_IO_PENDING)
+    callback.Run(result);
+}
+
+int RemoteFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
+  DCHECK(!callback.is_null());
+  DCHECK(pending_cancel_callback_.is_null());
+
+  // If file open operation is in-flight, wait for its completion and cancel
+  // further write operation in OnFileOpened.
+  if (has_pending_create_snapshot_) {
+    pending_cancel_callback_ = callback;
+    return net::ERR_IO_PENDING;
+  }
+
+  // If LocalFileWriter is already created, just delegate the cancel to it.
+  if (local_file_writer_) {
+    pending_cancel_callback_ = callback;
+    return local_file_writer_->Cancel(
+        base::Bind(&RemoteFileStreamWriter::InvokePendingCancelCallback,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  // Write() is not called yet.
+  return net::ERR_UNEXPECTED;
+}
+
+int RemoteFileStreamWriter::Flush(const net::CompletionCallback& callback) {
+  // For remote file writer, Flush() is a no-op. Synchronization to the remote
+  // server is not done until the file is closed.
+  return net::OK;
+}
+
+void RemoteFileStreamWriter::InvokePendingCancelCallback(int result) {
+  net::CompletionCallback callback = pending_cancel_callback_;
+  pending_cancel_callback_.Reset();
+  callback.Run(result);
+}
+
+}  // namespace gdata
diff --git a/webkit/browser/chromeos/fileapi/remote_file_stream_writer.h b/webkit/browser/chromeos/fileapi/remote_file_stream_writer.h
new file mode 100644
index 0000000..4799182
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/remote_file_stream_writer.h
@@ -0,0 +1,75 @@
+// 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_CHROMEOS_FILEAPI_REMOTE_FILE_STREAM_WRITER_H_
+#define WEBKIT_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_STREAM_WRITER_H_
+
+#include "base/basictypes.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/browser/fileapi/file_system_url.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace webkit_blob {
+class ShareableFileReference;
+}
+
+namespace fileapi {
+
+class RemoteFileSystemProxyInterface;
+
+// FileStreamWriter interface for writing to a file on remote file system.
+class RemoteFileStreamWriter : public fileapi::FileStreamWriter {
+ public:
+  // Creates a writer for a file on |remote_filesystem| with path url |url|
+  // (like "filesystem:chrome-extension://id/external/special/drive/...") that
+  // starts writing from |offset|. When invalid parameters are set, the first
+  // call to Write() method fails.
+  RemoteFileStreamWriter(
+      const scoped_refptr<RemoteFileSystemProxyInterface>& remote_filesystem,
+      const FileSystemURL& url,
+      int64 offset);
+  virtual ~RemoteFileStreamWriter();
+
+  // FileWriter override.
+  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:
+  // Callback function to do the continuation of the work of the first Write()
+  // call, which tries to open the local copy of the file before writing.
+  void OnFileOpened(
+      net::IOBuffer* buf,
+      int buf_len,
+      const net::CompletionCallback& callback,
+      base::PlatformFileError open_result,
+      const base::FilePath& local_path,
+      const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref);
+  // Calls |pending_cancel_callback_|, assuming it is non-null.
+  void InvokePendingCancelCallback(int result);
+
+  scoped_refptr<RemoteFileSystemProxyInterface> remote_filesystem_;
+  const FileSystemURL url_;
+  const int64 initial_offset_;
+  scoped_ptr<fileapi::FileStreamWriter> local_file_writer_;
+  scoped_refptr<webkit_blob::ShareableFileReference> file_ref_;
+  bool has_pending_create_snapshot_;
+  net::CompletionCallback pending_cancel_callback_;
+
+  base::WeakPtrFactory<RemoteFileStreamWriter> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteFileStreamWriter);
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_STREAM_WRITER_H_
diff --git a/webkit/browser/chromeos/fileapi/remote_file_system_operation.cc b/webkit/browser/chromeos/fileapi/remote_file_system_operation.cc
new file mode 100644
index 0000000..fcf129d
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/remote_file_system_operation.cc
@@ -0,0 +1,321 @@
+// 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/chromeos/fileapi/remote_file_system_operation.h"
+
+#include "base/bind.h"
+#include "base/platform_file.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_context.h"
+#include "webkit/browser/chromeos/fileapi/remote_file_stream_writer.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
+
+using fileapi::FileSystemURL;
+
+namespace chromeos {
+
+RemoteFileSystemOperation::RemoteFileSystemOperation(
+    scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy)
+      : remote_proxy_(remote_proxy),
+        pending_operation_(kOperationNone) {
+}
+
+RemoteFileSystemOperation::~RemoteFileSystemOperation() {
+}
+
+void RemoteFileSystemOperation::GetMetadata(const FileSystemURL& url,
+    const GetMetadataCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationGetMetadata));
+  remote_proxy_->GetFileInfo(url,
+      base::Bind(&RemoteFileSystemOperation::DidGetMetadata,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::DirectoryExists(const FileSystemURL& url,
+    const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationDirectoryExists));
+  remote_proxy_->GetFileInfo(url,
+      base::Bind(&RemoteFileSystemOperation::DidDirectoryExists,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::FileExists(const FileSystemURL& url,
+    const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationFileExists));
+  remote_proxy_->GetFileInfo(url,
+      base::Bind(base::Bind(&RemoteFileSystemOperation::DidFileExists,
+                            base::Owned(this), callback)));
+}
+
+void RemoteFileSystemOperation::ReadDirectory(const FileSystemURL& url,
+    const ReadDirectoryCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationReadDirectory));
+  remote_proxy_->ReadDirectory(url,
+      base::Bind(&RemoteFileSystemOperation::DidReadDirectory,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::Remove(const FileSystemURL& url, bool recursive,
+                                       const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationRemove));
+  remote_proxy_->Remove(url, recursive,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+
+void RemoteFileSystemOperation::CreateDirectory(
+    const FileSystemURL& url, bool exclusive, bool recursive,
+    const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCreateDirectory));
+  remote_proxy_->CreateDirectory(url, exclusive, recursive,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::CreateFile(const FileSystemURL& url,
+                                           bool exclusive,
+                                           const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCreateFile));
+  remote_proxy_->CreateFile(url, exclusive,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::Copy(const FileSystemURL& src_url,
+                                     const FileSystemURL& dest_url,
+                                     const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCopy));
+
+  remote_proxy_->Copy(src_url, dest_url,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::Move(const FileSystemURL& src_url,
+                                     const FileSystemURL& dest_url,
+                                     const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationMove));
+
+  remote_proxy_->Move(src_url, dest_url,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::Write(
+    const net::URLRequestContext* url_request_context,
+    const FileSystemURL& url,
+    const GURL& blob_url,
+    int64 offset,
+    const WriteCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationWrite));
+  DCHECK(write_callback_.is_null());
+
+  write_callback_ = callback;
+  file_writer_delegate_.reset(
+      new fileapi::FileWriterDelegate(
+          base::Bind(&RemoteFileSystemOperation::DidWrite,
+                     // FileWriterDelegate is owned by |this|. So Unretained.
+                     base::Unretained(this)),
+          scoped_ptr<fileapi::FileStreamWriter>(
+              new fileapi::RemoteFileStreamWriter(remote_proxy_,
+                                                  url,
+                                                  offset))));
+
+  scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest(
+      blob_url, file_writer_delegate_.get()));
+
+  file_writer_delegate_->Start(blob_request.Pass());
+}
+
+void RemoteFileSystemOperation::Truncate(const FileSystemURL& url,
+                                         int64 length,
+                                         const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationTruncate));
+
+  remote_proxy_->Truncate(url, length,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::Cancel(const StatusCallback& cancel_callback) {
+  if (file_writer_delegate_) {
+    DCHECK_EQ(kOperationWrite, pending_operation_);
+
+    // Writes are done without proxying through FileUtilProxy after the initial
+    // opening of the PlatformFile.  All state changes are done on this thread,
+    // so we're guaranteed to be able to shut down atomically.
+    const bool delete_now = file_writer_delegate_->Cancel();
+
+    if (!write_callback_.is_null()) {
+      // Notify the failure status to the ongoing operation's callback.
+      write_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT, 0, false);
+    }
+    cancel_callback.Run(base::PLATFORM_FILE_OK);
+    write_callback_.Reset();
+
+    if (delete_now) {
+      delete this;
+      return;
+    }
+  } else {
+    DCHECK_EQ(kOperationTruncate, pending_operation_);
+    // We're cancelling a truncate operation, but we can't actually stop it
+    // since it's been proxied to another thread.  We need to save the
+    // cancel_callback so that when the truncate returns, it can see that it's
+    // been cancelled, report it, and report that the cancel has succeeded.
+    DCHECK(cancel_callback_.is_null());
+    cancel_callback_ = cancel_callback;
+  }
+}
+
+void RemoteFileSystemOperation::TouchFile(const FileSystemURL& url,
+                                          const base::Time& last_access_time,
+                                          const base::Time& last_modified_time,
+                                          const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationTouchFile));
+  remote_proxy_->TouchFile(
+      url,
+      last_access_time,
+      last_modified_time,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 base::Owned(this), callback));
+}
+
+void RemoteFileSystemOperation::OpenFile(const FileSystemURL& url,
+                                         int file_flags,
+                                         base::ProcessHandle peer_handle,
+                                         const OpenFileCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationOpenFile));
+  remote_proxy_->OpenFile(
+      url,
+      file_flags,
+      peer_handle,
+      base::Bind(&RemoteFileSystemOperation::DidOpenFile,
+                 base::Owned(this), url, callback));
+}
+
+fileapi::LocalFileSystemOperation*
+RemoteFileSystemOperation::AsLocalFileSystemOperation() {
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+void RemoteFileSystemOperation::CreateSnapshotFile(
+    const FileSystemURL& url,
+    const SnapshotFileCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCreateSnapshotFile));
+  remote_proxy_->CreateSnapshotFile(
+      url,
+      base::Bind(&RemoteFileSystemOperation::DidCreateSnapshotFile,
+                 base::Owned(this), callback));
+}
+
+bool RemoteFileSystemOperation::SetPendingOperationType(OperationType type) {
+  if (pending_operation_ != kOperationNone)
+    return false;
+  pending_operation_ = type;
+  return true;
+}
+
+void RemoteFileSystemOperation::DidDirectoryExists(
+    const StatusCallback& callback,
+    base::PlatformFileError rv,
+    const base::PlatformFileInfo& file_info,
+    const base::FilePath& unused) {
+  if (rv == base::PLATFORM_FILE_OK && !file_info.is_directory)
+    rv = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+  callback.Run(rv);
+}
+
+void RemoteFileSystemOperation::DidFileExists(
+    const StatusCallback& callback,
+    base::PlatformFileError rv,
+    const base::PlatformFileInfo& file_info,
+    const base::FilePath& unused) {
+  if (rv == base::PLATFORM_FILE_OK && file_info.is_directory)
+    rv = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
+  callback.Run(rv);
+}
+
+void RemoteFileSystemOperation::DidGetMetadata(
+    const GetMetadataCallback& callback,
+    base::PlatformFileError rv,
+    const base::PlatformFileInfo& file_info,
+    const base::FilePath& platform_path) {
+  callback.Run(rv, file_info, platform_path);
+}
+
+void RemoteFileSystemOperation::DidReadDirectory(
+    const ReadDirectoryCallback& callback,
+    base::PlatformFileError rv,
+    const std::vector<fileapi::DirectoryEntry>& entries,
+    bool has_more) {
+  callback.Run(rv, entries, has_more /* has_more */);
+}
+
+void RemoteFileSystemOperation::DidWrite(
+    base::PlatformFileError rv,
+    int64 bytes,
+    FileWriterDelegate::WriteProgressStatus write_status) {
+  if (write_callback_.is_null()) {
+    // If cancelled, callback is already invoked and set to null in Cancel().
+    // We must not call it twice. Just shut down this operation object.
+    delete this;
+    return;
+  }
+
+  bool complete = (write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
+  write_callback_.Run(rv, bytes, complete);
+  if (rv != base::PLATFORM_FILE_OK || complete) {
+    // Other Did*'s doesn't have "delete this", because it is automatic since
+    // they are base::Owned by the caller of the callback. For DidWrite, the
+    // owner is file_writer_delegate_ which itself is owned by this Operation
+    // object. Hence we need manual life time management here.
+    // TODO(kinaba): think about refactoring FileWriterDelegate to be self
+    // destructing, for avoiding the manual management.
+    delete this;
+  }
+}
+
+void RemoteFileSystemOperation::DidFinishFileOperation(
+    const StatusCallback& callback,
+    base::PlatformFileError rv) {
+  if (!cancel_callback_.is_null()) {
+    DCHECK_EQ(kOperationTruncate, pending_operation_);
+
+    callback.Run(base::PLATFORM_FILE_ERROR_ABORT);
+    cancel_callback_.Run(base::PLATFORM_FILE_OK);
+    cancel_callback_.Reset();
+  } else {
+    callback.Run(rv);
+  }
+}
+
+void RemoteFileSystemOperation::DidCreateSnapshotFile(
+    const SnapshotFileCallback& callback,
+    base::PlatformFileError result,
+    const base::PlatformFileInfo& file_info,
+    const base::FilePath& platform_path,
+    const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
+  callback.Run(result, file_info, platform_path, file_ref);
+}
+
+void RemoteFileSystemOperation::DidOpenFile(
+    const fileapi::FileSystemURL& url,
+    const OpenFileCallback& callback,
+    base::PlatformFileError result,
+    base::PlatformFile file,
+    base::ProcessHandle peer_handle) {
+  callback.Run(
+      result, file,
+      base::Bind(&fileapi::RemoteFileSystemProxyInterface::NotifyCloseFile,
+                 remote_proxy_, url),
+      peer_handle);
+}
+
+}  // namespace chromeos
diff --git a/webkit/browser/chromeos/fileapi/remote_file_system_operation.h b/webkit/browser/chromeos/fileapi/remote_file_system_operation.h
new file mode 100644
index 0000000..e89fb71
--- /dev/null
+++ b/webkit/browser/chromeos/fileapi/remote_file_system_operation.h
@@ -0,0 +1,135 @@
+// 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_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
+#define WEBKIT_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
+
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
+#include "webkit/browser/fileapi/remote_file_system_proxy.h"
+
+namespace base {
+class Value;
+}
+
+namespace fileapi {
+class FileWriterDelegate;
+class LocalFileSystemOperation;
+}
+
+namespace chromeos {
+
+// FileSystemOperation implementation for local file systems.
+class RemoteFileSystemOperation : public fileapi::FileSystemOperation {
+ public:
+  typedef fileapi::FileWriterDelegate FileWriterDelegate;
+  virtual ~RemoteFileSystemOperation();
+
+  // FileSystemOperation overrides.
+  virtual void CreateFile(const fileapi::FileSystemURL& url,
+                          bool exclusive,
+                          const StatusCallback& callback) OVERRIDE;
+  virtual void CreateDirectory(const fileapi::FileSystemURL& url,
+                               bool exclusive,
+                               bool recursive,
+                               const StatusCallback& callback) OVERRIDE;
+  virtual void Copy(const fileapi::FileSystemURL& src_url,
+                    const fileapi::FileSystemURL& dest_url,
+                    const StatusCallback& callback) OVERRIDE;
+  virtual void Move(const fileapi::FileSystemURL& src_url,
+                    const fileapi::FileSystemURL& dest_url,
+                    const StatusCallback& callback) OVERRIDE;
+  virtual void DirectoryExists(const fileapi::FileSystemURL& url,
+                               const StatusCallback& callback) OVERRIDE;
+  virtual void FileExists(const fileapi::FileSystemURL& url,
+                          const StatusCallback& callback) OVERRIDE;
+  virtual void GetMetadata(const fileapi::FileSystemURL& url,
+                           const GetMetadataCallback& callback) OVERRIDE;
+  virtual void ReadDirectory(const fileapi::FileSystemURL& url,
+                             const ReadDirectoryCallback& callback) OVERRIDE;
+  virtual void Remove(const fileapi::FileSystemURL& url, bool recursive,
+                      const StatusCallback& callback) OVERRIDE;
+  virtual void Write(const net::URLRequestContext* url_request_context,
+                     const fileapi::FileSystemURL& url,
+                     const GURL& blob_url,
+                     int64 offset,
+                     const WriteCallback& callback) OVERRIDE;
+  virtual void Truncate(const fileapi::FileSystemURL& url, int64 length,
+                        const StatusCallback& callback) OVERRIDE;
+  virtual void Cancel(const StatusCallback& cancel_callback) OVERRIDE;
+  virtual void TouchFile(const fileapi::FileSystemURL& url,
+                         const base::Time& last_access_time,
+                         const base::Time& last_modified_time,
+                         const StatusCallback& callback) OVERRIDE;
+  virtual void OpenFile(
+      const fileapi::FileSystemURL& url,
+      int file_flags,
+      base::ProcessHandle peer_handle,
+      const OpenFileCallback& callback) OVERRIDE;
+  virtual fileapi::LocalFileSystemOperation*
+      AsLocalFileSystemOperation() OVERRIDE;
+  virtual void CreateSnapshotFile(
+      const fileapi::FileSystemURL& url,
+      const SnapshotFileCallback& callback) OVERRIDE;
+
+ private:
+  friend class CrosMountPointProvider;
+
+  RemoteFileSystemOperation(
+      scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy);
+
+  // Used only for internal assertions.
+  // Returns false if there's another inflight pending operation.
+  bool SetPendingOperationType(OperationType type);
+
+  // Generic callback that translates platform errors to WebKit error codes.
+  void DidDirectoryExists(const StatusCallback& callback,
+                          base::PlatformFileError rv,
+                          const base::PlatformFileInfo& file_info,
+                          const base::FilePath& unused);
+  void DidFileExists(const StatusCallback& callback,
+                     base::PlatformFileError rv,
+                     const base::PlatformFileInfo& file_info,
+                     const base::FilePath& unused);
+  void DidGetMetadata(const GetMetadataCallback& callback,
+                      base::PlatformFileError rv,
+                      const base::PlatformFileInfo& file_info,
+                      const base::FilePath& platform_path);
+  void DidReadDirectory(const ReadDirectoryCallback& callback,
+                        base::PlatformFileError rv,
+                        const std::vector<fileapi::DirectoryEntry>& entries,
+                        bool has_more);
+  void DidWrite(base::PlatformFileError result,
+                int64 bytes,
+                FileWriterDelegate::WriteProgressStatus write_status);
+  void DidFinishFileOperation(const StatusCallback& callback,
+                              base::PlatformFileError rv);
+  void DidCreateSnapshotFile(
+      const SnapshotFileCallback& callback,
+      base::PlatformFileError result,
+      const base::PlatformFileInfo& file_info,
+      const base::FilePath& platform_path,
+      const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref);
+  void DidOpenFile(
+      const fileapi::FileSystemURL& url,
+      const OpenFileCallback& callback,
+      base::PlatformFileError result,
+      base::PlatformFile file,
+      base::ProcessHandle peer_handle);
+
+
+  scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy_;
+  // A flag to make sure we call operation only once per instance.
+  OperationType pending_operation_;
+  scoped_ptr<fileapi::FileWriterDelegate> file_writer_delegate_;
+
+  WriteCallback write_callback_;
+  StatusCallback cancel_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteFileSystemOperation);
+};
+
+}  // namespace chromeos
+
+#endif  // WEBKIT_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
diff --git a/webkit/browser/fileapi/file_system_context.cc b/webkit/browser/fileapi/file_system_context.cc
index a25f050..977db2d 100644
--- a/webkit/browser/fileapi/file_system_context.cc
+++ b/webkit/browser/fileapi/file_system_context.cc
@@ -31,7 +31,7 @@
 #include "webkit/quota/special_storage_policy.h"
 
 #if defined(OS_CHROMEOS)
-#include "webkit/chromeos/fileapi/cros_mount_point_provider.h"
+#include "webkit/browser/chromeos/fileapi/cros_mount_point_provider.h"
 #endif
 
 using quota::QuotaClient;
diff --git a/webkit/browser/fileapi/webkit_browser_fileapi.gypi b/webkit/browser/fileapi/webkit_browser_fileapi.gypi
index ecea36e..7502072 100644
--- a/webkit/browser/fileapi/webkit_browser_fileapi.gypi
+++ b/webkit/browser/fileapi/webkit_browser_fileapi.gypi
@@ -111,6 +111,18 @@
       '../browser/fileapi/upload_file_system_file_element_reader.cc',
       '../browser/fileapi/upload_file_system_file_element_reader.h',
     ],
+    'webkit_browser_fileapi_chromeos_sources': [
+      '../browser/chromeos/fileapi/async_file_stream.h',
+      '../browser/chromeos/fileapi/cros_mount_point_provider.cc',
+      '../browser/chromeos/fileapi/cros_mount_point_provider.h',
+      '../browser/chromeos/fileapi/file_access_permissions.cc',
+      '../browser/chromeos/fileapi/file_access_permissions.h',
+      '../browser/chromeos/fileapi/file_util_async.h',
+      '../browser/chromeos/fileapi/remote_file_system_operation.cc',
+      '../browser/chromeos/fileapi/remote_file_system_operation.h',
+      '../browser/chromeos/fileapi/remote_file_stream_writer.cc',
+      '../browser/chromeos/fileapi/remote_file_stream_writer.h',
+    ],
   },
   'targets': [
     {
-- 
cgit v1.1