• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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