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 // Preset the number of merged ops. Only useful for testing. 43 uint64_t num_merge_ops = 0; 44 }; 45 46 // Interface for writing to a snapuserd COW. All operations are ordered; merges 47 // will occur in the sequence they were added to the COW. 48 class ICowWriter { 49 public: ICowWriter(const CowOptions & options)50 explicit ICowWriter(const CowOptions& options) : options_(options) {} 51 ~ICowWriter()52 virtual ~ICowWriter() {} 53 54 // Encode an operation that copies the contents of |old_block| to the 55 // location of |new_block|. 56 bool AddCopy(uint64_t new_block, uint64_t old_block); 57 58 // Encode a sequence of raw blocks. |size| must be a multiple of the block size. 59 bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size); 60 61 // Add a sequence of xor'd blocks. |size| must be a multiple of the block size. 62 bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, 63 uint16_t offset); 64 65 // Encode a sequence of zeroed blocks. |size| must be a multiple of the block size. 66 bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks); 67 68 // Add a label to the op sequence. 69 bool AddLabel(uint64_t label); 70 71 // Add sequence data for op merging. Data is a list of the destination block numbers. 72 bool AddSequenceData(size_t num_ops, const uint32_t* data); 73 74 // Flush all pending writes. This must be called before closing the writer 75 // to ensure that the correct headers and footers are written. 76 virtual bool Finalize() = 0; 77 78 // Return number of bytes the cow image occupies on disk. 79 virtual uint64_t GetCowSize() = 0; 80 81 // Returns true if AddCopy() operations are supported. SupportsCopyOperation()82 virtual bool SupportsCopyOperation() const { return true; } 83 options()84 const CowOptions& options() { return options_; } 85 86 protected: 87 virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0; 88 virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0; 89 virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, 90 uint32_t old_block, uint16_t offset) = 0; 91 virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0; 92 virtual bool EmitLabel(uint64_t label) = 0; 93 virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) = 0; 94 95 bool ValidateNewBlock(uint64_t new_block); 96 97 protected: 98 CowOptions options_; 99 }; 100 101 class CowWriter : public ICowWriter { 102 public: 103 explicit CowWriter(const CowOptions& options); 104 105 // Set up the writer. 106 // The file starts from the beginning. 107 // 108 // If fd is < 0, the CowWriter will be opened against /dev/null. This is for 109 // computing COW sizes without using storage space. 110 bool Initialize(android::base::unique_fd&& fd); 111 bool Initialize(android::base::borrowed_fd fd); 112 // Set up a writer, assuming that the given label is the last valid label. 113 // This will result in dropping any labels that occur after the given on, and will fail 114 // if the given label does not appear. 115 bool InitializeAppend(android::base::unique_fd&&, uint64_t label); 116 bool InitializeAppend(android::base::borrowed_fd fd, uint64_t label); 117 118 bool Finalize() override; 119 120 uint64_t GetCowSize() override; 121 GetCowVersion()122 uint32_t GetCowVersion() { return header_.major_version; } 123 124 protected: 125 virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override; 126 virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; 127 virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, 128 uint32_t old_block, uint16_t offset) override; 129 virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; 130 virtual bool EmitLabel(uint64_t label) override; 131 virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; 132 133 private: 134 bool EmitCluster(); 135 bool EmitClusterIfNeeded(); 136 bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block, 137 uint16_t offset, uint8_t type); 138 void SetupHeaders(); 139 bool ParseOptions(); 140 bool OpenForWrite(); 141 bool OpenForAppend(uint64_t label); 142 bool GetDataPos(uint64_t* pos); 143 bool WriteRawData(const void* data, size_t size); 144 bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0); 145 void AddOperation(const CowOperation& op); 146 std::basic_string<uint8_t> Compress(const void* data, size_t length); 147 void InitPos(); 148 149 bool SetFd(android::base::borrowed_fd fd); 150 bool Sync(); 151 bool Truncate(off_t length); 152 153 private: 154 android::base::unique_fd owned_fd_; 155 android::base::borrowed_fd fd_; 156 CowHeader header_{}; 157 CowFooter footer_{}; 158 int compression_ = 0; 159 uint64_t next_op_pos_ = 0; 160 uint64_t next_data_pos_ = 0; 161 uint32_t cluster_size_ = 0; 162 uint32_t current_cluster_size_ = 0; 163 uint64_t current_data_size_ = 0; 164 bool is_dev_null_ = false; 165 bool merge_in_progress_ = false; 166 bool is_block_device_ = false; 167 168 // :TODO: this is not efficient, but stringstream ubsan aborts because some 169 // bytes overflow a signed char. 170 std::basic_string<uint8_t> ops_; 171 }; 172 173 } // namespace snapshot 174 } // namespace android 175