mkfat.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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          * Make a conservative guess on the FAT size needed for the file
00214          * system. The optimum could be potentially smaller since we
00215          * do not subtract size of the FAT itself when computing the
00216          * size of the data region.
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         /* Reserved sectors */
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         /* File allocation tables */
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         /* Root directory */
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         /* BIOS Parameter Block */
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         /* Extended BPB */
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 

Generated on Thu Jun 2 07:45:42 2011 for HelenOS/USB by  doxygen 1.4.7