Home | History | Annotate | Download | only in fileapi
      1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/files/file.h"
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
     12 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "storage/browser/fileapi/file_system_operation_context.h"
     15 #include "storage/browser/fileapi/file_system_url.h"
     16 #include "storage/common/blob/shareable_file_reference.h"
     17 
     18 using content::BrowserThread;
     19 
     20 namespace chromeos {
     21 namespace file_system_provider {
     22 namespace internal {
     23 namespace {
     24 
     25 // Executes GetFileInfo on the UI thread.
     26 void GetFileInfoOnUIThread(
     27     scoped_ptr<storage::FileSystemOperationContext> context,
     28     const storage::FileSystemURL& url,
     29     const ProvidedFileSystemInterface::GetMetadataCallback& callback) {
     30   util::FileSystemURLParser parser(url);
     31   if (!parser.Parse()) {
     32     callback.Run(make_scoped_ptr<EntryMetadata>(NULL),
     33                  base::File::FILE_ERROR_INVALID_OPERATION);
     34     return;
     35   }
     36 
     37   parser.file_system()->GetMetadata(
     38       parser.file_path(),
     39       ProvidedFileSystemInterface::METADATA_FIELD_DEFAULT,
     40       callback);
     41 }
     42 
     43 // Routes the response of GetFileInfo back to the IO thread with a type
     44 // conversion.
     45 void OnGetFileInfo(const storage::AsyncFileUtil::GetFileInfoCallback& callback,
     46                    scoped_ptr<EntryMetadata> metadata,
     47                    base::File::Error result) {
     48   if (result != base::File::FILE_OK) {
     49     BrowserThread::PostTask(BrowserThread::IO,
     50                             FROM_HERE,
     51                             base::Bind(callback, result, base::File::Info()));
     52     return;
     53   }
     54 
     55   DCHECK(metadata.get());
     56   base::File::Info file_info;
     57 
     58   // TODO(mtomasz): Add support for last modified time and creation time.
     59   // See: crbug.com/388540.
     60   file_info.size = metadata->size;
     61   file_info.is_directory = metadata->is_directory;
     62   file_info.is_symbolic_link = false;  // Not supported.
     63   file_info.last_modified = metadata->modification_time;
     64   file_info.last_accessed = metadata->modification_time;  // Not supported.
     65   file_info.creation_time = metadata->modification_time;  // Not supported.
     66 
     67   BrowserThread::PostTask(BrowserThread::IO,
     68                           FROM_HERE,
     69                           base::Bind(callback, base::File::FILE_OK, file_info));
     70 }
     71 
     72 // Executes ReadDirectory on the UI thread.
     73 void ReadDirectoryOnUIThread(
     74     scoped_ptr<storage::FileSystemOperationContext> context,
     75     const storage::FileSystemURL& url,
     76     const storage::AsyncFileUtil::ReadDirectoryCallback& callback) {
     77   util::FileSystemURLParser parser(url);
     78   if (!parser.Parse()) {
     79     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION,
     80                  storage::AsyncFileUtil::EntryList(),
     81                  false /* has_more */);
     82     return;
     83   }
     84 
     85   parser.file_system()->ReadDirectory(parser.file_path(), callback);
     86 }
     87 
     88 // Routes the response of ReadDirectory back to the IO thread.
     89 void OnReadDirectory(
     90     const storage::AsyncFileUtil::ReadDirectoryCallback& callback,
     91     base::File::Error result,
     92     const storage::AsyncFileUtil::EntryList& entry_list,
     93     bool has_more) {
     94   BrowserThread::PostTask(BrowserThread::IO,
     95                           FROM_HERE,
     96                           base::Bind(callback, result, entry_list, has_more));
     97 }
     98 
     99 // Executes CreateDirectory on the UI thread.
    100 void CreateDirectoryOnUIThread(
    101     scoped_ptr<storage::FileSystemOperationContext> context,
    102     const storage::FileSystemURL& url,
    103     bool exclusive,
    104     bool recursive,
    105     const storage::AsyncFileUtil::StatusCallback& callback) {
    106   util::FileSystemURLParser parser(url);
    107   if (!parser.Parse()) {
    108     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    109     return;
    110   }
    111 
    112   parser.file_system()->CreateDirectory(
    113       parser.file_path(), recursive, callback);
    114 }
    115 
    116 // Routes the response of CreateDirectory back to the IO thread.
    117 void OnCreateDirectory(bool exclusive,
    118                        const storage::AsyncFileUtil::StatusCallback& callback,
    119                        base::File::Error result) {
    120   // If the directory already existed and the operation wasn't exclusive, then
    121   // return success anyway, since it is not an error.
    122   const base::File::Error error =
    123       (result == base::File::FILE_ERROR_EXISTS && !exclusive)
    124           ? base::File::FILE_OK
    125           : result;
    126 
    127   BrowserThread::PostTask(
    128       BrowserThread::IO, FROM_HERE, base::Bind(callback, error));
    129 }
    130 
    131 // Executes DeleteEntry on the UI thread.
    132 void DeleteEntryOnUIThread(
    133     scoped_ptr<storage::FileSystemOperationContext> context,
    134     const storage::FileSystemURL& url,
    135     bool recursive,
    136     const storage::AsyncFileUtil::StatusCallback& callback) {
    137   util::FileSystemURLParser parser(url);
    138   if (!parser.Parse()) {
    139     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    140     return;
    141   }
    142 
    143   parser.file_system()->DeleteEntry(parser.file_path(), recursive, callback);
    144 }
    145 
    146 // Routes the response of DeleteEntry back to the IO thread.
    147 void OnDeleteEntry(const storage::AsyncFileUtil::StatusCallback& callback,
    148                    base::File::Error result) {
    149   BrowserThread::PostTask(
    150       BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
    151 }
    152 
    153 // Executes CreateFile on the UI thread.
    154 void CreateFileOnUIThread(
    155     scoped_ptr<storage::FileSystemOperationContext> context,
    156     const storage::FileSystemURL& url,
    157     const storage::AsyncFileUtil::StatusCallback& callback) {
    158   util::FileSystemURLParser parser(url);
    159   if (!parser.Parse()) {
    160     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    161     return;
    162   }
    163 
    164   parser.file_system()->CreateFile(parser.file_path(), callback);
    165 }
    166 
    167 // Routes the response of CreateFile to a callback of EnsureFileExists() on the
    168 // IO thread.
    169 void OnCreateFileForEnsureFileExists(
    170     const storage::AsyncFileUtil::EnsureFileExistsCallback& callback,
    171     base::File::Error result) {
    172   const bool created = result == base::File::FILE_OK;
    173 
    174   // If the file already existed, then return success anyway, since it is not
    175   // an error.
    176   const base::File::Error error =
    177       result == base::File::FILE_ERROR_EXISTS ? base::File::FILE_OK : result;
    178 
    179   BrowserThread::PostTask(
    180       BrowserThread::IO, FROM_HERE, base::Bind(callback, error, created));
    181 }
    182 
    183 // Executes CopyEntry on the UI thread.
    184 void CopyEntryOnUIThread(
    185     scoped_ptr<storage::FileSystemOperationContext> context,
    186     const storage::FileSystemURL& source_url,
    187     const storage::FileSystemURL& target_url,
    188     const storage::AsyncFileUtil::StatusCallback& callback) {
    189   util::FileSystemURLParser source_parser(source_url);
    190   util::FileSystemURLParser target_parser(target_url);
    191 
    192   if (!source_parser.Parse() || !target_parser.Parse() ||
    193       source_parser.file_system() != target_parser.file_system()) {
    194     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    195     return;
    196   }
    197 
    198   target_parser.file_system()->CopyEntry(
    199       source_parser.file_path(), target_parser.file_path(), callback);
    200 }
    201 
    202 // Routes the response of CopyEntry to a callback of CopyLocalFile() on the
    203 // IO thread.
    204 void OnCopyEntry(const storage::AsyncFileUtil::StatusCallback& callback,
    205                  base::File::Error result) {
    206   BrowserThread::PostTask(
    207       BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
    208 }
    209 
    210 // Executes MoveEntry on the UI thread.
    211 void MoveEntryOnUIThread(
    212     scoped_ptr<storage::FileSystemOperationContext> context,
    213     const storage::FileSystemURL& source_url,
    214     const storage::FileSystemURL& target_url,
    215     const storage::AsyncFileUtil::StatusCallback& callback) {
    216   util::FileSystemURLParser source_parser(source_url);
    217   util::FileSystemURLParser target_parser(target_url);
    218 
    219   if (!source_parser.Parse() || !target_parser.Parse() ||
    220       source_parser.file_system() != target_parser.file_system()) {
    221     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    222     return;
    223   }
    224 
    225   target_parser.file_system()->MoveEntry(
    226       source_parser.file_path(), target_parser.file_path(), callback);
    227 }
    228 
    229 // Routes the response of CopyEntry to a callback of MoveLocalFile() on the
    230 // IO thread.
    231 void OnMoveEntry(const storage::AsyncFileUtil::StatusCallback& callback,
    232                  base::File::Error result) {
    233   BrowserThread::PostTask(
    234       BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
    235 }
    236 
    237 // Executes Truncate on the UI thread.
    238 void TruncateOnUIThread(
    239     scoped_ptr<storage::FileSystemOperationContext> context,
    240     const storage::FileSystemURL& url,
    241     int64 length,
    242     const storage::AsyncFileUtil::StatusCallback& callback) {
    243   util::FileSystemURLParser parser(url);
    244   if (!parser.Parse()) {
    245     callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    246     return;
    247   }
    248 
    249   parser.file_system()->Truncate(parser.file_path(), length, callback);
    250 }
    251 
    252 // Routes the response of Truncate back to the IO thread.
    253 void OnTruncate(const storage::AsyncFileUtil::StatusCallback& callback,
    254                 base::File::Error result) {
    255   BrowserThread::PostTask(
    256       BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
    257 }
    258 
    259 }  // namespace
    260 
    261 ProviderAsyncFileUtil::ProviderAsyncFileUtil() {}
    262 
    263 ProviderAsyncFileUtil::~ProviderAsyncFileUtil() {}
    264 
    265 void ProviderAsyncFileUtil::CreateOrOpen(
    266     scoped_ptr<storage::FileSystemOperationContext> context,
    267     const storage::FileSystemURL& url,
    268     int file_flags,
    269     const CreateOrOpenCallback& callback) {
    270   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    271   if ((file_flags & base::File::FLAG_CREATE) ||
    272       (file_flags & base::File::FLAG_OPEN_ALWAYS) ||
    273       (file_flags & base::File::FLAG_CREATE_ALWAYS) ||
    274       (file_flags & base::File::FLAG_OPEN_TRUNCATED)) {
    275     callback.Run(base::File(base::File::FILE_ERROR_ACCESS_DENIED),
    276                  base::Closure());
    277     return;
    278   }
    279 
    280   NOTIMPLEMENTED();
    281   callback.Run(base::File(base::File::FILE_ERROR_INVALID_OPERATION),
    282                base::Closure());
    283 }
    284 
    285 void ProviderAsyncFileUtil::EnsureFileExists(
    286     scoped_ptr<storage::FileSystemOperationContext> context,
    287     const storage::FileSystemURL& url,
    288     const EnsureFileExistsCallback& callback) {
    289   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    290   BrowserThread::PostTask(
    291       BrowserThread::UI,
    292       FROM_HERE,
    293       base::Bind(&CreateFileOnUIThread,
    294                  base::Passed(&context),
    295                  url,
    296                  base::Bind(&OnCreateFileForEnsureFileExists, callback)));
    297 }
    298 
    299 void ProviderAsyncFileUtil::CreateDirectory(
    300     scoped_ptr<storage::FileSystemOperationContext> context,
    301     const storage::FileSystemURL& url,
    302     bool exclusive,
    303     bool recursive,
    304     const StatusCallback& callback) {
    305   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    306   BrowserThread::PostTask(
    307       BrowserThread::UI,
    308       FROM_HERE,
    309       base::Bind(&CreateDirectoryOnUIThread,
    310                  base::Passed(&context),
    311                  url,
    312                  exclusive,
    313                  recursive,
    314                  base::Bind(&OnCreateDirectory, exclusive, callback)));
    315 }
    316 
    317 void ProviderAsyncFileUtil::GetFileInfo(
    318     scoped_ptr<storage::FileSystemOperationContext> context,
    319     const storage::FileSystemURL& url,
    320     const GetFileInfoCallback& callback) {
    321   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    322   BrowserThread::PostTask(BrowserThread::UI,
    323                           FROM_HERE,
    324                           base::Bind(&GetFileInfoOnUIThread,
    325                                      base::Passed(&context),
    326                                      url,
    327                                      base::Bind(&OnGetFileInfo, callback)));
    328 }
    329 
    330 void ProviderAsyncFileUtil::ReadDirectory(
    331     scoped_ptr<storage::FileSystemOperationContext> context,
    332     const storage::FileSystemURL& url,
    333     const ReadDirectoryCallback& callback) {
    334   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    335   BrowserThread::PostTask(BrowserThread::UI,
    336                           FROM_HERE,
    337                           base::Bind(&ReadDirectoryOnUIThread,
    338                                      base::Passed(&context),
    339                                      url,
    340                                      base::Bind(&OnReadDirectory, callback)));
    341 }
    342 
    343 void ProviderAsyncFileUtil::Touch(
    344     scoped_ptr<storage::FileSystemOperationContext> context,
    345     const storage::FileSystemURL& url,
    346     const base::Time& last_access_time,
    347     const base::Time& last_modified_time,
    348     const StatusCallback& callback) {
    349   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    350   callback.Run(base::File::FILE_ERROR_ACCESS_DENIED);
    351 }
    352 
    353 void ProviderAsyncFileUtil::Truncate(
    354     scoped_ptr<storage::FileSystemOperationContext> context,
    355     const storage::FileSystemURL& url,
    356     int64 length,
    357     const StatusCallback& callback) {
    358   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    359   BrowserThread::PostTask(BrowserThread::UI,
    360                           FROM_HERE,
    361                           base::Bind(&TruncateOnUIThread,
    362                                      base::Passed(&context),
    363                                      url,
    364                                      length,
    365                                      base::Bind(&OnTruncate, callback)));
    366 }
    367 
    368 void ProviderAsyncFileUtil::CopyFileLocal(
    369     scoped_ptr<storage::FileSystemOperationContext> context,
    370     const storage::FileSystemURL& src_url,
    371     const storage::FileSystemURL& dest_url,
    372     CopyOrMoveOption option,
    373     const CopyFileProgressCallback& progress_callback,
    374     const StatusCallback& callback) {
    375   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    376   // TODO(mtomasz): Consier adding support for options (preserving last modified
    377   // time) as well as the progress callback.
    378   BrowserThread::PostTask(BrowserThread::UI,
    379                           FROM_HERE,
    380                           base::Bind(&CopyEntryOnUIThread,
    381                                      base::Passed(&context),
    382                                      src_url,
    383                                      dest_url,
    384                                      base::Bind(&OnCopyEntry, callback)));
    385 }
    386 
    387 void ProviderAsyncFileUtil::MoveFileLocal(
    388     scoped_ptr<storage::FileSystemOperationContext> context,
    389     const storage::FileSystemURL& src_url,
    390     const storage::FileSystemURL& dest_url,
    391     CopyOrMoveOption option,
    392     const StatusCallback& callback) {
    393   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    394   // TODO(mtomasz): Consier adding support for options (preserving last modified
    395   // time) as well as the progress callback.
    396   BrowserThread::PostTask(BrowserThread::UI,
    397                           FROM_HERE,
    398                           base::Bind(&MoveEntryOnUIThread,
    399                                      base::Passed(&context),
    400                                      src_url,
    401                                      dest_url,
    402                                      base::Bind(&OnMoveEntry, callback)));
    403 }
    404 
    405 void ProviderAsyncFileUtil::CopyInForeignFile(
    406     scoped_ptr<storage::FileSystemOperationContext> context,
    407     const base::FilePath& src_file_path,
    408     const storage::FileSystemURL& dest_url,
    409     const StatusCallback& callback) {
    410   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    411   callback.Run(base::File::FILE_ERROR_ACCESS_DENIED);
    412 }
    413 
    414 void ProviderAsyncFileUtil::DeleteFile(
    415     scoped_ptr<storage::FileSystemOperationContext> context,
    416     const storage::FileSystemURL& url,
    417     const StatusCallback& callback) {
    418   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    419   BrowserThread::PostTask(BrowserThread::UI,
    420                           FROM_HERE,
    421                           base::Bind(&DeleteEntryOnUIThread,
    422                                      base::Passed(&context),
    423                                      url,
    424                                      false,  // recursive
    425                                      base::Bind(&OnDeleteEntry, callback)));
    426 }
    427 
    428 void ProviderAsyncFileUtil::DeleteDirectory(
    429     scoped_ptr<storage::FileSystemOperationContext> context,
    430     const storage::FileSystemURL& url,
    431     const StatusCallback& callback) {
    432   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    433   BrowserThread::PostTask(BrowserThread::UI,
    434                           FROM_HERE,
    435                           base::Bind(&DeleteEntryOnUIThread,
    436                                      base::Passed(&context),
    437                                      url,
    438                                      false,  // recursive
    439                                      base::Bind(&OnDeleteEntry, callback)));
    440 }
    441 
    442 void ProviderAsyncFileUtil::DeleteRecursively(
    443     scoped_ptr<storage::FileSystemOperationContext> context,
    444     const storage::FileSystemURL& url,
    445     const StatusCallback& callback) {
    446   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    447   BrowserThread::PostTask(BrowserThread::UI,
    448                           FROM_HERE,
    449                           base::Bind(&DeleteEntryOnUIThread,
    450                                      base::Passed(&context),
    451                                      url,
    452                                      true,  // recursive
    453                                      base::Bind(&OnDeleteEntry, callback)));
    454 }
    455 
    456 void ProviderAsyncFileUtil::CreateSnapshotFile(
    457     scoped_ptr<storage::FileSystemOperationContext> context,
    458     const storage::FileSystemURL& url,
    459     const CreateSnapshotFileCallback& callback) {
    460   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    461   NOTIMPLEMENTED();
    462   callback.Run(base::File::FILE_ERROR_INVALID_OPERATION,
    463                base::File::Info(),
    464                base::FilePath(),
    465                scoped_refptr<storage::ShareableFileReference>());
    466 }
    467 
    468 }  // namespace internal
    469 }  // namespace file_system_provider
    470 }  // namespace chromeos
    471