Introduce FileSystemFileUtil and -Proxy to decorate base::file_util in webkit/fileapi.

BUG=74841
TEST=none

Review URL: http://codereview.chromium.org/6604020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76875 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h
index f37c428..0da1d99e 100644
--- a/webkit/fileapi/file_system_context.h
+++ b/webkit/fileapi/file_system_context.h
@@ -22,9 +22,9 @@
 
 namespace fileapi {
 
+class FileSystemContext;
 class FileSystemPathManager;
 class FileSystemUsageTracker;
-class FileSystemContext;
 
 struct DefaultContextDeleter;
 
diff --git a/webkit/fileapi/file_system_file_util.cc b/webkit/fileapi/file_system_file_util.cc
new file mode 100644
index 0000000..52f2c70f
--- /dev/null
+++ b/webkit/fileapi/file_system_file_util.cc
@@ -0,0 +1,253 @@
+// 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/fileapi/file_system_file_util.h"
+
+#include "base/file_util_proxy.h"
+
+// This also removes the destination directory if it's non-empty and all other
+// checks are passed (so that the copy/move correctly overwrites the
+// destination).
+// TODO(ericu, dmikurube): This method won't work with obfuscation and quota
+// since all (file_util::) operations should consider obfuscation and quota.
+// We will need to virtualize all these calls.  We should do that by making this
+// method a non-virtual member of FileSystemFileUtil, but changing all of its
+// file_util calls to be FileSystemFileUtil calls.  That way when we override
+// them for obfuscation or quota, it'll just work.
+static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy(
+    const FilePath& src_file_path,
+    const FilePath& dest_file_path) {
+  // Exits earlier if the source path does not exist.
+  if (!file_util::PathExists(src_file_path))
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+
+  // The parent of the |dest_file_path| does not exist.
+  if (!file_util::DirectoryExists(dest_file_path.DirName()))
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+
+  // It is an error to try to copy/move an entry into its child.
+  if (src_file_path.IsParent(dest_file_path))
+    return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+
+  // Now it is ok to return if the |dest_file_path| does not exist.
+  if (!file_util::PathExists(dest_file_path))
+    return base::PLATFORM_FILE_OK;
+
+  // |src_file_path| exists and is a directory.
+  // |dest_file_path| exists and is a file.
+  bool src_is_directory = file_util::DirectoryExists(src_file_path);
+  bool dest_is_directory = file_util::DirectoryExists(dest_file_path);
+  if (src_is_directory && !dest_is_directory)
+    return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+
+  // |src_file_path| exists and is a file.
+  // |dest_file_path| exists and is a directory.
+  if (!src_is_directory && dest_is_directory)
+    return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
+
+  // It is an error to copy/move an entry into the same path.
+  if (src_file_path.value() == dest_file_path.value())
+    return base::PLATFORM_FILE_ERROR_EXISTS;
+
+  if (dest_is_directory) {
+    // It is an error to copy/move an entry to a non-empty directory.
+    // Otherwise the copy/move attempt must overwrite the destination, but
+    // the file_util's Copy or Move method doesn't perform overwrite
+    // on all platforms, so we delete the destination directory here.
+    // TODO(kinuko): may be better to change the file_util::{Copy,Move}.
+    if (!file_util::Delete(dest_file_path, false /* recursive */)) {
+      if (!file_util::IsDirectoryEmpty(dest_file_path))
+        return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
+      return base::PLATFORM_FILE_ERROR_FAILED;
+    }
+  }
+  return base::PLATFORM_FILE_OK;
+}
+
+namespace fileapi {
+
+FileSystemFileUtil* FileSystemFileUtil::GetInstance() {
+  return Singleton<FileSystemFileUtil>::get();
+}
+
+PlatformFileError FileSystemFileUtil::CreateOrOpen(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path, int file_flags,
+    PlatformFile* file_handle, bool* created) {
+  if (!file_util::DirectoryExists(file_path.DirName())) {
+    // If its parent does not exist, should return NOT_FOUND error.
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  }
+  PlatformFileError error_code = base::PLATFORM_FILE_OK;
+  *file_handle = base::CreatePlatformFile(file_path, file_flags,
+                                          created, &error_code);
+  return error_code;
+}
+
+PlatformFileError FileSystemFileUtil::Close(
+    FileSystemOperationContext* unused,
+    PlatformFile file_handle) {
+  if (!base::ClosePlatformFile(file_handle))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::EnsureFileExists(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    bool* created) {
+  if (!file_util::DirectoryExists(file_path.DirName()))
+    // If its parent does not exist, should return NOT_FOUND error.
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  PlatformFileError error_code = base::PLATFORM_FILE_OK;
+  // Tries to create the |file_path| exclusively.  This should fail
+  // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists.
+  PlatformFile handle = base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
+      created, &error_code);
+  if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) {
+    // Make sure created_ is false.
+    *created = false;
+    error_code = base::PLATFORM_FILE_OK;
+  }
+  if (handle != base::kInvalidPlatformFileValue)
+    base::ClosePlatformFile(handle);
+  return error_code;
+}
+
+PlatformFileError FileSystemFileUtil::GetFileInfo(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    base::PlatformFileInfo* file_info) {
+  if (!file_util::PathExists(file_path))
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  if (!file_util::GetFileInfo(file_path, file_info))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::ReadDirectory(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    std::vector<base::FileUtilProxy::Entry>* entries) {
+  // TODO(kkanetkar): Implement directory read in multiple chunks.
+  if (!file_util::DirectoryExists(file_path))
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+
+  file_util::FileEnumerator file_enum(
+      file_path, false, static_cast<file_util::FileEnumerator::FILE_TYPE>(
+      file_util::FileEnumerator::FILES |
+      file_util::FileEnumerator::DIRECTORIES));
+  FilePath current;
+  while (!(current = file_enum.Next()).empty()) {
+    base::FileUtilProxy::Entry entry;
+    file_util::FileEnumerator::FindInfo info;
+    file_enum.GetFindInfo(&info);
+    entry.is_directory = file_enum.IsDirectory(info);
+    // This will just give the entry's name instead of entire path
+    // if we use current.value().
+    entry.name = file_util::FileEnumerator::GetFilename(info).value();
+    entries->push_back(entry);
+  }
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::CreateDirectory(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    bool exclusive) {
+  bool path_exists = file_util::PathExists(file_path);
+  if (!file_util::PathExists(file_path.DirName()))
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  // If parent dir of file doesn't exist.
+  if (exclusive && path_exists)
+    return base::PLATFORM_FILE_ERROR_EXISTS;
+  // If file exists at the path.
+  if (path_exists && !file_util::DirectoryExists(file_path))
+    return base::PLATFORM_FILE_ERROR_EXISTS;
+  if (!file_util::CreateDirectory(file_path))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::Copy(
+    FileSystemOperationContext* unused,
+    const FilePath& src_file_path,
+    const FilePath& dest_file_path) {
+  PlatformFileError error_code;
+  error_code =
+      PerformCommonCheckAndPreparationForMoveAndCopy(
+          src_file_path, dest_file_path);
+  if (error_code != base::PLATFORM_FILE_OK)
+    return error_code;
+  if (!file_util::CopyDirectory(src_file_path, dest_file_path,
+      true /* recursive */))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::Move(
+    FileSystemOperationContext* unused,
+    const FilePath& src_file_path,
+    const FilePath& dest_file_path) {
+  PlatformFileError error_code;
+  error_code =
+      PerformCommonCheckAndPreparationForMoveAndCopy(
+          src_file_path, dest_file_path);
+  if (error_code != base::PLATFORM_FILE_OK)
+    return error_code;
+  if (!file_util::Move(src_file_path, dest_file_path))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::Delete(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    bool recursive) {
+  if (!file_util::PathExists(file_path)) {
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  }
+  if (!file_util::Delete(file_path, recursive)) {
+    if (!recursive && !file_util::IsDirectoryEmpty(file_path)) {
+      return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
+    }
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  }
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::Touch(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    const base::Time& last_access_time,
+    const base::Time& last_modified_time) {
+  if (!file_util::TouchFile(
+          file_path, last_access_time, last_modified_time))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError FileSystemFileUtil::Truncate(
+    FileSystemOperationContext* unused,
+    const FilePath& file_path,
+    int64 length) {
+  PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
+  PlatformFile file =
+      base::CreatePlatformFile(
+          file_path,
+          base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
+          NULL,
+          &error_code);
+  if (error_code != base::PLATFORM_FILE_OK) {
+    return error_code;
+  }
+  if (!base::TruncatePlatformFile(file, length))
+    error_code = base::PLATFORM_FILE_ERROR_FAILED;
+  base::ClosePlatformFile(file);
+  return error_code;
+}
+
+}  // namespace fileapi
diff --git a/webkit/fileapi/file_system_file_util.h b/webkit/fileapi/file_system_file_util.h
new file mode 100644
index 0000000..433c0bc
--- /dev/null
+++ b/webkit/fileapi/file_system_file_util.h
@@ -0,0 +1,135 @@
+// 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_FILEAPI_FILE_SYSTEM_FILE_UTIL_H_
+#define WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_H_
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "base/ref_counted.h"
+#include "base/singleton.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+struct PlatformFileInfo;
+class MessageLoopProxy;
+class Time;
+}
+
+namespace fileapi {
+
+using base::PlatformFile;
+using base::PlatformFileError;
+
+class FileSystemOperationContext;
+
+// A large part of this implementation is taken from base::FileUtilProxy.
+// TODO(dmikurube, kinuko): Clean up base::FileUtilProxy to factor out common
+// routines. It includes dropping FileAPI-specific routines from FileUtilProxy.
+class FileSystemFileUtil {
+ public:
+  static FileSystemFileUtil* GetInstance();
+
+  // Creates or opens a file with the given flags.  It is invalid to pass NULL
+  // for the callback.
+  // If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to create
+  // a new file at the given |file_path| and calls back with
+  // PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists.
+  virtual PlatformFileError CreateOrOpen(
+      FileSystemOperationContext* context,
+      const FilePath& file_path,
+      int file_flags,
+      PlatformFile* file_handle,
+      bool* created);
+
+  // Close the given file handle.
+  virtual PlatformFileError Close(
+      FileSystemOperationContext* context,
+      PlatformFile);
+
+  // Ensures that the given |file_path| exist.  This creates a empty new file
+  // at |file_path| if the |file_path| does not exist.
+  // If a new file han not existed and is created at the |file_path|,
+  // |created| of the callback argument is set true and |error code|
+  // is set PLATFORM_FILE_OK.
+  // If the file already exists, |created| is set false and |error code|
+  // is set PLATFORM_FILE_OK.
+  // If the file hasn't existed but it couldn't be created for some other
+  // reasons, |created| is set false and |error code| indicates the error.
+  virtual PlatformFileError EnsureFileExists(
+      FileSystemOperationContext* context,
+      const FilePath& file_path, bool* created);
+
+  // Retrieves the information about a file. It is invalid to pass NULL for the
+  // callback.
+  virtual PlatformFileError GetFileInfo(
+      FileSystemOperationContext* context,
+      const FilePath& file_, base::PlatformFileInfo* file_info);
+
+  virtual PlatformFileError ReadDirectory(
+      FileSystemOperationContext* context,
+      const FilePath& file_path,
+      std::vector<base::FileUtilProxy::Entry>* entries);
+
+  // Creates directory at given path. It's an error to create
+  // if |exclusive| is true and dir already exists.
+  virtual PlatformFileError CreateDirectory(
+      FileSystemOperationContext* context,
+      const FilePath& file_path,
+      bool exclusive);
+
+  // Copies a file or a directory from |src_file_path| to |dest_file_path|
+  // Error cases:
+  // If destination file doesn't exist or destination's parent
+  // doesn't exists.
+  // If source dir exists but destination path is an existing file.
+  // If source file exists but destination path is an existing directory.
+  // If source is a parent of destination.
+  // If source doesn't exists.
+  virtual PlatformFileError Copy(
+      FileSystemOperationContext* context,
+      const FilePath& src_file_path,
+      const FilePath& dest_file_path);
+
+  // Moves a file or a directory from src_file_path to dest_file_path.
+  // Error cases are similar to Copy method's error cases.
+  virtual PlatformFileError Move(
+      FileSystemOperationContext* context,
+      const FilePath& src_file_path,
+      const FilePath& dest_file_path);
+
+  // Deletes a file or a directory.
+  // It is an error to delete a non-empty directory with recursive=false.
+  virtual PlatformFileError Delete(
+      FileSystemOperationContext* context,
+      const FilePath& file_path,
+      bool recursive);
+
+  // Touches a file. The callback can be NULL.
+  virtual PlatformFileError Touch(
+      FileSystemOperationContext* context,
+      const FilePath& file_path,
+      const base::Time& last_access_time,
+      const base::Time& last_modified_time);
+
+  // Truncates a file to the given length. If |length| is greater than the
+  // current length of the file, the file will be extended with zeroes.
+  // The callback can be NULL.
+  virtual PlatformFileError Truncate(
+      FileSystemOperationContext* context,
+      const FilePath& path,
+      int64 length);
+
+ protected:
+  FileSystemFileUtil() { }
+  friend struct DefaultSingletonTraits<FileSystemFileUtil>;
+  DISALLOW_COPY_AND_ASSIGN(FileSystemFileUtil);
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_H_
diff --git a/webkit/fileapi/file_system_file_util_proxy.cc b/webkit/fileapi/file_system_file_util_proxy.cc
new file mode 100644
index 0000000..3b14e16
--- /dev/null
+++ b/webkit/fileapi/file_system_file_util_proxy.cc
@@ -0,0 +1,527 @@
+// Copyright (c) 2010 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/fileapi/file_system_file_util_proxy.h"
+
+#include "base/message_loop_proxy.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_file_util.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+
+namespace {
+
+class MessageLoopRelay
+    : public base::RefCountedThreadSafe<MessageLoopRelay> {
+ public:
+  // FileSystemOperationContext is passed by value from the IO thread to the
+  // File thread.
+  explicit MessageLoopRelay(const fileapi::FileSystemOperationContext& context)
+      : origin_message_loop_proxy_(
+            base::MessageLoopProxy::CreateForCurrentThread()),
+        error_code_(base::PLATFORM_FILE_OK),
+        context_(context) {
+  }
+
+  bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+             const tracked_objects::Location& from_here) {
+    return message_loop_proxy->PostTask(
+        from_here,
+        NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread));
+  }
+
+ protected:
+  friend class base::RefCountedThreadSafe<MessageLoopRelay>;
+  virtual ~MessageLoopRelay() {}
+
+  // Called to perform work on the FILE thread.
+  virtual void RunWork() = 0;
+
+  // Called to notify the callback on the origin thread.
+  virtual void RunCallback() = 0;
+
+  void set_error_code(base::PlatformFileError error_code) {
+    error_code_ = error_code;
+  }
+
+  base::PlatformFileError error_code() const {
+    return error_code_;
+  }
+
+  fileapi::FileSystemOperationContext* context() {
+    return &context_;
+  }
+
+  fileapi::FileSystemFileUtil* file_system_file_util() const {
+    return context_.file_system_file_util();
+  }
+
+ private:
+  void ProcessOnTargetThread() {
+    RunWork();
+    origin_message_loop_proxy_->PostTask(
+        FROM_HERE,
+        NewRunnableMethod(this, &MessageLoopRelay::RunCallback));
+  }
+
+  scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
+  base::PlatformFileError error_code_;
+  fileapi::FileSystemOperationContext context_;
+  fileapi::FileSystemFileUtil* file_system_file_util_;
+};
+
+class RelayCreateOrOpen : public MessageLoopRelay {
+ public:
+  RelayCreateOrOpen(
+      const fileapi::FileSystemOperationContext& context,
+      scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+      const FilePath& file_path,
+      int file_flags,
+      fileapi::FileSystemFileUtilProxy::CreateOrOpenCallback* callback)
+      : MessageLoopRelay(context),
+        message_loop_proxy_(message_loop_proxy),
+        file_path_(file_path),
+        file_flags_(file_flags),
+        callback_(callback),
+        file_handle_(base::kInvalidPlatformFileValue),
+        created_(false) {
+    DCHECK(callback);
+  }
+
+ protected:
+  virtual ~RelayCreateOrOpen() {
+    if (file_handle_ != base::kInvalidPlatformFileValue)
+      fileapi::FileSystemFileUtilProxy::Close(*context(),
+          message_loop_proxy_, file_handle_, NULL);
+  }
+
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->CreateOrOpen(
+            context(), file_path_, file_flags_, &file_handle_, &created_));
+  }
+
+  virtual void RunCallback() {
+    callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
+                   created_);
+    delete callback_;
+  }
+
+ private:
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  FilePath file_path_;
+  int file_flags_;
+  fileapi::FileSystemFileUtilProxy::CreateOrOpenCallback* callback_;
+  base::PlatformFile file_handle_;
+  bool created_;
+};
+
+class RelayWithStatusCallback : public MessageLoopRelay {
+ public:
+  RelayWithStatusCallback(
+      const fileapi::FileSystemOperationContext& context,
+      fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : MessageLoopRelay(context),
+        callback_(callback) {
+    // It is OK for callback to be NULL.
+  }
+
+ protected:
+  virtual void RunCallback() {
+    // The caller may not have been interested in the result.
+    if (callback_) {
+      callback_->Run(error_code());
+      delete callback_;
+    }
+  }
+
+ private:
+  fileapi::FileSystemFileUtilProxy::StatusCallback* callback_;
+};
+
+class RelayClose : public RelayWithStatusCallback {
+ public:
+  RelayClose(const fileapi::FileSystemOperationContext& context,
+             base::PlatformFile file_handle,
+             fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        file_handle_(file_handle) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->Close(context(), file_handle_));
+  }
+
+ private:
+  base::PlatformFile file_handle_;
+};
+
+class RelayEnsureFileExists : public MessageLoopRelay {
+ public:
+  RelayEnsureFileExists(
+      const fileapi::FileSystemOperationContext& context,
+      scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+      const FilePath& file_path,
+      fileapi::FileSystemFileUtilProxy::EnsureFileExistsCallback* callback)
+      : MessageLoopRelay(context),
+        message_loop_proxy_(message_loop_proxy),
+        file_path_(file_path),
+        callback_(callback),
+        created_(false) {
+    DCHECK(callback);
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->EnsureFileExists(
+            context(), file_path_, &created_));
+  }
+
+  virtual void RunCallback() {
+    callback_->Run(error_code(), created_);
+    delete callback_;
+  }
+
+ private:
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  FilePath file_path_;
+  fileapi::FileSystemFileUtilProxy::EnsureFileExistsCallback* callback_;
+  bool created_;
+};
+
+class RelayGetFileInfo : public MessageLoopRelay {
+ public:
+  RelayGetFileInfo(
+      const fileapi::FileSystemOperationContext& context,
+      const FilePath& file_path,
+      fileapi::FileSystemFileUtilProxy::GetFileInfoCallback* callback)
+      : MessageLoopRelay(context),
+        callback_(callback),
+        file_path_(file_path) {
+    DCHECK(callback);
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->GetFileInfo(
+            context(), file_path_, &file_info_));
+  }
+
+  virtual void RunCallback() {
+    callback_->Run(error_code(), file_info_);
+    delete callback_;
+  }
+
+ private:
+  fileapi::FileSystemFileUtilProxy::GetFileInfoCallback* callback_;
+  FilePath file_path_;
+  base::PlatformFileInfo file_info_;
+};
+
+class RelayReadDirectory : public MessageLoopRelay {
+ public:
+  RelayReadDirectory(
+      const fileapi::FileSystemOperationContext& context,
+      const FilePath& file_path,
+      fileapi::FileSystemFileUtilProxy::ReadDirectoryCallback* callback)
+      : MessageLoopRelay(context),
+        callback_(callback), file_path_(file_path) {
+    DCHECK(callback);
+  }
+
+ protected:
+  virtual void RunWork() {
+    // TODO(kkanetkar): Implement directory read in multiple chunks.
+    set_error_code(
+        file_system_file_util()->ReadDirectory(
+            context(), file_path_, &entries_));
+  }
+
+  virtual void RunCallback() {
+    callback_->Run(error_code(), entries_);
+    delete callback_;
+  }
+
+ private:
+  fileapi::FileSystemFileUtilProxy::ReadDirectoryCallback* callback_;
+  FilePath file_path_;
+  std::vector<base::FileUtilProxy::Entry> entries_;
+};
+
+class RelayCreateDirectory : public RelayWithStatusCallback {
+ public:
+  RelayCreateDirectory(
+      const fileapi::FileSystemOperationContext& context,
+      const FilePath& file_path,
+      bool exclusive,
+      fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        file_path_(file_path),
+        exclusive_(exclusive) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->CreateDirectory(
+            context(), file_path_, exclusive_));
+  }
+
+ private:
+  FilePath file_path_;
+  bool exclusive_;
+};
+
+class RelayCopy : public RelayWithStatusCallback {
+ public:
+  RelayCopy(const fileapi::FileSystemOperationContext& context,
+            const FilePath& src_file_path,
+            const FilePath& dest_file_path,
+            fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        src_file_path_(src_file_path),
+        dest_file_path_(dest_file_path) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->Copy(
+            context(), src_file_path_, dest_file_path_));
+  }
+
+ private:
+  FilePath src_file_path_;
+  FilePath dest_file_path_;
+};
+
+class RelayMove : public RelayWithStatusCallback {
+ public:
+  RelayMove(const fileapi::FileSystemOperationContext& context,
+            const FilePath& src_file_path,
+            const FilePath& dest_file_path,
+            fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        src_file_path_(src_file_path),
+        dest_file_path_(dest_file_path) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->Move(
+            context(), src_file_path_, dest_file_path_));
+  }
+
+ private:
+  FilePath src_file_path_;
+  FilePath dest_file_path_;
+};
+
+class RelayDelete : public RelayWithStatusCallback {
+ public:
+  RelayDelete(const fileapi::FileSystemOperationContext& context,
+              const FilePath& file_path,
+              bool recursive,
+              fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        file_path_(file_path),
+        recursive_(recursive) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->Delete(
+            context(), file_path_, recursive_));
+  }
+
+ private:
+  FilePath file_path_;
+  bool recursive_;
+};
+
+class RelayTouchFilePath : public RelayWithStatusCallback {
+ public:
+  RelayTouchFilePath(const fileapi::FileSystemOperationContext& context,
+                     const FilePath& file_path,
+                     const base::Time& last_access_time,
+                     const base::Time& last_modified_time,
+                     fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        file_path_(file_path),
+        last_access_time_(last_access_time),
+        last_modified_time_(last_modified_time) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->Touch(
+            context(), file_path_, last_access_time_, last_modified_time_));
+  }
+
+ private:
+  FilePath file_path_;
+  base::Time last_access_time_;
+  base::Time last_modified_time_;
+};
+
+class RelayTruncate : public RelayWithStatusCallback {
+ public:
+  RelayTruncate(const fileapi::FileSystemOperationContext& context,
+                const FilePath& file_path,
+                int64 length,
+                fileapi::FileSystemFileUtilProxy::StatusCallback* callback)
+      : RelayWithStatusCallback(context, callback),
+        file_path_(file_path),
+        length_(length) {
+  }
+
+ protected:
+  virtual void RunWork() {
+    set_error_code(
+        file_system_file_util()->Truncate(context(), file_path_, length_));
+  }
+
+ private:
+  FilePath file_path_;
+  int64 length_;
+};
+
+bool Start(const tracked_objects::Location& from_here,
+           scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+           scoped_refptr<MessageLoopRelay> relay) {
+  return relay->Start(message_loop_proxy, from_here);
+}
+
+}  // namespace
+
+namespace fileapi {
+
+// static
+bool FileSystemFileUtilProxy::CreateOrOpen(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path, int file_flags,
+    CreateOrOpenCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(context,
+      message_loop_proxy, file_path, file_flags, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::Close(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    base::PlatformFile file_handle,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy,
+               new RelayClose(context, file_handle, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::EnsureFileExists(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path,
+    EnsureFileExistsCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists(
+      context, message_loop_proxy, file_path, callback));
+}
+
+// Retrieves the information about a file. It is invalid to pass NULL for the
+// callback.
+bool FileSystemFileUtilProxy::GetFileInfo(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path,
+    GetFileInfoCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(context,
+               file_path, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::ReadDirectory(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path,
+    ReadDirectoryCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(context,
+               file_path, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::CreateDirectory(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path,
+    bool exclusive,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
+      context, file_path, exclusive, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::Copy(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& src_file_path,
+    const FilePath& dest_file_path,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy,
+               new RelayCopy(context, src_file_path, dest_file_path,
+                   callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::Move(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& src_file_path,
+    const FilePath& dest_file_path,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy,
+               new RelayMove(context, src_file_path, dest_file_path,
+                   callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::Delete(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path,
+    bool recursive,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy,
+               new RelayDelete(context, file_path, recursive, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::Touch(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& file_path,
+    const base::Time& last_access_time,
+    const base::Time& last_modified_time,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy,
+               new RelayTouchFilePath(context, file_path, last_access_time,
+                                      last_modified_time, callback));
+}
+
+// static
+bool FileSystemFileUtilProxy::Truncate(
+    const FileSystemOperationContext& context,
+    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    const FilePath& path,
+    int64 length,
+    StatusCallback* callback) {
+  return Start(FROM_HERE, message_loop_proxy,
+               new RelayTruncate(context, path, length, callback));
+}
+
+}  // namespace fileapi
diff --git a/webkit/fileapi/file_system_file_util_proxy.h b/webkit/fileapi/file_system_file_util_proxy.h
new file mode 100644
index 0000000..0f10507
--- /dev/null
+++ b/webkit/fileapi/file_system_file_util_proxy.h
@@ -0,0 +1,150 @@
+// 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_FILEAPI_FILE_SYSTEM_FILE_UTIL_PROXY_H_
+#define WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_PROXY_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "base/ref_counted.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+class MessageLoopProxy;
+class Time;
+}
+
+namespace fileapi {
+
+class FileSystemOperationContext;
+
+using base::MessageLoopProxy;
+using base::PlatformFile;
+
+// This class provides asynchronous access to common file routines for the
+// FileSystem API.
+class FileSystemFileUtilProxy {
+ public:
+  typedef base::FileUtilProxy::StatusCallback StatusCallback;
+  typedef base::FileUtilProxy::CreateOrOpenCallback CreateOrOpenCallback;
+  typedef base::FileUtilProxy::EnsureFileExistsCallback
+    EnsureFileExistsCallback;
+  typedef base::FileUtilProxy::GetFileInfoCallback GetFileInfoCallback;
+  typedef base::FileUtilProxy::ReadDirectoryCallback ReadDirectoryCallback;
+
+  // Creates or opens a file with the given flags.  It is invalid to pass NULL
+  // for the callback.
+  // If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to create
+  // a new file at the given |file_path| and calls back with
+  // PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists.
+  static bool CreateOrOpen(const FileSystemOperationContext& context,
+                           scoped_refptr<MessageLoopProxy> message_loop_proxy,
+                           const FilePath& file_path,
+                           int file_flags,
+                           CreateOrOpenCallback* callback);
+
+  // Close the given file handle.
+  static bool Close(const FileSystemOperationContext& context,
+                    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+                    PlatformFile,
+                    StatusCallback* callback);
+
+  // Ensures that the given |file_path| exist.  This creates a empty new file
+  // at |file_path| if the |file_path| does not exist.
+  // If a new file han not existed and is created at the |file_path|,
+  // |created| of the callback argument is set true and |error code|
+  // is set PLATFORM_FILE_OK.
+  // If the file already exists, |created| is set false and |error code|
+  // is set PLATFORM_FILE_OK.
+  // If the file hasn't existed but it couldn't be created for some other
+  // reasons, |created| is set false and |error code| indicates the error.
+  static bool EnsureFileExists(
+      const FileSystemOperationContext& context,
+      scoped_refptr<MessageLoopProxy> message_loop_proxy,
+      const FilePath& file_path,
+      EnsureFileExistsCallback* callback);
+
+  // Retrieves the information about a file. It is invalid to pass NULL for the
+  // callback.
+  static bool GetFileInfo(
+      const FileSystemOperationContext& context,
+      scoped_refptr<MessageLoopProxy> message_loop_proxy,
+      const FilePath& file_path,
+      GetFileInfoCallback* callback);
+
+  static bool ReadDirectory(const FileSystemOperationContext& context,
+                            scoped_refptr<MessageLoopProxy> message_loop_proxy,
+                            const FilePath& file_path,
+                            ReadDirectoryCallback* callback);
+
+  // Creates directory at given path. It's an error to create
+  // if |exclusive| is true and dir already exists.
+  static bool CreateDirectory(
+      const FileSystemOperationContext& context,
+      scoped_refptr<MessageLoopProxy> message_loop_proxy,
+      const FilePath& file_path,
+      bool exclusive,
+      StatusCallback* callback);
+
+  // Copies a file or a directory from |src_file_path| to |dest_file_path|
+  // Error cases:
+  // If destination file doesn't exist or destination's parent
+  // doesn't exists.
+  // If source dir exists but destination path is an existing file.
+  // If source file exists but destination path is an existing directory.
+  // If source is a parent of destination.
+  // If source doesn't exists.
+  static bool Copy(const FileSystemOperationContext& context,
+                   scoped_refptr<MessageLoopProxy> message_loop_proxy,
+                   const FilePath& src_file_path,
+                   const FilePath& dest_file_path,
+                   StatusCallback* callback);
+
+  // Moves a file or a directory from src_file_path to dest_file_path.
+  // Error cases are similar to Copy method's error cases.
+  static bool Move(
+      const FileSystemOperationContext& context,
+      scoped_refptr<MessageLoopProxy> message_loop_proxy,
+      const FilePath& src_file_path,
+      const FilePath& dest_file_path,
+      StatusCallback* callback);
+
+  // Deletes a file or a directory.
+  // It is an error to delete a non-empty directory with recursive=false.
+  static bool Delete(const FileSystemOperationContext& context,
+                     scoped_refptr<MessageLoopProxy> message_loop_proxy,
+                     const FilePath& file_path,
+                     bool recursive,
+                     StatusCallback* callback);
+
+  // Touches a file. The callback can be NULL.
+  static bool Touch(
+      const FileSystemOperationContext& context,
+      scoped_refptr<MessageLoopProxy> message_loop_proxy,
+      const FilePath& file_path,
+      const base::Time& last_access_time,
+      const base::Time& last_modified_time,
+      StatusCallback* callback);
+
+  // Truncates a file to the given length. If |length| is greater than the
+  // current length of the file, the file will be extended with zeroes.
+  // The callback can be NULL.
+  static bool Truncate(
+      const FileSystemOperationContext& context,
+      scoped_refptr<MessageLoopProxy> message_loop_proxy,
+      const FilePath& path,
+      int64 length,
+      StatusCallback* callback);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemFileUtilProxy);
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_PROXY_H_
diff --git a/webkit/fileapi/file_system_operation.cc b/webkit/fileapi/file_system_operation.cc
index d3d4908..ec3ea7ed 100644
--- a/webkit/fileapi/file_system_operation.cc
+++ b/webkit/fileapi/file_system_operation.cc
@@ -8,6 +8,8 @@
 #include "net/url_request/url_request_context.h"
 #include "webkit/fileapi/file_system_callback_dispatcher.h"
 #include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_file_util_proxy.h"
+#include "webkit/fileapi/file_system_operation_context.h"
 #include "webkit/fileapi/file_system_path_manager.h"
 #include "webkit/fileapi/file_writer_delegate.h"
 
@@ -20,6 +22,7 @@
     : proxy_(proxy),
       dispatcher_(dispatcher),
       file_system_context_(file_system_context),
+      file_system_operation_context_(FileSystemFileUtil::GetInstance()),
       callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
   DCHECK(dispatcher);
 #ifndef NDEBUG
@@ -29,7 +32,9 @@
 
 FileSystemOperation::~FileSystemOperation() {
   if (file_writer_delegate_.get())
-    base::FileUtilProxy::Close(proxy_, file_writer_delegate_->file(), NULL);
+    FileSystemFileUtilProxy::Close(
+        file_system_operation_context_,
+        proxy_, file_writer_delegate_->file(), NULL);
 }
 
 void FileSystemOperation::OpenFileSystem(
@@ -57,26 +62,29 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::EnsureFileExists(
-    proxy_, path, callback_factory_.NewCallback(
-        exclusive ? &FileSystemOperation::DidEnsureFileExistsExclusive
-                  : &FileSystemOperation::DidEnsureFileExistsNonExclusive));
+  FileSystemFileUtilProxy::EnsureFileExists(
+      file_system_operation_context_,
+      proxy_, path, callback_factory_.NewCallback(
+          exclusive ? &FileSystemOperation::DidEnsureFileExistsExclusive
+                    : &FileSystemOperation::DidEnsureFileExistsNonExclusive));
 }
 
 void FileSystemOperation::CreateDirectory(const FilePath& path,
                                           bool exclusive,
-                                          bool recursive) {
+                                          bool unused) {
 #ifndef NDEBUG
   DCHECK(kOperationNone == pending_operation_);
   pending_operation_ = kOperationCreateDirectory;
 #endif
+  DCHECK(!unused);
 
   if (!VerifyFileSystemPathForWrite(path, true /* create */)) {
     delete this;
     return;
   }
-  base::FileUtilProxy::CreateDirectory(
-      proxy_, path, exclusive, recursive, callback_factory_.NewCallback(
+  FileSystemFileUtilProxy::CreateDirectory(
+      file_system_operation_context_,
+      proxy_, path, exclusive, callback_factory_.NewCallback(
           &FileSystemOperation::DidFinishFileOperation));
 }
 
@@ -92,8 +100,9 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::Copy(proxy_, src_path, dest_path,
-      callback_factory_.NewCallback(
+  FileSystemFileUtilProxy::Copy(
+      file_system_operation_context_,
+      proxy_, src_path, dest_path, callback_factory_.NewCallback(
           &FileSystemOperation::DidFinishFileOperation));
 }
 
@@ -109,8 +118,9 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::Move(proxy_, src_path, dest_path,
-      callback_factory_.NewCallback(
+  FileSystemFileUtilProxy::Move(
+      file_system_operation_context_,
+      proxy_, src_path, dest_path, callback_factory_.NewCallback(
           &FileSystemOperation::DidFinishFileOperation));
 }
 
@@ -124,8 +134,10 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback(
-      &FileSystemOperation::DidDirectoryExists));
+  FileSystemFileUtilProxy::GetFileInfo(
+      file_system_operation_context_,
+      proxy_, path, callback_factory_.NewCallback(
+          &FileSystemOperation::DidDirectoryExists));
 }
 
 void FileSystemOperation::FileExists(const FilePath& path) {
@@ -138,8 +150,10 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback(
-      &FileSystemOperation::DidFileExists));
+  FileSystemFileUtilProxy::GetFileInfo(
+      file_system_operation_context_,
+      proxy_, path, callback_factory_.NewCallback(
+          &FileSystemOperation::DidFileExists));
 }
 
 void FileSystemOperation::GetMetadata(const FilePath& path) {
@@ -152,8 +166,10 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback(
-      &FileSystemOperation::DidGetMetadata));
+  FileSystemFileUtilProxy::GetFileInfo(
+      file_system_operation_context_,
+      proxy_, path, callback_factory_.NewCallback(
+          &FileSystemOperation::DidGetMetadata));
 }
 
 void FileSystemOperation::ReadDirectory(const FilePath& path) {
@@ -166,8 +182,9 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::ReadDirectory(proxy_, path,
-      callback_factory_.NewCallback(
+  FileSystemFileUtilProxy::ReadDirectory(
+      file_system_operation_context_,
+      proxy_, path, callback_factory_.NewCallback(
           &FileSystemOperation::DidReadDirectory));
 }
 
@@ -181,8 +198,9 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::Delete(proxy_, path, recursive,
-      callback_factory_.NewCallback(
+  FileSystemFileUtilProxy::Delete(
+      file_system_operation_context_,
+      proxy_, path, recursive, callback_factory_.NewCallback(
           &FileSystemOperation::DidFinishFileOperation));
 }
 
@@ -204,7 +222,8 @@
   blob_request_.reset(
       new net::URLRequest(blob_url, file_writer_delegate_.get()));
   blob_request_->set_context(url_request_context);
-  base::FileUtilProxy::CreateOrOpen(
+  FileSystemFileUtilProxy::CreateOrOpen(
+      file_system_operation_context_,
       proxy_,
       path,
       base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE |
@@ -222,8 +241,9 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::Truncate(proxy_, path, length,
-      callback_factory_.NewCallback(
+  FileSystemFileUtilProxy::Truncate(
+      file_system_operation_context_,
+      proxy_, path, length, callback_factory_.NewCallback(
           &FileSystemOperation::DidFinishFileOperation));
 }
 
@@ -239,7 +259,8 @@
     delete this;
     return;
   }
-  base::FileUtilProxy::Touch(
+  FileSystemFileUtilProxy::Touch(
+      file_system_operation_context_,
       proxy_, path, last_access_time, last_modified_time,
       callback_factory_.NewCallback(&FileSystemOperation::DidTouchFile));
 }
diff --git a/webkit/fileapi/file_system_operation.h b/webkit/fileapi/file_system_operation.h
index 4630fe7..9fa2db4 100644
--- a/webkit/fileapi/file_system_operation.h
+++ b/webkit/fileapi/file_system_operation.h
@@ -16,6 +16,7 @@
 #include "base/scoped_ptr.h"
 #include "googleurl/src/gurl.h"
 #include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_operation_context.h"
 
 namespace base {
 class Time;
@@ -55,7 +56,7 @@
                   bool exclusive);
   void CreateDirectory(const FilePath& path,
                        bool exclusive,
-                       bool recursive);
+                       bool unused);
   void Copy(const FilePath& src_path,
             const FilePath& dest_path);
   void Move(const FilePath& src_path,
@@ -170,6 +171,7 @@
   scoped_ptr<FileSystemCallbackDispatcher> dispatcher_;
 
   scoped_refptr<FileSystemContext> file_system_context_;
+  FileSystemOperationContext file_system_operation_context_;
 
   base::ScopedCallbackFactory<FileSystemOperation> callback_factory_;
 
diff --git a/webkit/fileapi/file_system_operation_context.h b/webkit/fileapi/file_system_operation_context.h
new file mode 100644
index 0000000..68f5e47
--- /dev/null
+++ b/webkit/fileapi/file_system_operation_context.h
@@ -0,0 +1,30 @@
+// 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_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
+#define WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
+
+#include "webkit/fileapi/file_system_file_util.h"
+
+namespace fileapi {
+
+class FileSystemOperationContext {
+ public:
+  FileSystemOperationContext(FileSystemFileUtil* file_system_file_util)
+      : file_system_file_util_(file_system_file_util) {
+  }
+
+  FileSystemFileUtil* file_system_file_util() const {
+    return file_system_file_util_;
+  }
+
+ private:
+  // This file_system_file_util_ is not "owned" by FileSystemOperationContext.
+  // It is supposed to be a pointer to a singleton.
+  FileSystemFileUtil* file_system_file_util_;
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi
index 564b1b7..f1191c6 100644
--- a/webkit/fileapi/webkit_fileapi.gypi
+++ b/webkit/fileapi/webkit_fileapi.gypi
@@ -19,6 +19,10 @@
         'file_system_context.h',
         'file_system_dir_url_request_job.cc',
         'file_system_dir_url_request_job.h',
+        'file_system_file_util.cc',
+        'file_system_file_util.h',
+        'file_system_file_util_proxy.cc',
+        'file_system_file_util_proxy.h',
         'file_system_operation.cc',
         'file_system_operation.h',
         'file_system_path_manager.cc',