Home | History | Annotate | Download | only in fileapi
      1 // Copyright (c) 2012 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/media_galleries/fileapi/native_media_file_util.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/files/file_enumerator.h"
     12 #include "base/files/file_util.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/task_runner_util.h"
     15 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "net/base/io_buffer.h"
     18 #include "net/base/mime_sniffer.h"
     19 #include "storage/browser/fileapi/file_system_context.h"
     20 #include "storage/browser/fileapi/file_system_operation_context.h"
     21 #include "storage/browser/fileapi/native_file_util.h"
     22 #include "storage/common/blob/shareable_file_reference.h"
     23 #include "url/gurl.h"
     24 
     25 namespace {
     26 
     27 // Returns true if the current thread is capable of doing IO.
     28 bool IsOnTaskRunnerThread(storage::FileSystemOperationContext* context) {
     29   return context->task_runner()->RunsTasksOnCurrentThread();
     30 }
     31 
     32 base::File::Error IsMediaHeader(const char* buf, size_t length) {
     33   if (length == 0)
     34     return base::File::FILE_ERROR_SECURITY;
     35 
     36   std::string mime_type;
     37   if (!net::SniffMimeTypeFromLocalData(buf, length, &mime_type))
     38     return base::File::FILE_ERROR_SECURITY;
     39 
     40   if (StartsWithASCII(mime_type, "image/", true) ||
     41       StartsWithASCII(mime_type, "audio/", true) ||
     42       StartsWithASCII(mime_type, "video/", true) ||
     43       mime_type == "application/x-shockwave-flash") {
     44     return base::File::FILE_OK;
     45   }
     46   return base::File::FILE_ERROR_SECURITY;
     47 }
     48 
     49 void HoldFileRef(
     50     const scoped_refptr<storage::ShareableFileReference>& file_ref) {
     51 }
     52 
     53 void DidOpenSnapshot(
     54     const storage::AsyncFileUtil::CreateOrOpenCallback& callback,
     55     const scoped_refptr<storage::ShareableFileReference>& file_ref,
     56     base::File file) {
     57   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
     58   if (!file.IsValid()) {
     59     callback.Run(file.Pass(), base::Closure());
     60     return;
     61   }
     62   callback.Run(file.Pass(), base::Bind(&HoldFileRef, file_ref));
     63 }
     64 
     65 }  // namespace
     66 
     67 NativeMediaFileUtil::NativeMediaFileUtil(MediaPathFilter* media_path_filter)
     68     : media_path_filter_(media_path_filter),
     69       weak_factory_(this) {
     70 }
     71 
     72 NativeMediaFileUtil::~NativeMediaFileUtil() {
     73 }
     74 
     75 // static
     76 base::File::Error NativeMediaFileUtil::IsMediaFile(
     77     const base::FilePath& path) {
     78   base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
     79   if (!file.IsValid())
     80     return file.error_details();
     81 
     82   char buffer[net::kMaxBytesToSniff];
     83 
     84   // Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
     85   int64 len = file.Read(0, buffer, net::kMaxBytesToSniff);
     86   if (len < 0)
     87     return base::File::FILE_ERROR_FAILED;
     88 
     89   return IsMediaHeader(buffer, len);
     90 }
     91 
     92 // static
     93 base::File::Error NativeMediaFileUtil::BufferIsMediaHeader(
     94     net::IOBuffer* buf, size_t length) {
     95   return IsMediaHeader(buf->data(), length);
     96 }
     97 
     98 // static
     99 void NativeMediaFileUtil::CreatedSnapshotFileForCreateOrOpen(
    100     base::SequencedTaskRunner* media_task_runner,
    101     int file_flags,
    102     const storage::AsyncFileUtil::CreateOrOpenCallback& callback,
    103     base::File::Error result,
    104     const base::File::Info& file_info,
    105     const base::FilePath& platform_path,
    106     const scoped_refptr<storage::ShareableFileReference>& file_ref) {
    107   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    108   if (result != base::File::FILE_OK) {
    109     callback.Run(base::File(), base::Closure());
    110     return;
    111   }
    112   base::PostTaskAndReplyWithResult(
    113       media_task_runner,
    114       FROM_HERE,
    115       base::Bind(
    116           &storage::NativeFileUtil::CreateOrOpen, platform_path, file_flags),
    117       base::Bind(&DidOpenSnapshot, callback, file_ref));
    118 }
    119 
    120 void NativeMediaFileUtil::CreateOrOpen(
    121     scoped_ptr<storage::FileSystemOperationContext> context,
    122     const storage::FileSystemURL& url,
    123     int file_flags,
    124     const CreateOrOpenCallback& callback) {
    125   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    126   // Returns an error if any unsupported flag is found.
    127   if (file_flags & ~(base::File::FLAG_OPEN |
    128                      base::File::FLAG_READ |
    129                      base::File::FLAG_WRITE_ATTRIBUTES)) {
    130     callback.Run(base::File(base::File::FILE_ERROR_SECURITY), base::Closure());
    131     return;
    132   }
    133   scoped_refptr<base::SequencedTaskRunner> task_runner = context->task_runner();
    134   CreateSnapshotFile(
    135       context.Pass(),
    136       url,
    137       base::Bind(&NativeMediaFileUtil::CreatedSnapshotFileForCreateOrOpen,
    138                  task_runner,
    139                  file_flags,
    140                  callback));
    141 }
    142 
    143 void NativeMediaFileUtil::EnsureFileExists(
    144     scoped_ptr<storage::FileSystemOperationContext> context,
    145     const storage::FileSystemURL& url,
    146     const EnsureFileExistsCallback& callback) {
    147   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    148   callback.Run(base::File::FILE_ERROR_SECURITY, false);
    149 }
    150 
    151 void NativeMediaFileUtil::CreateDirectory(
    152     scoped_ptr<storage::FileSystemOperationContext> context,
    153     const storage::FileSystemURL& url,
    154     bool exclusive,
    155     bool recursive,
    156     const StatusCallback& callback) {
    157   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    158   storage::FileSystemOperationContext* context_ptr = context.get();
    159   const bool success = context_ptr->task_runner()->PostTask(
    160       FROM_HERE,
    161       base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread,
    162                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    163                  url, exclusive, recursive, callback));
    164   DCHECK(success);
    165 }
    166 
    167 void NativeMediaFileUtil::GetFileInfo(
    168     scoped_ptr<storage::FileSystemOperationContext> context,
    169     const storage::FileSystemURL& url,
    170     const GetFileInfoCallback& callback) {
    171   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    172   storage::FileSystemOperationContext* context_ptr = context.get();
    173   const bool success = context_ptr->task_runner()->PostTask(
    174       FROM_HERE,
    175       base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread,
    176                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    177                  url, callback));
    178   DCHECK(success);
    179 }
    180 
    181 void NativeMediaFileUtil::ReadDirectory(
    182     scoped_ptr<storage::FileSystemOperationContext> context,
    183     const storage::FileSystemURL& url,
    184     const ReadDirectoryCallback& callback) {
    185   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    186   storage::FileSystemOperationContext* context_ptr = context.get();
    187   const bool success = context_ptr->task_runner()->PostTask(
    188       FROM_HERE,
    189       base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread,
    190                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    191                  url, callback));
    192   DCHECK(success);
    193 }
    194 
    195 void NativeMediaFileUtil::Touch(
    196     scoped_ptr<storage::FileSystemOperationContext> context,
    197     const storage::FileSystemURL& url,
    198     const base::Time& last_access_time,
    199     const base::Time& last_modified_time,
    200     const StatusCallback& callback) {
    201   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    202   callback.Run(base::File::FILE_ERROR_SECURITY);
    203 }
    204 
    205 void NativeMediaFileUtil::Truncate(
    206     scoped_ptr<storage::FileSystemOperationContext> context,
    207     const storage::FileSystemURL& url,
    208     int64 length,
    209     const StatusCallback& callback) {
    210   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    211   callback.Run(base::File::FILE_ERROR_SECURITY);
    212 }
    213 
    214 void NativeMediaFileUtil::CopyFileLocal(
    215     scoped_ptr<storage::FileSystemOperationContext> context,
    216     const storage::FileSystemURL& src_url,
    217     const storage::FileSystemURL& dest_url,
    218     CopyOrMoveOption option,
    219     const CopyFileProgressCallback& progress_callback,
    220     const StatusCallback& callback) {
    221   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    222   storage::FileSystemOperationContext* context_ptr = context.get();
    223   const bool success = context_ptr->task_runner()->PostTask(
    224       FROM_HERE,
    225       base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
    226                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    227                  src_url, dest_url, option, true /* copy */, callback));
    228   DCHECK(success);
    229 }
    230 
    231 void NativeMediaFileUtil::MoveFileLocal(
    232     scoped_ptr<storage::FileSystemOperationContext> context,
    233     const storage::FileSystemURL& src_url,
    234     const storage::FileSystemURL& dest_url,
    235     CopyOrMoveOption option,
    236     const StatusCallback& callback) {
    237   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    238   storage::FileSystemOperationContext* context_ptr = context.get();
    239   const bool success = context_ptr->task_runner()->PostTask(
    240       FROM_HERE,
    241       base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
    242                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    243                  src_url, dest_url, option, false /* copy */, callback));
    244   DCHECK(success);
    245 }
    246 
    247 void NativeMediaFileUtil::CopyInForeignFile(
    248     scoped_ptr<storage::FileSystemOperationContext> context,
    249     const base::FilePath& src_file_path,
    250     const storage::FileSystemURL& dest_url,
    251     const StatusCallback& callback) {
    252   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    253   storage::FileSystemOperationContext* context_ptr = context.get();
    254   const bool success = context_ptr->task_runner()->PostTask(
    255       FROM_HERE,
    256       base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread,
    257                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    258                  src_file_path, dest_url, callback));
    259   DCHECK(success);
    260 }
    261 
    262 void NativeMediaFileUtil::DeleteFile(
    263     scoped_ptr<storage::FileSystemOperationContext> context,
    264     const storage::FileSystemURL& url,
    265     const StatusCallback& callback) {
    266   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    267   storage::FileSystemOperationContext* context_ptr = context.get();
    268   const bool success = context_ptr->task_runner()->PostTask(
    269       FROM_HERE,
    270       base::Bind(&NativeMediaFileUtil::DeleteFileOnTaskRunnerThread,
    271                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    272                  url, callback));
    273   DCHECK(success);
    274 }
    275 
    276 // This is needed to support Copy and Move.
    277 void NativeMediaFileUtil::DeleteDirectory(
    278     scoped_ptr<storage::FileSystemOperationContext> context,
    279     const storage::FileSystemURL& url,
    280     const StatusCallback& callback) {
    281   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    282   storage::FileSystemOperationContext* context_ptr = context.get();
    283   const bool success = context_ptr->task_runner()->PostTask(
    284       FROM_HERE,
    285       base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread,
    286                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    287                  url, callback));
    288   DCHECK(success);
    289 }
    290 
    291 void NativeMediaFileUtil::DeleteRecursively(
    292     scoped_ptr<storage::FileSystemOperationContext> context,
    293     const storage::FileSystemURL& url,
    294     const StatusCallback& callback) {
    295   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    296   callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
    297 }
    298 
    299 void NativeMediaFileUtil::CreateSnapshotFile(
    300     scoped_ptr<storage::FileSystemOperationContext> context,
    301     const storage::FileSystemURL& url,
    302     const CreateSnapshotFileCallback& callback) {
    303   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
    304   storage::FileSystemOperationContext* context_ptr = context.get();
    305   const bool success = context_ptr->task_runner()->PostTask(
    306       FROM_HERE,
    307       base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread,
    308                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    309                  url, callback));
    310   DCHECK(success);
    311 }
    312 
    313 void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread(
    314     scoped_ptr<storage::FileSystemOperationContext> context,
    315     const storage::FileSystemURL& url,
    316     bool exclusive,
    317     bool recursive,
    318     const StatusCallback& callback) {
    319   DCHECK(IsOnTaskRunnerThread(context.get()));
    320   base::File::Error error =
    321       CreateDirectorySync(context.get(), url, exclusive, recursive);
    322   content::BrowserThread::PostTask(
    323       content::BrowserThread::IO,
    324       FROM_HERE,
    325       base::Bind(callback, error));
    326 }
    327 
    328 void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
    329     scoped_ptr<storage::FileSystemOperationContext> context,
    330     const storage::FileSystemURL& url,
    331     const GetFileInfoCallback& callback) {
    332   DCHECK(IsOnTaskRunnerThread(context.get()));
    333   base::File::Info file_info;
    334   base::File::Error error =
    335       GetFileInfoSync(context.get(), url, &file_info, NULL);
    336   content::BrowserThread::PostTask(
    337       content::BrowserThread::IO,
    338       FROM_HERE,
    339       base::Bind(callback, error, file_info));
    340 }
    341 
    342 void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
    343     scoped_ptr<storage::FileSystemOperationContext> context,
    344     const storage::FileSystemURL& url,
    345     const ReadDirectoryCallback& callback) {
    346   DCHECK(IsOnTaskRunnerThread(context.get()));
    347   EntryList entry_list;
    348   base::File::Error error =
    349       ReadDirectorySync(context.get(), url, &entry_list);
    350   content::BrowserThread::PostTask(
    351       content::BrowserThread::IO,
    352       FROM_HERE,
    353       base::Bind(callback, error, entry_list, false /* has_more */));
    354 }
    355 
    356 void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread(
    357     scoped_ptr<storage::FileSystemOperationContext> context,
    358     const storage::FileSystemURL& src_url,
    359     const storage::FileSystemURL& dest_url,
    360     CopyOrMoveOption option,
    361     bool copy,
    362     const StatusCallback& callback) {
    363   DCHECK(IsOnTaskRunnerThread(context.get()));
    364   base::File::Error error =
    365       CopyOrMoveFileSync(context.get(), src_url, dest_url, option, copy);
    366   content::BrowserThread::PostTask(
    367       content::BrowserThread::IO,
    368       FROM_HERE,
    369       base::Bind(callback, error));
    370 }
    371 
    372 void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread(
    373     scoped_ptr<storage::FileSystemOperationContext> context,
    374     const base::FilePath& src_file_path,
    375     const storage::FileSystemURL& dest_url,
    376     const StatusCallback& callback) {
    377   DCHECK(IsOnTaskRunnerThread(context.get()));
    378   base::File::Error error =
    379       CopyInForeignFileSync(context.get(), src_file_path, dest_url);
    380   content::BrowserThread::PostTask(
    381       content::BrowserThread::IO,
    382       FROM_HERE,
    383       base::Bind(callback, error));
    384 }
    385 
    386 void NativeMediaFileUtil::DeleteFileOnTaskRunnerThread(
    387     scoped_ptr<storage::FileSystemOperationContext> context,
    388     const storage::FileSystemURL& url,
    389     const StatusCallback& callback) {
    390   DCHECK(IsOnTaskRunnerThread(context.get()));
    391   base::File::Error error = DeleteFileSync(context.get(), url);
    392   content::BrowserThread::PostTask(
    393       content::BrowserThread::IO,
    394       FROM_HERE,
    395       base::Bind(callback, error));
    396 }
    397 
    398 void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread(
    399     scoped_ptr<storage::FileSystemOperationContext> context,
    400     const storage::FileSystemURL& url,
    401     const StatusCallback& callback) {
    402   DCHECK(IsOnTaskRunnerThread(context.get()));
    403   base::File::Error error = DeleteDirectorySync(context.get(), url);
    404   content::BrowserThread::PostTask(
    405       content::BrowserThread::IO,
    406       FROM_HERE,
    407       base::Bind(callback, error));
    408 }
    409 
    410 void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(
    411     scoped_ptr<storage::FileSystemOperationContext> context,
    412     const storage::FileSystemURL& url,
    413     const CreateSnapshotFileCallback& callback) {
    414   DCHECK(IsOnTaskRunnerThread(context.get()));
    415   base::File::Info file_info;
    416   base::FilePath platform_path;
    417   scoped_refptr<storage::ShareableFileReference> file_ref;
    418   base::File::Error error = CreateSnapshotFileSync(
    419       context.get(), url, &file_info, &platform_path, &file_ref);
    420   content::BrowserThread::PostTask(
    421       content::BrowserThread::IO,
    422       FROM_HERE,
    423       base::Bind(callback, error, file_info, platform_path, file_ref));
    424 }
    425 
    426 base::File::Error NativeMediaFileUtil::CreateDirectorySync(
    427     storage::FileSystemOperationContext* context,
    428     const storage::FileSystemURL& url,
    429     bool exclusive,
    430     bool recursive) {
    431   base::FilePath file_path;
    432   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    433   if (error != base::File::FILE_OK)
    434     return error;
    435   return storage::NativeFileUtil::CreateDirectory(
    436       file_path, exclusive, recursive);
    437 }
    438 
    439 base::File::Error NativeMediaFileUtil::CopyOrMoveFileSync(
    440     storage::FileSystemOperationContext* context,
    441     const storage::FileSystemURL& src_url,
    442     const storage::FileSystemURL& dest_url,
    443     CopyOrMoveOption option,
    444     bool copy) {
    445   DCHECK(IsOnTaskRunnerThread(context));
    446   base::FilePath src_file_path;
    447   base::File::Error error =
    448       GetFilteredLocalFilePathForExistingFileOrDirectory(
    449           context, src_url,
    450           base::File::FILE_ERROR_NOT_FOUND,
    451           &src_file_path);
    452   if (error != base::File::FILE_OK)
    453     return error;
    454   if (storage::NativeFileUtil::DirectoryExists(src_file_path))
    455     return base::File::FILE_ERROR_NOT_A_FILE;
    456 
    457   base::FilePath dest_file_path;
    458   error = GetLocalFilePath(context, dest_url, &dest_file_path);
    459   if (error != base::File::FILE_OK)
    460     return error;
    461   base::File::Info file_info;
    462   error = storage::NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
    463   if (error != base::File::FILE_OK &&
    464       error != base::File::FILE_ERROR_NOT_FOUND) {
    465     return error;
    466   }
    467   if (error == base::File::FILE_OK && file_info.is_directory)
    468     return base::File::FILE_ERROR_INVALID_OPERATION;
    469   if (!media_path_filter_->Match(dest_file_path))
    470     return base::File::FILE_ERROR_SECURITY;
    471 
    472   return storage::NativeFileUtil::CopyOrMoveFile(
    473       src_file_path,
    474       dest_file_path,
    475       option,
    476       storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url, copy));
    477 }
    478 
    479 base::File::Error NativeMediaFileUtil::CopyInForeignFileSync(
    480     storage::FileSystemOperationContext* context,
    481     const base::FilePath& src_file_path,
    482     const storage::FileSystemURL& dest_url) {
    483   DCHECK(IsOnTaskRunnerThread(context));
    484   if (src_file_path.empty())
    485     return base::File::FILE_ERROR_INVALID_OPERATION;
    486 
    487   base::FilePath dest_file_path;
    488   base::File::Error error =
    489       GetFilteredLocalFilePath(context, dest_url, &dest_file_path);
    490   if (error != base::File::FILE_OK)
    491     return error;
    492   return storage::NativeFileUtil::CopyOrMoveFile(
    493       src_file_path,
    494       dest_file_path,
    495       storage::FileSystemOperation::OPTION_NONE,
    496       storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url,
    497                                                             true /* copy */));
    498 }
    499 
    500 base::File::Error NativeMediaFileUtil::GetFileInfoSync(
    501     storage::FileSystemOperationContext* context,
    502     const storage::FileSystemURL& url,
    503     base::File::Info* file_info,
    504     base::FilePath* platform_path) {
    505   DCHECK(context);
    506   DCHECK(IsOnTaskRunnerThread(context));
    507   DCHECK(file_info);
    508 
    509   base::FilePath file_path;
    510   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    511   if (error != base::File::FILE_OK)
    512     return error;
    513   if (base::IsLink(file_path))
    514     return base::File::FILE_ERROR_NOT_FOUND;
    515   error = storage::NativeFileUtil::GetFileInfo(file_path, file_info);
    516   if (error != base::File::FILE_OK)
    517     return error;
    518 
    519   if (platform_path)
    520     *platform_path = file_path;
    521   if (file_info->is_directory ||
    522       media_path_filter_->Match(file_path)) {
    523     return base::File::FILE_OK;
    524   }
    525   return base::File::FILE_ERROR_NOT_FOUND;
    526 }
    527 
    528 base::File::Error NativeMediaFileUtil::GetLocalFilePath(
    529     storage::FileSystemOperationContext* context,
    530     const storage::FileSystemURL& url,
    531     base::FilePath* local_file_path) {
    532   DCHECK(local_file_path);
    533   DCHECK(url.is_valid());
    534   if (url.path().empty()) {
    535     // Root direcory case, which should not be accessed.
    536     return base::File::FILE_ERROR_ACCESS_DENIED;
    537   }
    538   *local_file_path = url.path();
    539   return base::File::FILE_OK;
    540 }
    541 
    542 base::File::Error NativeMediaFileUtil::ReadDirectorySync(
    543     storage::FileSystemOperationContext* context,
    544     const storage::FileSystemURL& url,
    545     EntryList* file_list) {
    546   DCHECK(IsOnTaskRunnerThread(context));
    547   DCHECK(file_list);
    548   DCHECK(file_list->empty());
    549   base::File::Info file_info;
    550   base::FilePath dir_path;
    551   base::File::Error error =
    552       GetFileInfoSync(context, url, &file_info, &dir_path);
    553 
    554   if (error != base::File::FILE_OK)
    555     return error;
    556 
    557   if (!file_info.is_directory)
    558     return base::File::FILE_ERROR_NOT_A_DIRECTORY;
    559 
    560   base::FileEnumerator file_enum(
    561       dir_path,
    562       false /* recursive */,
    563       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
    564   for (base::FilePath enum_path = file_enum.Next();
    565        !enum_path.empty();
    566        enum_path = file_enum.Next()) {
    567     // Skip symlinks.
    568     if (base::IsLink(enum_path))
    569       continue;
    570 
    571     base::FileEnumerator::FileInfo info = file_enum.GetInfo();
    572 
    573     // NativeMediaFileUtil skip criteria.
    574     if (MediaPathFilter::ShouldSkip(enum_path))
    575       continue;
    576     if (!info.IsDirectory() && !media_path_filter_->Match(enum_path))
    577       continue;
    578 
    579     storage::DirectoryEntry entry;
    580     entry.is_directory = info.IsDirectory();
    581     entry.name = enum_path.BaseName().value();
    582     entry.size = info.GetSize();
    583     entry.last_modified_time = info.GetLastModifiedTime();
    584 
    585     file_list->push_back(entry);
    586   }
    587 
    588   return base::File::FILE_OK;
    589 }
    590 
    591 base::File::Error NativeMediaFileUtil::DeleteFileSync(
    592     storage::FileSystemOperationContext* context,
    593     const storage::FileSystemURL& url) {
    594   DCHECK(IsOnTaskRunnerThread(context));
    595   base::File::Info file_info;
    596   base::FilePath file_path;
    597   base::File::Error error =
    598       GetFileInfoSync(context, url, &file_info, &file_path);
    599   if (error != base::File::FILE_OK)
    600     return error;
    601   if (file_info.is_directory)
    602     return base::File::FILE_ERROR_NOT_A_FILE;
    603   return storage::NativeFileUtil::DeleteFile(file_path);
    604 }
    605 
    606 base::File::Error NativeMediaFileUtil::DeleteDirectorySync(
    607     storage::FileSystemOperationContext* context,
    608     const storage::FileSystemURL& url) {
    609   DCHECK(IsOnTaskRunnerThread(context));
    610   base::FilePath file_path;
    611   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    612   if (error != base::File::FILE_OK)
    613     return error;
    614   return storage::NativeFileUtil::DeleteDirectory(file_path);
    615 }
    616 
    617 base::File::Error NativeMediaFileUtil::CreateSnapshotFileSync(
    618     storage::FileSystemOperationContext* context,
    619     const storage::FileSystemURL& url,
    620     base::File::Info* file_info,
    621     base::FilePath* platform_path,
    622     scoped_refptr<storage::ShareableFileReference>* file_ref) {
    623   DCHECK(IsOnTaskRunnerThread(context));
    624   base::File::Error error =
    625       GetFileInfoSync(context, url, file_info, platform_path);
    626   if (error == base::File::FILE_OK && file_info->is_directory)
    627     error = base::File::FILE_ERROR_NOT_A_FILE;
    628   if (error == base::File::FILE_OK)
    629     error = NativeMediaFileUtil::IsMediaFile(*platform_path);
    630 
    631   // We're just returning the local file information.
    632   *file_ref = scoped_refptr<storage::ShareableFileReference>();
    633 
    634   return error;
    635 }
    636 
    637 base::File::Error NativeMediaFileUtil::GetFilteredLocalFilePath(
    638     storage::FileSystemOperationContext* context,
    639     const storage::FileSystemURL& file_system_url,
    640     base::FilePath* local_file_path) {
    641   DCHECK(IsOnTaskRunnerThread(context));
    642   base::FilePath file_path;
    643   base::File::Error error =
    644       GetLocalFilePath(context, file_system_url, &file_path);
    645   if (error != base::File::FILE_OK)
    646     return error;
    647   if (!media_path_filter_->Match(file_path))
    648     return base::File::FILE_ERROR_SECURITY;
    649 
    650   *local_file_path = file_path;
    651   return base::File::FILE_OK;
    652 }
    653 
    654 base::File::Error
    655 NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory(
    656     storage::FileSystemOperationContext* context,
    657     const storage::FileSystemURL& file_system_url,
    658     base::File::Error failure_error,
    659     base::FilePath* local_file_path) {
    660   DCHECK(IsOnTaskRunnerThread(context));
    661   base::FilePath file_path;
    662   base::File::Error error =
    663       GetLocalFilePath(context, file_system_url, &file_path);
    664   if (error != base::File::FILE_OK)
    665     return error;
    666 
    667   if (!base::PathExists(file_path))
    668     return failure_error;
    669   base::File::Info file_info;
    670   if (!base::GetFileInfo(file_path, &file_info))
    671     return base::File::FILE_ERROR_FAILED;
    672 
    673   if (!file_info.is_directory &&
    674       !media_path_filter_->Match(file_path)) {
    675     return failure_error;
    676   }
    677 
    678   *local_file_path = file_path;
    679   return base::File::FILE_OK;
    680 }
    681