]> git.sven.stormbind.net Git - sven/exfatprogs.git/blobdiff - mkfs/mkfs.c
releasing package exfatprogs version 1.2.3-1
[sven/exfatprogs.git] / mkfs / mkfs.c
index f9e5bb4d49cbb04be22ece70d1a4a1f748145c5c..f9286c1d159e92fe7f8bc3682cf1241abeaf4764 100644 (file)
@@ -312,15 +312,27 @@ 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(round_up(finfo.bitmap_byte_len, sizeof(bitmap_t)),
-                       sizeof(*bitmap));
+       bitmap = malloc(finfo.bitmap_byte_len);
        if (!bitmap)
                return -1;
 
-       for (i = EXFAT_FIRST_CLUSTER; i < finfo.used_clu_cnt; i++)
-               exfat_bitmap_set(bitmap, i);
+       full_bytes = finfo.used_clu_cnt / 8;
+       rem_bits = finfo.used_clu_cnt % 8;
+       zero_offset = full_bytes;
+
+       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) {
@@ -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] = {0};
-       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,17 +359,29 @@ 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);
 
        nbytes = pwrite(bd->dev_fd, ed, dentries_len, finfo.root_byte_off);
        if (nbytes != dentries_len) {
@@ -373,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);
@@ -389,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,   '?' },
@@ -437,7 +467,9 @@ 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",
@@ -451,14 +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;
+
+       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 (bd->num_clusters > UINT32_MAX / 4) {
+       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((bd->num_clusters * 4), ui->cluster_size);
+       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;
@@ -492,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;
@@ -605,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);
 
@@ -612,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
@@ -629,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)
@@ -664,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;
@@ -673,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]);
 
@@ -708,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;
 }