00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <libblock.h>
00043 #include <mem.h>
00044 #include <devmap.h>
00045 #include <byteorder.h>
00046 #include <sys/types.h>
00047 #include <sys/typefmt.h>
00048 #include <inttypes.h>
00049 #include <errno.h>
00050 #include "fat.h"
00051
00052 #define NAME "mkfat"
00053
00055 #define div_round_up(a, b) (((a) + (b) - 1) / (b))
00056
00058 enum {
00059 sector_size = 512,
00060 sectors_per_cluster = 8,
00061 fat_count = 2,
00062 reserved_clusters = 2,
00063 media_descriptor = 0xF8
00064 };
00065
00067 typedef struct fat_cfg {
00068 uint32_t total_sectors;
00069 uint16_t root_ent_max;
00070 uint16_t addt_res_sectors;
00071 } fat_cfg_t;
00072
00074 typedef struct fat_params {
00075 struct fat_cfg cfg;
00076 uint16_t reserved_sectors;
00077 uint16_t rootdir_sectors;
00078 uint32_t fat_sectors;
00079 uint16_t total_clusters;
00080 } fat_params_t;
00081
00082 static void syntax_print(void);
00083
00084 static int fat_params_compute(struct fat_cfg const *cfg,
00085 struct fat_params *par);
00086 static int fat_blocks_write(struct fat_params const *par,
00087 devmap_handle_t handle);
00088 static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs);
00089
00090 int main(int argc, char **argv)
00091 {
00092 struct fat_params par;
00093 struct fat_cfg cfg;
00094
00095 int rc;
00096 char *dev_path;
00097 devmap_handle_t handle;
00098 size_t block_size;
00099 char *endptr;
00100 aoff64_t dev_nblocks;
00101
00102 cfg.total_sectors = 0;
00103 cfg.addt_res_sectors = 0;
00104 cfg.root_ent_max = 128;
00105
00106 if (argc < 2) {
00107 printf(NAME ": Error, argument missing.\n");
00108 syntax_print();
00109 return 1;
00110 }
00111
00112 --argc; ++argv;
00113
00114 if (str_cmp(*argv, "--size") == 0) {
00115 --argc; ++argv;
00116 if (*argv == NULL) {
00117 printf(NAME ": Error, argument missing.\n");
00118 syntax_print();
00119 return 1;
00120 }
00121
00122 cfg.total_sectors = strtol(*argv, &endptr, 10);
00123 if (*endptr != '\0') {
00124 printf(NAME ": Error, invalid argument.\n");
00125 syntax_print();
00126 return 1;
00127 }
00128
00129 --argc; ++argv;
00130 }
00131
00132 if (argc != 1) {
00133 printf(NAME ": Error, unexpected argument.\n");
00134 syntax_print();
00135 return 1;
00136 }
00137
00138 dev_path = *argv;
00139
00140 rc = devmap_device_get_handle(dev_path, &handle, 0);
00141 if (rc != EOK) {
00142 printf(NAME ": Error resolving device `%s'.\n", dev_path);
00143 return 2;
00144 }
00145
00146 rc = block_init(handle, 2048);
00147 if (rc != EOK) {
00148 printf(NAME ": Error initializing libblock.\n");
00149 return 2;
00150 }
00151
00152 rc = block_get_bsize(handle, &block_size);
00153 if (rc != EOK) {
00154 printf(NAME ": Error determining device block size.\n");
00155 return 2;
00156 }
00157
00158 rc = block_get_nblocks(handle, &dev_nblocks);
00159 if (rc != EOK) {
00160 printf(NAME ": Warning, failed to obtain block device size.\n");
00161 } else {
00162 printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
00163 dev_nblocks);
00164 cfg.total_sectors = dev_nblocks;
00165 }
00166
00167 if (block_size != 512) {
00168 printf(NAME ": Error. Device block size is not 512 bytes.\n");
00169 return 2;
00170 }
00171
00172 if (cfg.total_sectors == 0) {
00173 printf(NAME ": Error. You must specify filesystem size.\n");
00174 return 1;
00175 }
00176
00177 printf(NAME ": Creating FAT filesystem on device %s.\n", dev_path);
00178
00179 rc = fat_params_compute(&cfg, &par);
00180 if (rc != EOK) {
00181 printf(NAME ": Invalid file-system parameters.\n");
00182 return 2;
00183 }
00184
00185 rc = fat_blocks_write(&par, handle);
00186 if (rc != EOK) {
00187 printf(NAME ": Error writing device.\n");
00188 return 2;
00189 }
00190
00191 block_fini(handle);
00192 printf("Success.\n");
00193
00194 return 0;
00195 }
00196
00197 static void syntax_print(void)
00198 {
00199 printf("syntax: mkfat [--size <num_blocks>] <device_name>\n");
00200 }
00201
00207 static int fat_params_compute(struct fat_cfg const *cfg, struct fat_params *par)
00208 {
00209 uint32_t fat_bytes;
00210 uint32_t non_data_sectors_lb;
00211
00212
00213
00214
00215
00216
00217
00218
00219 par->reserved_sectors = 1 + cfg->addt_res_sectors;
00220 par->rootdir_sectors = div_round_up(cfg->root_ent_max * DIRENT_SIZE,
00221 sector_size);
00222 non_data_sectors_lb = par->reserved_sectors + par->rootdir_sectors;
00223
00224 par->total_clusters = div_round_up(cfg->total_sectors - non_data_sectors_lb,
00225 sectors_per_cluster);
00226
00227 fat_bytes = (par->total_clusters + 2) * 2;
00228 par->fat_sectors = div_round_up(fat_bytes, sector_size);
00229
00230 par->cfg = *cfg;
00231
00232 return EOK;
00233 }
00234
00236 static int fat_blocks_write(struct fat_params const *par, devmap_handle_t handle)
00237 {
00238 aoff64_t addr;
00239 uint8_t *buffer;
00240 int i;
00241 uint32_t j;
00242 int rc;
00243 struct fat_bs bs;
00244
00245 fat_bootsec_create(par, &bs);
00246
00247 rc = block_write_direct(handle, BS_BLOCK, 1, &bs);
00248 if (rc != EOK)
00249 return EIO;
00250
00251 addr = BS_BLOCK + 1;
00252
00253 buffer = calloc(sector_size, 1);
00254 if (buffer == NULL)
00255 return ENOMEM;
00256
00257
00258 for (i = 0; i < par->reserved_sectors - 1; ++i) {
00259 rc = block_write_direct(handle, addr, 1, buffer);
00260 if (rc != EOK)
00261 return EIO;
00262
00263 ++addr;
00264 }
00265
00266
00267 for (i = 0; i < fat_count; ++i) {
00268 printf("Writing allocation table %d.\n", i + 1);
00269
00270 for (j = 0; j < par->fat_sectors; ++j) {
00271 memset(buffer, 0, sector_size);
00272 if (j == 0) {
00273 buffer[0] = media_descriptor;
00274 buffer[1] = 0xFF;
00275 buffer[2] = 0xFF;
00276 buffer[3] = 0xFF;
00277 }
00278
00279 rc = block_write_direct(handle, addr, 1, buffer);
00280 if (rc != EOK)
00281 return EIO;
00282
00283 ++addr;
00284 }
00285 }
00286
00287 printf("Writing root directory.\n");
00288
00289 memset(buffer, 0, sector_size);
00290
00291
00292 for (i = 0; i < par->rootdir_sectors; ++i) {
00293 rc = block_write_direct(handle, addr, 1, buffer);
00294 if (rc != EOK)
00295 return EIO;
00296
00297 ++addr;
00298 }
00299
00300 free(buffer);
00301
00302 return EOK;
00303 }
00304
00306 static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs)
00307 {
00308 memset(bs, 0, sizeof(*bs));
00309
00310 bs->ji[0] = 0xEB;
00311 bs->ji[1] = 0x3C;
00312 bs->ji[2] = 0x90;
00313
00314 memcpy(bs->oem_name, "HELENOS ", 8);
00315
00316
00317 bs->bps = host2uint16_t_le(sector_size);
00318 bs->spc = sectors_per_cluster;
00319 bs->rscnt = host2uint16_t_le(par->reserved_sectors);
00320 bs->fatcnt = fat_count;
00321 bs->root_ent_max = host2uint16_t_le(par->cfg.root_ent_max);
00322
00323 if (par->cfg.total_sectors < 0x10000)
00324 bs->totsec16 = host2uint16_t_le(par->cfg.total_sectors);
00325 else
00326 bs->totsec16 = host2uint16_t_le(0);
00327
00328 bs->mdesc = media_descriptor;
00329 bs->sec_per_fat = host2uint16_t_le(par->fat_sectors);
00330 bs->sec_per_track = host2uint16_t_le(63);
00331 bs->headcnt = host2uint16_t_le(6);
00332 bs->hidden_sec = host2uint32_t_le(0);
00333
00334 if (par->cfg.total_sectors >= 0x10000)
00335 bs->totsec32 = host2uint32_t_le(par->cfg.total_sectors);
00336 else
00337 bs->totsec32 = host2uint32_t_le(0);
00338
00339
00340 bs->pdn = 0x80;
00341 bs->ebs = 0x29;
00342 bs->id = host2uint32_t_be(0x12345678);
00343
00344 memcpy(bs->label, "HELENOS_NEW", 11);
00345 memcpy(bs->type, "FAT16 ", 8);
00346 bs->signature = host2uint16_t_be(0x55AA);
00347 }
00348