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