1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <sys/stat.h>
10 #include <time.h>
11 
12 #include <blobfs/format.h>
13 #include <blobfs/fsck.h>
14 #include <blobfs/host.h>
15 #include <fbl/unique_fd.h>
16 #include <fs-management/mount.h>
17 #include <fvm/fvm.h>
18 #include <fvm/fvm-sparse.h>
19 #include <minfs/bcache.h>
20 #include <minfs/format.h>
21 #include <minfs/fsck.h>
22 #include <fbl/vector.h>
23 
24 #define TRACE 0
25 
26 #if TRACE
27 #define xprintf(fmt...) printf(fmt)
28 #else
29 #define xprintf(fmt...) \
30     do {                \
31     } while (0)
32 #endif
33 
34 // File system names
35 static constexpr char kMinfsName[] = "minfs";
36 static constexpr char kBlobfsName[] = "blobfs";
37 
38 // Guid type names
39 static constexpr char kDefaultTypeName[] = "default";
40 static constexpr char kDataTypeName[] = "data";
41 static constexpr char kDataUnsafeTypeName[] = "data-unsafe";
42 static constexpr char kSystemTypeName[] = "system";
43 static constexpr char kBlobTypeName[] = "blob";
44 
45 // Guid type values
46 static constexpr uint8_t kDefaultType[] = GUID_EMPTY_VALUE;
47 static constexpr uint8_t kDataType[] = GUID_DATA_VALUE;
48 static constexpr uint8_t kSystemType[] = GUID_SYSTEM_VALUE;
49 static constexpr uint8_t kBlobType[] = GUID_BLOB_VALUE;
50 
51 typedef struct {
52     size_t vslice_start;
53     uint32_t slice_count;
54     uint32_t block_offset;
55     uint32_t block_count;
56     bool zero_fill;
57 } vslice_info_t;
58 
59 // Format defines an interface for file systems to implement in order to be placed into an FVM or
60 // sparse container
61 class Format {
62 public:
63     // Detect the type of partition starting at |offset| bytes
64     static zx_status_t Detect(int fd, off_t offset, disk_format_t* out);
65     // Read file at |path| and generate appropriate Format
66     static zx_status_t Create(const char* path, const char* type, fbl::unique_ptr<Format>* out);
67     // Fun fsck on partition contained between bytes |start| and |end|
68     static zx_status_t Check(fbl::unique_fd fd, off_t start, off_t end,
69                              const fbl::Vector<size_t>& extent_lengths, disk_format_t part);
~Format()70     virtual ~Format() {}
71     // Update the file system's superblock (e.g. set FVM flag), and any other information required
72     // for the partition to be placed in FVM.
73     virtual zx_status_t MakeFvmReady(size_t slice_size, uint32_t vpart_index) = 0;
74     // Get FVM data for each extent
75     virtual zx_status_t GetVsliceRange(unsigned extent_index, vslice_info_t* vslice_info) const = 0;
76     // Get total number of slices required for this partition
77     virtual zx_status_t GetSliceCount(uint32_t* slices_out) const = 0;
78     // Fill the in-memory data block with data from the specified block on disk
79     virtual zx_status_t FillBlock(size_t block_offset) = 0;
80     // Empty the data block (i.e. fill with all 0's)
81     virtual zx_status_t EmptyBlock() = 0;
82 
GetPartitionInfo(fvm::partition_descriptor_t * partition)83     void GetPartitionInfo(fvm::partition_descriptor_t* partition) const {
84         memcpy(partition->type, type_, sizeof(type_));
85         strncpy(reinterpret_cast<char*>(partition->name), Name(), FVM_NAME_LEN);
86         partition->flags = flags_;
87     }
88 
Guid(uint8_t * guid)89     void Guid(uint8_t* guid) const {
90         memcpy(guid, guid_, sizeof(guid_));
91     }
92 
93     virtual void* Data() = 0;
94     virtual uint32_t BlockSize() const = 0;
95     virtual uint32_t BlocksPerSlice() const = 0;
96 
VpartIndex()97     uint32_t VpartIndex() const {
98         CheckFvmReady();
99         return vpart_index_;
100     }
101 
102 protected:
103     bool fvm_ready_;
104     uint32_t vpart_index_;
105     uint8_t guid_[FVM_GUID_LEN];
106     uint8_t type_[GPT_GUID_LEN];
107     uint32_t flags_;
108 
109     Format();
110 
CheckFvmReady()111     void CheckFvmReady() const {
112         if (!fvm_ready_) {
113             fprintf(stderr, "Error: File system has not been converted to an FVM-ready format\n");
114             exit(-1);
115         }
116     }
117 
GenerateGuid()118     void GenerateGuid() {
119         srand(time(0));
120         for (unsigned i = 0; i < FVM_GUID_LEN; i++) {
121             guid_[i] = static_cast<uint8_t>(rand());
122         }
123     }
124 
125 private:
126     virtual const char* Name() const = 0;
127 };
128 
129 class MinfsFormat final : public Format {
130 public:
131     MinfsFormat(fbl::unique_fd fd, const char* type);
132     zx_status_t MakeFvmReady(size_t slice_size, uint32_t vpart_index) final;
133     zx_status_t GetVsliceRange(unsigned extent_index, vslice_info_t* vslice_info) const final;
134     zx_status_t GetSliceCount(uint32_t* slices_out) const final;
135     zx_status_t FillBlock(size_t block_offset) final;
136     zx_status_t EmptyBlock() final;
137     void* Data() final;
138     uint32_t BlockSize() const final;
139     uint32_t BlocksPerSlice() const final;
140     uint8_t datablk[minfs::kMinfsBlockSize];
141 
142 private:
143     const char* Name() const final;
144 
145     fbl::unique_ptr<minfs::Bcache> bc_;
146 
147     // Input superblock
148     union {
149         char blk_[minfs::kMinfsBlockSize];
150         minfs::Superblock info_;
151     };
152 
153     // Output superblock
154     union {
155         char fvm_blk_[minfs::kMinfsBlockSize];
156         minfs::Superblock fvm_info_;
157     };
158 };
159 
160 class BlobfsFormat final : public Format {
161 public:
162     BlobfsFormat(fbl::unique_fd fd, const char* type);
163     ~BlobfsFormat();
164     zx_status_t MakeFvmReady(size_t slice_size, uint32_t vpart_index) final;
165     zx_status_t GetVsliceRange(unsigned extent_index, vslice_info_t* vslice_info) const final;
166     zx_status_t GetSliceCount(uint32_t* slices_out) const final;
167     zx_status_t FillBlock(size_t block_offset) final;
168     zx_status_t EmptyBlock() final;
169     void* Data() final;
170     uint32_t BlockSize() const final;
171     uint32_t BlocksPerSlice() const final;
172     uint8_t datablk[blobfs::kBlobfsBlockSize];
173 
174 private:
175     const char* Name() const final;
176 
177     fbl::unique_fd fd_;
178     uint64_t blocks_;
179 
180     // Input superblock
181     union {
182         char blk_[blobfs::kBlobfsBlockSize];
183         blobfs::Superblock info_;
184     };
185 
186     // Output superblock
187     union {
188         char fvm_blk_[blobfs::kBlobfsBlockSize];
189         blobfs::Superblock fvm_info_;
190     };
191 
192     uint32_t BlocksToSlices(uint32_t block_count) const;
193     uint32_t SlicesToBlocks(uint32_t slice_count) const;
194 };
195