+exfatprogs 1.1.1 - released 2021-04-21
+======================================
+
+CHANGES :
+ * mkfs.exfat: adjust the boundary alignment calculations to compensate
+ for the volume offset.
+
+NEW FEATURES :
+ * mkfs.exfat: add the "--pack-bitmap" option to relocate the allocation
+ bitmap to allow the FAT and the bitmap to share the same allocation
+ unit on flash media.
+
+BUG FIXES :
+ * Fix wrong bit operations on 64-bit big.
+ * Fix memory leaks in error paths.
+
exfatprogs 1.1.0 - released 2021-02-09
======================================
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for exfatprogs 1.1.0.
+# Generated by GNU Autoconf 2.69 for exfatprogs 1.1.1.
#
# Report bugs to <linkinjeon@kernel.org>.
#
# Identity of this package.
PACKAGE_NAME='exfatprogs'
PACKAGE_TARNAME='exfatprogs'
-PACKAGE_VERSION='1.1.0'
-PACKAGE_STRING='exfatprogs 1.1.0'
+PACKAGE_VERSION='1.1.1'
+PACKAGE_STRING='exfatprogs 1.1.1'
PACKAGE_BUGREPORT='linkinjeon@kernel.org'
PACKAGE_URL='https://github.com/exfatprogs/exfatprogs'
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures exfatprogs 1.1.0 to adapt to many kinds of systems.
+\`configure' configures exfatprogs 1.1.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of exfatprogs 1.1.0:";;
+ short | recursive ) echo "Configuration of exfatprogs 1.1.1:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-exfatprogs configure 1.1.0
+exfatprogs configure 1.1.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by exfatprogs $as_me 1.1.0, which was
+It was created by exfatprogs $as_me 1.1.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='exfatprogs'
- VERSION='1.1.0'
+ VERSION='1.1.1'
cat >>confdefs.h <<_ACEOF
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by exfatprogs $as_me 1.1.0, which was
+This file was extended by exfatprogs $as_me 1.1.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-exfatprogs config.status 1.1.0
+exfatprogs config.status 1.1.1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
return count;
}
-int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd)
+static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd)
{
struct pbr *ppbr;
struct bsx64 *pbsx;
ppbr = malloc(bd->sector_size);
if (!ppbr) {
exfat_err("Cannot allocate pbr: out of memory\n");
- return -1;
+ return -ENOMEM;
}
/* read main boot sector */
ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX);
if (ret < 0) {
exfat_err("main boot sector read failed\n");
- ret = -1;
+ ret = -EIO;
goto free_ppbr;
}
pbsx->sect_size_bits > EXFAT_MAX_SECT_SIZE_BITS) {
exfat_err("bogus sector size bits : %u\n",
pbsx->sect_size_bits);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_ppbr;
}
if (pbsx->sect_per_clus_bits > 25 - pbsx->sect_size_bits) {
exfat_err("bogus sectors bits per cluster : %u\n",
pbsx->sect_per_clus_bits);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_ppbr;
}
if (bd->sector_size != 1 << pbsx->sect_size_bits) {
- exfat_err("bogus sectors size : %u(sector size bits : %u)\n",
+ exfat_err("bogus sector size : %u (sector size bits : %u)\n",
bd->sector_size, pbsx->sect_size_bits);
-
+ ret = -EINVAL;
+ goto free_ppbr;
}
clu_offset = le32_to_cpu(pbsx->clu_offset);
goto free_entry;
}
- volume_label = exfat_conv_volume_serial(&ed[0]);
+ volume_label = exfat_conv_volume_label(&ed[0]);
if (!volume_label) {
ret = -EINVAL;
goto free_entry;
bitmap = malloc(bitmap_len);
if (!bitmap) {
exfat_err("bitmap allocation failed\n");
+ ret = -ENOMEM;
goto free_volume_label;
}
exfat_info("Cluster size: \t\t\t\t%u\n", bd->cluster_size);
exfat_info("Total Clusters: \t\t\t%u\n", total_clus);
exfat_info("Free Clusters: \t\t\t\t%u\n", total_clus-used_clus);
+ ret = 0;
free(bitmap);
fprintf(stderr, "\t-y | --repair-yes Repair without ask\n");
fprintf(stderr, "\t-n | --repair-no No repair\n");
fprintf(stderr, "\t-p | --repair-auto Repair automatically\n");
+ fprintf(stderr, "\t-a Repair automatically\n");
fprintf(stderr, "\t-V | --version Show version\n");
fprintf(stderr, "\t-v | --verbose Print debug\n");
fprintf(stderr, "\t-h | --help Show help\n");
{
int i;
char *sector;
+ int ret;
sector = malloc(bd->sector_size);
if (!sector)
if (exfat_read(bd->dev_fd, sector, bd->sector_size,
BACKUP_BOOT_SEC_IDX * bd->sector_size +
i * bd->sector_size) !=
- (ssize_t)bd->sector_size)
- return -EIO;
+ (ssize_t)bd->sector_size) {
+ ret = -EIO;
+ goto free_sector;
+ }
if (i == 0)
((struct pbr *)sector)->bsx.perc_in_use = 0xff;
if (exfat_write(bd->dev_fd, sector, bd->sector_size,
BOOT_SEC_IDX * bd->sector_size +
i * bd->sector_size) !=
- (ssize_t)bd->sector_size)
- return -EIO;
+ (ssize_t)bd->sector_size) {
+ ret = -EIO;
+ goto free_sector;
+ }
}
- if (fsync(bd->dev_fd))
- return -EIO;
+
+ if (fsync(bd->dev_fd)) {
+ ret = -EIO;
+ goto free_sector;
+ }
+ ret = 0;
+
+free_sector:
free(sector);
- return 0;
+ return ret;
}
static int exfat_boot_region_check(struct exfat *exfat, struct pbr **bs)
exfat_err("failed to init locale/codeset\n");
opterr = 0;
- while ((c = getopt_long(argc, argv, "rynpVvh", opts, NULL)) != EOF) {
+ while ((c = getopt_long(argc, argv, "arynpVvh", opts, NULL)) != EOF) {
switch (c) {
case 'n':
if (ui.options & FSCK_OPTS_REPAIR_ALL)
usage(argv[0]);
ui.options |= FSCK_OPTS_REPAIR_YES;
break;
+ case 'a':
case 'p':
if (ui.options & FSCK_OPTS_REPAIR_ALL)
usage(argv[0]);
#define EXFAT_BAD_CLUSTER (0xFFFFFFF7U)
#define EXFAT_FREE_CLUSTER (0)
#define EXFAT_FIRST_CLUSTER (2)
-#define EXFAT_REVERVED_CLUSTERS (2)
+#define EXFAT_RESERVED_CLUSTERS (2)
/* EXFAT BIOS parameter block (64 bytes) */
struct exfat_blk_dev {
int dev_fd;
+ unsigned long long offset;
unsigned long long size;
unsigned int sector_size;
unsigned int sector_size_bits;
unsigned int cluster_size;
unsigned int sec_per_clu;
unsigned int boundary_align;
+ bool pack_bitmap;
bool quick;
__u16 volume_label[VOLUME_LABEL_MAX_LEN];
int volume_label_len;
unsigned int sec_off);
int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
unsigned int checksum, bool is_backup);
-char *exfat_conv_volume_serial(struct exfat_dentry *vol_entry);
+char *exfat_conv_volume_label(struct exfat_dentry *vol_entry);
int exfat_show_volume_serial(struct exfat_blk_dev *bd,
struct exfat_user_input *ui);
int exfat_set_volume_serial(struct exfat_blk_dev *bd,
#ifndef _VERSION_H
-#define EXFAT_PROGS_VERSION "1.1.0"
+#define EXFAT_PROGS_VERSION "1.1.1"
#endif /* !_VERSION_H */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include "libexfat.h"
#include "version.h"
+#define BITS_PER_LONG (sizeof(long) * CHAR_BIT)
+
#ifdef WORDS_BIGENDIAN
-#define BITOP_LE_SWIZZLE (~0x7)
+#define BITOP_LE_SWIZZLE ((BITS_PER_LONG - 1) & ~0x7)
#else
#define BITOP_LE_SWIZZLE 0
#endif
-#define BIT_MASK(nr) ((1) << ((nr) % 32))
-#define BIT_WORD(nr) ((nr) / 32)
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
unsigned int print_level = EXFAT_INFO;
-static inline void set_bit(int nr, unsigned int *addr)
+static inline void set_bit(int nr, void *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
-static inline void clear_bit(int nr, unsigned int *addr)
+static inline void clear_bit(int nr, void *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
{
int fd, ret = -1;
off_t blk_dev_size;
+ struct stat st;
+ unsigned long long blk_dev_offset = 0;
fd = open(ui->dev_name, ui->writeable ? O_RDWR|O_EXCL : O_RDONLY);
if (fd < 0) {
goto out;
}
+ if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) {
+ char pathname[sizeof("/sys/dev/block/4294967295:4294967295/start")];
+ FILE *fp;
+
+ snprintf(pathname, sizeof(pathname), "/sys/dev/block/%u:%u/start",
+ major(st.st_rdev), minor(st.st_rdev));
+ fp = fopen(pathname, "r");
+ if (fp != NULL) {
+ if (fscanf(fp, "%llu", &blk_dev_offset) == 1) {
+ /*
+ * Linux kernel always reports partition offset
+ * in 512-byte units, regardless of sector size
+ */
+ blk_dev_offset <<= 9;
+ }
+ fclose(fp);
+ }
+ }
+
bd->dev_fd = fd;
+ bd->offset = blk_dev_offset;
bd->size = blk_dev_size;
if (!ui->cluster_size)
exfat_set_default_cluster_size(bd, ui);
bd->num_clusters = blk_dev_size / ui->cluster_size;
exfat_debug("Block device name : %s\n", ui->dev_name);
- exfat_debug("Block device size : %lld\n", bd->size);
+ exfat_debug("Block device offset : %llu\n", bd->offset);
+ exfat_debug("Block device size : %llu\n", bd->size);
exfat_debug("Block sector size : %u\n", bd->sector_size);
exfat_debug("Number of the sectors : %llu\n",
bd->num_sectors);
nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0);
if (nbytes != sizeof(struct pbr)) {
exfat_err("boot sector read failed: %d\n", errno);
+ free(bs);
return -1;
}
cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size;
root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size +
- le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS)
+ le32_to_cpu(bs->bsx.root_cluster - EXFAT_RESERVED_CLUSTERS)
* cluster_size;
free(bs);
return root_clu_off;
}
-char *exfat_conv_volume_serial(struct exfat_dentry *vol_entry)
+char *exfat_conv_volume_label(struct exfat_dentry *vol_entry)
{
char *volume_label;
__le16 disk_label[VOLUME_LABEL_MAX_LEN];
if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2,
volume_label, VOLUME_LABEL_BUFFER_SIZE) < 0) {
exfat_err("failed to decode volume label\n");
+ free(volume_label);
return NULL;
}
sizeof(struct exfat_dentry), root_clu_off);
if (nbytes != sizeof(struct exfat_dentry)) {
exfat_err("volume entry read failed: %d\n", errno);
+ free(vol_entry);
return -1;
}
- volume_label = exfat_conv_volume_serial(vol_entry);
- if (!volume_label)
+ volume_label = exfat_conv_volume_label(vol_entry);
+ if (!volume_label) {
+ free(vol_entry);
return -EINVAL;
+ }
exfat_info("label: %s\n", volume_label);
free(volume_label);
+ free(vol_entry);
return 0;
}
unsigned int clu_off_sectnr, unsigned int clu)
{
return clu_off_sectnr * bd->sector_size +
- (clu - EXFAT_REVERVED_CLUSTERS) * bd->cluster_size;
+ (clu - EXFAT_RESERVED_CLUSTERS) * bd->cluster_size;
}
.SH SYNOPSIS
.B fsck.exfat
[
+.B \-a
+] [
.B \-n
] [
.B \-r
.PP
.SH OPTIONS
.TP
+.BI \-a
+This option does the same thing as the -p option. It is provided for backwards compatibility only; it is suggested that people use -p option whenever possible.
+.TP
.BI \-n
Check the filesystem but do not attempt to repair the filesystem.
.TP
.B \-L
.I volume_label
] [
+.B \-\-pack\-bitmap
+] [
.B \-v
]
.I device
.PP
.SH OPTIONS
.TP
-.BI \-b " boundary_alignment"
-Specify the alignment for FAT and start of cluster.
-Boundary alignment can be specified in m/M for megabytes
-and k/K for kilobytes. It should be a power of two.
-Some media like sdcard need this.
+.BR \-b ", " \-\-boundary\-align =\fIalignment\fR
+Specifies the alignment for the FAT and the start of the cluster heap.
+The \fIalignment\fR argument is specified in bytes or may be specified with
+\fBm\fR/\fBM\fR suffix for mebibytes or \fBk\fR/\fBK\fR suffix for kibibytes
+and should be a power of two.
+Some media like SD cards need this for optimal performance and endurance,
+in which case \fIalignment\fR should be set to half of the card's native
+boundary unit size.
+If the card's native boundary unit size is not known, refer to the following
+table of boundary unit sizes recommended by the SD Card Association.
+.\" source: SD Specifications Part 2: File System Specification Version 3.00
+.TS
+center;
+cb1s6cbcb,nnnn.
+Card Capacity Range Cluster Size Boundary Unit
+_
+ \[<=]8 MiB 8 KiB 8 KiB
+>8 MiB \[<=]64 MiB 16 KiB 16 KiB
+>64 MiB \[<=]256 MiB 16 KiB 32 KiB
+>256 MiB \[<=]1 GiB 16 KiB 64 KiB
+>1 GiB \[<=]2 GiB 32 KiB 64 KiB
+>2 GiB \[<=]32 GiB 32 KiB 4 MiB
+>32 GiB \[<=]128 GiB 128 KiB 16 MiB
+>128 GiB \[<=]512 GiB 256 KiB 32 MiB
+>512 GiB \[<=]2 TiB 512 KiB 64 MiB
+.TE
.TP
-.BI \-c " cluster_size"
-Specify the cluster size. Cluster size can be specified in m/M for megabytes
-and k/K for kilobytes.
+.BR \-c ", " \-\-cluster\-size =\fIsize\fR
+Specifies the cluster size of the exFAT file system.
+The \fIsize\fR argument is specified in bytes or may be specified with
+\fBm\fR/\fBM\fR suffix for mebibytes or \fBk\fR/\fBK\fR suffix for kibibytes
+and must be a power of two.
.TP
-.BI \-f
-Performs a full format. This zeros the entire disk device while
-creating the exFAT filesystem.
+.BR \-f ", " \-\-full\-format
+Performs a full format.
+This zeros the entire disk device while creating the exFAT filesystem.
.TP
-.BI \-h
+.BR \-h ", " \-\-help
Prints the help and exit.
.TP
-.BI \-L " volume_label"
-Specifies the volume label associated with the exFAT filesystem.
+.BR \-L ", " \-\-volume\-label =\fIlabel\fR
+Specifies the volume label to be associated with the exFAT filesystem.
+.TP
+.B \-\-pack\-bitmap
+Attempts to relocate the exFAT allocation bitmap so that it ends at the
+alignment boundary immediately following the FAT rather than beginning at that
+boundary.
+This strictly violates the SD card specification but may improve performance
+and endurance on SD cards and other flash media not designed for use with exFAT
+by allowing file-system metadata updates to touch fewer flash allocation units.
+Furthermore, many SD cards and other flash devices specially optimize the
+allocation unit where the FAT resides so as to support tiny writes with reduced
+write amplification but expect only larger writes in subsequent allocation
+units \[em] where the exFAT bitmap would be placed by default.
+Specifying \fB\-\-pack\-bitmap\fR attempts to avoid the potential problems
+associated with issuing many small writes to the bitmap by making it share an
+allocation unit with the FAT.
+If there is insufficient space for the bitmap there, then this option will have
+no effect, and the bitmap will be aligned at the boundary as by default.
.TP
-.BI \-v
+.BR \-v ", " \-\-verbose
Prints verbose debugging information while creating the exFAT filesystem.
.TP
-.B \-V
+.BR \-V ", " \-\-version
Prints the version number and exits.
.SH SEE ALSO
.BR mkfs (8),
.BI \-L " set-label"
Set the volume label of the filesystem to the provided argument.
.TP
-.TP
.BI \-i " print-serial"
Print the volume serial of the exFAT filesystem.
.TP
.BI \-I " set-serial"
Set the volume serial of the filesystem to the provided argument.
+.TP
.BI \-v
Prints verbose debugging information while extracting or tuning parameters of the exFAT filesystem.
.TP
#include <fcntl.h>
#include <getopt.h>
#include <inttypes.h>
+#include <limits.h>
#include <errno.h>
#include <locale.h>
#include <time.h>
memset(pbpb->res_zero, 0, 53);
/* Fill exfat extend BIOS paramemter block */
- pbsx->vol_offset = 0;
+ 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);
pbsx->fat_length = cpu_to_le32(finfo.fat_byte_len / bd->sector_size);
memset(ppbr->boot_code, 0, 390);
ppbr->signature = cpu_to_le16(PBR_SIGNATURE);
+ exfat_debug("Volume Offset(sectors) : %" PRIu64 "\n",
+ le64_to_cpu(pbsx->vol_offset));
exfat_debug("Volume Length(sectors) : %" PRIu64 "\n",
le64_to_cpu(pbsx->vol_length));
exfat_debug("FAT Offset(sector offset) : %u\n",
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");
- fprintf(stderr, "\t-h | --help Show help\n");
+ fputs("Usage: mkfs.exfat\n"
+ "\t-L | --volume-label=label Set volume label\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-v | --verbose Print debug\n"
+ "\t-h | --help Show help\n",
+ stderr);
exit(EXIT_FAILURE);
}
-static struct option opts[] = {
+#define PACK_BITMAP (CHAR_MAX + 1)
+
+static const struct option opts[] = {
{"volume-label", required_argument, NULL, 'L' },
{"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' },
{"verbose", no_argument, NULL, 'v' },
{NULL, 0, NULL, 0 }
};
+/*
+ * Moves the bitmap to just before the alignment boundary if there is space
+ * between the boundary and the end of the FAT. This may allow the FAT and the
+ * bitmap to share the same allocation unit on flash media, thereby improving
+ * performance and endurance.
+ */
+static int exfat_pack_bitmap(const struct exfat_user_input *ui)
+{
+ unsigned int fat_byte_end = finfo.fat_byte_off + finfo.fat_byte_len,
+ bitmap_byte_len = finfo.bitmap_byte_len,
+ bitmap_clu_len = round_up(bitmap_byte_len, ui->cluster_size),
+ bitmap_clu_cnt, total_clu_cnt, new_bitmap_clu_len;
+
+ for (;;) {
+ bitmap_clu_cnt = bitmap_clu_len / ui->cluster_size;
+ if (finfo.clu_byte_off - bitmap_clu_len < fat_byte_end ||
+ finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER -
+ bitmap_clu_cnt)
+ return -1;
+ total_clu_cnt = finfo.total_clu_cnt + bitmap_clu_cnt;
+ bitmap_byte_len = round_up(total_clu_cnt, 8) / 8;
+ new_bitmap_clu_len = round_up(bitmap_byte_len, ui->cluster_size);
+ if (new_bitmap_clu_len == bitmap_clu_len) {
+ finfo.clu_byte_off -= bitmap_clu_len;
+ finfo.total_clu_cnt = total_clu_cnt;
+ finfo.bitmap_byte_off -= bitmap_clu_len;
+ finfo.bitmap_byte_len = bitmap_byte_len;
+ return 0;
+ }
+ bitmap_clu_len = new_bitmap_clu_len;
+ }
+}
+
static int exfat_build_mkfs_info(struct exfat_blk_dev *bd,
struct exfat_user_input *ui)
{
+ unsigned long long total_clu_cnt;
int clu_len;
if (ui->boundary_align < bd->sector_size) {
bd->sector_size);
return -1;
}
- finfo.fat_byte_off = round_up(24 * bd->sector_size,
- ui->boundary_align);
+ 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);
- finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len,
- ui->boundary_align);
+ finfo.clu_byte_off = round_up(bd->offset + finfo.fat_byte_off +
+ finfo.fat_byte_len, ui->boundary_align) - bd->offset;
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) {
+ total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size;
+ if (total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) {
exfat_err("cluster size is too small\n");
return -1;
}
+ finfo.total_clu_cnt = (unsigned int) total_clu_cnt;
finfo.bitmap_byte_off = finfo.clu_byte_off;
finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8;
+ if (ui->pack_bitmap)
+ exfat_pack_bitmap(ui);
clu_len = round_up(finfo.bitmap_byte_len, ui->cluster_size);
finfo.ut_start_clu = EXFAT_FIRST_CLUSTER + clu_len / ui->cluster_size;
}
ui.boundary_align = ret;
break;
+ case PACK_BITMAP:
+ ui.pack_bitmap = true;
+ break;
case 'f':
ui.quick = false;
break;
fprintf(stderr, "\t-l | --print-label Print volume label\n");
fprintf(stderr, "\t-L | --set-label=label Set volume label\n");
fprintf(stderr, "\t-i | --print-serial Print volume serial\n");
- fprintf(stderr, "\t-L | --set-serial=value Set volume serial\n");
+ fprintf(stderr, "\t-I | --set-serial=value Set volume serial\n");
fprintf(stderr, "\t-V | --version Show version\n");
fprintf(stderr, "\t-v | --verbose Print debug\n");
fprintf(stderr, "\t-h | --help Show help\n");