chromium/chrome/services/file_util/public/cpp/zip_file_creator.h

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

#ifndef CHROME_SERVICES_FILE_UTIL_PUBLIC_CPP_ZIP_FILE_CREATOR_H_
#define CHROME_SERVICES_FILE_UTIL_PUBLIC_CPP_ZIP_FILE_CREATOR_H_

#include <memory>

#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
#include "chrome/services/file_util/public/mojom/zip_file_creator.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"

// ZipFileCreator creates a ZIP file from a specified list of files and
// directories under a common parent directory. This is done in a sandboxed
// utility process to protect the browser process from handling arbitrary
// input data from untrusted sources.
class ZipFileCreator : public base::RefCountedThreadSafe<ZipFileCreator>,
                       private chrome::mojom::ZipListener {
 public:
  // ZIP creator result.
  // These values are persisted to logs and UMA (except kInProgress).
  // Entries should not be renumbered and numeric values should never be reused.
  enum Result {
    kInProgress = -1,  // This one is not recorded in UMA.
    kSuccess = 0,
    kCancelled = 1,
    kError = 2,
    kMaxValue = kError,
  };

  // Output operator for logging.
  friend std::ostream& operator<<(std::ostream& out, Result result);

  // Progress event of a ZIP creation operation.
  struct Progress {
    // Total number of bytes read from files getting zipped so far.
    int64_t bytes = 0;

    // Number of file entries added to the ZIP so far.
    // A file entry is added after its bytes have been processed.
    int files = 0;

    // Number of directory entries added to the ZIP so far.
    // A directory entry is added before items in it.
    int directories = 0;

    // Number of progress events received so far.
    int update_count = 0;

    // ZIP creator result.
    Result result = kInProgress;
  };

  // Creates a zip file from the specified list of files and directories.
  ZipFileCreator(base::FilePath src_dir,
                 std::vector<base::FilePath> src_relative_paths,
                 base::FilePath dest_file);

  ZipFileCreator(const ZipFileCreator&) = delete;
  ZipFileCreator& operator=(const ZipFileCreator&) = delete;

  // Sets the optional progress callback.
  // This callback will be called the next time a progress event is received.
  // Precondition: the progress callback hasn't been set yet, or the previously
  // set progress callback has already been called.
  // Precondition: this ZipFileCreator is not in its final state yet.
  void SetProgressCallback(base::OnceClosure callback);

  // Sets the optional completion callback.
  // Precondition: the completion callback hasn't been set yet.
  // Precondition: this ZipFileCreator is not in its final state yet.
  void SetCompletionCallback(base::OnceClosure callback);

  // Gets the latest progress information.
  Progress GetProgress() const { return progress_; }

  // Gets the final result.
  Result GetResult() const { return progress_.result; }

  // Starts creating the ZIP file.
  void Start(mojo::PendingRemote<chrome::mojom::FileUtilService> service);

  // Stops creating the ZIP file.
  void Stop();

 private:
  friend class base::RefCountedThreadSafe<ZipFileCreator>;

  ~ZipFileCreator() override;

  // Called after the dest_file |file| is opened on the blocking pool to
  // create the ZIP file in it using a sandboxed utility process.
  void CreateZipFile(
      mojo::PendingRemote<chrome::mojom::FileUtilService> service,
      base::File file);

  // Binds the Directory receiver to its implementation.
  void BindDirectory(
      mojo::PendingReceiver<filesystem::mojom::Directory> receiver) const;

  // Called when the ZipFileCreator service finished.
  void OnFinished(bool success) override;

  // Notifies the end of the ZIP operation.
  void ReportResult(Result result);

  // ZIP progress report.
  void OnProgress(uint64_t bytes,
                  uint32_t files,
                  uint32_t directories) override;

  // Latest progress information.
  Progress progress_;

  // Progress callback.
  base::OnceClosure progress_callback_;

  // Final completion callback.
  base::OnceClosure completion_callback_;

  // The source directory for input files.
  const base::FilePath src_dir_;

  // The list of source files paths to be included in the zip file.
  // Entries are relative paths under directory |src_dir_|.
  const std::vector<base::FilePath> src_relative_paths_;

  // The output ZIP file path.
  const base::FilePath dest_file_;

  // Remote interfaces to the file util service. Only used from the UI thread.
  mojo::Remote<chrome::mojom::FileUtilService> service_;
  mojo::Remote<chrome::mojom::ZipFileCreator> remote_zip_file_creator_;

  // Listener receiver.
  mojo::Receiver<chrome::mojom::ZipListener> listener_{this};
};

#endif  // CHROME_SERVICES_FILE_UTIL_PUBLIC_CPP_ZIP_FILE_CREATOR_H_