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.
5 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.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"
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"
27 // Used to skip the hidden folders and files. Returns true if the file specified
28 // by |path| should be skipped.
29 bool ShouldSkip(const base::FilePath& path) {
30 const base::FilePath::StringType base_name = path.BaseName().value();
31 if (base_name.empty())
34 // Dot files (aka hidden files)
35 if (base_name[0] == '.')
39 if (base_name == FILE_PATH_LITERAL("__MACOSX"))
43 DWORD file_attributes = ::GetFileAttributes(path.value().c_str());
44 if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
45 ((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0))
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))
71 // Returns true if the current thread is capable of doing IO.
72 bool IsOnTaskRunnerThread(fileapi::FileSystemOperationContext* context) {
73 return context->task_runner()->RunsTasksOnCurrentThread();
78 NativeMediaFileUtil::NativeMediaFileUtil(MediaPathFilter* media_path_filter)
79 : media_path_filter_(media_path_filter),
83 NativeMediaFileUtil::~NativeMediaFileUtil() {
87 base::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)
96 base::ScopedPlatformFileCloser scoped_platform_file(&file_handle);
97 char buffer[net::kMaxBytesToSniff];
99 // Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
101 base::ReadPlatformFile(file_handle, 0, buffer, net::kMaxBytesToSniff);
103 return base::PLATFORM_FILE_ERROR_FAILED;
105 return base::PLATFORM_FILE_ERROR_SECURITY;
107 std::string mime_type;
108 if (!net::SniffMimeTypeFromLocalData(buffer, len, &mime_type))
109 return base::PLATFORM_FILE_ERROR_SECURITY;
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;
117 return base::PLATFORM_FILE_ERROR_SECURITY;
120 void NativeMediaFileUtil::CreateOrOpen(
121 scoped_ptr<fileapi::FileSystemOperationContext> context,
122 const fileapi::FileSystemURL& url,
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),
133 void 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);
141 void NativeMediaFileUtil::CreateDirectory(
142 scoped_ptr<fileapi::FileSystemOperationContext> context,
143 const fileapi::FileSystemURL& url,
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(
151 base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread,
152 weak_factory_.GetWeakPtr(), base::Passed(&context),
153 url, exclusive, recursive, callback));
157 void 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(
165 base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread,
166 weak_factory_.GetWeakPtr(), base::Passed(&context),
171 void 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(
179 base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread,
180 weak_factory_.GetWeakPtr(), base::Passed(&context),
185 void 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);
195 void NativeMediaFileUtil::Truncate(
196 scoped_ptr<fileapi::FileSystemOperationContext> context,
197 const fileapi::FileSystemURL& url,
199 const StatusCallback& callback) {
200 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
201 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
204 void NativeMediaFileUtil::CopyFileLocal(
205 scoped_ptr<fileapi::FileSystemOperationContext> context,
206 const fileapi::FileSystemURL& src_url,
207 const fileapi::FileSystemURL& dest_url,
208 CopyOrMoveOption option,
209 const CopyFileProgressCallback& progress_callback,
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(
215 base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
216 weak_factory_.GetWeakPtr(), base::Passed(&context),
217 src_url, dest_url, option, true /* copy */, callback));
221 void NativeMediaFileUtil::MoveFileLocal(
222 scoped_ptr<fileapi::FileSystemOperationContext> context,
223 const fileapi::FileSystemURL& src_url,
224 const fileapi::FileSystemURL& dest_url,
225 CopyOrMoveOption option,
226 const StatusCallback& callback) {
227 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
228 fileapi::FileSystemOperationContext* context_ptr = context.get();
229 const bool success = context_ptr->task_runner()->PostTask(
231 base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
232 weak_factory_.GetWeakPtr(), base::Passed(&context),
233 src_url, dest_url, option, false /* copy */, callback));
237 void NativeMediaFileUtil::CopyInForeignFile(
238 scoped_ptr<fileapi::FileSystemOperationContext> context,
239 const base::FilePath& src_file_path,
240 const fileapi::FileSystemURL& dest_url,
241 const StatusCallback& callback) {
242 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
243 fileapi::FileSystemOperationContext* context_ptr = context.get();
244 const bool success = context_ptr->task_runner()->PostTask(
246 base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread,
247 weak_factory_.GetWeakPtr(), base::Passed(&context),
248 src_file_path, dest_url, callback));
252 void NativeMediaFileUtil::DeleteFile(
253 scoped_ptr<fileapi::FileSystemOperationContext> context,
254 const fileapi::FileSystemURL& url,
255 const StatusCallback& callback) {
256 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
257 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
260 // This is needed to support Copy and Move.
261 void NativeMediaFileUtil::DeleteDirectory(
262 scoped_ptr<fileapi::FileSystemOperationContext> context,
263 const fileapi::FileSystemURL& url,
264 const StatusCallback& callback) {
265 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
266 fileapi::FileSystemOperationContext* context_ptr = context.get();
267 const bool success = context_ptr->task_runner()->PostTask(
269 base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread,
270 weak_factory_.GetWeakPtr(), base::Passed(&context),
275 void NativeMediaFileUtil::DeleteRecursively(
276 scoped_ptr<fileapi::FileSystemOperationContext> context,
277 const fileapi::FileSystemURL& url,
278 const StatusCallback& callback) {
279 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
280 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
283 void NativeMediaFileUtil::CreateSnapshotFile(
284 scoped_ptr<fileapi::FileSystemOperationContext> context,
285 const fileapi::FileSystemURL& url,
286 const CreateSnapshotFileCallback& callback) {
287 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
288 fileapi::FileSystemOperationContext* context_ptr = context.get();
289 const bool success = context_ptr->task_runner()->PostTask(
291 base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread,
292 weak_factory_.GetWeakPtr(), base::Passed(&context),
297 void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread(
298 scoped_ptr<fileapi::FileSystemOperationContext> context,
299 const fileapi::FileSystemURL& url,
302 const StatusCallback& callback) {
303 DCHECK(IsOnTaskRunnerThread(context.get()));
304 base::PlatformFileError error =
305 CreateDirectorySync(context.get(), url, exclusive, recursive);
306 content::BrowserThread::PostTask(
307 content::BrowserThread::IO,
309 base::Bind(callback, error));
312 void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
313 scoped_ptr<fileapi::FileSystemOperationContext> context,
314 const fileapi::FileSystemURL& url,
315 const GetFileInfoCallback& callback) {
316 DCHECK(IsOnTaskRunnerThread(context.get()));
317 base::PlatformFileInfo file_info;
318 base::PlatformFileError error =
319 GetFileInfoSync(context.get(), url, &file_info, NULL);
320 content::BrowserThread::PostTask(
321 content::BrowserThread::IO,
323 base::Bind(callback, error, file_info));
326 void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
327 scoped_ptr<fileapi::FileSystemOperationContext> context,
328 const fileapi::FileSystemURL& url,
329 const ReadDirectoryCallback& callback) {
330 DCHECK(IsOnTaskRunnerThread(context.get()));
331 EntryList entry_list;
332 base::PlatformFileError error =
333 ReadDirectorySync(context.get(), url, &entry_list);
334 content::BrowserThread::PostTask(
335 content::BrowserThread::IO,
337 base::Bind(callback, error, entry_list, false /* has_more */));
340 void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread(
341 scoped_ptr<fileapi::FileSystemOperationContext> context,
342 const fileapi::FileSystemURL& src_url,
343 const fileapi::FileSystemURL& dest_url,
344 CopyOrMoveOption option,
346 const StatusCallback& callback) {
347 DCHECK(IsOnTaskRunnerThread(context.get()));
348 base::PlatformFileError error =
349 CopyOrMoveFileSync(context.get(), src_url, dest_url, option, copy);
350 content::BrowserThread::PostTask(
351 content::BrowserThread::IO,
353 base::Bind(callback, error));
356 void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread(
357 scoped_ptr<fileapi::FileSystemOperationContext> context,
358 const base::FilePath& src_file_path,
359 const fileapi::FileSystemURL& dest_url,
360 const StatusCallback& callback) {
361 DCHECK(IsOnTaskRunnerThread(context.get()));
362 base::PlatformFileError error =
363 CopyInForeignFileSync(context.get(), src_file_path, dest_url);
364 content::BrowserThread::PostTask(
365 content::BrowserThread::IO,
367 base::Bind(callback, error));
370 void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread(
371 scoped_ptr<fileapi::FileSystemOperationContext> context,
372 const fileapi::FileSystemURL& url,
373 const StatusCallback& callback) {
374 DCHECK(IsOnTaskRunnerThread(context.get()));
375 base::PlatformFileError error = DeleteDirectorySync(context.get(), url);
376 content::BrowserThread::PostTask(
377 content::BrowserThread::IO,
379 base::Bind(callback, error));
382 void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(
383 scoped_ptr<fileapi::FileSystemOperationContext> context,
384 const fileapi::FileSystemURL& url,
385 const CreateSnapshotFileCallback& callback) {
386 DCHECK(IsOnTaskRunnerThread(context.get()));
387 base::PlatformFileInfo file_info;
388 base::FilePath platform_path;
389 scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
390 base::PlatformFileError error =
391 CreateSnapshotFileSync(context.get(), url, &file_info, &platform_path,
393 content::BrowserThread::PostTask(
394 content::BrowserThread::IO,
396 base::Bind(callback, error, file_info, platform_path, file_ref));
399 base::PlatformFileError NativeMediaFileUtil::CreateDirectorySync(
400 fileapi::FileSystemOperationContext* context,
401 const fileapi::FileSystemURL& url,
404 base::FilePath file_path;
405 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
406 if (error != base::PLATFORM_FILE_OK)
408 return fileapi::NativeFileUtil::CreateDirectory(file_path, exclusive,
412 base::PlatformFileError NativeMediaFileUtil::CopyOrMoveFileSync(
413 fileapi::FileSystemOperationContext* context,
414 const fileapi::FileSystemURL& src_url,
415 const fileapi::FileSystemURL& dest_url,
416 CopyOrMoveOption option,
418 DCHECK(IsOnTaskRunnerThread(context));
419 base::FilePath src_file_path;
420 base::PlatformFileError error =
421 GetFilteredLocalFilePathForExistingFileOrDirectory(
423 base::PLATFORM_FILE_ERROR_NOT_FOUND,
425 if (error != base::PLATFORM_FILE_OK)
427 if (fileapi::NativeFileUtil::DirectoryExists(src_file_path))
428 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
430 base::FilePath dest_file_path;
431 error = GetLocalFilePath(context, dest_url, &dest_file_path);
432 if (error != base::PLATFORM_FILE_OK)
434 base::PlatformFileInfo file_info;
435 error = fileapi::NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
436 if (error != base::PLATFORM_FILE_OK &&
437 error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
439 if (error == base::PLATFORM_FILE_OK && file_info.is_directory)
440 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
441 if (!media_path_filter_->Match(dest_file_path))
442 return base::PLATFORM_FILE_ERROR_SECURITY;
444 return fileapi::NativeFileUtil::CopyOrMoveFile(
445 src_file_path, dest_file_path, option, copy);
448 base::PlatformFileError NativeMediaFileUtil::CopyInForeignFileSync(
449 fileapi::FileSystemOperationContext* context,
450 const base::FilePath& src_file_path,
451 const fileapi::FileSystemURL& dest_url) {
452 DCHECK(IsOnTaskRunnerThread(context));
453 if (src_file_path.empty())
454 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
456 base::FilePath dest_file_path;
457 base::PlatformFileError error =
458 GetFilteredLocalFilePath(context, dest_url, &dest_file_path);
459 if (error != base::PLATFORM_FILE_OK)
461 return fileapi::NativeFileUtil::CopyOrMoveFile(
462 src_file_path, dest_file_path,
463 fileapi::FileSystemOperation::OPTION_NONE, true);
466 base::PlatformFileError NativeMediaFileUtil::GetFileInfoSync(
467 fileapi::FileSystemOperationContext* context,
468 const fileapi::FileSystemURL& url,
469 base::PlatformFileInfo* file_info,
470 base::FilePath* platform_path) {
472 DCHECK(IsOnTaskRunnerThread(context));
475 base::FilePath file_path;
476 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
477 if (error != base::PLATFORM_FILE_OK)
479 if (file_util::IsLink(file_path))
480 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
481 error = fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
482 if (error != base::PLATFORM_FILE_OK)
486 *platform_path = file_path;
487 if (file_info->is_directory ||
488 media_path_filter_->Match(file_path)) {
489 return base::PLATFORM_FILE_OK;
491 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
494 base::PlatformFileError NativeMediaFileUtil::GetLocalFilePath(
495 fileapi::FileSystemOperationContext* context,
496 const fileapi::FileSystemURL& url,
497 base::FilePath* local_file_path) {
498 DCHECK(local_file_path);
499 DCHECK(url.is_valid());
500 if (url.path().empty()) {
501 // Root direcory case, which should not be accessed.
502 return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
504 *local_file_path = url.path();
505 return base::PLATFORM_FILE_OK;
508 base::PlatformFileError NativeMediaFileUtil::ReadDirectorySync(
509 fileapi::FileSystemOperationContext* context,
510 const fileapi::FileSystemURL& url,
511 EntryList* file_list) {
512 DCHECK(IsOnTaskRunnerThread(context));
514 DCHECK(file_list->empty());
515 base::PlatformFileInfo file_info;
516 base::FilePath dir_path;
517 base::PlatformFileError error =
518 GetFileInfoSync(context, url, &file_info, &dir_path);
520 if (error != base::PLATFORM_FILE_OK)
523 if (!file_info.is_directory)
524 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
526 base::FileEnumerator file_enum(
528 false /* recursive */,
529 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
530 for (base::FilePath enum_path = file_enum.Next();
532 enum_path = file_enum.Next()) {
534 if (file_util::IsLink(enum_path))
537 base::FileEnumerator::FileInfo info = file_enum.GetInfo();
539 // NativeMediaFileUtil skip criteria.
540 if (ShouldSkip(enum_path))
542 if (!info.IsDirectory() && !media_path_filter_->Match(enum_path))
545 fileapi::DirectoryEntry entry;
546 entry.is_directory = info.IsDirectory();
547 entry.name = enum_path.BaseName().value();
548 entry.size = info.GetSize();
549 entry.last_modified_time = info.GetLastModifiedTime();
551 file_list->push_back(entry);
554 return base::PLATFORM_FILE_OK;
557 base::PlatformFileError NativeMediaFileUtil::DeleteDirectorySync(
558 fileapi::FileSystemOperationContext* context,
559 const fileapi::FileSystemURL& url) {
560 DCHECK(IsOnTaskRunnerThread(context));
561 base::FilePath file_path;
562 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
563 if (error != base::PLATFORM_FILE_OK)
565 return fileapi::NativeFileUtil::DeleteDirectory(file_path);
568 base::PlatformFileError NativeMediaFileUtil::CreateSnapshotFileSync(
569 fileapi::FileSystemOperationContext* context,
570 const fileapi::FileSystemURL& url,
571 base::PlatformFileInfo* file_info,
572 base::FilePath* platform_path,
573 scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
574 DCHECK(IsOnTaskRunnerThread(context));
575 base::PlatformFileError error =
576 GetFileInfoSync(context, url, file_info, platform_path);
577 if (error == base::PLATFORM_FILE_OK && file_info->is_directory)
578 error = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
579 if (error == base::PLATFORM_FILE_OK)
580 error = NativeMediaFileUtil::IsMediaFile(*platform_path);
582 // We're just returning the local file information.
583 *file_ref = scoped_refptr<webkit_blob::ShareableFileReference>();
588 base::PlatformFileError NativeMediaFileUtil::GetFilteredLocalFilePath(
589 fileapi::FileSystemOperationContext* context,
590 const fileapi::FileSystemURL& file_system_url,
591 base::FilePath* local_file_path) {
592 DCHECK(IsOnTaskRunnerThread(context));
593 base::FilePath file_path;
594 base::PlatformFileError error =
595 GetLocalFilePath(context, file_system_url, &file_path);
596 if (error != base::PLATFORM_FILE_OK)
598 if (!media_path_filter_->Match(file_path))
599 return base::PLATFORM_FILE_ERROR_SECURITY;
601 *local_file_path = file_path;
602 return base::PLATFORM_FILE_OK;
605 base::PlatformFileError
606 NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory(
607 fileapi::FileSystemOperationContext* context,
608 const fileapi::FileSystemURL& file_system_url,
609 base::PlatformFileError failure_error,
610 base::FilePath* local_file_path) {
611 DCHECK(IsOnTaskRunnerThread(context));
612 base::FilePath file_path;
613 base::PlatformFileError error =
614 GetLocalFilePath(context, file_system_url, &file_path);
615 if (error != base::PLATFORM_FILE_OK)
618 if (!base::PathExists(file_path))
619 return failure_error;
620 base::PlatformFileInfo file_info;
621 if (!file_util::GetFileInfo(file_path, &file_info))
622 return base::PLATFORM_FILE_ERROR_FAILED;
624 if (!file_info.is_directory &&
625 !media_path_filter_->Match(file_path)) {
626 return failure_error;
629 *local_file_path = file_path;
630 return base::PLATFORM_FILE_OK;