X-Git-Url: https://git.sven.stormbind.net/?a=blobdiff_plain;f=mkfs%2Fmkfs.c;h=18376692791b60acd584f05f0f84ad428cf7451e;hb=HEAD;hp=8c812213dda3728a2e597cba3c94667f9ab4801f;hpb=20b882b37d525f27c85037871c4f35f7ad2c55ba;p=sven%2Fexfatprogs.git diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 8c81221..f9286c1 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -46,14 +46,14 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, struct bsx64 *pbsx = &ppbr->bsx; unsigned int i; - /* Fill exfat BIOS paramemter block */ + /* Fill exfat BIOS parameter block */ pbpb->jmp_boot[0] = 0xeb; pbpb->jmp_boot[1] = 0x76; pbpb->jmp_boot[2] = 0x90; memcpy(pbpb->oem_name, "EXFAT ", 8); memset(pbpb->res_zero, 0, 53); - /* Fill exfat extend BIOS paramemter block */ + /* Fill exfat extend BIOS parameter block */ pbsx->vol_offset = cpu_to_le64(bd->offset / bd->sector_size); pbsx->vol_length = cpu_to_le64(bd->size / bd->sector_size); pbsx->fat_offset = cpu_to_le32(finfo.fat_byte_off / bd->sector_size); @@ -235,9 +235,9 @@ static int write_fat_entry(int fd, __le32 clu, unsigned long long offset) { int nbyte; + off_t fat_entry_offset = finfo.fat_byte_off + (offset * sizeof(__le32)); - lseek(fd, finfo.fat_byte_off + (offset * sizeof(__le32)), SEEK_SET); - nbyte = write(fd, (__u8 *) &clu, sizeof(__le32)); + nbyte = pwrite(fd, (__u8 *) &clu, sizeof(__le32), fat_entry_offset); if (nbyte != sizeof(int)) { exfat_err("write failed, offset : %llu, clu : %x\n", offset, clu); @@ -312,17 +312,29 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, static int exfat_create_bitmap(struct exfat_blk_dev *bd) { char *bitmap; - unsigned int i, nbytes; + unsigned int full_bytes, rem_bits, zero_offset; + unsigned int nbytes; - bitmap = calloc(finfo.bitmap_byte_len, sizeof(*bitmap)); + bitmap = malloc(finfo.bitmap_byte_len); if (!bitmap) return -1; - for (i = 0; i < finfo.used_clu_cnt - EXFAT_FIRST_CLUSTER; i++) - exfat_set_bit(bd, bitmap, i); + full_bytes = finfo.used_clu_cnt / 8; + rem_bits = finfo.used_clu_cnt % 8; + zero_offset = full_bytes; - lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); - nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); + memset(bitmap, 0xff, full_bytes); + + if (rem_bits != 0) { + bitmap[full_bytes] = (1 << rem_bits) - 1; + ++zero_offset; + } + + if (zero_offset < finfo.bitmap_byte_len) + memset(bitmap + zero_offset, 0, finfo.bitmap_byte_len - zero_offset); + + + nbytes = pwrite(bd->dev_fd, bitmap, finfo.bitmap_byte_len, finfo.bitmap_byte_off); if (nbytes != finfo.bitmap_byte_len) { exfat_err("write failed, nbytes : %d, bitmap_len : %d\n", nbytes, finfo.bitmap_byte_len); @@ -337,8 +349,8 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd) static int exfat_create_root_dir(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - struct exfat_dentry ed[3]; - int dentries_len = sizeof(struct exfat_dentry) * 3; + struct exfat_dentry ed[4] = {0}; + int dentries_len = sizeof(ed); int nbytes; /* Set volume label entry */ @@ -347,20 +359,31 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, memcpy(ed[0].vol_label, ui->volume_label, ui->volume_label_len); ed[0].vol_char_cnt = ui->volume_label_len/2; + /* Set volume GUID entry */ + if (ui->guid) { + if (__exfat_set_volume_guid(&ed[1], ui->guid)) + return -1; + } else { + /* + * Since a single empty entry cannot be allocated for a + * file, this can reserve the entry for volume GUID. + */ + ed[1].type = EXFAT_GUID & ~EXFAT_INVAL; + } + /* Set bitmap entry */ - ed[1].type = EXFAT_BITMAP; - ed[1].bitmap_flags = 0; - ed[1].bitmap_start_clu = cpu_to_le32(EXFAT_FIRST_CLUSTER); - ed[1].bitmap_size = cpu_to_le64(finfo.bitmap_byte_len); + ed[2].type = EXFAT_BITMAP; + ed[2].bitmap_flags = 0; + ed[2].bitmap_start_clu = cpu_to_le32(EXFAT_FIRST_CLUSTER); + ed[2].bitmap_size = cpu_to_le64(finfo.bitmap_byte_len); /* Set upcase table entry */ - ed[2].type = EXFAT_UPCASE; - ed[2].upcase_checksum = cpu_to_le32(0xe619d30d); - ed[2].upcase_start_clu = cpu_to_le32(finfo.ut_start_clu); - ed[2].upcase_size = cpu_to_le64(EXFAT_UPCASE_TABLE_SIZE); + ed[3].type = EXFAT_UPCASE; + ed[3].upcase_checksum = cpu_to_le32(0xe619d30d); + ed[3].upcase_start_clu = cpu_to_le32(finfo.ut_start_clu); + ed[3].upcase_size = cpu_to_le64(EXFAT_UPCASE_TABLE_SIZE); - lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET); - nbytes = write(bd->dev_fd, ed, dentries_len); + nbytes = pwrite(bd->dev_fd, ed, dentries_len, finfo.root_byte_off); if (nbytes != dentries_len) { exfat_err("write failed, nbytes : %d, dentries_len : %d\n", nbytes, dentries_len); @@ -374,11 +397,14 @@ static void usage(void) { fputs("Usage: mkfs.exfat\n" "\t-L | --volume-label=label Set volume label\n" + "\t-U | --volume-guid=guid Set volume GUID\n" + "\t-s | --sector-size=size(or suffixed by 'K') Specify sector size\n" "\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n" "\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignment\n" "\t --pack-bitmap Move bitmap into FAT segment\n" "\t-f | --full-format Full format\n" "\t-V | --version Show version\n" + "\t-q | --quiet Print only errors\n" "\t-v | --verbose Print debug\n" "\t-h | --help Show help\n", stderr); @@ -390,11 +416,14 @@ static void usage(void) static const struct option opts[] = { {"volume-label", required_argument, NULL, 'L' }, + {"volume-guid", required_argument, NULL, 'U' }, + {"sector-size", required_argument, NULL, 's' }, {"cluster-size", required_argument, NULL, 'c' }, {"boundary-align", required_argument, NULL, 'b' }, {"pack-bitmap", no_argument, NULL, PACK_BITMAP }, {"full-format", no_argument, NULL, 'f' }, {"version", no_argument, NULL, 'V' }, + {"quiet", no_argument, NULL, 'q' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, {"?", no_argument, NULL, '?' }, @@ -438,8 +467,15 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { unsigned long long total_clu_cnt; + unsigned long long max_clusters; int clu_len; + int num_fats = 1; + if (ui->cluster_size < bd->sector_size) { + exfat_err("cluster size (%u bytes) is smaller than sector size (%u bytes)\n", + ui->cluster_size, bd->sector_size); + return -1; + } if (ui->boundary_align < bd->sector_size) { exfat_err("boundary alignment is too small (min %d)\n", bd->sector_size); @@ -447,10 +483,17 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, } finfo.fat_byte_off = round_up(bd->offset + 24 * bd->sector_size, ui->boundary_align) - bd->offset; - finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)), - ui->cluster_size); + + max_clusters = (bd->size - finfo.fat_byte_off - 8 * num_fats - 1) / + (ui->cluster_size + 4 * num_fats) + 1; + /* Prevent integer overflow when computing the FAT length */ + if (max_clusters > UINT_MAX / 4 - 2) { + exfat_err("cluster size (%u bytes) is too small\n", ui->cluster_size); + return -1; + } + finfo.fat_byte_len = round_up((max_clusters + 2) * 4, bd->sector_size); finfo.clu_byte_off = round_up(bd->offset + finfo.fat_byte_off + - finfo.fat_byte_len, ui->boundary_align) - bd->offset; + finfo.fat_byte_len * num_fats, ui->boundary_align) - bd->offset; if (bd->size <= finfo.clu_byte_off) { exfat_err("boundary alignment is too big\n"); return -1; @@ -484,35 +527,21 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, static int exfat_zero_out_disk(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - int nbytes; + int ret; unsigned long long total_written = 0; - char *buf; - unsigned int chunk_size = ui->cluster_size; unsigned long long size; if (ui->quick) - size = finfo.root_byte_off + chunk_size; + size = finfo.root_byte_off + ui->cluster_size; else size = bd->size; - buf = malloc(chunk_size); - if (!buf) - return -1; - - memset(buf, 0, chunk_size); - lseek(bd->dev_fd, 0, SEEK_SET); - do { - - nbytes = write(bd->dev_fd, buf, chunk_size); - if (nbytes <= 0) { - if (nbytes < 0) - exfat_err("write failed(errno : %d)\n", errno); - break; - } - total_written += nbytes; - } while (total_written < size); + ret = exfat_write_zero(bd->dev_fd, size, 0); + if (ret) { + exfat_err("write failed(errno : %d)\n", errno); + return ret; + } - free(buf); exfat_debug("zero out written size : %llu, disk size : %llu\n", total_written, bd->size); return 0; @@ -597,6 +626,7 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; bool version_only = false; + bool quiet = false; init_user_input(&ui); @@ -604,7 +634,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:b:fVvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "n:L:U:s:c:b:fVqvh", opts, NULL)) != EOF) switch (c) { /* * Make 'n' option fallthrough to 'L' option for for backward @@ -621,6 +651,26 @@ int main(int argc, char *argv[]) ui.volume_label_len = ret; break; } + case 'U': + if (*optarg != '\0' && *optarg != '\r') + ui.guid = optarg; + break; + case 's': + ret = parse_size(optarg); + if (ret < 0) + goto out; + else if (ret & (ret - 1)) { + exfat_err("sector size(%d) is not a power of 2\n", + ret); + goto out; + } else if ((ret & 0x1e00) == 0) { + exfat_err("sector size(%d) must be 512, 1024, " + "2048 or 4096 bytes\n", + ret); + goto out; + } + ui.sector_size = ret; + break; case 'c': ret = parse_size(optarg); if (ret < 0) @@ -656,6 +706,10 @@ int main(int argc, char *argv[]) case 'V': version_only = true; break; + case 'q': + print_level = EXFAT_ERROR; + quiet = true; + break; case 'v': print_level = EXFAT_DEBUG; break; @@ -665,14 +719,24 @@ int main(int argc, char *argv[]) usage(); } - show_version(); - if (version_only) + if (version_only) { + show_version(); exit(EXIT_FAILURE); + } else if (!quiet) { + show_version(); + } if (argc - optind != 1) { usage(); } + if (ui.sector_size && ui.cluster_size && ui.sector_size > ui.cluster_size) { + exfat_err("cluster size (%u bytes) is smaller than sector size (%u bytes)\n", + ui.cluster_size, ui.sector_size); + ret = -1; + goto out; + } + memset(ui.dev_name, 0, sizeof(ui.dev_name)); snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[optind]); @@ -700,6 +764,6 @@ out: if (!ret) exfat_info("\nexFAT format complete!\n"); else - exfat_info("\nexFAT format fail!\n"); + exfat_err("\nexFAT format fail!\n"); return ret; }