| // Copyright 2019 The Chromium OS 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 VM_TOOLS_CONCIERGE_DISK_IMAGE_H_ |
| #define VM_TOOLS_CONCIERGE_DISK_IMAGE_H_ |
| |
| #include <archive.h> |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include <base/files/file.h> |
| #include <base/files/file_path.h> |
| #include <base/files/scoped_file.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <crypto/secure_hash.h> |
| #include <dbus/exported_object.h> |
| #include <dbus/object_proxy.h> |
| |
| #include <vm_concierge/proto_bindings/concierge_service.pb.h> |
| |
| #include "vm_tools/common/vm_id.h" |
| |
| namespace vm_tools { |
| namespace concierge { |
| |
| class Service; |
| |
| class DiskImageOperation { |
| public: |
| virtual ~DiskImageOperation() = default; |
| |
| // Execute next chunk of the disk operation, handling up to |io_limit| bytes. |
| void Run(uint64_t io_limit); |
| |
| // Report operation progress, in 0..100 range. |
| int GetProgress() const; |
| |
| const std::string& uuid() const { return uuid_; } |
| DiskImageStatus status() const { return status_; } |
| const std::string& failure_reason() const { return failure_reason_; } |
| int64_t processed_size() const { return processed_size_; } |
| |
| protected: |
| DiskImageOperation(); |
| DiskImageOperation(const DiskImageOperation&) = delete; |
| DiskImageOperation& operator=(const DiskImageOperation&) = delete; |
| |
| // Executes up to |io_limit| bytes of disk operation. |
| virtual bool ExecuteIo(uint64_t io_limit) = 0; |
| |
| // Called after all IO is done to commit the result. |
| virtual void Finalize() = 0; |
| |
| void AccumulateProcessedSize(uint64_t size) { processed_size_ += size; } |
| |
| void set_status(DiskImageStatus status) { status_ = status; } |
| void set_failure_reason(const std::string& reason) { |
| failure_reason_ = reason; |
| } |
| void set_source_size(uint64_t source_size) { source_size_ = source_size; } |
| |
| private: |
| // UUID assigned to the operation. |
| const std::string uuid_; |
| |
| // Status of the operation. |
| DiskImageStatus status_; |
| |
| // Failure reason, if any, to be communicated to the callers. |
| std::string failure_reason_; |
| |
| // Size of the source of disk operation (bytes). |
| uint64_t source_size_; |
| |
| // Number of bytes consumed from the source. |
| uint64_t processed_size_; |
| }; |
| |
| class PluginVmCreateOperation : public DiskImageOperation { |
| public: |
| static std::unique_ptr<PluginVmCreateOperation> Create( |
| base::ScopedFD in_fd, |
| const base::FilePath& iso_dir, |
| uint64_t source_size, |
| const VmId vm_id, |
| const std::vector<std::string> params); |
| |
| protected: |
| bool ExecuteIo(uint64_t io_limit) override; |
| void Finalize() override; |
| |
| private: |
| PluginVmCreateOperation(base::ScopedFD in_fd, |
| uint64_t source_size, |
| const VmId vm_id_, |
| const std::vector<std::string> params); |
| PluginVmCreateOperation(const PluginVmCreateOperation&) = delete; |
| PluginVmCreateOperation& operator=(const PluginVmCreateOperation&) = delete; |
| |
| bool PrepareOutput(const base::FilePath& iso_dir); |
| |
| void MarkFailed(const char* msg, int error_code); |
| |
| // VM owner and name. Used when registering imported image with the |
| // dispatcher. |
| const VmId vm_id_; |
| |
| // Parameters that need to be passed to the Plugin VM helper when |
| // creating the VM. |
| const std::vector<std::string> params_; |
| |
| // File descriptor from which to fetch the source image. |
| base::ScopedFD in_fd_; |
| |
| // File descriptor to where the data from source image will |
| // be written to. |
| base::ScopedFD out_fd_; |
| |
| // Destination directory object. |
| base::ScopedTempDir output_dir_; |
| }; |
| |
| struct ArchiveReadDeleter { |
| void operator()(struct archive* in) { archive_read_free(in); } |
| }; |
| using ArchiveReader = std::unique_ptr<struct archive, ArchiveReadDeleter>; |
| |
| struct ArchiveWriteDeleter { |
| void operator()(struct archive* out) { archive_write_free(out); } |
| }; |
| using ArchiveWriter = std::unique_ptr<struct archive, ArchiveWriteDeleter>; |
| |
| enum class ArchiveFormat { |
| ZIP, |
| TAR_GZ, |
| }; |
| |
| class VmExportOperation : public DiskImageOperation { |
| public: |
| static std::unique_ptr<VmExportOperation> Create( |
| const VmId vm_id, |
| const base::FilePath disk_path, |
| base::ScopedFD out_fd, |
| base::ScopedFD out_digest_fd, |
| ArchiveFormat out_fmt); |
| |
| ~VmExportOperation() override; |
| |
| protected: |
| bool ExecuteIo(uint64_t io_limit) override; |
| void Finalize() override; |
| |
| private: |
| static int OutputFileOpenCallback(archive* a, void* data); |
| static ssize_t OutputFileWriteCallback(archive* a, |
| void* data, |
| const void* buf, |
| size_t length); |
| static int OutputFileCloseCallback(archive* a, void* data); |
| |
| VmExportOperation(const VmId vm_id, |
| const base::FilePath disk_path, |
| base::ScopedFD out_fd, |
| base::ScopedFD out_digest_fd, |
| ArchiveFormat out_fmt); |
| VmExportOperation(const VmExportOperation&) = delete; |
| VmExportOperation& operator=(const VmExportOperation&) = delete; |
| |
| bool PrepareInput(); |
| bool PrepareOutput(); |
| |
| void MarkFailed(const char* msg, struct archive* a); |
| |
| // Copies up to |io_limit| bytes of one file of the image. |
| // Returns number of bytes read. |
| uint64_t CopyEntry(uint64_t io_limit); |
| |
| // VM owner and name. |
| const VmId vm_id_; |
| |
| // Path to the directory containing source image. |
| const base::FilePath src_image_path_; |
| |
| // File descriptor to write the compressed image to. |
| base::ScopedFD out_fd_; |
| |
| // File descriptor to write the SHA256 digest of the compressed image to. |
| base::ScopedFD out_digest_fd_; |
| |
| // We are in a middle of copying an archive entry. Copying of one archive |
| // entry may span several Run() invocations, depending on the size of the |
| // entry. |
| bool copying_data_; |
| |
| // If true, disk image is a directory potentially containing multiple files. |
| // If false, disk image is a single file. |
| bool image_is_directory_; |
| |
| // Source directory "archive". |
| ArchiveReader in_; |
| |
| // Output archive backed by the file descriptor. |
| ArchiveWriter out_; |
| |
| // Output archive format. |
| ArchiveFormat out_fmt_; |
| |
| // Hasher to generate digest of the produced image. |
| std::unique_ptr<crypto::SecureHash> sha256_; |
| }; |
| |
| class PluginVmImportOperation : public DiskImageOperation { |
| public: |
| static std::unique_ptr<PluginVmImportOperation> Create( |
| base::ScopedFD in_fd, |
| const base::FilePath disk_path, |
| uint64_t source_size, |
| const VmId vm_id, |
| scoped_refptr<dbus::Bus> bus, |
| dbus::ObjectProxy* vmplugin_service_proxy); |
| |
| ~PluginVmImportOperation() override; |
| |
| protected: |
| bool ExecuteIo(uint64_t io_limit) override; |
| void Finalize() override; |
| |
| private: |
| PluginVmImportOperation(base::ScopedFD in_fd, |
| uint64_t source_size, |
| const base::FilePath disk_path, |
| const VmId vm_id_, |
| scoped_refptr<dbus::Bus> bus, |
| dbus::ObjectProxy* vmplugin_service_proxy); |
| PluginVmImportOperation(const PluginVmImportOperation&) = delete; |
| PluginVmImportOperation& operator=(const PluginVmImportOperation&) = delete; |
| |
| bool PrepareInput(); |
| bool PrepareOutput(); |
| |
| void MarkFailed(const char* msg, struct archive* a); |
| |
| // Copies up to |io_limit| bytes of one archive entry of the image. |
| // Returns number of bytes read. |
| uint64_t CopyEntry(uint64_t io_limit); |
| |
| // Path to the directory that will contain the imported image. |
| const base::FilePath dest_image_path_; |
| |
| // VM owner and name. Used when registering imported image with the |
| // dispatcher. |
| const VmId vm_id_; |
| |
| // Connection to the system bus. |
| scoped_refptr<dbus::Bus> bus_; |
| |
| // Proxy to the dispatcher service. Not owned. |
| dbus::ObjectProxy* vmplugin_service_proxy_; |
| |
| // File descriptor from which to fetch the source image. |
| base::ScopedFD in_fd_; |
| |
| // We are in a middle of copying an archive entry. Copying of one archive |
| // entry may span several Run() invocations, depending on the size of the |
| // entry. |
| bool copying_data_; |
| |
| // Destination directory object. |
| base::ScopedTempDir output_dir_; |
| |
| // Input compressed archive backed up by the file descriptor. |
| ArchiveReader in_; |
| |
| // "Archive" representing output uncompressed directory. |
| ArchiveWriter out_; |
| }; |
| |
| class VmResizeOperation : public DiskImageOperation { |
| public: |
| using ResizeCallback = base::Callback<void(const std::string& owner_id, |
| const std::string& vm_name, |
| StorageLocation location, |
| uint64_t target_size, |
| DiskImageStatus* status, |
| std::string* failure_reason)>; |
| |
| static std::unique_ptr<VmResizeOperation> Create( |
| const VmId vm_id, |
| StorageLocation location, |
| const base::FilePath disk_path, |
| uint64_t disk_size, |
| ResizeCallback start_resize_cb, |
| ResizeCallback process_resize_cb); |
| |
| protected: |
| bool ExecuteIo(uint64_t io_limit) override; |
| void Finalize() override; |
| |
| private: |
| VmResizeOperation(const VmId vm_id, |
| StorageLocation location, |
| const base::FilePath disk_path, |
| uint64_t size, |
| ResizeCallback process_resize_cb); |
| VmResizeOperation(const VmResizeOperation&) = delete; |
| VmResizeOperation& operator=(const VmResizeOperation&) = delete; |
| |
| ResizeCallback process_resize_cb_; |
| |
| // VM owner and name. |
| const VmId vm_id_; |
| |
| StorageLocation location_; |
| |
| base::FilePath disk_path_; |
| |
| uint64_t target_size_; |
| }; |
| |
| } // namespace concierge |
| } // namespace vm_tools |
| |
| #endif // VM_TOOLS_CONCIERGE_DISK_IMAGE_H_ |