]> git.sven.stormbind.net Git - sven/exfatprogs.git/blobdiff - mkfs/mkfs.c
New upstream version 1.2.3
[sven/exfatprogs.git] / mkfs / mkfs.c
index 773c64e1232c04316fe94637afaa89f2261bf8c2..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) {
@@ -386,6 +398,7 @@ 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"
@@ -404,6 +417,7 @@ 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 },
@@ -453,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",
@@ -467,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;
@@ -508,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;
@@ -629,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:U:c:b:fVqvh", 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
@@ -650,6 +655,22 @@ int main(int argc, char *argv[])
                        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)
@@ -709,6 +730,13 @@ int main(int argc, char *argv[])
                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]);