Home | History | Annotate | Download | only in fileapi
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "webkit/browser/fileapi/file_system_operation_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/single_thread_task_runner.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/time/time.h"
     11 #include "net/base/escape.h"
     12 #include "net/url_request/url_request.h"
     13 #include "webkit/browser/fileapi/async_file_util.h"
     14 #include "webkit/browser/fileapi/copy_or_move_operation_delegate.h"
     15 #include "webkit/browser/fileapi/file_observers.h"
     16 #include "webkit/browser/fileapi/file_system_backend.h"
     17 #include "webkit/browser/fileapi/file_system_context.h"
     18 #include "webkit/browser/fileapi/file_system_file_util.h"
     19 #include "webkit/browser/fileapi/file_system_operation_context.h"
     20 #include "webkit/browser/fileapi/file_system_url.h"
     21 #include "webkit/browser/fileapi/file_writer_delegate.h"
     22 #include "webkit/browser/fileapi/remove_operation_delegate.h"
     23 #include "webkit/browser/fileapi/sandbox_file_system_backend.h"
     24 #include "webkit/browser/quota/quota_manager_proxy.h"
     25 #include "webkit/common/blob/shareable_file_reference.h"
     26 #include "webkit/common/fileapi/file_system_types.h"
     27 #include "webkit/common/fileapi/file_system_util.h"
     28 #include "webkit/common/quota/quota_types.h"
     29 
     30 using webkit_blob::ScopedFile;
     31 
     32 namespace fileapi {
     33 
     34 FileSystemOperation* FileSystemOperation::Create(
     35     const FileSystemURL& url,
     36     FileSystemContext* file_system_context,
     37     scoped_ptr<FileSystemOperationContext> operation_context) {
     38   return new FileSystemOperationImpl(url, file_system_context,
     39                                      operation_context.Pass());
     40 }
     41 
     42 FileSystemOperationImpl::~FileSystemOperationImpl() {
     43 }
     44 
     45 void FileSystemOperationImpl::CreateFile(const FileSystemURL& url,
     46                                          bool exclusive,
     47                                          const StatusCallback& callback) {
     48   DCHECK(SetPendingOperationType(kOperationCreateFile));
     49   GetUsageAndQuotaThenRunTask(
     50       url,
     51       base::Bind(&FileSystemOperationImpl::DoCreateFile,
     52                  weak_factory_.GetWeakPtr(), url, callback, exclusive),
     53       base::Bind(callback, base::File::FILE_ERROR_FAILED));
     54 }
     55 
     56 void FileSystemOperationImpl::CreateDirectory(const FileSystemURL& url,
     57                                               bool exclusive,
     58                                               bool recursive,
     59                                               const StatusCallback& callback) {
     60   DCHECK(SetPendingOperationType(kOperationCreateDirectory));
     61   GetUsageAndQuotaThenRunTask(
     62       url,
     63       base::Bind(&FileSystemOperationImpl::DoCreateDirectory,
     64                  weak_factory_.GetWeakPtr(), url, callback,
     65                  exclusive, recursive),
     66       base::Bind(callback, base::File::FILE_ERROR_FAILED));
     67 }
     68 
     69 void FileSystemOperationImpl::Copy(
     70     const FileSystemURL& src_url,
     71     const FileSystemURL& dest_url,
     72     CopyOrMoveOption option,
     73     const CopyProgressCallback& progress_callback,
     74     const StatusCallback& callback) {
     75   DCHECK(SetPendingOperationType(kOperationCopy));
     76   DCHECK(!recursive_operation_delegate_);
     77 
     78   // TODO(hidehiko): Support |progress_callback|. (crbug.com/278038).
     79   recursive_operation_delegate_.reset(
     80       new CopyOrMoveOperationDelegate(
     81           file_system_context(),
     82           src_url, dest_url,
     83           CopyOrMoveOperationDelegate::OPERATION_COPY,
     84           option,
     85           progress_callback,
     86           base::Bind(&FileSystemOperationImpl::DidFinishOperation,
     87                      weak_factory_.GetWeakPtr(), callback)));
     88   recursive_operation_delegate_->RunRecursively();
     89 }
     90 
     91 void FileSystemOperationImpl::Move(const FileSystemURL& src_url,
     92                                    const FileSystemURL& dest_url,
     93                                    CopyOrMoveOption option,
     94                                    const StatusCallback& callback) {
     95   DCHECK(SetPendingOperationType(kOperationMove));
     96   DCHECK(!recursive_operation_delegate_);
     97   recursive_operation_delegate_.reset(
     98       new CopyOrMoveOperationDelegate(
     99           file_system_context(),
    100           src_url, dest_url,
    101           CopyOrMoveOperationDelegate::OPERATION_MOVE,
    102           option,
    103           FileSystemOperation::CopyProgressCallback(),
    104           base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    105                      weak_factory_.GetWeakPtr(), callback)));
    106   recursive_operation_delegate_->RunRecursively();
    107 }
    108 
    109 void FileSystemOperationImpl::DirectoryExists(const FileSystemURL& url,
    110                                               const StatusCallback& callback) {
    111   DCHECK(SetPendingOperationType(kOperationDirectoryExists));
    112   async_file_util_->GetFileInfo(
    113       operation_context_.Pass(), url,
    114       base::Bind(&FileSystemOperationImpl::DidDirectoryExists,
    115                  weak_factory_.GetWeakPtr(), callback));
    116 }
    117 
    118 void FileSystemOperationImpl::FileExists(const FileSystemURL& url,
    119                                          const StatusCallback& callback) {
    120   DCHECK(SetPendingOperationType(kOperationFileExists));
    121   async_file_util_->GetFileInfo(
    122       operation_context_.Pass(), url,
    123       base::Bind(&FileSystemOperationImpl::DidFileExists,
    124                  weak_factory_.GetWeakPtr(), callback));
    125 }
    126 
    127 void FileSystemOperationImpl::GetMetadata(
    128     const FileSystemURL& url, const GetMetadataCallback& callback) {
    129   DCHECK(SetPendingOperationType(kOperationGetMetadata));
    130   async_file_util_->GetFileInfo(operation_context_.Pass(), url, callback);
    131 }
    132 
    133 void FileSystemOperationImpl::ReadDirectory(
    134     const FileSystemURL& url, const ReadDirectoryCallback& callback) {
    135   DCHECK(SetPendingOperationType(kOperationReadDirectory));
    136   async_file_util_->ReadDirectory(
    137       operation_context_.Pass(), url, callback);
    138 }
    139 
    140 void FileSystemOperationImpl::Remove(const FileSystemURL& url,
    141                                      bool recursive,
    142                                      const StatusCallback& callback) {
    143   DCHECK(SetPendingOperationType(kOperationRemove));
    144   DCHECK(!recursive_operation_delegate_);
    145 
    146   if (recursive) {
    147     // For recursive removal, try to delegate the operation to AsyncFileUtil
    148     // first. If not supported, it is delegated to RemoveOperationDelegate
    149     // in DidDeleteRecursively.
    150     async_file_util_->DeleteRecursively(
    151         operation_context_.Pass(), url,
    152         base::Bind(&FileSystemOperationImpl::DidDeleteRecursively,
    153                    weak_factory_.GetWeakPtr(), url, callback));
    154     return;
    155   }
    156 
    157   recursive_operation_delegate_.reset(
    158       new RemoveOperationDelegate(
    159           file_system_context(), url,
    160           base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    161                      weak_factory_.GetWeakPtr(), callback)));
    162   recursive_operation_delegate_->Run();
    163 }
    164 
    165 void FileSystemOperationImpl::Write(
    166     const FileSystemURL& url,
    167     scoped_ptr<FileWriterDelegate> writer_delegate,
    168     scoped_ptr<net::URLRequest> blob_request,
    169     const WriteCallback& callback) {
    170   DCHECK(SetPendingOperationType(kOperationWrite));
    171   file_writer_delegate_ = writer_delegate.Pass();
    172   file_writer_delegate_->Start(
    173       blob_request.Pass(),
    174       base::Bind(&FileSystemOperationImpl::DidWrite,
    175                  weak_factory_.GetWeakPtr(), url, callback));
    176 }
    177 
    178 void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length,
    179                                        const StatusCallback& callback) {
    180   DCHECK(SetPendingOperationType(kOperationTruncate));
    181   GetUsageAndQuotaThenRunTask(
    182       url,
    183       base::Bind(&FileSystemOperationImpl::DoTruncate,
    184                  weak_factory_.GetWeakPtr(), url, callback, length),
    185       base::Bind(callback, base::File::FILE_ERROR_FAILED));
    186 }
    187 
    188 void FileSystemOperationImpl::TouchFile(const FileSystemURL& url,
    189                                         const base::Time& last_access_time,
    190                                         const base::Time& last_modified_time,
    191                                         const StatusCallback& callback) {
    192   DCHECK(SetPendingOperationType(kOperationTouchFile));
    193   async_file_util_->Touch(
    194       operation_context_.Pass(), url,
    195       last_access_time, last_modified_time,
    196       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    197                  weak_factory_.GetWeakPtr(), callback));
    198 }
    199 
    200 void FileSystemOperationImpl::OpenFile(const FileSystemURL& url,
    201                                        int file_flags,
    202                                        const OpenFileCallback& callback) {
    203   DCHECK(SetPendingOperationType(kOperationOpenFile));
    204 
    205   if (file_flags &
    206       (base::File::FLAG_TEMPORARY | base::File::FLAG_HIDDEN)) {
    207     callback.Run(base::File(base::File::FILE_ERROR_FAILED),
    208                  base::Closure());
    209     return;
    210   }
    211   GetUsageAndQuotaThenRunTask(
    212       url,
    213       base::Bind(&FileSystemOperationImpl::DoOpenFile,
    214                  weak_factory_.GetWeakPtr(),
    215                  url, callback, file_flags),
    216       base::Bind(callback, Passed(base::File(base::File::FILE_ERROR_FAILED)),
    217                  base::Closure()));
    218 }
    219 
    220 // We can only get here on a write or truncate that's not yet completed.
    221 // We don't support cancelling any other operation at this time.
    222 void FileSystemOperationImpl::Cancel(const StatusCallback& cancel_callback) {
    223   DCHECK(cancel_callback_.is_null());
    224   cancel_callback_ = cancel_callback;
    225 
    226   if (file_writer_delegate_.get()) {
    227     DCHECK_EQ(kOperationWrite, pending_operation_);
    228     // This will call DidWrite() with ABORT status code.
    229     file_writer_delegate_->Cancel();
    230   } else if (recursive_operation_delegate_) {
    231     // This will call DidFinishOperation() with ABORT status code.
    232     recursive_operation_delegate_->Cancel();
    233   } else {
    234     // For truncate we have no way to cancel the inflight operation (for now).
    235     // Let it just run and dispatch cancel callback later.
    236     DCHECK_EQ(kOperationTruncate, pending_operation_);
    237   }
    238 }
    239 
    240 void FileSystemOperationImpl::CreateSnapshotFile(
    241     const FileSystemURL& url,
    242     const SnapshotFileCallback& callback) {
    243   DCHECK(SetPendingOperationType(kOperationCreateSnapshotFile));
    244   async_file_util_->CreateSnapshotFile(
    245       operation_context_.Pass(), url, callback);
    246 }
    247 
    248 void FileSystemOperationImpl::CopyInForeignFile(
    249     const base::FilePath& src_local_disk_file_path,
    250     const FileSystemURL& dest_url,
    251     const StatusCallback& callback) {
    252   DCHECK(SetPendingOperationType(kOperationCopyInForeignFile));
    253   GetUsageAndQuotaThenRunTask(
    254       dest_url,
    255       base::Bind(&FileSystemOperationImpl::DoCopyInForeignFile,
    256                  weak_factory_.GetWeakPtr(), src_local_disk_file_path, dest_url,
    257                  callback),
    258       base::Bind(callback, base::File::FILE_ERROR_FAILED));
    259 }
    260 
    261 void FileSystemOperationImpl::RemoveFile(
    262     const FileSystemURL& url,
    263     const StatusCallback& callback) {
    264   DCHECK(SetPendingOperationType(kOperationRemove));
    265   async_file_util_->DeleteFile(
    266       operation_context_.Pass(), url,
    267       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    268                  weak_factory_.GetWeakPtr(), callback));
    269 }
    270 
    271 void FileSystemOperationImpl::RemoveDirectory(
    272     const FileSystemURL& url,
    273     const StatusCallback& callback) {
    274   DCHECK(SetPendingOperationType(kOperationRemove));
    275   async_file_util_->DeleteDirectory(
    276       operation_context_.Pass(), url,
    277       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    278                  weak_factory_.GetWeakPtr(), callback));
    279 }
    280 
    281 void FileSystemOperationImpl::CopyFileLocal(
    282     const FileSystemURL& src_url,
    283     const FileSystemURL& dest_url,
    284     CopyOrMoveOption option,
    285     const CopyFileProgressCallback& progress_callback,
    286     const StatusCallback& callback) {
    287   DCHECK(SetPendingOperationType(kOperationCopy));
    288   DCHECK(src_url.IsInSameFileSystem(dest_url));
    289 
    290   GetUsageAndQuotaThenRunTask(
    291       dest_url,
    292       base::Bind(&FileSystemOperationImpl::DoCopyFileLocal,
    293                  weak_factory_.GetWeakPtr(), src_url, dest_url, option,
    294                  progress_callback, callback),
    295       base::Bind(callback, base::File::FILE_ERROR_FAILED));
    296 }
    297 
    298 void FileSystemOperationImpl::MoveFileLocal(
    299     const FileSystemURL& src_url,
    300     const FileSystemURL& dest_url,
    301     CopyOrMoveOption option,
    302     const StatusCallback& callback) {
    303   DCHECK(SetPendingOperationType(kOperationMove));
    304   DCHECK(src_url.IsInSameFileSystem(dest_url));
    305   GetUsageAndQuotaThenRunTask(
    306       dest_url,
    307       base::Bind(&FileSystemOperationImpl::DoMoveFileLocal,
    308                  weak_factory_.GetWeakPtr(),
    309                  src_url, dest_url, option, callback),
    310       base::Bind(callback, base::File::FILE_ERROR_FAILED));
    311 }
    312 
    313 base::File::Error FileSystemOperationImpl::SyncGetPlatformPath(
    314     const FileSystemURL& url,
    315     base::FilePath* platform_path) {
    316   DCHECK(SetPendingOperationType(kOperationGetLocalPath));
    317   if (!file_system_context()->IsSandboxFileSystem(url.type()))
    318     return base::File::FILE_ERROR_INVALID_OPERATION;
    319   FileSystemFileUtil* file_util =
    320       file_system_context()->sandbox_delegate()->sync_file_util();
    321   file_util->GetLocalFilePath(operation_context_.get(), url, platform_path);
    322   return base::File::FILE_OK;
    323 }
    324 
    325 FileSystemOperationImpl::FileSystemOperationImpl(
    326     const FileSystemURL& url,
    327     FileSystemContext* file_system_context,
    328     scoped_ptr<FileSystemOperationContext> operation_context)
    329     : file_system_context_(file_system_context),
    330       operation_context_(operation_context.Pass()),
    331       async_file_util_(NULL),
    332       pending_operation_(kOperationNone),
    333       weak_factory_(this) {
    334   DCHECK(operation_context_.get());
    335   operation_context_->DetachUserDataThread();
    336   async_file_util_ = file_system_context_->GetAsyncFileUtil(url.type());
    337   DCHECK(async_file_util_);
    338 }
    339 
    340 void FileSystemOperationImpl::GetUsageAndQuotaThenRunTask(
    341     const FileSystemURL& url,
    342     const base::Closure& task,
    343     const base::Closure& error_callback) {
    344   quota::QuotaManagerProxy* quota_manager_proxy =
    345       file_system_context()->quota_manager_proxy();
    346   if (!quota_manager_proxy ||
    347       !file_system_context()->GetQuotaUtil(url.type())) {
    348     // If we don't have the quota manager or the requested filesystem type
    349     // does not support quota, we should be able to let it go.
    350     operation_context_->set_allowed_bytes_growth(kint64max);
    351     task.Run();
    352     return;
    353   }
    354 
    355   DCHECK(quota_manager_proxy);
    356   DCHECK(quota_manager_proxy->quota_manager());
    357   quota_manager_proxy->quota_manager()->GetUsageAndQuota(
    358       url.origin(),
    359       FileSystemTypeToQuotaStorageType(url.type()),
    360       base::Bind(&FileSystemOperationImpl::DidGetUsageAndQuotaAndRunTask,
    361                  weak_factory_.GetWeakPtr(), task, error_callback));
    362 }
    363 
    364 void FileSystemOperationImpl::DidGetUsageAndQuotaAndRunTask(
    365     const base::Closure& task,
    366     const base::Closure& error_callback,
    367     quota::QuotaStatusCode status,
    368     int64 usage, int64 quota) {
    369   if (status != quota::kQuotaStatusOk) {
    370     LOG(WARNING) << "Got unexpected quota error : " << status;
    371     error_callback.Run();
    372     return;
    373   }
    374 
    375   operation_context_->set_allowed_bytes_growth(quota - usage);
    376   task.Run();
    377 }
    378 
    379 void FileSystemOperationImpl::DoCreateFile(
    380     const FileSystemURL& url,
    381     const StatusCallback& callback,
    382     bool exclusive) {
    383   async_file_util_->EnsureFileExists(
    384       operation_context_.Pass(), url,
    385       base::Bind(
    386           exclusive ?
    387               &FileSystemOperationImpl::DidEnsureFileExistsExclusive :
    388               &FileSystemOperationImpl::DidEnsureFileExistsNonExclusive,
    389           weak_factory_.GetWeakPtr(), callback));
    390 }
    391 
    392 void FileSystemOperationImpl::DoCreateDirectory(
    393     const FileSystemURL& url,
    394     const StatusCallback& callback,
    395     bool exclusive, bool recursive) {
    396   async_file_util_->CreateDirectory(
    397       operation_context_.Pass(),
    398       url, exclusive, recursive,
    399       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    400                  weak_factory_.GetWeakPtr(), callback));
    401 }
    402 
    403 void FileSystemOperationImpl::DoCopyFileLocal(
    404     const FileSystemURL& src_url,
    405     const FileSystemURL& dest_url,
    406     CopyOrMoveOption option,
    407     const CopyFileProgressCallback& progress_callback,
    408     const StatusCallback& callback) {
    409   async_file_util_->CopyFileLocal(
    410       operation_context_.Pass(), src_url, dest_url, option, progress_callback,
    411       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    412                  weak_factory_.GetWeakPtr(), callback));
    413 }
    414 
    415 void FileSystemOperationImpl::DoMoveFileLocal(
    416     const FileSystemURL& src_url,
    417     const FileSystemURL& dest_url,
    418     CopyOrMoveOption option,
    419     const StatusCallback& callback) {
    420   async_file_util_->MoveFileLocal(
    421       operation_context_.Pass(), src_url, dest_url, option,
    422       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    423                  weak_factory_.GetWeakPtr(), callback));
    424 }
    425 
    426 void FileSystemOperationImpl::DoCopyInForeignFile(
    427     const base::FilePath& src_local_disk_file_path,
    428     const FileSystemURL& dest_url,
    429     const StatusCallback& callback) {
    430   async_file_util_->CopyInForeignFile(
    431       operation_context_.Pass(),
    432       src_local_disk_file_path, dest_url,
    433       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    434                  weak_factory_.GetWeakPtr(), callback));
    435 }
    436 
    437 void FileSystemOperationImpl::DoTruncate(const FileSystemURL& url,
    438                                          const StatusCallback& callback,
    439                                          int64 length) {
    440   async_file_util_->Truncate(
    441       operation_context_.Pass(), url, length,
    442       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    443                  weak_factory_.GetWeakPtr(), callback));
    444 }
    445 
    446 void FileSystemOperationImpl::DoOpenFile(const FileSystemURL& url,
    447                                          const OpenFileCallback& callback,
    448                                          int file_flags) {
    449   async_file_util_->CreateOrOpen(
    450       operation_context_.Pass(), url, file_flags,
    451       base::Bind(&FileSystemOperationImpl::DidOpenFile,
    452                  weak_factory_.GetWeakPtr(), callback));
    453 }
    454 
    455 void FileSystemOperationImpl::DidEnsureFileExistsExclusive(
    456     const StatusCallback& callback,
    457     base::File::Error rv, bool created) {
    458   if (rv == base::File::FILE_OK && !created) {
    459     callback.Run(base::File::FILE_ERROR_EXISTS);
    460   } else {
    461     DidFinishOperation(callback, rv);
    462   }
    463 }
    464 
    465 void FileSystemOperationImpl::DidEnsureFileExistsNonExclusive(
    466     const StatusCallback& callback,
    467     base::File::Error rv, bool /* created */) {
    468   DidFinishOperation(callback, rv);
    469 }
    470 
    471 void FileSystemOperationImpl::DidFinishOperation(
    472     const StatusCallback& callback,
    473     base::File::Error rv) {
    474   if (!cancel_callback_.is_null()) {
    475     StatusCallback cancel_callback = cancel_callback_;
    476     callback.Run(rv);
    477 
    478     // Return OK only if we succeeded to stop the operation.
    479     cancel_callback.Run(rv == base::File::FILE_ERROR_ABORT ?
    480                         base::File::FILE_OK :
    481                         base::File::FILE_ERROR_INVALID_OPERATION);
    482   } else {
    483     callback.Run(rv);
    484   }
    485 }
    486 
    487 void FileSystemOperationImpl::DidDirectoryExists(
    488     const StatusCallback& callback,
    489     base::File::Error rv,
    490     const base::File::Info& file_info) {
    491   if (rv == base::File::FILE_OK && !file_info.is_directory)
    492     rv = base::File::FILE_ERROR_NOT_A_DIRECTORY;
    493   callback.Run(rv);
    494 }
    495 
    496 void FileSystemOperationImpl::DidFileExists(
    497     const StatusCallback& callback,
    498     base::File::Error rv,
    499     const base::File::Info& file_info) {
    500   if (rv == base::File::FILE_OK && file_info.is_directory)
    501     rv = base::File::FILE_ERROR_NOT_A_FILE;
    502   callback.Run(rv);
    503 }
    504 
    505 void FileSystemOperationImpl::DidDeleteRecursively(
    506     const FileSystemURL& url,
    507     const StatusCallback& callback,
    508     base::File::Error rv) {
    509   if (rv == base::File::FILE_ERROR_INVALID_OPERATION) {
    510     // Recursive removal is not supported on this platform.
    511     DCHECK(!recursive_operation_delegate_);
    512     recursive_operation_delegate_.reset(
    513         new RemoveOperationDelegate(
    514             file_system_context(), url,
    515             base::Bind(&FileSystemOperationImpl::DidFinishOperation,
    516                        weak_factory_.GetWeakPtr(), callback)));
    517     recursive_operation_delegate_->RunRecursively();
    518     return;
    519   }
    520 
    521   callback.Run(rv);
    522 }
    523 
    524 void FileSystemOperationImpl::DidWrite(
    525     const FileSystemURL& url,
    526     const WriteCallback& write_callback,
    527     base::File::Error rv,
    528     int64 bytes,
    529     FileWriterDelegate::WriteProgressStatus write_status) {
    530   const bool complete = (
    531       write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
    532   if (complete && write_status != FileWriterDelegate::ERROR_WRITE_NOT_STARTED) {
    533     DCHECK(operation_context_);
    534     operation_context_->change_observers()->Notify(
    535         &FileChangeObserver::OnModifyFile, MakeTuple(url));
    536   }
    537 
    538   StatusCallback cancel_callback = cancel_callback_;
    539   write_callback.Run(rv, bytes, complete);
    540   if (!cancel_callback.is_null())
    541     cancel_callback.Run(base::File::FILE_OK);
    542 }
    543 
    544 void FileSystemOperationImpl::DidOpenFile(
    545     const OpenFileCallback& callback,
    546     base::File file,
    547     const base::Closure& on_close_callback) {
    548   callback.Run(file.Pass(), on_close_callback);
    549 }
    550 
    551 bool FileSystemOperationImpl::SetPendingOperationType(OperationType type) {
    552   if (pending_operation_ != kOperationNone)
    553     return false;
    554   pending_operation_ = type;
    555   return true;
    556 }
    557 
    558 }  // namespace fileapi
    559