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