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