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