blob: 3c16c58fde92b878be5e5a4e9754475cae931438 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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 <string_view>
#include <utility>
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/string_util.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
#include "components/services/filesystem/public/mojom/types.mojom.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_operation_context.h"
#include "storage/browser/file_system/native_file_util.h"
#include "url/gurl.h"
namespace {
// Returns true if the current thread is capable of doing IO.
bool IsOnTaskRunnerThread(storage::FileSystemOperationContext* context) {
return context->task_runner()->RunsTasksInCurrentSequence();
}
base::File::Error IsMediaHeader(const char* buf, size_t length) {
if (length == 0)
return base::File::FILE_ERROR_SECURITY;
std::string mime_type;
if (!net::SniffMimeTypeFromLocalData(std::string_view(buf, length),
&mime_type)) {
return base::File::FILE_ERROR_SECURITY;
}
if (base::StartsWith(mime_type, "image/", base::CompareCase::SENSITIVE) ||
base::StartsWith(mime_type, "audio/", base::CompareCase::SENSITIVE) ||
base::StartsWith(mime_type, "video/", base::CompareCase::SENSITIVE) ||
mime_type == "application/x-shockwave-flash") {
return base::File::FILE_OK;
}
return base::File::FILE_ERROR_SECURITY;
}
void HoldFileRef(scoped_refptr<storage::ShareableFileReference> file_ref) {}
void DidOpenSnapshot(storage::AsyncFileUtil::CreateOrOpenCallback callback,
scoped_refptr<storage::ShareableFileReference> file_ref,
base::File file) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!file.IsValid()) {
std::move(callback).Run(std::move(file), base::OnceClosure());
return;
}
std::move(callback).Run(std::move(file),
base::BindOnce(&HoldFileRef, std::move(file_ref)));
}
} // namespace
// |NativeMediaFileUtil::Core| is used and torn-down on the media TaskRunner by
// the owning NativeMediaFileUtil.
class NativeMediaFileUtil::Core {
public:
explicit Core(scoped_refptr<base::SequencedTaskRunner> media_task_runner)
: media_task_runner_(std::move(media_task_runner)) {}
Core(const Core&) = delete;
Core& operator=(const Core&) = delete;
~Core() = default;
// The following calls are made on the media TaskRunner, using
// PostTaskAndReplyWithResult() to return the result to the IO thread.
// Necessary for copy/move to succeed.
base::File::Error CreateDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
bool exclusive,
bool recursive);
base::File::Error CopyOrMoveFileLocal(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& src_url,
const storage::FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
bool copy);
base::File::Error CopyInForeignFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const base::FilePath& src_file_path,
const storage::FileSystemURL& dest_url);
base::File::Error DeleteFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url);
// Necessary for move to succeed.
base::File::Error DeleteDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url);
// The following calls are posted to the media TaskRunner, where they perform
// the specified operation, before posting |callback| back to the IO thread
// with the result.
void GetFileInfoOnTaskRunnerThread(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
GetFileInfoCallback callback);
void ReadDirectoryOnTaskRunnerThread(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
ReadDirectoryCallback callback);
void CreateSnapshotFileOnTaskRunnerThread(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
CreateSnapshotFileCallback callback);
private:
base::File::Error GetFileInfoSync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::File::Info* file_info,
base::FilePath* platform_path);
base::File::Error ReadDirectorySync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
EntryList* file_list);
base::File::Error CreateSnapshotFileSync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::File::Info* file_info,
base::FilePath* platform_path,
scoped_refptr<storage::ShareableFileReference>* file_ref);
// Translates the specified URL to a |local_file_path|, with no filtering.
base::File::Error GetLocalFilePath(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& file_system_url,
base::FilePath* local_file_path);
// Like GetLocalFilePath(), but always take media_path_filter() into
// consideration. If the media_path_filter() check fails, return
// Fila::FILE_ERROR_SECURITY. |local_file_path| does not have to exist.
base::File::Error GetFilteredLocalFilePath(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& file_system_url,
base::FilePath* local_file_path);
// Like GetLocalFilePath(), but if the file does not exist, then return
// |failure_error|.
// If |local_file_path| is a file, then take media_path_filter() into
// consideration.
// If the media_path_filter() check fails, return |failure_error|.
// If |local_file_path| is a directory, return File::FILE_OK.
base::File::Error GetFilteredLocalFilePathForExistingFileOrDirectory(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& file_system_url,
base::File::Error failure_error,
base::FilePath* local_file_path);
MediaPathFilter media_path_filter_;
scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
};
NativeMediaFileUtil::NativeMediaFileUtil(
scoped_refptr<base::SequencedTaskRunner> media_task_runner)
: media_task_runner_(std::move(media_task_runner)),
core_(std::make_unique<Core>(media_task_runner_)) {}
NativeMediaFileUtil::~NativeMediaFileUtil() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
media_task_runner_->DeleteSoon(FROM_HERE, std::move(core_));
}
// static
base::File::Error NativeMediaFileUtil::IsMediaFile(
const base::FilePath& path) {
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid())
return file.error_details();
char buffer[net::kMaxBytesToSniff];
// Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
int64_t len = file.Read(0, buffer, net::kMaxBytesToSniff);
if (len < 0)
return base::File::FILE_ERROR_FAILED;
return IsMediaHeader(buffer, len);
}
// static
base::File::Error NativeMediaFileUtil::BufferIsMediaHeader(
net::IOBuffer* buf, size_t length) {
return IsMediaHeader(buf->data(), length);
}
// static
void NativeMediaFileUtil::CreatedSnapshotFileForCreateOrOpen(
base::SequencedTaskRunner* media_task_runner,
uint32_t file_flags,
storage::AsyncFileUtil::CreateOrOpenCallback callback,
base::File::Error result,
const base::File::Info& file_info,
const base::FilePath& platform_path,
scoped_refptr<storage::ShareableFileReference> file_ref) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (result != base::File::FILE_OK) {
std::move(callback).Run(base::File(), base::OnceClosure());
return;
}
media_task_runner->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&storage::NativeFileUtil::CreateOrOpen, platform_path,
file_flags),
base::BindOnce(&DidOpenSnapshot, std::move(callback),
std::move(file_ref)));
}
void NativeMediaFileUtil::CreateOrOpen(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
uint32_t file_flags,
CreateOrOpenCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// Returns an error if any unsupported flag is found.
if (file_flags &
~(base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_WRITE_ATTRIBUTES | base::File::FLAG_WIN_NO_EXECUTE)) {
std::move(callback).Run(base::File(base::File::FILE_ERROR_SECURITY),
base::OnceClosure());
return;
}
scoped_refptr<base::SequencedTaskRunner> task_runner = context->task_runner();
CreateSnapshotFile(
std::move(context), url,
base::BindOnce(&NativeMediaFileUtil::CreatedSnapshotFileForCreateOrOpen,
base::RetainedRef(task_runner), file_flags,
std::move(callback)));
}
void NativeMediaFileUtil::EnsureFileExists(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
EnsureFileExistsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::move(callback).Run(base::File::FILE_ERROR_SECURITY, false);
}
void NativeMediaFileUtil::CreateDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
bool exclusive,
bool recursive,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::CreateDirectory,
base::Unretained(core_.get()), std::move(context), url,
exclusive, recursive),
std::move(callback));
DCHECK(success);
}
void NativeMediaFileUtil::GetFileInfo(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
GetMetadataFieldSet fields,
GetFileInfoCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::GetFileInfoOnTaskRunnerThread,
base::Unretained(core_.get()), std::move(context), url,
std::move(callback)));
DCHECK(success);
}
void NativeMediaFileUtil::ReadDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
ReadDirectoryCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(
&NativeMediaFileUtil::Core::ReadDirectoryOnTaskRunnerThread,
base::Unretained(core_.get()), std::move(context), url,
std::move(callback)));
DCHECK(success);
}
void NativeMediaFileUtil::Touch(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
const base::Time& last_access_time,
const base::Time& last_modified_time,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
}
void NativeMediaFileUtil::Truncate(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
int64_t length,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
}
void NativeMediaFileUtil::CopyFileLocal(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& src_url,
const storage::FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
CopyFileProgressCallback progress_callback,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::CopyOrMoveFileLocal,
base::Unretained(core_.get()), std::move(context), src_url,
dest_url, options, true /* copy */),
std::move(callback));
DCHECK(success);
}
void NativeMediaFileUtil::MoveFileLocal(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& src_url,
const storage::FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::CopyOrMoveFileLocal,
base::Unretained(core_.get()), std::move(context), src_url,
dest_url, options, false /* copy */),
std::move(callback));
DCHECK(success);
}
void NativeMediaFileUtil::CopyInForeignFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const base::FilePath& src_file_path,
const storage::FileSystemURL& dest_url,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::CopyInForeignFile,
base::Unretained(core_.get()), std::move(context),
src_file_path, dest_url),
std::move(callback));
DCHECK(success);
}
void NativeMediaFileUtil::DeleteFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::DeleteFile,
base::Unretained(core_.get()), std::move(context), url),
std::move(callback));
DCHECK(success);
}
// This is needed to support Copy and Move.
void NativeMediaFileUtil::DeleteDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&NativeMediaFileUtil::Core::DeleteDirectory,
base::Unretained(core_.get()), std::move(context), url),
std::move(callback));
DCHECK(success);
}
void NativeMediaFileUtil::DeleteRecursively(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
StatusCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION);
}
void NativeMediaFileUtil::CreateSnapshotFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
CreateSnapshotFileCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
storage::FileSystemOperationContext* context_ptr = context.get();
const bool success = context_ptr->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(
&NativeMediaFileUtil::Core::CreateSnapshotFileOnTaskRunnerThread,
base::Unretained(core_.get()), std::move(context), url,
std::move(callback)));
DCHECK(success);
}
base::File::Error NativeMediaFileUtil::Core::CreateDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
bool exclusive,
bool recursive) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
base::FilePath file_path;
base::File::Error error = GetLocalFilePath(context.get(), url, &file_path);
if (error != base::File::FILE_OK)
return error;
return storage::NativeFileUtil::CreateDirectory(
file_path, exclusive, recursive);
}
base::File::Error NativeMediaFileUtil::Core::CopyOrMoveFileLocal(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& src_url,
const storage::FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
bool copy) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
base::FilePath src_file_path;
base::File::Error error = GetFilteredLocalFilePathForExistingFileOrDirectory(
context.get(), src_url, base::File::FILE_ERROR_NOT_FOUND, &src_file_path);
if (error != base::File::FILE_OK)
return error;
if (storage::NativeFileUtil::DirectoryExists(src_file_path))
return base::File::FILE_ERROR_NOT_A_FILE;
base::FilePath dest_file_path;
error = GetLocalFilePath(context.get(), dest_url, &dest_file_path);
if (error != base::File::FILE_OK)
return error;
base::File::Info file_info;
error = storage::NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
if (error != base::File::FILE_OK &&
error != base::File::FILE_ERROR_NOT_FOUND) {
return error;
}
if (error == base::File::FILE_OK && file_info.is_directory)
return base::File::FILE_ERROR_INVALID_OPERATION;
if (!media_path_filter_.Match(dest_file_path))
return base::File::FILE_ERROR_SECURITY;
return storage::NativeFileUtil::CopyOrMoveFile(
src_file_path, dest_file_path, options,
storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url, copy));
}
base::File::Error NativeMediaFileUtil::Core::CopyInForeignFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const base::FilePath& src_file_path,
const storage::FileSystemURL& dest_url) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
if (src_file_path.empty())
return base::File::FILE_ERROR_INVALID_OPERATION;
base::FilePath dest_file_path;
base::File::Error error =
GetFilteredLocalFilePath(context.get(), dest_url, &dest_file_path);
if (error != base::File::FILE_OK)
return error;
return storage::NativeFileUtil::CopyOrMoveFile(
src_file_path, dest_file_path,
storage::FileSystemOperation::CopyOrMoveOptionSet(),
storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url,
true /* copy */));
}
base::File::Error NativeMediaFileUtil::Core::DeleteFile(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
base::File::Info file_info;
base::FilePath file_path;
base::File::Error error =
GetFileInfoSync(context.get(), url, &file_info, &file_path);
if (error != base::File::FILE_OK)
return error;
if (file_info.is_directory)
return base::File::FILE_ERROR_NOT_A_FILE;
return storage::NativeFileUtil::DeleteFile(file_path);
}
base::File::Error NativeMediaFileUtil::Core::DeleteDirectory(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
base::FilePath file_path;
base::File::Error error = GetLocalFilePath(context.get(), url, &file_path);
if (error != base::File::FILE_OK)
return error;
return storage::NativeFileUtil::DeleteDirectory(file_path);
}
void NativeMediaFileUtil::Core::GetFileInfoOnTaskRunnerThread(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
GetFileInfoCallback callback) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
base::File::Info file_info;
base::File::Error error =
GetFileInfoSync(context.get(), url, &file_info, nullptr);
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), error, file_info));
}
void NativeMediaFileUtil::Core::ReadDirectoryOnTaskRunnerThread(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
ReadDirectoryCallback callback) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
EntryList entry_list;
base::File::Error error = ReadDirectorySync(context.get(), url, &entry_list);
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), error, entry_list,
false /* has_more */));
}
void NativeMediaFileUtil::Core::CreateSnapshotFileOnTaskRunnerThread(
std::unique_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
CreateSnapshotFileCallback callback) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(IsOnTaskRunnerThread(context.get()));
base::File::Info file_info;
base::FilePath platform_path;
scoped_refptr<storage::ShareableFileReference> file_ref;
base::File::Error error = CreateSnapshotFileSync(
context.get(), url, &file_info, &platform_path, &file_ref);
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), error, file_info,
platform_path, file_ref));
}
base::File::Error NativeMediaFileUtil::Core::GetFileInfoSync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::File::Info* file_info,
base::FilePath* platform_path) {
base::FilePath file_path;
base::File::Error error = GetLocalFilePath(context, url, &file_path);
if (error != base::File::FILE_OK)
return error;
if (base::IsLink(file_path))
return base::File::FILE_ERROR_NOT_FOUND;
error = storage::NativeFileUtil::GetFileInfo(file_path, file_info);
if (error != base::File::FILE_OK)
return error;
if (platform_path)
*platform_path = file_path;
if (file_info->is_directory || media_path_filter_.Match(file_path)) {
return base::File::FILE_OK;
}
return base::File::FILE_ERROR_NOT_FOUND;
}
base::File::Error NativeMediaFileUtil::Core::ReadDirectorySync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
EntryList* file_list) {
base::File::Info file_info;
base::FilePath dir_path;
base::File::Error error =
GetFileInfoSync(context, url, &file_info, &dir_path);
if (error != base::File::FILE_OK)
return error;
if (!file_info.is_directory)
return base::File::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 (base::IsLink(enum_path))
continue;
base::FileEnumerator::FileInfo info = file_enum.GetInfo();
// NativeMediaFileUtil skip criteria.
if (MediaPathFilter::ShouldSkip(enum_path))
continue;
if (!info.IsDirectory() && !media_path_filter_.Match(enum_path))
continue;
file_list->emplace_back(enum_path.BaseName(),
info.IsDirectory()
? filesystem::mojom::FsFileType::DIRECTORY
: filesystem::mojom::FsFileType::REGULAR_FILE);
}
return base::File::FILE_OK;
}
base::File::Error NativeMediaFileUtil::Core::CreateSnapshotFileSync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::File::Info* file_info,
base::FilePath* platform_path,
scoped_refptr<storage::ShareableFileReference>* file_ref) {
base::File::Error error =
GetFileInfoSync(context, url, file_info, platform_path);
if (error == base::File::FILE_OK && file_info->is_directory)
error = base::File::FILE_ERROR_NOT_A_FILE;
if (error == base::File::FILE_OK)
error = NativeMediaFileUtil::IsMediaFile(*platform_path);
// We're just returning the local file information.
*file_ref = scoped_refptr<storage::ShareableFileReference>();
return error;
}
base::File::Error NativeMediaFileUtil::Core::GetLocalFilePath(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::FilePath* local_file_path) {
DCHECK(url.is_valid());
if (url.path().empty()) {
// Root direcory case, which should not be accessed.
return base::File::FILE_ERROR_ACCESS_DENIED;
}
*local_file_path = url.path();
return base::File::FILE_OK;
}
base::File::Error NativeMediaFileUtil::Core::GetFilteredLocalFilePath(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& file_system_url,
base::FilePath* local_file_path) {
base::FilePath file_path;
base::File::Error error =
GetLocalFilePath(context, file_system_url, &file_path);
if (error != base::File::FILE_OK)
return error;
if (!media_path_filter_.Match(file_path))
return base::File::FILE_ERROR_SECURITY;
*local_file_path = file_path;
return base::File::FILE_OK;
}
base::File::Error
NativeMediaFileUtil::Core::GetFilteredLocalFilePathForExistingFileOrDirectory(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& file_system_url,
base::File::Error failure_error,
base::FilePath* local_file_path) {
base::FilePath file_path;
base::File::Error error =
GetLocalFilePath(context, file_system_url, &file_path);
if (error != base::File::FILE_OK)
return error;
if (!base::PathExists(file_path))
return failure_error;
base::File::Info file_info;
if (!base::GetFileInfo(file_path, &file_info))
return base::File::FILE_ERROR_FAILED;
if (!file_info.is_directory && !media_path_filter_.Match(file_path)) {
return failure_error;
}
*local_file_path = file_path;
return base::File::FILE_OK;
}