fs.c revision f79b2dff1024db4f6326f3422236bed169dd902f
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 <sys/endian.h> 20 21#include "extent.h" 22#include "errors.h" 23#include "fat.h" 24#include "fs.h" 25#include "types.h" 26#include "utils.h" 27 28#define DEFAULT_SECTOR_SIZE 512 29 30static void fs_add_extent(struct fs *fs, struct extent *extent, 31 offset_t start, offset_t len, int type) 32{ 33 assert(fs); 34 assert(extent); 35 36 extent->start = start; 37 extent->len = len; 38 extent->type = type; 39 40 extent->next = fs->extents; 41 fs->extents = extent; 42} 43 44struct extent *fs_find_extent(struct fs *fs, offset_t start, offset_t len, 45 struct extent *last, 46 offset_t *r_start_out, 47 offset_t *e_start_out, 48 offset_t *len_out) 49{ 50 struct extent *e; 51 offset_t end; 52 offset_t e_start, e_end, e_len, e_rel_start, r_rel_start, rel_len; 53 54 assert(fs); 55 56 end = start + len; 57 58 e = last ? last->next : fs->extents; 59 for (; e; e = e->next) { 60 e_start = e->start; 61 e_len = e->len; 62 e_end = e_start + e_len; 63 64 if (start >= e_end) 65 continue; 66 67 if (end <= e_start) 68 continue; 69 70 if (e_start <= start) { 71 r_rel_start = 0; 72 e_rel_start = start - e_start; 73 if (end <= e_end) 74 rel_len = len; 75 else 76 rel_len = e_end - start; 77 } else { 78 e_rel_start = 0; 79 r_rel_start = e_start - start; 80 if (e_end <= end) 81 rel_len = e_len; 82 else 83 rel_len = end - e_start; 84 } 85 86 assert(e_rel_start < e_len); 87 assert(e_rel_start + rel_len <= e_len); 88 assert(r_rel_start < len); 89 assert(r_rel_start + rel_len <= len); 90 91 if (r_start_out) 92 *r_start_out = r_rel_start; 93 if (e_start_out) 94 *e_start_out = e_rel_start; 95 if (len_out) 96 *len_out = rel_len; 97 98 return e; 99 } 100 101 return NULL; 102} 103 104static void fs_set_fat(struct fs *fs, cluster_t cluster, fat_entry_t entry) 105{ 106 assert(fs); 107 108 fs->fat[cluster] = htole32(entry); 109} 110 111int fs_alloc_extent(struct fs *fs, struct extent *extent, 112 offset_t len, int type, cluster_t *first_cluster_out) 113{ 114 assert(fs); 115 assert(extent); 116 117 cluster_t clusters_needed, start; 118 cluster_t i; 119 120 if (len == 0) { 121 extent->start = 0; 122 extent->len = 0; 123 extent->type = type; 124 *first_cluster_out = 0; 125 return 0; 126 } 127 128 clusters_needed = (len + fs->cluster_size - 1) / fs->cluster_size; 129 130 /* Check for adequate space. */ 131 if (fs->next_cluster + clusters_needed > fs->num_clusters) { 132 WARN("allocating extent: filesystem is full!\n"); 133 return -1; 134 } 135 136 /* Allocate clusters. */ 137 start = fs->next_cluster; 138 fs->next_cluster += clusters_needed; 139 140 /* Update FAT. */ 141 for (i = 0; i < clusters_needed - 1; i++) { 142 fs_set_fat(fs, start + i, start + i + 1); 143 } 144 fs_set_fat(fs, start + clusters_needed - 1, FAT_ENTRY_EOC); 145 146 *first_cluster_out = start; 147 148 fs_add_extent(fs, 149 extent, 150 fs->data_offset + (offset_t)(start - FAT_CLUSTER_ZERO) 151 * fs->cluster_size, 152 (offset_t)clusters_needed * fs->cluster_size, 153 type); 154 155 return 0; 156} 157 158int fs_init(struct fs *fs, uint16_t cluster_size, offset_t data_size, offset_t *total_size_out) 159{ 160 uint16_t sector_size; 161 cluster_t data_clusters; 162 sector_t reserved_sectors, fat_sectors, data_sectors, total_sectors; 163 sector_t sectors_per_cluster; 164 int fat_entries_per_sector; 165 fat_entry_t *fat; 166 struct fat_boot_sector *bs; 167 struct fat_info_sector *is; 168 169 assert(fs); 170 171 sector_size = DEFAULT_SECTOR_SIZE; 172 fs->cluster_size = cluster_size; 173 174 sectors_per_cluster = cluster_size / DEFAULT_SECTOR_SIZE; 175 fat_entries_per_sector = sector_size / sizeof(fat_entry_t); 176 177 data_clusters = (data_size + cluster_size - 1) / cluster_size; 178 data_sectors = data_clusters * sectors_per_cluster; 179 fat_sectors = ((data_clusters + 2) + fat_entries_per_sector - 1) 180 / fat_entries_per_sector; 181 reserved_sectors = 3; 182 total_sectors = reserved_sectors + fat_sectors + data_sectors; 183 184 memset(&fs->boot, 0, sizeof(fs->boot)); 185 bs = &fs->boot; 186 187 strpadcpy(bs->name, "FATBLOCK", ' ', sizeof(bs->name)); 188 bs->sector_size = htole16(sector_size); 189 bs->sectors_per_cluster = sectors_per_cluster; 190 bs->reserved_sectors = htole16(reserved_sectors); 191 bs->fats = 1; 192 bs->media_desc = FAT_MEDIA_DESC_FIXED; 193 /* TODO: Calculate geometry? */ 194 bs->sectors_per_track = htole16(42); 195 bs->heads = htole16(42); 196 bs->sectors32 = htole32(total_sectors); 197 bs->fat_sectors32 = htole32(fat_sectors); 198 /* bs->rootdir_start will be set later. */ 199 bs->fs_info_sector = htole16(1); 200 bs->backup_boot_sector = htole16(2); 201 bs->phys_drive = FAT_PHYS_DRIVE_REMOVABLE; 202 bs->ext_boot_sig = FAT_EXT_BOOT_SIG; 203 bs->serial = 0x42424242; 204 strpadcpy(bs->vol_label, "FATBLOCK", ' ', sizeof(bs->vol_label)); 205 strpadcpy(bs->type, "FAT32", ' ', sizeof(bs->type)); 206 memcpy(bs->boot_sig, FAT_BOOT_SIG, sizeof(bs->boot_sig)); 207 208 memset(&fs->info, 0, sizeof(fs->info)); 209 is = &fs->info; 210 211 memcpy(is->info_sig1, FAT_INFO_SIG1, sizeof(is->info_sig1)); 212 memcpy(is->info_sig2, FAT_INFO_SIG2, sizeof(is->info_sig2)); 213 is->free_clusters = htole32(-1); 214 is->last_cluster = htole32(FAT_CLUSTER_ZERO); 215 memcpy(is->info_sig3, FAT_INFO_SIG3, sizeof(is->info_sig3)); 216 217 fs->num_clusters = FAT_CLUSTER_ZERO + data_clusters; 218 fs->next_cluster = FAT_CLUSTER_ZERO; 219 220 fs->fat_size = fat_sectors * sector_size; 221 fs->fat = malloc(fs->fat_size); 222 if (!fs->fat) { 223 WARN("initializing filesystem: couldn't allocate FAT extent: 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 249void 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 256void 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