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/files/scoped_platform_file_closer.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/task_runner_util.h"
     16 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
     17 #include "content/public/browser/browser_thread.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 chrome {
     26 
     27 namespace {
     28 
     29 // Used to skip the hidden folders and files. Returns true if the file specified
     30 // by |path| should be skipped.
     31 bool ShouldSkip(const base::FilePath& path) {
     32   const base::FilePath::StringType base_name = path.BaseName().value();
     33   if (base_name.empty())
     34     return false;
     35 
     36   // Dot files (aka hidden files)
     37   if (base_name[0] == '.')
     38     return true;
     39 
     40   // Mac OS X file.
     41   if (base_name == FILE_PATH_LITERAL("__MACOSX"))
     42     return true;
     43 
     44 #if defined(OS_WIN)
     45   DWORD file_attributes = ::GetFileAttributes(path.value().c_str());
     46   if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
     47       ((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0))
     48     return true;
     49 #else
     50   // Windows always creates a recycle bin folder in the attached device to store
     51   // all the deleted contents. On non-windows operating systems, there is no way
     52   // to get the hidden attribute of windows recycle bin folders that are present
     53   // on the attached device. Therefore, compare the file path name to the
     54   // recycle bin name and exclude those folders. For more details, please refer
     55   // to http://support.microsoft.com/kb/171694.
     56   const char win_98_recycle_bin_name[] = "RECYCLED";
     57   const char win_xp_recycle_bin_name[] = "RECYCLER";
     58   const char win_vista_recycle_bin_name[] = "$Recycle.bin";
     59   if ((base::strncasecmp(base_name.c_str(),
     60                          win_98_recycle_bin_name,
     61                          strlen(win_98_recycle_bin_name)) == 0) ||
     62       (base::strncasecmp(base_name.c_str(),
     63                          win_xp_recycle_bin_name,
     64                          strlen(win_xp_recycle_bin_name)) == 0) ||
     65       (base::strncasecmp(base_name.c_str(),
     66                          win_vista_recycle_bin_name,
     67                          strlen(win_vista_recycle_bin_name)) == 0))
     68     return true;
     69 #endif
     70   return false;
     71 }
     72 
     73 // Returns true if the current thread is capable of doing IO.
     74 bool IsOnTaskRunnerThread(fileapi::FileSystemOperationContext* context) {
     75   return context->task_runner()->RunsTasksOnCurrentThread();
     76 }
     77 
     78 }  // namespace
     79 
     80 NativeMediaFileUtil::NativeMediaFileUtil(MediaPathFilter* media_path_filter)
     81     : weak_factory_(this),
     82       media_path_filter_(media_path_filter) {
     83 }
     84 
     85 NativeMediaFileUtil::~NativeMediaFileUtil() {
     86 }
     87 
     88 // static
     89 base::PlatformFileError NativeMediaFileUtil::IsMediaFile(
     90     const base::FilePath& path) {
     91   base::PlatformFile file_handle;
     92   const int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
     93   base::PlatformFileError error =
     94       fileapi::NativeFileUtil::CreateOrOpen(path, flags, &file_handle, NULL);
     95   if (error != base::PLATFORM_FILE_OK)
     96     return error;
     97 
     98   base::ScopedPlatformFileCloser scoped_platform_file(&file_handle);
     99   char buffer[net::kMaxBytesToSniff];
    100 
    101   // Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
    102   int64 len =
    103       base::ReadPlatformFile(file_handle, 0, buffer, net::kMaxBytesToSniff);
    104   if (len < 0)
    105     return base::PLATFORM_FILE_ERROR_FAILED;
    106   if (len == 0)
    107     return base::PLATFORM_FILE_ERROR_SECURITY;
    108 
    109   std::string mime_type;
    110   if (!net::SniffMimeTypeFromLocalData(buffer, len, &mime_type))
    111     return base::PLATFORM_FILE_ERROR_SECURITY;
    112 
    113   if (StartsWithASCII(mime_type, "image/", true) ||
    114       StartsWithASCII(mime_type, "audio/", true) ||
    115       StartsWithASCII(mime_type, "video/", true) ||
    116       mime_type == "application/x-shockwave-flash") {
    117     return base::PLATFORM_FILE_OK;
    118   }
    119   return base::PLATFORM_FILE_ERROR_SECURITY;
    120 }
    121 
    122 void NativeMediaFileUtil::CreateOrOpen(
    123     scoped_ptr<fileapi::FileSystemOperationContext> context,
    124     const fileapi::FileSystemURL& url,
    125     int file_flags,
    126     const CreateOrOpenCallback& callback) {
    127   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    128   // Only called by NaCl, which should not have access to media file systems.
    129   base::PlatformFile invalid_file(base::kInvalidPlatformFileValue);
    130   callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
    131                base::PassPlatformFile(&invalid_file),
    132                base::Closure());
    133 }
    134 
    135 void NativeMediaFileUtil::EnsureFileExists(
    136     scoped_ptr<fileapi::FileSystemOperationContext> context,
    137     const fileapi::FileSystemURL& url,
    138     const EnsureFileExistsCallback& callback) {
    139   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    140   callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, false);
    141 }
    142 
    143 void NativeMediaFileUtil::CreateDirectory(
    144     scoped_ptr<fileapi::FileSystemOperationContext> context,
    145     const fileapi::FileSystemURL& url,
    146     bool exclusive,
    147     bool recursive,
    148     const StatusCallback& callback) {
    149   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    150   fileapi::FileSystemOperationContext* context_ptr = context.get();
    151   const bool success = context_ptr->task_runner()->PostTask(
    152       FROM_HERE,
    153       base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread,
    154                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    155                  url, exclusive, recursive, callback));
    156   DCHECK(success);
    157 }
    158 
    159 void NativeMediaFileUtil::GetFileInfo(
    160     scoped_ptr<fileapi::FileSystemOperationContext> context,
    161     const fileapi::FileSystemURL& url,
    162     const GetFileInfoCallback& callback) {
    163   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    164   fileapi::FileSystemOperationContext* context_ptr = context.get();
    165   const bool success = context_ptr->task_runner()->PostTask(
    166       FROM_HERE,
    167       base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread,
    168                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    169                  url, callback));
    170   DCHECK(success);
    171 }
    172 
    173 void NativeMediaFileUtil::ReadDirectory(
    174     scoped_ptr<fileapi::FileSystemOperationContext> context,
    175     const fileapi::FileSystemURL& url,
    176     const ReadDirectoryCallback& callback) {
    177   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    178   fileapi::FileSystemOperationContext* context_ptr = context.get();
    179   const bool success = context_ptr->task_runner()->PostTask(
    180       FROM_HERE,
    181       base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread,
    182                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    183                  url, callback));
    184   DCHECK(success);
    185 }
    186 
    187 void NativeMediaFileUtil::Touch(
    188     scoped_ptr<fileapi::FileSystemOperationContext> context,
    189     const fileapi::FileSystemURL& url,
    190     const base::Time& last_access_time,
    191     const base::Time& last_modified_time,
    192     const StatusCallback& callback) {
    193   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    194   callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
    195 }
    196 
    197 void NativeMediaFileUtil::Truncate(
    198     scoped_ptr<fileapi::FileSystemOperationContext> context,
    199     const fileapi::FileSystemURL& url,
    200     int64 length,
    201     const StatusCallback& callback) {
    202   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    203   callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
    204 }
    205 
    206 void NativeMediaFileUtil::CopyFileLocal(
    207     scoped_ptr<fileapi::FileSystemOperationContext> context,
    208     const fileapi::FileSystemURL& src_url,
    209     const fileapi::FileSystemURL& dest_url,
    210     const StatusCallback& callback) {
    211   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    212   fileapi::FileSystemOperationContext* context_ptr = context.get();
    213   const bool success = context_ptr->task_runner()->PostTask(
    214       FROM_HERE,
    215       base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
    216                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    217                  src_url, dest_url, true /* copy */, callback));
    218   DCHECK(success);
    219 }
    220 
    221 void NativeMediaFileUtil::MoveFileLocal(
    222     scoped_ptr<fileapi::FileSystemOperationContext> context,
    223     const fileapi::FileSystemURL& src_url,
    224     const fileapi::FileSystemURL& dest_url,
    225     const StatusCallback& callback) {
    226   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    227   fileapi::FileSystemOperationContext* context_ptr = context.get();
    228   const bool success = context_ptr->task_runner()->PostTask(
    229       FROM_HERE,
    230       base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
    231                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    232                  src_url, dest_url, false /* copy */, callback));
    233   DCHECK(success);
    234 }
    235 
    236 void NativeMediaFileUtil::CopyInForeignFile(
    237     scoped_ptr<fileapi::FileSystemOperationContext> context,
    238     const base::FilePath& src_file_path,
    239     const fileapi::FileSystemURL& dest_url,
    240     const StatusCallback& callback) {
    241   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    242   fileapi::FileSystemOperationContext* context_ptr = context.get();
    243   const bool success = context_ptr->task_runner()->PostTask(
    244       FROM_HERE,
    245       base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread,
    246                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    247                  src_file_path, dest_url, callback));
    248   DCHECK(success);
    249 }
    250 
    251 void NativeMediaFileUtil::DeleteFile(
    252     scoped_ptr<fileapi::FileSystemOperationContext> context,
    253     const fileapi::FileSystemURL& url,
    254     const StatusCallback& callback) {
    255   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    256   callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
    257 }
    258 
    259 // This is needed to support Copy and Move.
    260 void NativeMediaFileUtil::DeleteDirectory(
    261     scoped_ptr<fileapi::FileSystemOperationContext> context,
    262     const fileapi::FileSystemURL& url,
    263     const StatusCallback& callback) {
    264   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    265   fileapi::FileSystemOperationContext* context_ptr = context.get();
    266   const bool success = context_ptr->task_runner()->PostTask(
    267       FROM_HERE,
    268       base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread,
    269                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    270                  url, callback));
    271   DCHECK(success);
    272 }
    273 
    274 void NativeMediaFileUtil::DeleteRecursively(
    275     scoped_ptr<fileapi::FileSystemOperationContext> context,
    276     const fileapi::FileSystemURL& url,
    277     const StatusCallback& callback) {
    278   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    279   callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
    280 }
    281 
    282 void NativeMediaFileUtil::CreateSnapshotFile(
    283     scoped_ptr<fileapi::FileSystemOperationContext> context,
    284     const fileapi::FileSystemURL& url,
    285     const CreateSnapshotFileCallback& callback) {
    286   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    287   fileapi::FileSystemOperationContext* context_ptr = context.get();
    288   const bool success = context_ptr->task_runner()->PostTask(
    289       FROM_HERE,
    290       base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread,
    291                  weak_factory_.GetWeakPtr(), base::Passed(&context),
    292                  url, callback));
    293   DCHECK(success);
    294 }
    295 
    296 void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread(
    297     scoped_ptr<fileapi::FileSystemOperationContext> context,
    298     const fileapi::FileSystemURL& url,
    299     bool exclusive,
    300     bool recursive,
    301     const StatusCallback& callback) {
    302   DCHECK(IsOnTaskRunnerThread(context.get()));
    303   base::PlatformFileError error =
    304       CreateDirectorySync(context.get(), url, exclusive, recursive);
    305   content::BrowserThread::PostTask(
    306       content::BrowserThread::IO,
    307       FROM_HERE,
    308       base::Bind(callback, error));
    309 }
    310 
    311 void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
    312     scoped_ptr<fileapi::FileSystemOperationContext> context,
    313     const fileapi::FileSystemURL& url,
    314     const GetFileInfoCallback& callback) {
    315   DCHECK(IsOnTaskRunnerThread(context.get()));
    316   base::PlatformFileInfo file_info;
    317   base::PlatformFileError error =
    318       GetFileInfoSync(context.get(), url, &file_info, NULL);
    319   content::BrowserThread::PostTask(
    320       content::BrowserThread::IO,
    321       FROM_HERE,
    322       base::Bind(callback, error, file_info));
    323 }
    324 
    325 void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
    326     scoped_ptr<fileapi::FileSystemOperationContext> context,
    327     const fileapi::FileSystemURL& url,
    328     const ReadDirectoryCallback& callback) {
    329   DCHECK(IsOnTaskRunnerThread(context.get()));
    330   EntryList entry_list;
    331   base::PlatformFileError error =
    332       ReadDirectorySync(context.get(), url, &entry_list);
    333   content::BrowserThread::PostTask(
    334       content::BrowserThread::IO,
    335       FROM_HERE,
    336       base::Bind(callback, error, entry_list, false /* has_more */));
    337 }
    338 
    339 void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread(
    340     scoped_ptr<fileapi::FileSystemOperationContext> context,
    341     const fileapi::FileSystemURL& src_url,
    342     const fileapi::FileSystemURL& dest_url,
    343     bool copy,
    344     const StatusCallback& callback) {
    345   DCHECK(IsOnTaskRunnerThread(context.get()));
    346   base::PlatformFileError error =
    347       CopyOrMoveFileSync(context.get(), src_url, dest_url, copy);
    348   content::BrowserThread::PostTask(
    349       content::BrowserThread::IO,
    350       FROM_HERE,
    351       base::Bind(callback, error));
    352 }
    353 
    354 void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread(
    355     scoped_ptr<fileapi::FileSystemOperationContext> context,
    356     const base::FilePath& src_file_path,
    357     const fileapi::FileSystemURL& dest_url,
    358     const StatusCallback& callback) {
    359   DCHECK(IsOnTaskRunnerThread(context.get()));
    360   base::PlatformFileError error =
    361       CopyInForeignFileSync(context.get(), src_file_path, dest_url);
    362   content::BrowserThread::PostTask(
    363       content::BrowserThread::IO,
    364       FROM_HERE,
    365       base::Bind(callback, error));
    366 }
    367 
    368 void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread(
    369     scoped_ptr<fileapi::FileSystemOperationContext> context,
    370     const fileapi::FileSystemURL& url,
    371     const StatusCallback& callback) {
    372   DCHECK(IsOnTaskRunnerThread(context.get()));
    373   base::PlatformFileError error = DeleteDirectorySync(context.get(), url);
    374   content::BrowserThread::PostTask(
    375       content::BrowserThread::IO,
    376       FROM_HERE,
    377       base::Bind(callback, error));
    378 }
    379 
    380 void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(
    381     scoped_ptr<fileapi::FileSystemOperationContext> context,
    382     const fileapi::FileSystemURL& url,
    383     const CreateSnapshotFileCallback& callback) {
    384   DCHECK(IsOnTaskRunnerThread(context.get()));
    385   base::PlatformFileInfo file_info;
    386   base::FilePath platform_path;
    387   scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
    388   base::PlatformFileError error =
    389       CreateSnapshotFileSync(context.get(), url, &file_info, &platform_path,
    390                              &file_ref);
    391   content::BrowserThread::PostTask(
    392       content::BrowserThread::IO,
    393       FROM_HERE,
    394       base::Bind(callback, error, file_info, platform_path, file_ref));
    395 }
    396 
    397 base::PlatformFileError NativeMediaFileUtil::CreateDirectorySync(
    398     fileapi::FileSystemOperationContext* context,
    399     const fileapi::FileSystemURL& url,
    400     bool exclusive,
    401     bool recursive) {
    402   base::FilePath file_path;
    403   base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
    404   if (error != base::PLATFORM_FILE_OK)
    405     return error;
    406   return fileapi::NativeFileUtil::CreateDirectory(file_path, exclusive,
    407                                                   recursive);
    408 }
    409 
    410 base::PlatformFileError NativeMediaFileUtil::CopyOrMoveFileSync(
    411     fileapi::FileSystemOperationContext* context,
    412     const fileapi::FileSystemURL& src_url,
    413     const fileapi::FileSystemURL& dest_url,
    414     bool copy) {
    415   DCHECK(IsOnTaskRunnerThread(context));
    416   base::FilePath src_file_path;
    417   base::PlatformFileError error =
    418       GetFilteredLocalFilePathForExistingFileOrDirectory(
    419           context, src_url,
    420           base::PLATFORM_FILE_ERROR_NOT_FOUND,
    421           &src_file_path);
    422   if (error != base::PLATFORM_FILE_OK)
    423     return error;
    424   if (fileapi::NativeFileUtil::DirectoryExists(src_file_path))
    425     return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
    426 
    427   base::FilePath dest_file_path;
    428   error = GetLocalFilePath(context, dest_url, &dest_file_path);
    429   if (error != base::PLATFORM_FILE_OK)
    430     return error;
    431   base::PlatformFileInfo file_info;
    432   error = fileapi::NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
    433   if (error != base::PLATFORM_FILE_OK &&
    434       error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
    435     return error;
    436   if (error == base::PLATFORM_FILE_OK && file_info.is_directory)
    437     return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
    438   if (!media_path_filter_->Match(dest_file_path))
    439     return base::PLATFORM_FILE_ERROR_SECURITY;
    440 
    441   return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path,
    442                                                  copy);
    443 }
    444 
    445 base::PlatformFileError NativeMediaFileUtil::CopyInForeignFileSync(
    446     fileapi::FileSystemOperationContext* context,
    447     const base::FilePath& src_file_path,
    448     const fileapi::FileSystemURL& dest_url) {
    449   DCHECK(IsOnTaskRunnerThread(context));
    450   if (src_file_path.empty())
    451     return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
    452 
    453   base::FilePath dest_file_path;
    454   base::PlatformFileError error =
    455       GetFilteredLocalFilePath(context, dest_url, &dest_file_path);
    456   if (error != base::PLATFORM_FILE_OK)
    457     return error;
    458   return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path,
    459                                                  true);
    460 }
    461 
    462 base::PlatformFileError NativeMediaFileUtil::GetFileInfoSync(
    463     fileapi::FileSystemOperationContext* context,
    464     const fileapi::FileSystemURL& url,
    465     base::PlatformFileInfo* file_info,
    466     base::FilePath* platform_path) {
    467   DCHECK(context);
    468   DCHECK(IsOnTaskRunnerThread(context));
    469   DCHECK(file_info);
    470 
    471   base::FilePath file_path;
    472   base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
    473   if (error != base::PLATFORM_FILE_OK)
    474     return error;
    475   if (file_util::IsLink(file_path))
    476     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    477   error = fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
    478   if (error != base::PLATFORM_FILE_OK)
    479     return error;
    480 
    481   if (platform_path)
    482     *platform_path = file_path;
    483   if (file_info->is_directory ||
    484       media_path_filter_->Match(file_path)) {
    485     return base::PLATFORM_FILE_OK;
    486   }
    487   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    488 }
    489 
    490 base::PlatformFileError NativeMediaFileUtil::GetLocalFilePath(
    491     fileapi::FileSystemOperationContext* context,
    492     const fileapi::FileSystemURL& url,
    493     base::FilePath* local_file_path) {
    494   DCHECK(local_file_path);
    495   DCHECK(url.is_valid());
    496   if (url.path().empty()) {
    497     // Root direcory case, which should not be accessed.
    498     return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    499   }
    500   *local_file_path = url.path();
    501   return base::PLATFORM_FILE_OK;
    502 }
    503 
    504 base::PlatformFileError NativeMediaFileUtil::ReadDirectorySync(
    505       fileapi::FileSystemOperationContext* context,
    506       const fileapi::FileSystemURL& url,
    507       EntryList* file_list) {
    508   DCHECK(IsOnTaskRunnerThread(context));
    509   DCHECK(file_list);
    510   DCHECK(file_list->empty());
    511   base::PlatformFileInfo file_info;
    512   base::FilePath dir_path;
    513   base::PlatformFileError error =
    514       GetFileInfoSync(context, url, &file_info, &dir_path);
    515 
    516   if (error != base::PLATFORM_FILE_OK)
    517     return error;
    518 
    519   if (!file_info.is_directory)
    520     return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
    521 
    522   base::FileEnumerator file_enum(
    523       dir_path,
    524       false /* recursive */,
    525       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
    526   for (base::FilePath enum_path = file_enum.Next();
    527        !enum_path.empty();
    528        enum_path = file_enum.Next()) {
    529     // Skip symlinks.
    530     if (file_util::IsLink(enum_path))
    531       continue;
    532 
    533     base::FileEnumerator::FileInfo info = file_enum.GetInfo();
    534 
    535     // NativeMediaFileUtil skip criteria.
    536     if (ShouldSkip(enum_path))
    537       continue;
    538     if (!info.IsDirectory() && !media_path_filter_->Match(enum_path))
    539       continue;
    540 
    541     fileapi::DirectoryEntry entry;
    542     entry.is_directory = info.IsDirectory();
    543     entry.name = enum_path.BaseName().value();
    544     entry.size = info.GetSize();
    545     entry.last_modified_time = info.GetLastModifiedTime();
    546 
    547     file_list->push_back(entry);
    548   }
    549 
    550   return base::PLATFORM_FILE_OK;
    551 }
    552 
    553 base::PlatformFileError NativeMediaFileUtil::DeleteDirectorySync(
    554     fileapi::FileSystemOperationContext* context,
    555     const fileapi::FileSystemURL& url) {
    556   DCHECK(IsOnTaskRunnerThread(context));
    557   base::FilePath file_path;
    558   base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
    559   if (error != base::PLATFORM_FILE_OK)
    560     return error;
    561   return fileapi::NativeFileUtil::DeleteDirectory(file_path);
    562 }
    563 
    564 base::PlatformFileError NativeMediaFileUtil::CreateSnapshotFileSync(
    565     fileapi::FileSystemOperationContext* context,
    566     const fileapi::FileSystemURL& url,
    567     base::PlatformFileInfo* file_info,
    568     base::FilePath* platform_path,
    569     scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
    570   DCHECK(IsOnTaskRunnerThread(context));
    571   base::PlatformFileError error =
    572       GetFileInfoSync(context, url, file_info, platform_path);
    573   if (error == base::PLATFORM_FILE_OK && file_info->is_directory)
    574     error = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
    575   if (error == base::PLATFORM_FILE_OK)
    576     error = NativeMediaFileUtil::IsMediaFile(*platform_path);
    577 
    578   // We're just returning the local file information.
    579   *file_ref = scoped_refptr<webkit_blob::ShareableFileReference>();
    580 
    581   return error;
    582 }
    583 
    584 base::PlatformFileError NativeMediaFileUtil::GetFilteredLocalFilePath(
    585     fileapi::FileSystemOperationContext* context,
    586     const fileapi::FileSystemURL& file_system_url,
    587     base::FilePath* local_file_path) {
    588   DCHECK(IsOnTaskRunnerThread(context));
    589   base::FilePath file_path;
    590   base::PlatformFileError error =
    591       GetLocalFilePath(context, file_system_url, &file_path);
    592   if (error != base::PLATFORM_FILE_OK)
    593     return error;
    594   if (!media_path_filter_->Match(file_path))
    595     return base::PLATFORM_FILE_ERROR_SECURITY;
    596 
    597   *local_file_path = file_path;
    598   return base::PLATFORM_FILE_OK;
    599 }
    600 
    601 base::PlatformFileError
    602 NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory(
    603     fileapi::FileSystemOperationContext* context,
    604     const fileapi::FileSystemURL& file_system_url,
    605     base::PlatformFileError failure_error,
    606     base::FilePath* local_file_path) {
    607   DCHECK(IsOnTaskRunnerThread(context));
    608   base::FilePath file_path;
    609   base::PlatformFileError error =
    610       GetLocalFilePath(context, file_system_url, &file_path);
    611   if (error != base::PLATFORM_FILE_OK)
    612     return error;
    613 
    614   if (!base::PathExists(file_path))
    615     return failure_error;
    616   base::PlatformFileInfo file_info;
    617   if (!file_util::GetFileInfo(file_path, &file_info))
    618     return base::PLATFORM_FILE_ERROR_FAILED;
    619 
    620   if (!file_info.is_directory &&
    621       !media_path_filter_->Match(file_path)) {
    622     return failure_error;
    623   }
    624 
    625   *local_file_path = file_path;
    626   return base::PLATFORM_FILE_OK;
    627 }
    628 
    629 }  // namespace chrome
    630