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