X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fexfatprogs.git;a=blobdiff_plain;f=mkfs%2Fmkfs.c;fp=mkfs%2Fmkfs.c;h=9fff97811160e3a5bcce8a01814dabf34bc78ce6;hp=4cafb3e56c59fba1e7d68306384f7dfc7269f612;hb=77466d00ac72316d70c469b34dc8f5247520a31e;hpb=2d56c0684b4a1bc6dfa3efccb0200928850734f3 diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4cafb3e..9fff978 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -15,8 +15,8 @@ #include #include #include -#include #include +#include #include "exfat_ondisk.h" #include "libexfat.h" @@ -24,11 +24,26 @@ struct exfat_mkfs_info finfo; +/* random serial generator based on current time */ +static unsigned int get_new_serial(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts)) { + /* set 0000-0000 on error */ + ts.tv_sec = 0; + ts.tv_nsec = 0; + } + + return (unsigned int)(ts.tv_nsec << 12 | ts.tv_sec); +} + static void exfat_setup_boot_sector(struct pbr *ppbr, struct exfat_blk_dev *bd, struct exfat_user_input *ui) { struct bpb64 *pbpb = &ppbr->bpb; struct bsx64 *pbsx = &ppbr->bsx; + unsigned int i; /* Fill exfat BIOS paramemter block */ pbpb->jmp_boot[0] = 0xeb; @@ -45,10 +60,13 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbsx->clu_offset = cpu_to_le32(finfo.clu_byte_off / bd->sector_size); pbsx->clu_count = cpu_to_le32(finfo.total_clu_cnt); pbsx->root_cluster = cpu_to_le32(finfo.root_start_clu); - pbsx->vol_serial = cpu_to_le32(1234); + pbsx->vol_serial = cpu_to_le32(finfo.volume_serial); pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; - pbsx->sect_per_clus_bits = log2(ui->cluster_size / bd->sector_size); + pbsx->sect_per_clus_bits = 0; + /* Compute base 2 logarithm of ui->cluster_size / bd->sector_size */ + for (i = ui->cluster_size / bd->sector_size; i > 1; i /= 2) + pbsx->sect_per_clus_bits++; pbsx->num_fats = 1; /* fs_version[0] : minor and fs_version[1] : major */ pbsx->fs_version[0] = 0; @@ -387,6 +405,7 @@ static void usage(void) fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-L | --volume-label=label Set volume label\n"); fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n"); + fprintf(stderr, "\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignment\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); fprintf(stderr, "\t-v | --verbose Print debug\n"); @@ -398,6 +417,7 @@ static void usage(void) static struct option opts[] = { {"volume-label", required_argument, NULL, 'L' }, {"cluster-size", required_argument, NULL, 'c' }, + {"boundary-align", required_argument, NULL, 'b' }, {"full-format", no_argument, NULL, 'f' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, @@ -409,14 +429,23 @@ static struct option opts[] = { static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - if (ui->cluster_size > DEFAULT_CLUSTER_SIZE) - finfo.fat_byte_off = ui->cluster_size; - else - finfo.fat_byte_off = DEFAULT_CLUSTER_SIZE; + int clu_len; + + if (ui->boundary_align < bd->sector_size) { + exfat_err("boundary alignment is too small (min %d)\n", + bd->sector_size); + return -1; + } + finfo.fat_byte_off = round_up(24 * bd->sector_size, + ui->boundary_align); finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)), ui->cluster_size); finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, - DEFAULT_CLUSTER_SIZE); + ui->boundary_align); + if (bd->size <= finfo.clu_byte_off) { + exfat_err("boundary alignment is too big\n"); + return -1; + } finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { @@ -426,17 +455,17 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; - finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * - ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / - ui->cluster_size; - finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + - finfo.bitmap_byte_len, ui->cluster_size); + clu_len = round_up(finfo.bitmap_byte_len, ui->cluster_size); + + finfo.ut_start_clu = EXFAT_FIRST_CLUSTER + clu_len / ui->cluster_size; + finfo.ut_byte_off = finfo.bitmap_byte_off + clu_len; finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE; - finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size - + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size; - finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, - ui->cluster_size); + clu_len = round_up(finfo.ut_byte_len, ui->cluster_size); + + finfo.root_start_clu = finfo.ut_start_clu + clu_len / ui->cluster_size; + finfo.root_byte_off = finfo.ut_byte_off + clu_len; finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; + finfo.volume_serial = get_new_serial(); return 0; } @@ -525,7 +554,7 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) return 0; } -static long long parse_cluster_size(const char *size) +static long long parse_size(const char *size) { char *data_unit; unsigned long long byte_size = strtoull(size, &data_unit, 0); @@ -539,8 +568,10 @@ static long long parse_cluster_size(const char *size) case 'k': byte_size <<= 10; break; + case '\0': + break; default: - exfat_err("Wrong unit input('%c') for cluster size\n", + exfat_err("Wrong unit input('%c') for size\n", *data_unit); return -EINVAL; } @@ -562,7 +593,7 @@ int main(int argc, char *argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "n:L:c:fVvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "n:L:c:b:fVvh", opts, NULL)) != EOF) switch (c) { /* * Make 'n' option fallthrough to 'L' option for for backward @@ -580,16 +611,31 @@ int main(int argc, char *argv[]) break; } case 'c': - ret = parse_cluster_size(optarg); + ret = parse_size(optarg); if (ret < 0) goto out; - else if (ret > EXFAT_MAX_CLUSTER_SIZE) { + else if (ret & (ret - 1)) { + exfat_err("cluster size(%d) is not a power of 2)\n", + ret); + goto out; + } else if (ret > EXFAT_MAX_CLUSTER_SIZE) { exfat_err("cluster size(%d) exceeds max cluster size(%d)\n", ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE); goto out; } ui.cluster_size = ret; break; + case 'b': + ret = parse_size(optarg); + if (ret < 0) + goto out; + else if (ret & (ret - 1)) { + exfat_err("boundary align(%d) is not a power of 2)\n", + ret); + goto out; + } + ui.boundary_align = ret; + break; case 'f': ui.quick = false; break; @@ -622,23 +668,24 @@ int main(int argc, char *argv[]) ret = exfat_build_mkfs_info(&bd, &ui); if (ret) - goto out; + goto close; ret = exfat_zero_out_disk(&bd, &ui); if (ret) - goto out; + goto close; ret = make_exfat(&bd, &ui); if (ret) - goto out; + goto close; exfat_info("Synchronizing...\n"); ret = fsync(bd.dev_fd); +close: + close(bd.dev_fd); out: if (!ret) exfat_info("\nexFAT format complete!\n"); else exfat_info("\nexFAT format fail!\n"); - close(bd.dev_fd); return ret; }