blob: ae3b06f26105961a6d651681024e53d2d5fb4975 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
#include <string>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/scoped_platform_file_closer.h"
#include "base/strings/string_util.h"
#include "base/task_runner_util.h"
#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/mime_sniffer.h"
#include "url/gurl.h"
#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/native_file_util.h"
#include "webkit/common/blob/shareable_file_reference.h"
namespace {
// Used to skip the hidden folders and files. Returns true if the file specified
// by |path| should be skipped.
bool ShouldSkip(const base::FilePath& path) {
const base::FilePath::StringType base_name = path.BaseName().value();
if (base_name.empty())
return false;
// Dot files (aka hidden files)
if (base_name[0] == '.')
return true;
// Mac OS X file.
if (base_name == FILE_PATH_LITERAL("__MACOSX"))
return true;
#if defined(OS_WIN)
DWORD file_attributes = ::GetFileAttributes(path.value().c_str());
if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0))
return true;
#else
// Windows always creates a recycle bin folder in the attached device to store
// all the deleted contents. On non-windows operating systems, there is no way
// to get the hidden attribute of windows recycle bin folders that are present
// on the attached device. Therefore, compare the file path name to the
// recycle bin name and exclude those folders. For more details, please refer
// to http://support.microsoft.com/kb/171694.
const char win_98_recycle_bin_name[] = "RECYCLED";
const char win_xp_recycle_bin_name[] = "RECYCLER";
const char win_vista_recycle_bin_name[] = "$Recycle.bin";
if ((base::strncasecmp(base_name.c_str(),
win_98_recycle_bin_name,
strlen(win_98_recycle_bin_name)) == 0) ||
(base::strncasecmp(base_name.c_str(),
win_xp_recycle_bin_name,
strlen(win_xp_recycle_bin_name)) == 0) ||
(base::strncasecmp(base_name.c_str(),
win_vista_recycle_bin_name,
strlen(win_vista_recycle_bin_name)) == 0))
return true;
#endif
return false;
}
// Returns true if the current thread is capable of doing IO.
bool IsOnTaskRunnerThread(fileapi::FileSystemOperationContext* context) {
return context->task_runner()->RunsTasksOnCurrentThread();
}
} // namespace
NativeMediaFileUtil::NativeMediaFileUtil(MediaPathFilter* media_path_filter)
: weak_factory_(this),
media_path_filter_(media_path_filter) {
}
NativeMediaFileUtil::~NativeMediaFileUtil() {
}
// static
base::PlatformFileError NativeMediaFileUtil::IsMediaFile(
const base::FilePath& path) {
base::PlatformFile file_handle;
const int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
base::PlatformFileError error =
fileapi::NativeFileUtil::CreateOrOpen(path, flags, &file_handle, NULL);
if (error != base::PLATFORM_FILE_OK)
return error;
base::ScopedPlatformFileCloser scoped_platform_file(&file_handle);
char buffer[net::kMaxBytesToSniff];
// Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
int64 len =
base::ReadPlatformFile(file_handle, 0, buffer, net::kMaxBytesToSniff);
if (len < 0)
return base::PLATFORM_FILE_ERROR_FAILED;
if (len == 0)
return base::PLATFORM_FILE_ERROR_SECURITY;
std::string mime_type;
if (!net::SniffMimeTypeFromLocalData(buffer, len, &mime_type))
return base::PLATFORM_FILE_ERROR_SECURITY;
if (StartsWithASCII(mime_type, "image/", true) ||
StartsWithASCII(mime_type, "audio/", true) ||
StartsWithASCII(mime_type, "video/", true) ||
mime_type == "application/x-shockwave-flash") {
return base::PLATFORM_FILE_OK;
}
return base::PLATFORM_FILE_ERROR_SECURITY;
}
void NativeMediaFileUtil::CreateOrOpen(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
int file_flags,
const CreateOrOpenCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
// Only called by NaCl, which should not have access to media file systems.
base::PlatformFile invalid_file(base::kInvalidPlatformFileValue);
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
base::PassPlatformFile(&invalid_file),
base::Closure());
}
void NativeMediaFileUtil::EnsureFileExists(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const EnsureFileExistsCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, false);
}
void NativeMediaFileUtil::CreateDirectory(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
bool exclusive,
bool recursive,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
url, exclusive, recursive, callback));
DCHECK(success);
}
void NativeMediaFileUtil::GetFileInfo(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const GetFileInfoCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
url, callback));
DCHECK(success);
}
void NativeMediaFileUtil::ReadDirectory(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const ReadDirectoryCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
url, callback));
DCHECK(success);
}
void NativeMediaFileUtil::Touch(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const base::Time& last_access_time,
const base::Time& last_modified_time,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
}
void NativeMediaFileUtil::Truncate(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
int64 length,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
}
void NativeMediaFileUtil::CopyFileLocal(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& src_url,
const fileapi::FileSystemURL& dest_url,
CopyOrMoveOption option,
const CopyFileProgressCallback& progress_callback,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
src_url, dest_url, option, true /* copy */, callback));
DCHECK(success);
}
void NativeMediaFileUtil::MoveFileLocal(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& src_url,
const fileapi::FileSystemURL& dest_url,
CopyOrMoveOption option,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
src_url, dest_url, option, false /* copy */, callback));
DCHECK(success);
}
void NativeMediaFileUtil::CopyInForeignFile(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const base::FilePath& src_file_path,
const fileapi::FileSystemURL& dest_url,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
src_file_path, dest_url, callback));
DCHECK(success);
}
void NativeMediaFileUtil::DeleteFile(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
}
// This is needed to support Copy and Move.
void NativeMediaFileUtil::DeleteDirectory(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
url, callback));
DCHECK(success);
}
void NativeMediaFileUtil::DeleteRecursively(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const StatusCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
}
void NativeMediaFileUtil::CreateSnapshotFile(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const CreateSnapshotFileCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
fileapi::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread,
weak_factory_.GetWeakPtr(), base::Passed(&context),
url, callback));
DCHECK(success);
}
void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
bool exclusive,
bool recursive,
const StatusCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
base::PlatformFileError error =
CreateDirectorySync(context.get(), url, exclusive, recursive);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error));
}
void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const GetFileInfoCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
base::PlatformFileInfo file_info;
base::PlatformFileError error =
GetFileInfoSync(context.get(), url, &file_info, NULL);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error, file_info));
}
void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const ReadDirectoryCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
EntryList entry_list;
base::PlatformFileError error =
ReadDirectorySync(context.get(), url, &entry_list);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error, entry_list, false /* has_more */));
}
void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& src_url,
const fileapi::FileSystemURL& dest_url,
CopyOrMoveOption option,
bool copy,
const StatusCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
base::PlatformFileError error =
CopyOrMoveFileSync(context.get(), src_url, dest_url, option, copy);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error));
}
void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const base::FilePath& src_file_path,
const fileapi::FileSystemURL& dest_url,
const StatusCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
base::PlatformFileError error =
CopyInForeignFileSync(context.get(), src_file_path, dest_url);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error));
}
void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const StatusCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
base::PlatformFileError error = DeleteDirectorySync(context.get(), url);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error));
}
void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(
scoped_ptr<fileapi::FileSystemOperationContext> context,
const fileapi::FileSystemURL& url,
const CreateSnapshotFileCallback& callback) {
DCHECK(IsOnTaskRunnerThread(context.get()));
base::PlatformFileInfo file_info;
base::FilePath platform_path;
scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
base::PlatformFileError error =
CreateSnapshotFileSync(context.get(), url, &file_info, &platform_path,
&file_ref);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(callback, error, file_info, platform_path, file_ref));
}
base::PlatformFileError NativeMediaFileUtil::CreateDirectorySync(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& url,
bool exclusive,
bool recursive) {
base::FilePath file_path;
base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
return fileapi::NativeFileUtil::CreateDirectory(file_path, exclusive,
recursive);
}
base::PlatformFileError NativeMediaFileUtil::CopyOrMoveFileSync(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& src_url,
const fileapi::FileSystemURL& dest_url,
CopyOrMoveOption option,
bool copy) {
DCHECK(IsOnTaskRunnerThread(context));
base::FilePath src_file_path;
base::PlatformFileError error =
GetFilteredLocalFilePathForExistingFileOrDirectory(
context, src_url,
base::PLATFORM_FILE_ERROR_NOT_FOUND,
&src_file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
if (fileapi::NativeFileUtil::DirectoryExists(src_file_path))
return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
base::FilePath dest_file_path;
error = GetLocalFilePath(context, dest_url, &dest_file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
base::PlatformFileInfo file_info;
error = fileapi::NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
if (error != base::PLATFORM_FILE_OK &&
error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
return error;
if (error == base::PLATFORM_FILE_OK && file_info.is_directory)
return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
if (!media_path_filter_->Match(dest_file_path))
return base::PLATFORM_FILE_ERROR_SECURITY;
return fileapi::NativeFileUtil::CopyOrMoveFile(
src_file_path, dest_file_path, option, copy);
}
base::PlatformFileError NativeMediaFileUtil::CopyInForeignFileSync(
fileapi::FileSystemOperationContext* context,
const base::FilePath& src_file_path,
const fileapi::FileSystemURL& dest_url) {
DCHECK(IsOnTaskRunnerThread(context));
if (src_file_path.empty())
return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
base::FilePath dest_file_path;
base::PlatformFileError error =
GetFilteredLocalFilePath(context, dest_url, &dest_file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
return fileapi::NativeFileUtil::CopyOrMoveFile(
src_file_path, dest_file_path,
fileapi::FileSystemOperation::OPTION_NONE, true);
}
base::PlatformFileError NativeMediaFileUtil::GetFileInfoSync(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& url,
base::PlatformFileInfo* file_info,
base::FilePath* platform_path) {
DCHECK(context);
DCHECK(IsOnTaskRunnerThread(context));
DCHECK(file_info);
base::FilePath file_path;
base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
if (file_util::IsLink(file_path))
return base::PLATFORM_FILE_ERROR_NOT_FOUND;
error = fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
if (error != base::PLATFORM_FILE_OK)
return error;
if (platform_path)
*platform_path = file_path;
if (file_info->is_directory ||
media_path_filter_->Match(file_path)) {
return base::PLATFORM_FILE_OK;
}
return base::PLATFORM_FILE_ERROR_NOT_FOUND;
}
base::PlatformFileError NativeMediaFileUtil::GetLocalFilePath(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& url,
base::FilePath* local_file_path) {
DCHECK(local_file_path);
DCHECK(url.is_valid());
if (url.path().empty()) {
// Root direcory case, which should not be accessed.
return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}
*local_file_path = url.path();
return base::PLATFORM_FILE_OK;
}
base::PlatformFileError NativeMediaFileUtil::ReadDirectorySync(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& url,
EntryList* file_list) {
DCHECK(IsOnTaskRunnerThread(context));
DCHECK(file_list);
DCHECK(file_list->empty());
base::PlatformFileInfo file_info;
base::FilePath dir_path;
base::PlatformFileError error =
GetFileInfoSync(context, url, &file_info, &dir_path);
if (error != base::PLATFORM_FILE_OK)
return error;
if (!file_info.is_directory)
return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
base::FileEnumerator file_enum(
dir_path,
false /* recursive */,
base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
for (base::FilePath enum_path = file_enum.Next();
!enum_path.empty();
enum_path = file_enum.Next()) {
// Skip symlinks.
if (file_util::IsLink(enum_path))
continue;
base::FileEnumerator::FileInfo info = file_enum.GetInfo();
// NativeMediaFileUtil skip criteria.
if (ShouldSkip(enum_path))
continue;
if (!info.IsDirectory() && !media_path_filter_->Match(enum_path))
continue;
fileapi::DirectoryEntry entry;
entry.is_directory = info.IsDirectory();
entry.name = enum_path.BaseName().value();
entry.size = info.GetSize();
entry.last_modified_time = info.GetLastModifiedTime();
file_list->push_back(entry);
}
return base::PLATFORM_FILE_OK;
}
base::PlatformFileError NativeMediaFileUtil::DeleteDirectorySync(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& url) {
DCHECK(IsOnTaskRunnerThread(context));
base::FilePath file_path;
base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
return fileapi::NativeFileUtil::DeleteDirectory(file_path);
}
base::PlatformFileError NativeMediaFileUtil::CreateSnapshotFileSync(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& url,
base::PlatformFileInfo* file_info,
base::FilePath* platform_path,
scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
DCHECK(IsOnTaskRunnerThread(context));
base::PlatformFileError error =
GetFileInfoSync(context, url, file_info, platform_path);
if (error == base::PLATFORM_FILE_OK && file_info->is_directory)
error = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
if (error == base::PLATFORM_FILE_OK)
error = NativeMediaFileUtil::IsMediaFile(*platform_path);
// We're just returning the local file information.
*file_ref = scoped_refptr<webkit_blob::ShareableFileReference>();
return error;
}
base::PlatformFileError NativeMediaFileUtil::GetFilteredLocalFilePath(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& file_system_url,
base::FilePath* local_file_path) {
DCHECK(IsOnTaskRunnerThread(context));
base::FilePath file_path;
base::PlatformFileError error =
GetLocalFilePath(context, file_system_url, &file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
if (!media_path_filter_->Match(file_path))
return base::PLATFORM_FILE_ERROR_SECURITY;
*local_file_path = file_path;
return base::PLATFORM_FILE_OK;
}
base::PlatformFileError
NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory(
fileapi::FileSystemOperationContext* context,
const fileapi::FileSystemURL& file_system_url,
base::PlatformFileError failure_error,
base::FilePath* local_file_path) {
DCHECK(IsOnTaskRunnerThread(context));
base::FilePath file_path;
base::PlatformFileError error =
GetLocalFilePath(context, file_system_url, &file_path);
if (error != base::PLATFORM_FILE_OK)
return error;
if (!base::PathExists(file_path))
return failure_error;
base::PlatformFileInfo file_info;
if (!file_util::GetFileInfo(file_path, &file_info))
return base::PLATFORM_FILE_ERROR_FAILED;
if (!file_info.is_directory &&
!media_path_filter_->Match(file_path)) {
return failure_error;
}
*local_file_path = file_path;
return base::PLATFORM_FILE_OK;
}