// Copyright 2020 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/webshare/prepare_directory_task.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/system/sys_info.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "third_party/cros_system_api/constants/cryptohome.h"
#endif
using content::BrowserThread;
namespace {
void DeleteSharedFiles(std::vector<base::FilePath> file_paths) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
for (const base::FilePath& name : file_paths) {
base::DeletePathRecursively(name);
}
}
} // namespace
namespace webshare {
constexpr base::TimeDelta PrepareDirectoryTask::kSharedFileLifetime;
PrepareDirectoryTask::PrepareDirectoryTask(base::FilePath directory,
uint64_t required_space)
: directory_(std::move(directory)), required_space_(required_space) {}
PrepareDirectoryTask::PrepareDirectoryTask(
base::FilePath directory,
uint64_t required_space,
blink::mojom::ShareService::ShareCallback callback)
: directory_(std::move(directory)),
required_space_(required_space),
callback_(std::move(callback)) {}
PrepareDirectoryTask::~PrepareDirectoryTask() = default;
void PrepareDirectoryTask::Start() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
base::BindOnce(&PrepareDirectoryTask::PrepareDirectory, directory_,
required_space_),
base::BindOnce(&PrepareDirectoryTask::OnPrepareDirectory,
weak_ptr_factory_.GetWeakPtr()));
}
void PrepareDirectoryTask::StartWithCallback(
PrepareDirectoryCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
base::BindOnce(&PrepareDirectoryTask::PrepareDirectory, directory_,
required_space_),
std::move(callback));
}
// static
void PrepareDirectoryTask::ScheduleSharedFileDeletion(
std::vector<base::FilePath> file_paths,
base::TimeDelta delay) {
base::ThreadPool::PostDelayedTask(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&DeleteSharedFiles, std::move(file_paths)), delay);
}
// static
base::File::Error PrepareDirectoryTask::PrepareDirectory(
base::FilePath directory,
uint64_t required_space) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
base::File::Error result = base::File::FILE_OK;
if (base::CreateDirectoryAndGetError(directory, &result)) {
// Delete any old files in |directory|.
const base::Time cutoff_time = base::Time::Now() - kSharedFileLifetime;
base::FileEnumerator enumerator(
directory, /*recursive=*/false,
base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
for (base::FilePath name = enumerator.Next(); !name.empty();
name = enumerator.Next()) {
if (enumerator.GetInfo().GetLastModifiedTime() <= cutoff_time) {
base::DeletePathRecursively(name);
}
}
#if BUILDFLAG(IS_CHROMEOS)
if (base::SysInfo::AmountOfFreeDiskSpace(directory) <
static_cast<int64_t>(cryptohome::kMinFreeSpaceInBytes +
required_space)) {
#elif BUILDFLAG(IS_MAC)
if (base::SysInfo::AmountOfFreeDiskSpace(directory) <
static_cast<int64_t>(required_space)) {
#else
if (false) {
#endif
result = base::File::FILE_ERROR_NO_SPACE;
VLOG(1) << "Insufficient space for sharing files";
}
} else {
DCHECK(result != base::File::FILE_OK);
VLOG(1) << "Could not create directory for shared files";
}
return result;
}
void PrepareDirectoryTask::OnPrepareDirectory(base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (callback_) {
std::move(callback_).Run((result == base::File::FILE_OK)
? blink::mojom::ShareError::OK
: blink::mojom::ShareError::PERMISSION_DENIED);
}
}
} // namespace webshare