Skip to content

Commit

Permalink
exfatprogs: tune: use sector size extracted from the boot sector
Browse files Browse the repository at this point in the history
Eric Sandeen reported exfat dump image is damaged when tune.exfat was
executed against exfat dump image created in 4K native device.

# fsck/fsck.exfat /root/test.img
exfatprogs version : 1.1.1
/root/test.img: clean. directories 1, files 0
# tune/tune.exfat -I 0x1234  /root/test.img
exfatprogs version : 1.1.1
New volume serial : 0x1234
# fsck/fsck.exfat /root/test.img
exfatprogs version : 1.1.1
checksum of boot region is not correct. 0x3eedc5, but expected
0xe59577e3
boot region is corrupted. try to restore the region from backup. Fix
(y/N)? n

This patch read boot sector with 4KB(for 4K native) size, and use the
sector size extracted from the boot sector.

Reported-by: Eric Sandeen <[email protected]>
Signed-off-by: Namjae Jeon <[email protected]>
  • Loading branch information
namjaejeon committed May 13, 2021
1 parent 0032bd2 commit a13479b
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 16 deletions.
4 changes: 3 additions & 1 deletion include/libexfat.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#define EXFAT_GET_VOLUME_SERIAL 0x03
#define EXFAT_SET_VOLUME_SERIAL 0x04

#define EXFAT_MAX_SECTOR_SIZE 4096

enum {
BOOT_SEC_IDX = 0,
EXBOOT_SEC_IDX,
Expand Down Expand Up @@ -107,7 +109,7 @@ int exfat_write_sector(struct exfat_blk_dev *bd, void *buf,
int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
unsigned int checksum, bool is_backup);
char *exfat_conv_volume_label(struct exfat_dentry *vol_entry);
int exfat_show_volume_serial(struct exfat_blk_dev *bd);
int exfat_show_volume_serial(int fd);
int exfat_set_volume_serial(struct exfat_blk_dev *bd,
struct exfat_user_input *ui);
unsigned int exfat_clus_to_blk_dev_off(struct exfat_blk_dev *bd,
Expand Down
2 changes: 1 addition & 1 deletion label/label.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ int main(int argc, char *argv[])
if (serial_mode) {
/* Mode to change or display volume serial */
if (flags == EXFAT_GET_VOLUME_SERIAL) {
ret = exfat_show_volume_serial(&bd);
ret = exfat_show_volume_serial(bd.dev_fd);
} else if (flags == EXFAT_SET_VOLUME_SERIAL) {
ui.volume_serial = strtoul(argv[3], NULL, 0);
ret = exfat_set_volume_serial(&bd, &ui);
Expand Down
29 changes: 16 additions & 13 deletions lib/libexfat.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,26 +358,27 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd)
{
struct pbr *bs;
int nbytes;
unsigned int cluster_size;
unsigned int cluster_size, sector_size;
off_t root_clu_off;

bs = (struct pbr *)malloc(sizeof(struct pbr));
bs = (struct pbr *)malloc(EXFAT_MAX_SECTOR_SIZE);
if (!bs) {
exfat_err("failed to allocate memory\n");
return -ENOMEM;
}

nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0);
if (nbytes != sizeof(struct pbr)) {
nbytes = exfat_read(bd->dev_fd, bs, EXFAT_MAX_SECTOR_SIZE, 0);
if (nbytes != EXFAT_MAX_SECTOR_SIZE) {
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_RESERVED_CLUSTERS)
* cluster_size;
sector_size = 1 << bs->bsx.sect_size_bits;
cluster_size = (1 << bs->bsx.sect_per_clus_bits) * sector_size;
root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * sector_size +
le32_to_cpu(bs->bsx.root_cluster - EXFAT_RESERVED_CLUSTERS) *
cluster_size;
free(bs);

return root_clu_off;
Expand Down Expand Up @@ -528,19 +529,19 @@ int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
return ret;
}

int exfat_show_volume_serial(struct exfat_blk_dev *bd)
int exfat_show_volume_serial(int fd)
{
struct pbr *ppbr;
int ret;

ppbr = malloc(bd->sector_size);
ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
if (!ppbr) {
exfat_err("Cannot allocate pbr: out of memory\n");
return -1;
}

/* read main boot sector */
ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX);
ret = exfat_read(fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE, 0);
if (ret < 0) {
exfat_err("main boot sector read failed\n");
ret = -1;
Expand Down Expand Up @@ -600,20 +601,22 @@ int exfat_set_volume_serial(struct exfat_blk_dev *bd,
int ret;
struct pbr *ppbr;

ppbr = malloc(bd->sector_size);
ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
if (!ppbr) {
exfat_err("Cannot allocate pbr: out of memory\n");
return -1;
}

/* read main boot sector */
ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX);
ret = exfat_read(bd->dev_fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE,
BOOT_SEC_IDX);
if (ret < 0) {
exfat_err("main boot sector read failed\n");
ret = -1;
goto free_ppbr;
}

bd->sector_size = 1 << ppbr->bsx.sect_size_bits;
ppbr->bsx.vol_serial = ui->volume_serial;

/* update main boot sector */
Expand Down
2 changes: 1 addition & 1 deletion tune/tune.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ int main(int argc, char *argv[])

/* Mode to change or display volume serial */
if (flags == EXFAT_GET_VOLUME_SERIAL) {
ret = exfat_show_volume_serial(&bd);
ret = exfat_show_volume_serial(bd.dev_fd);
goto close_fd_out;
} else if (flags == EXFAT_SET_VOLUME_SERIAL) {
ret = exfat_set_volume_serial(&bd, &ui);
Expand Down

0 comments on commit a13479b

Please sign in to comment.