1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <assert.h> 18 #include <string.h> 19 #include <endian.h> 20 21 #include "fatblock.h" 22 #include "fat.h" 23 #include "fs.h" 24 #include "utils.h" 25 26 #define DEFAULT_SECTOR_SIZE 512 27 28 static void fs_add_extent(struct fs *fs, struct extent *extent, 29 offset_t start, offset_t len, int type) 30 { 31 assert(fs); 32 assert(extent); 33 34 extent->start = start; 35 extent->len = len; 36 extent->type = type; 37 38 extent->next = fs->extents; 39 fs->extents = extent; 40 } 41 42 struct extent *fs_find_extent(struct fs *fs, offset_t start, offset_t len, 43 struct extent *last, 44 offset_t *r_start_out, 45 offset_t *e_start_out, 46 offset_t *len_out) 47 { 48 struct extent *e; 49 offset_t end; 50 offset_t e_start, e_end, e_len, e_rel_start, r_rel_start, rel_len; 51 52 assert(fs); 53 54 end = start + len; 55 56 e = last ? last->next : fs->extents; 57 for (; e; e = e->next) { 58 e_start = e->start; 59 e_len = e->len; 60 e_end = e_start + e_len; 61 62 if (start >= e_end) 63 continue; 64 65 if (end <= e_start) 66 continue; 67 68 if (e_start <= start) { 69 r_rel_start = 0; 70 e_rel_start = start - e_start; 71 if (end <= e_end) 72 rel_len = len; 73 else 74 rel_len = e_end - start; 75 } else { 76 e_rel_start = 0; 77 r_rel_start = e_start - start; 78 if (e_end <= end) 79 rel_len = e_len; 80 else 81 rel_len = end - e_start; 82 } 83 84 assert(e_rel_start < e_len); 85 assert(e_rel_start + rel_len <= e_len); 86 assert(r_rel_start < len); 87 assert(r_rel_start + rel_len <= len); 88 89 if (r_start_out) 90 *r_start_out = r_rel_start; 91 if (e_start_out) 92 *e_start_out = e_rel_start; 93 if (len_out) 94 *len_out = rel_len; 95 96 return e; 97 } 98 99 return NULL; 100 } 101 102 static void fs_set_fat(struct fs *fs, cluster_t cluster, fat_entry_t entry) 103 { 104 assert(fs); 105 106 fs->fat[cluster] = htole32(entry); 107 } 108 109 int fs_alloc_extent(struct fs *fs, struct extent *extent, 110 offset_t len, int type, cluster_t *first_cluster_out) 111 { 112 assert(fs); 113 assert(extent); 114 115 cluster_t clusters_needed, start; 116 cluster_t i; 117 118 if (len == 0) { 119 extent->start = 0; 120 extent->len = 0; 121 extent->type = type; 122 *first_cluster_out = 0; 123 return 0; 124 } 125 126 clusters_needed = (len + fs->cluster_size - 1) / fs->cluster_size; 127 128 /* Check for adequate space. */ 129 if (fs->next_cluster + clusters_needed > fs->num_clusters) { 130 WARN("allocating extent: filesystem is full!\n"); 131 return -1; 132 } 133 134 /* Allocate clusters. */ 135 start = fs->next_cluster; 136 fs->next_cluster += clusters_needed; 137 138 /* Update FAT. */ 139 for (i = 0; i < clusters_needed - 1; i++) { 140 fs_set_fat(fs, start + i, start + i + 1); 141 } 142 fs_set_fat(fs, start + clusters_needed - 1, FAT_ENTRY_EOC); 143 144 *first_cluster_out = start; 145 146 fs_add_extent(fs, 147 extent, 148 fs->data_offset + (offset_t)(start - FAT_CLUSTER_ZERO) 149 * fs->cluster_size, 150 (offset_t)clusters_needed * fs->cluster_size, 151 type); 152 153 return 0; 154 } 155 156 int fs_init(struct fs *fs, uint16_t cluster_size, offset_t data_size, 157 offset_t *total_size_out) 158 { 159 uint16_t sector_size; 160 cluster_t data_clusters; 161 sector_t reserved_sectors, fat_sectors, data_sectors, total_sectors; 162 sector_t sectors_per_cluster; 163 int fat_entries_per_sector; 164 fat_entry_t *fat; 165 struct fat_boot_sector *bs; 166 struct fat_info_sector *is; 167 168 assert(fs); 169 170 sector_size = DEFAULT_SECTOR_SIZE; 171 fs->cluster_size = cluster_size; 172 173 sectors_per_cluster = cluster_size / DEFAULT_SECTOR_SIZE; 174 fat_entries_per_sector = sector_size / sizeof(fat_entry_t); 175 176 data_clusters = (data_size + cluster_size - 1) / cluster_size; 177 data_sectors = data_clusters * sectors_per_cluster; 178 fat_sectors = ((data_clusters + 2) + fat_entries_per_sector - 1) 179 / fat_entries_per_sector; 180 reserved_sectors = 3; 181 total_sectors = reserved_sectors + fat_sectors + data_sectors; 182 183 memset(&fs->boot, 0, sizeof(fs->boot)); 184 bs = &fs->boot; 185 186 strpadcpy(bs->name, "FATBLOCK", ' ', sizeof(bs->name)); 187 bs->sector_size = htole16(sector_size); 188 bs->sectors_per_cluster = sectors_per_cluster; 189 bs->reserved_sectors = htole16(reserved_sectors); 190 bs->fats = 1; 191 bs->media_desc = FAT_MEDIA_DESC_FIXED; 192 /* TODO: Calculate geometry? */ 193 bs->sectors_per_track = htole16(42); 194 bs->heads = htole16(42); 195 bs->sectors32 = htole32(total_sectors); 196 bs->fat_sectors32 = htole32(fat_sectors); 197 /* bs->rootdir_start will be set later. */ 198 bs->fs_info_sector = htole16(1); 199 bs->backup_boot_sector = htole16(2); 200 bs->phys_drive = FAT_PHYS_DRIVE_REMOVABLE; 201 bs->ext_boot_sig = FAT_EXT_BOOT_SIG; 202 bs->serial = 0x42424242; 203 strpadcpy(bs->vol_label, "FATBLOCK", ' ', sizeof(bs->vol_label)); 204 strpadcpy(bs->type, "FAT32", ' ', sizeof(bs->type)); 205 memcpy(bs->boot_sig, FAT_BOOT_SIG, sizeof(bs->boot_sig)); 206 207 memset(&fs->info, 0, sizeof(fs->info)); 208 is = &fs->info; 209 210 memcpy(is->info_sig1, FAT_INFO_SIG1, sizeof(is->info_sig1)); 211 memcpy(is->info_sig2, FAT_INFO_SIG2, sizeof(is->info_sig2)); 212 is->free_clusters = htole32(-1); 213 is->last_cluster = htole32(FAT_CLUSTER_ZERO); 214 memcpy(is->info_sig3, FAT_INFO_SIG3, sizeof(is->info_sig3)); 215 216 fs->num_clusters = FAT_CLUSTER_ZERO + data_clusters; 217 fs->next_cluster = FAT_CLUSTER_ZERO; 218 219 fs->fat_size = fat_sectors * sector_size; 220 fs->fat = malloc(fs->fat_size); 221 if (!fs->fat) { 222 WARN("initializing filesystem: couldn't allocate FAT extent: " 223 "out of memory\n"); 224 return MALLOC_FAIL; 225 } 226 memset(fs->fat, 0, fs->fat_size); 227 228 fs->data_offset = (reserved_sectors + fat_sectors) * sector_size; 229 230 fs->extents = NULL; 231 fs_add_extent(fs, &fs->boot_extent, 232 0, sector_size, 233 EXTENT_TYPE_BOOT); 234 fs_add_extent(fs, &fs->info_extent, 235 sector_size, sector_size, 236 EXTENT_TYPE_INFO); 237 fs_add_extent(fs, &fs->backup_boot_extent, 238 2 * sector_size, sector_size, 239 EXTENT_TYPE_BOOT); 240 fs_add_extent(fs, &fs->fat_extent, 241 reserved_sectors * sector_size, fs->fat_size, 242 EXTENT_TYPE_FAT); 243 244 *total_size_out = (offset_t)total_sectors * sector_size; 245 246 return 0; 247 } 248 249 void fs_set_rootdir_start(struct fs *fs, cluster_t rootdir_start) 250 { 251 assert(fs); 252 253 fs->boot.rootdir_start = htole32(rootdir_start); 254 } 255 256 void fs_update_free_clusters(struct fs *fs) 257 { 258 assert(fs); 259 260 fs->info.free_clusters = htole32(fs->num_clusters - fs->next_cluster); 261 } 262