blob: 30ac324a7b62d459fc4e74b00c560c2ed08c7094 [file] [log] [blame]
// Copyright 2022 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.
#ifndef CHROME_BROWSER_ASH_FILE_MANAGER_TRASH_IO_TASK_H_
#define CHROME_BROWSER_ASH_FILE_MANAGER_TRASH_IO_TASK_H_
#include <functional>
#include <memory>
#include <vector>
#include "base/files/file_error_or.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/file_manager/file_manager_copy_or_move_hook_delegate.h"
#include "chrome/browser/ash/file_manager/io_task.h"
#include "chrome/browser/ash/file_manager/speedometer.h"
#include "chrome/browser/ash/file_manager/trash_common_util.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_operation_runner.h"
#include "storage/browser/file_system/file_system_url.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
class Profile;
namespace file_manager::io_task {
namespace {
struct TrashEntry {
TrashEntry();
~TrashEntry();
TrashEntry(TrashEntry&& other);
TrashEntry& operator=(TrashEntry&& other);
// The relative path (to `trash_mount_path`) where the final location of the
// trashed file.
base::FilePath relative_trash_path;
// An absolute location which contains the `relative_trash_path` and combined
// represents the final location of the trashed file.
base::FilePath trash_mount_path;
// The date of deletion, stored in the metadata file to help scheduled
// cleanup.
base::Time deletion_time;
// The contents of the .trashinfo file containing the deletion date and
// original path of the trashed file.
std::string trash_info_contents;
// The source file size.
int64_t source_file_size;
};
} // namespace
// This class represents a trash task. A trash task attempts to trash zero or
// more files by first moving them to a .Trash/files or .Trash-{UID}/files
// folder that resides in a parent folder for:
// - My files
// - Downloads
// - Crostini
// - Drive
// A corresponding .trashinfo file will be created at .Trash/info or
// .Trash-{UID}/info that contains a timestamp of deletion and the original path
// (relative to the trash folder location).
//
// This follows the XDG specification
// https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
class TrashIOTask : public IOTask {
public:
TrashIOTask(std::vector<storage::FileSystemURL> file_urls,
Profile* profile,
scoped_refptr<storage::FileSystemContext> file_system_context,
const base::FilePath base_path,
bool show_notification = true);
~TrashIOTask() override;
// Starts trash trask.
void Execute(ProgressCallback progress_callback,
CompleteCallback complete_callback) override;
void Cancel() override;
private:
void Complete(State state);
void UpdateTrashEntry(size_t source_idx);
void GetFileSize(size_t source_idx);
void GotFileSize(size_t source_idx,
base::File::Error error,
const base::File::Info& file_info);
const storage::FileSystemURL CreateFileSystemURL(
const storage::FileSystemURL& original_url,
const base::FilePath& path);
void SetCurrentOperationID(
storage::FileSystemOperationRunner::OperationID id);
void ValidateAndDecrementFreeSpace(
size_t source_idx,
const trash::TrashPathsMap::reverse_iterator& it);
// Get the free disk space for `trash_parent_path` to know whether the
// metadata can be written. The `folder_name` is used to differentiate between
// .Trash and .Trash-1000 folder names on various file systems (both are valid
// in the XDG spec).
void GetFreeDiskSpace(size_t source_idx,
const trash::TrashPathsMap::reverse_iterator& it);
void GotFreeDiskSpace(size_t source_idx,
const trash::TrashPathsMap::reverse_iterator& it,
int64_t free_space);
// Sets up the .Trash/files and .Trash/info subdirectories specified by the
// `trash_subdirectory` parameter. Will create the parent directories as well
// in the instance .Trash folder does not exist.
void SetupSubDirectory(trash::TrashPathsMap::const_iterator& it,
const storage::FileSystemURL trash_subdirectory);
// During low-disk space situations, cryptohome needs a way to identify
// folders to purge. Trash should be considered prior to the rest of the
// users' profile.
void SetDirectoryTracking(
base::OnceCallback<void(base::File::Error)> on_setup_complete_callback,
const base::FilePath& trash_subdirectory,
base::File::Error error);
void OnSetupSubDirectory(trash::TrashPathsMap::const_iterator& it,
const storage::FileSystemURL trash_subdirectory,
base::File::Error error);
// After setting up directory permissions, `set_permissions_success` will have
// true on success and false otherwise.
void OnSetDirectoryPermissions(trash::TrashPathsMap::const_iterator& it,
bool set_permissions_success);
base::FilePath MakeRelativeFromBasePath(const base::FilePath& absolute_path);
base::FilePath MakeRelativePathAbsoluteFromBasePath(
const base::FilePath& relative_path);
// Attempts to generate a unique destination filename when saving to
// .Trash/files. Appends an increasing (N) suffix until a unique name is
// identified.
void GenerateDestinationURL(size_t source_idx, size_t output_idx);
// Creates a file in .Trash/info that matches the name generated from
// `GenerateDestinationURL`. Writes the relative restoration path as well as
// the date time of deletion.
void WriteMetadata(
size_t source_idx,
size_t output_idx,
const storage::FileSystemURL& files_folder_location,
base::FileErrorOr<storage::FileSystemURL> destination_result);
void OnWriteMetadata(size_t source_idx,
size_t output_idx,
const storage::FileSystemURL& destination_url,
bool success);
// Called upon either error of writing metadata or completion of moving the
// trashed file. Ensures progress is invoked and the next file is queued.
void TrashComplete(size_t source_idx,
size_t output_idx,
base::File::Error error);
// Move a file from it's location to the final .Trash/files destination with
// a unique name determined by `GenerateDestinationURL`.
void TrashFile(size_t source_idx,
size_t output_idx,
const storage::FileSystemURL& destination_url);
void OnMoveComplete(size_t source_idx,
size_t output_idx,
base::File::Error error);
raw_ptr<Profile> profile_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
// Stores the total size required for all the metadata files, keyed by the
// trash location to ensure enough disk space to write.
std::vector<TrashEntry> trash_entries_;
// Maintains the free space required to write all the metadata files along
// with the underlying locations of the .Trash/{files,info} directories.
trash::TrashPathsMap free_space_map_;
// Stores the size reported by the last progress update so we can compute the
// delta on the next progress update.
int64_t last_progress_size_;
// Stores the last url for the most recently updated metadata file, in the
// event of a move failure this file is removed.
storage::FileSystemURL last_metadata_url_;
// Speedometer for this operation, used to calculate the remaining time to
// finish the operation.
Speedometer speedometer_;
// Stores the id of the operations currently behind undertaken by Trash,
// including directory creation. Enables cancelling an inflight operation.
absl::optional<storage::FileSystemOperationRunner::OperationID> operation_id_;
ProgressCallback progress_callback_;
CompleteCallback complete_callback_;
// Represents the parent path that all the source URLs descend from. Used to
// work around the fact `FileSystemOperationRunner` requires relative paths
// only in testing.
const base::FilePath base_path_;
base::WeakPtrFactory<TrashIOTask> weak_ptr_factory_{this};
};
} // namespace file_manager::io_task
#endif // CHROME_BROWSER_ASH_FILE_MANAGER_TRASH_IO_TASK_H_