| // Copyright 2021 The Chromium Authors |
| // 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_IO_TASK_H_ |
| #define CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_H_ |
| |
| #include <cstddef> |
| #include <optional> |
| #include <ostream> |
| #include <string> |
| #include <vector> |
| |
| #include "base/files/file.h" |
| #include "base/functional/callback.h" |
| #include "base/memory/weak_ptr.h" |
| #include "chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.h" |
| #include "storage/browser/file_system/file_system_url.h" |
| |
| class Profile; |
| |
| namespace file_manager::io_task { |
| |
| enum class State { |
| // Task has been queued, but not yet started. |
| kQueued, |
| |
| // Task has started, but some initial scanning is performed. |
| kScanning, |
| |
| // Task is currently running. |
| kInProgress, |
| |
| // Task is currently paused. |
| kPaused, |
| |
| // Task has been successfully completed. |
| kSuccess, |
| |
| // Task has completed with errors. |
| kError, |
| |
| // Task has failed to finish due to missing password. |
| kNeedPassword, |
| |
| // Task has been canceled without finishing. |
| kCancelled, |
| }; |
| |
| enum class OperationType { |
| kCopy, |
| kDelete, |
| kEmptyTrash, |
| kExtract, |
| kMove, |
| |
| // This restores to the location supplied in the .trashinfo folder, recreating |
| // the parent hierarchy as required. As .Trash folders reside on the same |
| // filesystem as trashed files, this implies an intra filesystem move. |
| kRestore, |
| |
| // This restores to a supplied destination only extracting the file name to |
| // properly name the destination file. The destination folder is expected to |
| // exist and items can be restored cross filesystem. |
| kRestoreToDestination, |
| kTrash, |
| kZip, |
| }; |
| |
| std::ostream& operator<<(std::ostream& out, OperationType op); |
| |
| // The type of Data Protection policy error that occurred. |
| enum class PolicyErrorType { |
| // Error caused by Data Leak Prevention policy. |
| kDlp, |
| |
| // Error caused by Enterprise Connectors policy. |
| kEnterpriseConnectors, |
| |
| // Error caused by Data Leak Prevention warning timing out. |
| kDlpWarningTimeout, |
| }; |
| |
| // Holds information about data protection policy errors. |
| struct PolicyError { |
| // Type of the error. |
| PolicyErrorType type; |
| // The number of files blocked by the policy. |
| size_t blocked_files = 0; |
| // The name of the first file among those under block restriction. Used for |
| // notifications. |
| std::string file_name; |
| // Normally the review button is only shown when `blocked_files` is >1, this |
| // option allows to force the display of the review button irrespective of |
| // other conditions. |
| bool always_show_review = false; |
| |
| bool operator==(const PolicyError& other) const; |
| bool operator!=(const PolicyError& other) const; |
| }; |
| |
| // Unique identifier for any type of task. |
| using IOTaskId = uint64_t; |
| |
| // I/O task state::PAUSED parameters when paused to resolve a file name |
| // conflict. Currently, only supported by CopyOrMoveIOTask and |
| // RestoreToDestinationIOTask. |
| struct ConflictPauseParams { |
| // The conflict file name. |
| std::string conflict_name; |
| |
| // True if the conflict file name is a directory. |
| bool conflict_is_directory = false; |
| |
| // Set true if there are potentially multiple conflicted file names. |
| bool conflict_multiple = false; |
| |
| // The conflict copy or move target URL. |
| std::string conflict_target_url; |
| |
| bool operator==(const ConflictPauseParams& other) const; |
| }; |
| |
| // I/O task state::PAUSED parameters when paused to show a policy warning. |
| // Currently, only supported by CopyOrMovePolicyIOTask and |
| // RestoreToDestinationIOTask. |
| struct PolicyPauseParams { |
| // One of kDlp, kEnterpriseConnectors. |
| policy::Policy type; |
| // The number of files under warning restriction. Needed to show correct |
| // notifications. |
| size_t warning_files_count = 0; |
| // The name of the first file among those under warning restriction. Used for |
| // notifications. |
| std::string file_name; |
| // Normally the review button is only shown when `warning_files_count` is >1, |
| // this option allows to force the display of the review button irrespective |
| // of other conditions. |
| bool always_show_review = false; |
| |
| bool operator==(const PolicyPauseParams& other) const; |
| }; |
| |
| // I/O task state::PAUSED parameters. Only one of conflict or policy params |
| // should be set. |
| struct PauseParams { |
| PauseParams(); |
| |
| PauseParams(const PauseParams& other); |
| PauseParams& operator=(const PauseParams& other); |
| |
| PauseParams(PauseParams&& other); |
| PauseParams& operator=(PauseParams&& other); |
| |
| bool operator==(const PauseParams& other) const; |
| |
| ~PauseParams(); |
| |
| // Set iff pausing due to name conflict. |
| std::optional<ConflictPauseParams> conflict_params; |
| // Set iff pausing due to a policy warning. |
| std::optional<PolicyPauseParams> policy_params; |
| }; |
| |
| // Resume I/O task parameters when paused because of a name conflict. |
| struct ConflictResumeParams { |
| // How to resolve a CopyOrMoveIOTask file name conflict: either 'keepboth' |
| // or 'replace'. |
| std::string conflict_resolve; |
| |
| // True if |conflict_resolve| should apply to future file name conflicts. |
| bool conflict_apply_to_all = false; |
| }; |
| |
| // Resume I/O task parameters when paused because of a policy. |
| struct PolicyResumeParams { |
| // One of kDlp, kEnterpriseConnectors. |
| policy::Policy type; |
| }; |
| |
| // Resume I/O task parameters. |
| struct ResumeParams { |
| ResumeParams(); |
| |
| ResumeParams(const ResumeParams& other); |
| ResumeParams& operator=(const ResumeParams& other); |
| |
| ResumeParams(ResumeParams&& other); |
| ResumeParams& operator=(ResumeParams&& other); |
| |
| ~ResumeParams(); |
| |
| // Set iff paused due to name conflict. |
| std::optional<ConflictResumeParams> conflict_params; |
| // Set iff paused due to a policy warning. |
| std::optional<PolicyResumeParams> policy_params; |
| }; |
| |
| // Represents the status of a particular entry in an I/O task. |
| struct EntryStatus { |
| EntryStatus(storage::FileSystemURL file_url, |
| std::optional<base::File::Error> file_error, |
| std::optional<storage::FileSystemURL> source_url = std::nullopt); |
| ~EntryStatus(); |
| |
| EntryStatus(EntryStatus&& other); |
| EntryStatus& operator=(EntryStatus&& other); |
| |
| // The entry FileSystemURL. |
| storage::FileSystemURL url; |
| |
| // May be empty if the entry has not been fully processed yet. |
| std::optional<base::File::Error> error; |
| |
| // The source from which the entry identified by `url` is generated. May be |
| // empty if not relevant. |
| std::optional<storage::FileSystemURL> source_url; |
| |
| // True if entry is a directory when its metadata is processed. |
| bool is_directory = false; |
| }; |
| |
| // Represents the current progress of an I/O task. |
| class ProgressStatus { |
| public: |
| // Out-of-line constructors to appease the style linter. |
| ProgressStatus(); |
| ProgressStatus(const ProgressStatus& other) = delete; |
| ProgressStatus& operator=(const ProgressStatus& other) = delete; |
| ~ProgressStatus(); |
| |
| // Allow ProgressStatus to be moved. |
| ProgressStatus(ProgressStatus&& other); |
| ProgressStatus& operator=(ProgressStatus&& other); |
| |
| // True if the task is in kPaused state. |
| bool IsPaused() const; |
| |
| // True if the task is in a terminal state and won't receive further updates. |
| bool IsCompleted() const; |
| |
| // True if the task is paused due to a data protection policy warning. |
| bool HasWarning() const; |
| |
| // True if the task completed with security errors due to Data Leak Prevention |
| // or Enterprise Connectors policies. |
| bool HasPolicyError() const; |
| |
| // True if the task is in scanning state. |
| bool IsScanning() const; |
| |
| // Returns a default method for obtaining the source name. |
| std::string GetSourceName(Profile* profile) const; |
| |
| // Setter for the destination folder and the destination volume id. |
| void SetDestinationFolder(storage::FileSystemURL folder, |
| Profile* profile = nullptr); |
| const storage::FileSystemURL& GetDestinationFolder() const { |
| return destination_folder_; |
| } |
| const std::string& GetDestinationVolumeId() const { |
| return destination_volume_id_; |
| } |
| |
| // Task state. |
| State state; |
| |
| // Information about policy errors that occurred, if any. Empty otherwise. |
| // Can be set only if Data Leak Prevention or Enterprise Connectors policies |
| // apply. |
| std::optional<PolicyError> policy_error; |
| |
| // I/O Operation type (e.g. copy, move). |
| OperationType type; |
| |
| // Files the operation processes. |
| std::vector<EntryStatus> sources; |
| |
| // The file name to use when reporting progress. |
| std::string source_name; |
| |
| // Entries created by the I/O task. These files aren't necessarily related to |
| // |sources|. |
| std::vector<EntryStatus> outputs; |
| |
| // I/O task state::PAUSED parameters. |
| PauseParams pause_params; |
| |
| // ProgressStatus over all |sources|. |
| int64_t bytes_transferred = 0; |
| |
| // Total size of all |sources|. |
| int64_t total_bytes = 0; |
| |
| // The task id for this progress status. |
| IOTaskId task_id = 0; |
| |
| // The estimate time to finish the operation. |
| double remaining_seconds = 0; |
| |
| // Number of `sources` scanned - must be <= `sources.size()`. Only used when |
| // in kScanning `state`. When scanning files, the progress is roughly the |
| // percentage of the number of scanned items out of the total items. This |
| // isn't always accurate, e.g. when uploading entire folders or because some |
| // items are not scanned at all. The goal is to show the user that some |
| // progress is happening. |
| size_t sources_scanned = 0; |
| |
| // Whether notifications should be shown on progress status. |
| bool show_notification = true; |
| |
| // List of files skipped during the operation because we couldn't decrypt |
| // them. |
| std::vector<storage::FileSystemURL> skipped_encrypted_files; |
| |
| private: |
| // Optional destination folder for operations that transfer files to a |
| // directory (e.g. copy or move). |
| storage::FileSystemURL destination_folder_; |
| |
| // Volume id of the destination directory for operations that transfer files |
| // to a directory (e.g. copy or move). |
| std::string destination_volume_id_; |
| }; |
| |
| // An IOTask represents an I/O operation over multiple files, and is responsible |
| // for executing the operation and providing progress/completion reports. |
| class IOTask { |
| public: |
| IOTask() = delete; |
| IOTask(const IOTask& other) = delete; |
| IOTask& operator=(const IOTask& other) = delete; |
| virtual ~IOTask() = default; |
| |
| using ProgressCallback = base::RepeatingCallback<void(const ProgressStatus&)>; |
| using CompleteCallback = base::OnceCallback<void(ProgressStatus)>; |
| |
| // Executes the task. |progress_callback| should be called every so often to |
| // give updates, and |complete_callback| should be only called once at the end |
| // to signify completion with a |kSuccess|, |kError| or |kCancelled| state. |
| // |progress_callback| should be called on the same sequeuence Execute() was. |
| virtual void Execute(ProgressCallback progress_callback, |
| CompleteCallback complete_callback) = 0; |
| |
| // Pauses a task. |
| virtual void Pause(PauseParams params); |
| |
| // Resumes a task. |
| virtual void Resume(ResumeParams params); |
| |
| // Cancels the task. This should set the progress state to be |kCancelled|, |
| // but not call any of Execute()'s callbacks. The task will be deleted |
| // synchronously after this call returns. |
| virtual void Cancel() = 0; |
| |
| // Aborts the task because of policy error. This should set the progress state |
| // to be |kError| with `policy_error` but not call any of Execute()'s |
| // callbacks. The task will be deleted synchronously after this call returns. |
| virtual void CompleteWithError(PolicyError policy_error); |
| |
| // Gets the current progress status of the task. |
| const ProgressStatus& progress() { return progress_; } |
| |
| // Sets the task id. |
| void SetTaskID(IOTaskId task_id) { progress_.task_id = task_id; } |
| |
| protected: |
| explicit IOTask(bool show_notification) { |
| progress_.show_notification = show_notification; |
| } |
| |
| ProgressStatus progress_; |
| }; |
| |
| // No-op IO Task for testing. |
| // TODO(austinct): Move into io_task_controller_unittest file when the other |
| // IOTasks have been implemented. |
| class DummyIOTask : public IOTask { |
| public: |
| DummyIOTask(std::vector<storage::FileSystemURL> source_urls, |
| storage::FileSystemURL destination_folder, |
| OperationType type, |
| bool show_notification = true, |
| bool progress_succeeds = true); |
| ~DummyIOTask() override; |
| |
| // IOTask overrides: |
| void Execute(ProgressCallback progress_callback, |
| CompleteCallback complete_callback) override; |
| void Pause(PauseParams pause_params) override; |
| void Resume(ResumeParams resume_params) override; |
| void Cancel() override; |
| void CompleteWithError(PolicyError policy_error) override; |
| |
| private: |
| void DoProgress(); |
| void DoComplete(); |
| |
| ProgressCallback progress_callback_; |
| CompleteCallback complete_callback_; |
| |
| // Whether progressing the task should automatically complete it with |
| // kSuccess. |
| bool progress_succeeds_; |
| |
| base::WeakPtrFactory<DummyIOTask> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace file_manager::io_task |
| |
| #endif // CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_H_ |