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