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_runner.h"
      6 
      7 #include "base/bind.h"
      8 #include "net/url_request/url_request_context.h"
      9 #include "webkit/browser/fileapi/file_observers.h"
     10 #include "webkit/browser/fileapi/file_stream_writer.h"
     11 #include "webkit/browser/fileapi/file_system_context.h"
     12 #include "webkit/browser/fileapi/file_system_operation_impl.h"
     13 #include "webkit/browser/fileapi/file_writer_delegate.h"
     14 #include "webkit/common/blob/shareable_file_reference.h"
     15 
     16 namespace fileapi {
     17 
     18 typedef FileSystemOperationRunner::OperationID OperationID;
     19 
     20 const OperationID FileSystemOperationRunner::kErrorOperationID = -1;
     21 
     22 FileSystemOperationRunner::~FileSystemOperationRunner() {
     23 }
     24 
     25 void FileSystemOperationRunner::Shutdown() {
     26   operations_.Clear();
     27 }
     28 
     29 OperationID FileSystemOperationRunner::CreateFile(
     30     const FileSystemURL& url,
     31     bool exclusive,
     32     const StatusCallback& callback) {
     33   base::PlatformFileError error = base::PLATFORM_FILE_OK;
     34   FileSystemOperation* operation =
     35       file_system_context_->CreateFileSystemOperation(url, &error);
     36   if (!operation) {
     37     callback.Run(error);
     38     return kErrorOperationID;
     39   }
     40   OperationID id = operations_.Add(operation);
     41   PrepareForWrite(id, url);
     42   operation->CreateFile(
     43       url, exclusive,
     44       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
     45                  id, callback));
     46   return id;
     47 }
     48 
     49 OperationID FileSystemOperationRunner::CreateDirectory(
     50     const FileSystemURL& url,
     51     bool exclusive,
     52     bool recursive,
     53     const StatusCallback& callback) {
     54   base::PlatformFileError error = base::PLATFORM_FILE_OK;
     55   FileSystemOperation* operation =
     56       file_system_context_->CreateFileSystemOperation(url, &error);
     57   if (!operation) {
     58     callback.Run(error);
     59     return kErrorOperationID;
     60   }
     61   OperationID id = operations_.Add(operation);
     62   PrepareForWrite(id, url);
     63   operation->CreateDirectory(
     64       url, exclusive, recursive,
     65       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
     66                  id, callback));
     67   return id;
     68 }
     69 
     70 OperationID FileSystemOperationRunner::Copy(
     71     const FileSystemURL& src_url,
     72     const FileSystemURL& dest_url,
     73     const StatusCallback& callback) {
     74   base::PlatformFileError error = base::PLATFORM_FILE_OK;
     75   FileSystemOperation* operation =
     76       file_system_context_->CreateFileSystemOperation(dest_url, &error);
     77   if (!operation) {
     78     callback.Run(error);
     79     return kErrorOperationID;
     80   }
     81   OperationID id = operations_.Add(operation);
     82   PrepareForWrite(id, dest_url);
     83   PrepareForRead(id, src_url);
     84   operation->Copy(
     85       src_url, dest_url,
     86       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
     87                  id, callback));
     88   return id;
     89 }
     90 
     91 OperationID FileSystemOperationRunner::Move(
     92     const FileSystemURL& src_url,
     93     const FileSystemURL& dest_url,
     94     const StatusCallback& callback) {
     95   base::PlatformFileError error = base::PLATFORM_FILE_OK;
     96   FileSystemOperation* operation =
     97       file_system_context_->CreateFileSystemOperation(dest_url, &error);
     98   if (!operation) {
     99     callback.Run(error);
    100     return kErrorOperationID;
    101   }
    102   OperationID id = operations_.Add(operation);
    103   PrepareForWrite(id, dest_url);
    104   PrepareForWrite(id, src_url);
    105   operation->Move(
    106       src_url, dest_url,
    107       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    108                  id, callback));
    109   return id;
    110 }
    111 
    112 OperationID FileSystemOperationRunner::DirectoryExists(
    113     const FileSystemURL& url,
    114     const StatusCallback& callback) {
    115   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    116   FileSystemOperation* operation =
    117       file_system_context_->CreateFileSystemOperation(url, &error);
    118   if (!operation) {
    119     callback.Run(error);
    120     return kErrorOperationID;
    121   }
    122   OperationID id = operations_.Add(operation);
    123   PrepareForRead(id, url);
    124   operation->DirectoryExists(
    125       url,
    126       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    127                  id, callback));
    128   return id;
    129 }
    130 
    131 OperationID FileSystemOperationRunner::FileExists(
    132     const FileSystemURL& url,
    133     const StatusCallback& callback) {
    134   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    135   FileSystemOperation* operation =
    136       file_system_context_->CreateFileSystemOperation(url, &error);
    137   if (!operation) {
    138     callback.Run(error);
    139     return kErrorOperationID;
    140   }
    141   OperationID id = operations_.Add(operation);
    142   PrepareForRead(id, url);
    143   operation->FileExists(
    144       url,
    145       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    146                  id, callback));
    147   return id;
    148 }
    149 
    150 OperationID FileSystemOperationRunner::GetMetadata(
    151     const FileSystemURL& url,
    152     const GetMetadataCallback& callback) {
    153   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    154   FileSystemOperation* operation =
    155       file_system_context_->CreateFileSystemOperation(url, &error);
    156   if (!operation) {
    157     callback.Run(error, base::PlatformFileInfo());
    158     return kErrorOperationID;
    159   }
    160   OperationID id = operations_.Add(operation);
    161   PrepareForRead(id, url);
    162   operation->GetMetadata(
    163       url,
    164       base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(),
    165                  id, callback));
    166   return id;
    167 }
    168 
    169 OperationID FileSystemOperationRunner::ReadDirectory(
    170     const FileSystemURL& url,
    171     const ReadDirectoryCallback& callback) {
    172   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    173   FileSystemOperation* operation =
    174       file_system_context_->CreateFileSystemOperation(url, &error);
    175   if (!operation) {
    176     callback.Run(error, std::vector<DirectoryEntry>(), false);
    177     return kErrorOperationID;
    178   }
    179   OperationID id = operations_.Add(operation);
    180   PrepareForRead(id, url);
    181   operation->ReadDirectory(
    182       url,
    183       base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(),
    184                  id, callback));
    185   return id;
    186 }
    187 
    188 OperationID FileSystemOperationRunner::Remove(
    189     const FileSystemURL& url, bool recursive,
    190     const StatusCallback& callback) {
    191   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    192   FileSystemOperation* operation =
    193       file_system_context_->CreateFileSystemOperation(url, &error);
    194   if (!operation) {
    195     callback.Run(error);
    196     return kErrorOperationID;
    197   }
    198   OperationID id = operations_.Add(operation);
    199   PrepareForWrite(id, url);
    200   operation->Remove(
    201       url, recursive,
    202       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    203                  id, callback));
    204   return id;
    205 }
    206 
    207 OperationID FileSystemOperationRunner::Write(
    208     const net::URLRequestContext* url_request_context,
    209     const FileSystemURL& url,
    210     const GURL& blob_url,
    211     int64 offset,
    212     const WriteCallback& callback) {
    213   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    214   FileSystemOperation* operation =
    215       file_system_context_->CreateFileSystemOperation(url, &error);
    216   if (!operation) {
    217     callback.Run(error, 0, true);
    218     return kErrorOperationID;
    219   }
    220 
    221   scoped_ptr<FileStreamWriter> writer(
    222       file_system_context_->CreateFileStreamWriter(url, offset));
    223   if (!writer) {
    224     // Write is not supported.
    225     callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, 0, true);
    226     return kErrorOperationID;
    227   }
    228 
    229   DCHECK(blob_url.is_valid());
    230   scoped_ptr<FileWriterDelegate> writer_delegate(
    231       new FileWriterDelegate(writer.Pass()));
    232   scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest(
    233       blob_url, writer_delegate.get()));
    234 
    235   OperationID id = operations_.Add(operation);
    236   PrepareForWrite(id, url);
    237   operation->Write(
    238       url, writer_delegate.Pass(), blob_request.Pass(),
    239       base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
    240                  id, callback));
    241   return id;
    242 }
    243 
    244 OperationID FileSystemOperationRunner::Truncate(
    245     const FileSystemURL& url, int64 length,
    246     const StatusCallback& callback) {
    247   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    248   FileSystemOperation* operation =
    249       file_system_context_->CreateFileSystemOperation(url, &error);
    250   if (!operation) {
    251     callback.Run(error);
    252     return kErrorOperationID;
    253   }
    254   OperationID id = operations_.Add(operation);
    255   PrepareForWrite(id, url);
    256   operation->Truncate(
    257       url, length,
    258       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    259                  id, callback));
    260   return id;
    261 }
    262 
    263 void FileSystemOperationRunner::Cancel(
    264     OperationID id,
    265     const StatusCallback& callback) {
    266   FileSystemOperation* operation = operations_.Lookup(id);
    267   if (!operation) {
    268     // The operation is already finished; report that we failed to stop it.
    269     callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
    270     return;
    271   }
    272   operation->Cancel(callback);
    273 }
    274 
    275 OperationID FileSystemOperationRunner::TouchFile(
    276     const FileSystemURL& url,
    277     const base::Time& last_access_time,
    278     const base::Time& last_modified_time,
    279     const StatusCallback& callback) {
    280   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    281   FileSystemOperation* operation =
    282       file_system_context_->CreateFileSystemOperation(url, &error);
    283   if (!operation) {
    284     callback.Run(error);
    285     return kErrorOperationID;
    286   }
    287   OperationID id = operations_.Add(operation);
    288   PrepareForWrite(id, url);
    289   operation->TouchFile(
    290       url, last_access_time, last_modified_time,
    291       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    292                  id, callback));
    293   return id;
    294 }
    295 
    296 OperationID FileSystemOperationRunner::OpenFile(
    297     const FileSystemURL& url,
    298     int file_flags,
    299     base::ProcessHandle peer_handle,
    300     const OpenFileCallback& callback) {
    301   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    302   FileSystemOperation* operation =
    303       file_system_context_->CreateFileSystemOperation(url, &error);
    304   if (!operation) {
    305     callback.Run(error, base::kInvalidPlatformFileValue,
    306                  base::Closure(), base::ProcessHandle());
    307     return kErrorOperationID;
    308   }
    309   OperationID id = operations_.Add(operation);
    310   if (file_flags &
    311       (base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS |
    312        base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED |
    313        base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE |
    314        base::PLATFORM_FILE_DELETE_ON_CLOSE |
    315        base::PLATFORM_FILE_WRITE_ATTRIBUTES)) {
    316     PrepareForWrite(id, url);
    317   } else {
    318     PrepareForRead(id, url);
    319   }
    320   operation->OpenFile(
    321       url, file_flags, peer_handle,
    322       base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(),
    323                  id, callback));
    324   return id;
    325 }
    326 
    327 OperationID FileSystemOperationRunner::CreateSnapshotFile(
    328     const FileSystemURL& url,
    329     const SnapshotFileCallback& callback) {
    330   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    331   FileSystemOperation* operation =
    332       file_system_context_->CreateFileSystemOperation(url, &error);
    333   if (!operation) {
    334     callback.Run(error, base::PlatformFileInfo(), base::FilePath(), NULL);
    335     return kErrorOperationID;
    336   }
    337   OperationID id = operations_.Add(operation);
    338   PrepareForRead(id, url);
    339   operation->CreateSnapshotFile(
    340       url,
    341       base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(),
    342                  id, callback));
    343   return id;
    344 }
    345 
    346 OperationID FileSystemOperationRunner::CopyInForeignFile(
    347     const base::FilePath& src_local_disk_path,
    348     const FileSystemURL& dest_url,
    349     const StatusCallback& callback) {
    350   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    351   FileSystemOperation* operation = CreateFileSystemOperationImpl(
    352       dest_url, &error);
    353   if (!operation) {
    354     callback.Run(error);
    355     return kErrorOperationID;
    356   }
    357   OperationID id = operations_.Add(operation);
    358   operation->AsFileSystemOperationImpl()->CopyInForeignFile(
    359       src_local_disk_path, dest_url,
    360       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    361                  id, callback));
    362   return id;
    363 }
    364 
    365 OperationID FileSystemOperationRunner::RemoveFile(
    366     const FileSystemURL& url,
    367     const StatusCallback& callback) {
    368   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    369   FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error);
    370   if (!operation) {
    371     callback.Run(error);
    372     return kErrorOperationID;
    373   }
    374   OperationID id = operations_.Add(operation);
    375   operation->AsFileSystemOperationImpl()->RemoveFile(
    376       url,
    377       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    378                  id, callback));
    379   return id;
    380 }
    381 
    382 OperationID FileSystemOperationRunner::RemoveDirectory(
    383     const FileSystemURL& url,
    384     const StatusCallback& callback) {
    385   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    386   FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error);
    387   if (!operation) {
    388     callback.Run(error);
    389     return kErrorOperationID;
    390   }
    391   OperationID id = operations_.Add(operation);
    392   operation->AsFileSystemOperationImpl()->RemoveDirectory(
    393       url,
    394       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    395                  id, callback));
    396   return id;
    397 }
    398 
    399 OperationID FileSystemOperationRunner::CopyFileLocal(
    400     const FileSystemURL& src_url,
    401     const FileSystemURL& dest_url,
    402     const StatusCallback& callback) {
    403   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    404   FileSystemOperation* operation = CreateFileSystemOperationImpl(
    405       src_url, &error);
    406   if (!operation) {
    407     callback.Run(error);
    408     return kErrorOperationID;
    409   }
    410   OperationID id = operations_.Add(operation);
    411   operation->AsFileSystemOperationImpl()->CopyFileLocal(
    412       src_url, dest_url,
    413       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    414                  id, callback));
    415   return id;
    416 }
    417 
    418 OperationID FileSystemOperationRunner::MoveFileLocal(
    419     const FileSystemURL& src_url,
    420     const FileSystemURL& dest_url,
    421     const StatusCallback& callback) {
    422   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    423   FileSystemOperation* operation = CreateFileSystemOperationImpl(
    424       src_url, &error);
    425   if (!operation) {
    426     callback.Run(error);
    427     return kErrorOperationID;
    428   }
    429   OperationID id = operations_.Add(operation);
    430   operation->AsFileSystemOperationImpl()->MoveFileLocal(
    431       src_url, dest_url,
    432       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
    433                  id, callback));
    434   return id;
    435 }
    436 
    437 base::PlatformFileError FileSystemOperationRunner::SyncGetPlatformPath(
    438     const FileSystemURL& url,
    439     base::FilePath* platform_path) {
    440   base::PlatformFileError error = base::PLATFORM_FILE_OK;
    441   FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error);
    442   if (!operation)
    443     return error;
    444 
    445   return operation->AsFileSystemOperationImpl()->SyncGetPlatformPath(
    446       url, platform_path);
    447 }
    448 
    449 FileSystemOperationRunner::FileSystemOperationRunner(
    450     FileSystemContext* file_system_context)
    451     : file_system_context_(file_system_context) {}
    452 
    453 void FileSystemOperationRunner::DidFinish(
    454     OperationID id,
    455     const StatusCallback& callback,
    456     base::PlatformFileError rv) {
    457   callback.Run(rv);
    458   FinishOperation(id);
    459 }
    460 
    461 void FileSystemOperationRunner::DidGetMetadata(
    462     OperationID id,
    463     const GetMetadataCallback& callback,
    464     base::PlatformFileError rv,
    465     const base::PlatformFileInfo& file_info) {
    466   callback.Run(rv, file_info);
    467   FinishOperation(id);
    468 }
    469 
    470 void FileSystemOperationRunner::DidReadDirectory(
    471     OperationID id,
    472     const ReadDirectoryCallback& callback,
    473     base::PlatformFileError rv,
    474     const std::vector<DirectoryEntry>& entries,
    475     bool has_more) {
    476   callback.Run(rv, entries, has_more);
    477   if (rv != base::PLATFORM_FILE_OK || !has_more)
    478     FinishOperation(id);
    479 }
    480 
    481 void FileSystemOperationRunner::DidWrite(
    482     OperationID id,
    483     const WriteCallback& callback,
    484     base::PlatformFileError rv,
    485     int64 bytes,
    486     bool complete) {
    487   callback.Run(rv, bytes, complete);
    488   if (rv != base::PLATFORM_FILE_OK || complete)
    489     FinishOperation(id);
    490 }
    491 
    492 void FileSystemOperationRunner::DidOpenFile(
    493     OperationID id,
    494     const OpenFileCallback& callback,
    495     base::PlatformFileError rv,
    496     base::PlatformFile file,
    497     const base::Closure& on_close_callback,
    498     base::ProcessHandle peer_handle) {
    499   callback.Run(rv, file, on_close_callback, peer_handle);
    500   FinishOperation(id);
    501 }
    502 
    503 void FileSystemOperationRunner::DidCreateSnapshot(
    504     OperationID id,
    505     const SnapshotFileCallback& callback,
    506     base::PlatformFileError rv,
    507     const base::PlatformFileInfo& file_info,
    508     const base::FilePath& platform_path,
    509     const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
    510   callback.Run(rv, file_info, platform_path, file_ref);
    511   FinishOperation(id);
    512 }
    513 
    514 FileSystemOperation*
    515 FileSystemOperationRunner::CreateFileSystemOperationImpl(
    516     const FileSystemURL& url, base::PlatformFileError* error) {
    517   FileSystemOperation* operation =
    518       file_system_context_->CreateFileSystemOperation(url, error);
    519   if (!operation)
    520     return NULL;
    521   if (!operation->AsFileSystemOperationImpl()) {
    522     *error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
    523     delete operation;
    524     return NULL;
    525   }
    526   return operation;
    527 }
    528 
    529 void FileSystemOperationRunner::PrepareForWrite(OperationID id,
    530                                                 const FileSystemURL& url) {
    531   if (file_system_context_->GetUpdateObservers(url.type())) {
    532     file_system_context_->GetUpdateObservers(url.type())->Notify(
    533         &FileUpdateObserver::OnStartUpdate, MakeTuple(url));
    534   }
    535   write_target_urls_[id].insert(url);
    536 }
    537 
    538 void FileSystemOperationRunner::PrepareForRead(OperationID id,
    539                                                const FileSystemURL& url) {
    540   if (file_system_context_->GetAccessObservers(url.type())) {
    541     file_system_context_->GetAccessObservers(url.type())->Notify(
    542         &FileAccessObserver::OnAccess, MakeTuple(url));
    543   }
    544 }
    545 
    546 void FileSystemOperationRunner::FinishOperation(OperationID id) {
    547   OperationToURLSet::iterator found = write_target_urls_.find(id);
    548   if (found != write_target_urls_.end()) {
    549     const FileSystemURLSet& urls = found->second;
    550     for (FileSystemURLSet::const_iterator iter = urls.begin();
    551         iter != urls.end(); ++iter) {
    552       if (file_system_context_->GetUpdateObservers(iter->type())) {
    553         file_system_context_->GetUpdateObservers(iter->type())->Notify(
    554             &FileUpdateObserver::OnEndUpdate, MakeTuple(*iter));
    555       }
    556     }
    557     write_target_urls_.erase(found);
    558   }
    559   DCHECK(operations_.Lookup(id));
    560   operations_.Remove(id);
    561 }
    562 
    563 }  // namespace fileapi
    564