1 // Copyright (C) 2019 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #include <stdint.h> 18 19 #include <memory> 20 #include <optional> 21 #include <string> 22 23 #include <android-base/unique_fd.h> 24 #include <libsnapshot/cow_format.h> 25 #include <libsnapshot/cow_reader.h> 26 27 namespace android { 28 namespace snapshot { 29 30 struct CowOptions { 31 uint32_t block_size = 4096; 32 std::string compression; 33 34 // Maximum number of blocks that can be written. 35 std::optional<uint64_t> max_blocks; 36 37 // Number of CowOperations in a cluster. 0 for no clustering. Cannot be 1. 38 uint32_t cluster_ops = 200; 39 40 bool scratch_space = true; 41 }; 42 43 // Interface for writing to a snapuserd COW. All operations are ordered; merges 44 // will occur in the sequence they were added to the COW. 45 class ICowWriter { 46 public: ICowWriter(const CowOptions & options)47 explicit ICowWriter(const CowOptions& options) : options_(options) {} 48 ~ICowWriter()49 virtual ~ICowWriter() {} 50 51 // Encode an operation that copies the contents of |old_block| to the 52 // location of |new_block|. 53 bool AddCopy(uint64_t new_block, uint64_t old_block); 54 55 // Encode a sequence of raw blocks. |size| must be a multiple of the block size. 56 bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size); 57 58 // Encode a sequence of zeroed blocks. |size| must be a multiple of the block size. 59 bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks); 60 61 // Add a label to the op sequence. 62 bool AddLabel(uint64_t label); 63 64 // Flush all pending writes. This must be called before closing the writer 65 // to ensure that the correct headers and footers are written. 66 virtual bool Finalize() = 0; 67 68 // Return number of bytes the cow image occupies on disk. 69 virtual uint64_t GetCowSize() = 0; 70 71 // Returns true if AddCopy() operations are supported. SupportsCopyOperation()72 virtual bool SupportsCopyOperation() const { return true; } 73 options()74 const CowOptions& options() { return options_; } 75 76 protected: 77 virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0; 78 virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0; 79 virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0; 80 virtual bool EmitLabel(uint64_t label) = 0; 81 82 bool ValidateNewBlock(uint64_t new_block); 83 84 protected: 85 CowOptions options_; 86 }; 87 88 class CowWriter : public ICowWriter { 89 public: 90 explicit CowWriter(const CowOptions& options); 91 92 // Set up the writer. 93 // The file starts from the beginning. 94 // 95 // If fd is < 0, the CowWriter will be opened against /dev/null. This is for 96 // computing COW sizes without using storage space. 97 bool Initialize(android::base::unique_fd&& fd); 98 bool Initialize(android::base::borrowed_fd fd); 99 // Set up a writer, assuming that the given label is the last valid label. 100 // This will result in dropping any labels that occur after the given on, and will fail 101 // if the given label does not appear. 102 bool InitializeAppend(android::base::unique_fd&&, uint64_t label); 103 bool InitializeAppend(android::base::borrowed_fd fd, uint64_t label); 104 105 bool Finalize() override; 106 107 uint64_t GetCowSize() override; 108 GetCowVersion()109 uint32_t GetCowVersion() { return header_.major_version; } 110 111 protected: 112 virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override; 113 virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; 114 virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; 115 virtual bool EmitLabel(uint64_t label) override; 116 117 private: 118 bool EmitCluster(); 119 bool EmitClusterIfNeeded(); 120 void SetupHeaders(); 121 bool ParseOptions(); 122 bool OpenForWrite(); 123 bool OpenForAppend(uint64_t label); 124 bool GetDataPos(uint64_t* pos); 125 bool WriteRawData(const void* data, size_t size); 126 bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0); 127 void AddOperation(const CowOperation& op); 128 std::basic_string<uint8_t> Compress(const void* data, size_t length); 129 void InitPos(); 130 131 bool SetFd(android::base::borrowed_fd fd); 132 bool Sync(); 133 bool Truncate(off_t length); 134 135 private: 136 android::base::unique_fd owned_fd_; 137 android::base::borrowed_fd fd_; 138 CowHeader header_{}; 139 CowFooter footer_{}; 140 int compression_ = 0; 141 uint64_t next_op_pos_ = 0; 142 uint64_t next_data_pos_ = 0; 143 uint32_t cluster_size_ = 0; 144 uint32_t current_cluster_size_ = 0; 145 uint64_t current_data_size_ = 0; 146 bool is_dev_null_ = false; 147 bool merge_in_progress_ = false; 148 bool is_block_device_ = false; 149 150 // :TODO: this is not efficient, but stringstream ubsan aborts because some 151 // bytes overflow a signed char. 152 std::basic_string<uint8_t> ops_; 153 }; 154 155 } // namespace snapshot 156 } // namespace android 157