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 "storage/browser/fileapi/file_system_operation_runner.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "base/stl_util.h"
     10 #include "net/url_request/url_request_context.h"
     11 #include "storage/browser/blob/blob_url_request_job_factory.h"
     12 #include "storage/browser/fileapi/file_observers.h"
     13 #include "storage/browser/fileapi/file_stream_writer.h"
     14 #include "storage/browser/fileapi/file_system_context.h"
     15 #include "storage/browser/fileapi/file_system_operation.h"
     16 #include "storage/browser/fileapi/file_writer_delegate.h"
     17 #include "storage/common/blob/shareable_file_reference.h"
     18 
     19 namespace storage {
     20 
     21 typedef FileSystemOperationRunner::OperationID OperationID;
     22 
     23 class FileSystemOperationRunner::BeginOperationScoper
     24     : public base::SupportsWeakPtr<
     25           FileSystemOperationRunner::BeginOperationScoper> {
     26  public:
     27   BeginOperationScoper() {}
     28  private:
     29   DISALLOW_COPY_AND_ASSIGN(BeginOperationScoper);
     30 };
     31 
     32 FileSystemOperationRunner::OperationHandle::OperationHandle() {}
     33 FileSystemOperationRunner::OperationHandle::~OperationHandle() {}
     34 
     35 FileSystemOperationRunner::~FileSystemOperationRunner() {
     36 }
     37 
     38 void FileSystemOperationRunner::Shutdown() {
     39   operations_.Clear();
     40 }
     41 
     42 OperationID FileSystemOperationRunner::CreateFile(
     43     const FileSystemURL& url,
     44     bool exclusive,
     45     const StatusCallback& callback) {
     46   base::File::Error error = base::File::FILE_OK;
     47   FileSystemOperation* operation =
     48       file_system_context_->CreateFileSystemOperation(url, &error);
     49 
     50   BeginOperationScoper scope;
     51   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
     52   if (!operation) {
     53     DidFinish(handle, callback, error);
     54     return handle.id;
     55   }
     56   PrepareForWrite(handle.id, url);
     57   operation->CreateFile(
     58       url, exclusive,
     59       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
     60                  handle, callback));
     61   return handle.id;
     62 }
     63 
     64 OperationID FileSystemOperationRunner::CreateDirectory(
     65     const FileSystemURL& url,
     66     bool exclusive,
     67     bool recursive,
     68     const StatusCallback& callback) {
     69   base::File::Error error = base::File::FILE_OK;
     70   FileSystemOperation* operation =
     71       file_system_context_->CreateFileSystemOperation(url, &error);
     72   BeginOperationScoper scope;
     73   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
     74   if (!operation) {
     75     DidFinish(handle, callback, error);
     76     return handle.id;
     77   }
     78   PrepareForWrite(handle.id, url);
     79   operation->CreateDirectory(
     80       url, exclusive, recursive,
     81       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
     82                  handle, callback));
     83   return handle.id;
     84 }
     85 
     86 OperationID FileSystemOperationRunner::Copy(
     87     const FileSystemURL& src_url,
     88     const FileSystemURL& dest_url,
     89     CopyOrMoveOption option,
     90     const CopyProgressCallback& progress_callback,
     91     const StatusCallback& callback) {
     92   base::File::Error error = base::File::FILE_OK;
     93   FileSystemOperation* operation =
     94       file_system_context_->CreateFileSystemOperation(dest_url, &error);
     95   BeginOperationScoper scope;
     96   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
     97   if (!operation) {
     98     DidFinish(handle, callback, error);
     99     return handle.id;
    100   }
    101   PrepareForWrite(handle.id, dest_url);
    102   PrepareForRead(handle.id, src_url);
    103   operation->Copy(
    104       src_url, dest_url, option,
    105       progress_callback.is_null() ?
    106           CopyProgressCallback() :
    107           base::Bind(&FileSystemOperationRunner::OnCopyProgress, AsWeakPtr(),
    108                      handle, progress_callback),
    109       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    110                  handle, callback));
    111   return handle.id;
    112 }
    113 
    114 OperationID FileSystemOperationRunner::Move(
    115     const FileSystemURL& src_url,
    116     const FileSystemURL& dest_url,
    117     CopyOrMoveOption option,
    118     const StatusCallback& callback) {
    119   base::File::Error error = base::File::FILE_OK;
    120   FileSystemOperation* operation =
    121       file_system_context_->CreateFileSystemOperation(dest_url, &error);
    122   BeginOperationScoper scope;
    123   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    124   if (!operation) {
    125     DidFinish(handle, callback, error);
    126     return handle.id;
    127   }
    128   PrepareForWrite(handle.id, dest_url);
    129   PrepareForWrite(handle.id, src_url);
    130   operation->Move(
    131       src_url, dest_url, option,
    132       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    133                  handle, callback));
    134   return handle.id;
    135 }
    136 
    137 OperationID FileSystemOperationRunner::DirectoryExists(
    138     const FileSystemURL& url,
    139     const StatusCallback& callback) {
    140   base::File::Error error = base::File::FILE_OK;
    141   FileSystemOperation* operation =
    142       file_system_context_->CreateFileSystemOperation(url, &error);
    143   BeginOperationScoper scope;
    144   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    145   if (!operation) {
    146     DidFinish(handle, callback, error);
    147     return handle.id;
    148   }
    149   PrepareForRead(handle.id, url);
    150   operation->DirectoryExists(
    151       url,
    152       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    153                  handle, callback));
    154   return handle.id;
    155 }
    156 
    157 OperationID FileSystemOperationRunner::FileExists(
    158     const FileSystemURL& url,
    159     const StatusCallback& callback) {
    160   base::File::Error error = base::File::FILE_OK;
    161   FileSystemOperation* operation =
    162       file_system_context_->CreateFileSystemOperation(url, &error);
    163   BeginOperationScoper scope;
    164   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    165   if (!operation) {
    166     DidFinish(handle, callback, error);
    167     return handle.id;
    168   }
    169   PrepareForRead(handle.id, url);
    170   operation->FileExists(
    171       url,
    172       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    173                  handle, callback));
    174   return handle.id;
    175 }
    176 
    177 OperationID FileSystemOperationRunner::GetMetadata(
    178     const FileSystemURL& url,
    179     const GetMetadataCallback& callback) {
    180   base::File::Error error = base::File::FILE_OK;
    181   FileSystemOperation* operation =
    182       file_system_context_->CreateFileSystemOperation(url, &error);
    183   BeginOperationScoper scope;
    184   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    185   if (!operation) {
    186     DidGetMetadata(handle, callback, error, base::File::Info());
    187     return handle.id;
    188   }
    189   PrepareForRead(handle.id, url);
    190   operation->GetMetadata(
    191       url,
    192       base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(),
    193                  handle, callback));
    194   return handle.id;
    195 }
    196 
    197 OperationID FileSystemOperationRunner::ReadDirectory(
    198     const FileSystemURL& url,
    199     const ReadDirectoryCallback& callback) {
    200   base::File::Error error = base::File::FILE_OK;
    201   FileSystemOperation* operation =
    202       file_system_context_->CreateFileSystemOperation(url, &error);
    203   BeginOperationScoper scope;
    204   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    205   if (!operation) {
    206     DidReadDirectory(handle, callback, error, std::vector<DirectoryEntry>(),
    207                      false);
    208     return handle.id;
    209   }
    210   PrepareForRead(handle.id, url);
    211   operation->ReadDirectory(
    212       url,
    213       base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(),
    214                  handle, callback));
    215   return handle.id;
    216 }
    217 
    218 OperationID FileSystemOperationRunner::Remove(
    219     const FileSystemURL& url, bool recursive,
    220     const StatusCallback& callback) {
    221   base::File::Error error = base::File::FILE_OK;
    222   FileSystemOperation* operation =
    223       file_system_context_->CreateFileSystemOperation(url, &error);
    224   BeginOperationScoper scope;
    225   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    226   if (!operation) {
    227     DidFinish(handle, callback, error);
    228     return handle.id;
    229   }
    230   PrepareForWrite(handle.id, url);
    231   operation->Remove(
    232       url, recursive,
    233       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    234                  handle, callback));
    235   return handle.id;
    236 }
    237 
    238 OperationID FileSystemOperationRunner::Write(
    239     const net::URLRequestContext* url_request_context,
    240     const FileSystemURL& url,
    241     scoped_ptr<storage::BlobDataHandle> blob,
    242     int64 offset,
    243     const WriteCallback& callback) {
    244   base::File::Error error = base::File::FILE_OK;
    245   FileSystemOperation* operation =
    246       file_system_context_->CreateFileSystemOperation(url, &error);
    247 
    248   BeginOperationScoper scope;
    249   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    250   if (!operation) {
    251     DidWrite(handle, callback, error, 0, true);
    252     return handle.id;
    253   }
    254 
    255   scoped_ptr<FileStreamWriter> writer(
    256       file_system_context_->CreateFileStreamWriter(url, offset));
    257   if (!writer) {
    258     // Write is not supported.
    259     DidWrite(handle, callback, base::File::FILE_ERROR_SECURITY, 0, true);
    260     return handle.id;
    261   }
    262 
    263   FileWriterDelegate::FlushPolicy flush_policy =
    264       file_system_context_->ShouldFlushOnWriteCompletion(url.type())
    265           ? FileWriterDelegate::FLUSH_ON_COMPLETION
    266           : FileWriterDelegate::NO_FLUSH_ON_COMPLETION;
    267   scoped_ptr<FileWriterDelegate> writer_delegate(
    268       new FileWriterDelegate(writer.Pass(), flush_policy));
    269 
    270   scoped_ptr<net::URLRequest> blob_request(
    271       storage::BlobProtocolHandler::CreateBlobRequest(
    272           blob.Pass(), url_request_context, writer_delegate.get()));
    273 
    274   PrepareForWrite(handle.id, url);
    275   operation->Write(
    276       url, writer_delegate.Pass(), blob_request.Pass(),
    277       base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
    278                  handle, callback));
    279   return handle.id;
    280 }
    281 
    282 OperationID FileSystemOperationRunner::Truncate(
    283     const FileSystemURL& url, int64 length,
    284     const StatusCallback& callback) {
    285   base::File::Error error = base::File::FILE_OK;
    286   FileSystemOperation* operation =
    287       file_system_context_->CreateFileSystemOperation(url, &error);
    288   BeginOperationScoper scope;
    289   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    290   if (!operation) {
    291     DidFinish(handle, callback, error);
    292     return handle.id;
    293   }
    294   PrepareForWrite(handle.id, url);
    295   operation->Truncate(
    296       url, length,
    297       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    298                  handle, callback));
    299   return handle.id;
    300 }
    301 
    302 void FileSystemOperationRunner::Cancel(
    303     OperationID id,
    304     const StatusCallback& callback) {
    305   if (ContainsKey(finished_operations_, id)) {
    306     DCHECK(!ContainsKey(stray_cancel_callbacks_, id));
    307     stray_cancel_callbacks_[id] = callback;
    308     return;
    309   }
    310   FileSystemOperation* operation = operations_.Lookup(id);
    311   if (!operation) {
    312     // There is no operation with |id|.
    313     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    314     return;
    315   }
    316   operation->Cancel(callback);
    317 }
    318 
    319 OperationID FileSystemOperationRunner::TouchFile(
    320     const FileSystemURL& url,
    321     const base::Time& last_access_time,
    322     const base::Time& last_modified_time,
    323     const StatusCallback& callback) {
    324   base::File::Error error = base::File::FILE_OK;
    325   FileSystemOperation* operation =
    326       file_system_context_->CreateFileSystemOperation(url, &error);
    327   BeginOperationScoper scope;
    328   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    329   if (!operation) {
    330     DidFinish(handle, callback, error);
    331     return handle.id;
    332   }
    333   PrepareForWrite(handle.id, url);
    334   operation->TouchFile(
    335       url, last_access_time, last_modified_time,
    336       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    337                  handle, callback));
    338   return handle.id;
    339 }
    340 
    341 OperationID FileSystemOperationRunner::OpenFile(
    342     const FileSystemURL& url,
    343     int file_flags,
    344     const OpenFileCallback& callback) {
    345   base::File::Error error = base::File::FILE_OK;
    346   FileSystemOperation* operation =
    347       file_system_context_->CreateFileSystemOperation(url, &error);
    348   BeginOperationScoper scope;
    349   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    350   if (!operation) {
    351     DidOpenFile(handle, callback, base::File(error), base::Closure());
    352     return handle.id;
    353   }
    354   if (file_flags &
    355       (base::File::FLAG_CREATE | base::File::FLAG_OPEN_ALWAYS |
    356        base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_OPEN_TRUNCATED |
    357        base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_WRITE |
    358        base::File::FLAG_DELETE_ON_CLOSE |
    359        base::File::FLAG_WRITE_ATTRIBUTES)) {
    360     PrepareForWrite(handle.id, url);
    361   } else {
    362     PrepareForRead(handle.id, url);
    363   }
    364   operation->OpenFile(
    365       url, file_flags,
    366       base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(),
    367                  handle, callback));
    368   return handle.id;
    369 }
    370 
    371 OperationID FileSystemOperationRunner::CreateSnapshotFile(
    372     const FileSystemURL& url,
    373     const SnapshotFileCallback& callback) {
    374   base::File::Error error = base::File::FILE_OK;
    375   FileSystemOperation* operation =
    376       file_system_context_->CreateFileSystemOperation(url, &error);
    377   BeginOperationScoper scope;
    378   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    379   if (!operation) {
    380     DidCreateSnapshot(handle, callback, error, base::File::Info(),
    381                       base::FilePath(), NULL);
    382     return handle.id;
    383   }
    384   PrepareForRead(handle.id, url);
    385   operation->CreateSnapshotFile(
    386       url,
    387       base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(),
    388                  handle, callback));
    389   return handle.id;
    390 }
    391 
    392 OperationID FileSystemOperationRunner::CopyInForeignFile(
    393     const base::FilePath& src_local_disk_path,
    394     const FileSystemURL& dest_url,
    395     const StatusCallback& callback) {
    396   base::File::Error error = base::File::FILE_OK;
    397   FileSystemOperation* operation =
    398       file_system_context_->CreateFileSystemOperation(dest_url, &error);
    399   BeginOperationScoper scope;
    400   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    401   if (!operation) {
    402     DidFinish(handle, callback, error);
    403     return handle.id;
    404   }
    405   PrepareForWrite(handle.id, dest_url);
    406   operation->CopyInForeignFile(
    407       src_local_disk_path, dest_url,
    408       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    409                  handle, callback));
    410   return handle.id;
    411 }
    412 
    413 OperationID FileSystemOperationRunner::RemoveFile(
    414     const FileSystemURL& url,
    415     const StatusCallback& callback) {
    416   base::File::Error error = base::File::FILE_OK;
    417   FileSystemOperation* operation =
    418       file_system_context_->CreateFileSystemOperation(url, &error);
    419   BeginOperationScoper scope;
    420   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    421   if (!operation) {
    422     DidFinish(handle, callback, error);
    423     return handle.id;
    424   }
    425   PrepareForWrite(handle.id, url);
    426   operation->RemoveFile(
    427       url,
    428       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    429                  handle, callback));
    430   return handle.id;
    431 }
    432 
    433 OperationID FileSystemOperationRunner::RemoveDirectory(
    434     const FileSystemURL& url,
    435     const StatusCallback& callback) {
    436   base::File::Error error = base::File::FILE_OK;
    437   FileSystemOperation* operation =
    438       file_system_context_->CreateFileSystemOperation(url, &error);
    439   BeginOperationScoper scope;
    440   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    441   if (!operation) {
    442     DidFinish(handle, callback, error);
    443     return handle.id;
    444   }
    445   PrepareForWrite(handle.id, url);
    446   operation->RemoveDirectory(
    447       url,
    448       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    449                  handle, callback));
    450   return handle.id;
    451 }
    452 
    453 OperationID FileSystemOperationRunner::CopyFileLocal(
    454     const FileSystemURL& src_url,
    455     const FileSystemURL& dest_url,
    456     CopyOrMoveOption option,
    457     const CopyFileProgressCallback& progress_callback,
    458     const StatusCallback& callback) {
    459   base::File::Error error = base::File::FILE_OK;
    460   FileSystemOperation* operation =
    461       file_system_context_->CreateFileSystemOperation(src_url, &error);
    462   BeginOperationScoper scope;
    463   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    464   if (!operation) {
    465     DidFinish(handle, callback, error);
    466     return handle.id;
    467   }
    468   PrepareForRead(handle.id, src_url);
    469   PrepareForWrite(handle.id, dest_url);
    470   operation->CopyFileLocal(
    471       src_url, dest_url, option, progress_callback,
    472       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    473                  handle, callback));
    474   return handle.id;
    475 }
    476 
    477 OperationID FileSystemOperationRunner::MoveFileLocal(
    478     const FileSystemURL& src_url,
    479     const FileSystemURL& dest_url,
    480     CopyOrMoveOption option,
    481     const StatusCallback& callback) {
    482   base::File::Error error = base::File::FILE_OK;
    483   FileSystemOperation* operation =
    484       file_system_context_->CreateFileSystemOperation(src_url, &error);
    485   BeginOperationScoper scope;
    486   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
    487   if (!operation) {
    488     DidFinish(handle, callback, error);
    489     return handle.id;
    490   }
    491   PrepareForWrite(handle.id, src_url);
    492   PrepareForWrite(handle.id, dest_url);
    493   operation->MoveFileLocal(
    494       src_url, dest_url, option,
    495       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    496                  handle, callback));
    497   return handle.id;
    498 }
    499 
    500 base::File::Error FileSystemOperationRunner::SyncGetPlatformPath(
    501     const FileSystemURL& url,
    502     base::FilePath* platform_path) {
    503   base::File::Error error = base::File::FILE_OK;
    504   scoped_ptr<FileSystemOperation> operation(
    505       file_system_context_->CreateFileSystemOperation(url, &error));
    506   if (!operation.get())
    507     return error;
    508   return operation->SyncGetPlatformPath(url, platform_path);
    509 }
    510 
    511 FileSystemOperationRunner::FileSystemOperationRunner(
    512     FileSystemContext* file_system_context)
    513     : file_system_context_(file_system_context) {}
    514 
    515 void FileSystemOperationRunner::DidFinish(
    516     const OperationHandle& handle,
    517     const StatusCallback& callback,
    518     base::File::Error rv) {
    519   if (handle.scope) {
    520     finished_operations_.insert(handle.id);
    521     base::MessageLoopProxy::current()->PostTask(
    522         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidFinish,
    523                               AsWeakPtr(), handle, callback, rv));
    524     return;
    525   }
    526   callback.Run(rv);
    527   FinishOperation(handle.id);
    528 }
    529 
    530 void FileSystemOperationRunner::DidGetMetadata(
    531     const OperationHandle& handle,
    532     const GetMetadataCallback& callback,
    533     base::File::Error rv,
    534     const base::File::Info& file_info) {
    535   if (handle.scope) {
    536     finished_operations_.insert(handle.id);
    537     base::MessageLoopProxy::current()->PostTask(
    538         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidGetMetadata,
    539                               AsWeakPtr(), handle, callback, rv, file_info));
    540     return;
    541   }
    542   callback.Run(rv, file_info);
    543   FinishOperation(handle.id);
    544 }
    545 
    546 void FileSystemOperationRunner::DidReadDirectory(
    547     const OperationHandle& handle,
    548     const ReadDirectoryCallback& callback,
    549     base::File::Error rv,
    550     const std::vector<DirectoryEntry>& entries,
    551     bool has_more) {
    552   if (handle.scope) {
    553     finished_operations_.insert(handle.id);
    554     base::MessageLoopProxy::current()->PostTask(
    555         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidReadDirectory,
    556                               AsWeakPtr(), handle, callback, rv,
    557                               entries, has_more));
    558     return;
    559   }
    560   callback.Run(rv, entries, has_more);
    561   if (rv != base::File::FILE_OK || !has_more)
    562     FinishOperation(handle.id);
    563 }
    564 
    565 void FileSystemOperationRunner::DidWrite(
    566     const OperationHandle& handle,
    567     const WriteCallback& callback,
    568     base::File::Error rv,
    569     int64 bytes,
    570     bool complete) {
    571   if (handle.scope) {
    572     finished_operations_.insert(handle.id);
    573     base::MessageLoopProxy::current()->PostTask(
    574         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
    575                               handle, callback, rv, bytes, complete));
    576     return;
    577   }
    578   callback.Run(rv, bytes, complete);
    579   if (rv != base::File::FILE_OK || complete)
    580     FinishOperation(handle.id);
    581 }
    582 
    583 void FileSystemOperationRunner::DidOpenFile(
    584     const OperationHandle& handle,
    585     const OpenFileCallback& callback,
    586     base::File file,
    587     const base::Closure& on_close_callback) {
    588   if (handle.scope) {
    589     finished_operations_.insert(handle.id);
    590     base::MessageLoopProxy::current()->PostTask(
    591         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidOpenFile,
    592                               AsWeakPtr(), handle, callback, Passed(&file),
    593                               on_close_callback));
    594     return;
    595   }
    596   callback.Run(file.Pass(), on_close_callback);
    597   FinishOperation(handle.id);
    598 }
    599 
    600 void FileSystemOperationRunner::DidCreateSnapshot(
    601     const OperationHandle& handle,
    602     const SnapshotFileCallback& callback,
    603     base::File::Error rv,
    604     const base::File::Info& file_info,
    605     const base::FilePath& platform_path,
    606     const scoped_refptr<storage::ShareableFileReference>& file_ref) {
    607   if (handle.scope) {
    608     finished_operations_.insert(handle.id);
    609     base::MessageLoopProxy::current()->PostTask(
    610         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidCreateSnapshot,
    611                               AsWeakPtr(), handle, callback, rv, file_info,
    612                               platform_path, file_ref));
    613     return;
    614   }
    615   callback.Run(rv, file_info, platform_path, file_ref);
    616   FinishOperation(handle.id);
    617 }
    618 
    619 void FileSystemOperationRunner::OnCopyProgress(
    620     const OperationHandle& handle,
    621     const CopyProgressCallback& callback,
    622     FileSystemOperation::CopyProgressType type,
    623     const FileSystemURL& source_url,
    624     const FileSystemURL& dest_url,
    625     int64 size) {
    626   if (handle.scope) {
    627     base::MessageLoopProxy::current()->PostTask(
    628         FROM_HERE, base::Bind(
    629             &FileSystemOperationRunner::OnCopyProgress,
    630             AsWeakPtr(), handle, callback, type, source_url, dest_url, size));
    631     return;
    632   }
    633   callback.Run(type, source_url, dest_url, size);
    634 }
    635 
    636 void FileSystemOperationRunner::PrepareForWrite(OperationID id,
    637                                                 const FileSystemURL& url) {
    638   if (file_system_context_->GetUpdateObservers(url.type())) {
    639     file_system_context_->GetUpdateObservers(url.type())->Notify(
    640         &FileUpdateObserver::OnStartUpdate, MakeTuple(url));
    641   }
    642   write_target_urls_[id].insert(url);
    643 }
    644 
    645 void FileSystemOperationRunner::PrepareForRead(OperationID id,
    646                                                const FileSystemURL& url) {
    647   if (file_system_context_->GetAccessObservers(url.type())) {
    648     file_system_context_->GetAccessObservers(url.type())->Notify(
    649         &FileAccessObserver::OnAccess, MakeTuple(url));
    650   }
    651 }
    652 
    653 FileSystemOperationRunner::OperationHandle
    654 FileSystemOperationRunner::BeginOperation(
    655     FileSystemOperation* operation,
    656     base::WeakPtr<BeginOperationScoper> scope) {
    657   OperationHandle handle;
    658   handle.id = operations_.Add(operation);
    659   handle.scope = scope;
    660   return handle;
    661 }
    662 
    663 void FileSystemOperationRunner::FinishOperation(OperationID id) {
    664   OperationToURLSet::iterator found = write_target_urls_.find(id);
    665   if (found != write_target_urls_.end()) {
    666     const FileSystemURLSet& urls = found->second;
    667     for (FileSystemURLSet::const_iterator iter = urls.begin();
    668         iter != urls.end(); ++iter) {
    669       if (file_system_context_->GetUpdateObservers(iter->type())) {
    670         file_system_context_->GetUpdateObservers(iter->type())->Notify(
    671             &FileUpdateObserver::OnEndUpdate, MakeTuple(*iter));
    672       }
    673     }
    674     write_target_urls_.erase(found);
    675   }
    676 
    677   // IDMap::Lookup fails if the operation is NULL, so we don't check
    678   // operations_.Lookup(id) here.
    679 
    680   operations_.Remove(id);
    681   finished_operations_.erase(id);
    682 
    683   // Dispatch stray cancel callback if exists.
    684   std::map<OperationID, StatusCallback>::iterator found_cancel =
    685       stray_cancel_callbacks_.find(id);
    686   if (found_cancel != stray_cancel_callbacks_.end()) {
    687     // This cancel has been requested after the operation has finished,
    688     // so report that we failed to stop it.
    689     found_cancel->second.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    690     stray_cancel_callbacks_.erase(found_cancel);
    691   }
    692 }
    693 
    694 }  // namespace storage
    695