| // 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_ |