diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 02:56:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 02:56:46 +0000 |
commit | 38da4eee80f4b01610d38c264cb03cb28048131f (patch) | |
tree | 1ef86b5dd7f73f7d756985339dc1d6bff16233aa /lib | |
parent | Adding upstream version 1.2.2. (diff) | |
download | exfatprogs-38da4eee80f4b01610d38c264cb03cb28048131f.tar.xz exfatprogs-38da4eee80f4b01610d38c264cb03cb28048131f.zip |
Adding upstream version 1.2.3.upstream/1.2.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/exfat_dir.c | 57 | ||||
-rw-r--r-- | lib/exfat_fs.c | 51 | ||||
-rw-r--r-- | lib/libexfat.c | 53 |
3 files changed, 100 insertions, 61 deletions
diff --git a/lib/exfat_dir.c b/lib/exfat_dir.c index 98e820f..7b99af1 100644 --- a/lib/exfat_dir.c +++ b/lib/exfat_dir.c @@ -27,6 +27,12 @@ static struct path_resolve_ctx path_resolve_ctx; ##__VA_ARGS__); \ }) +static inline struct buffer_desc *exfat_de_iter_get_buffer( + struct exfat_de_iter *iter, unsigned int block) +{ + return &iter->buffer_desc[block % iter->exfat->buffer_count]; +} + static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block) { off_t device_offset; @@ -34,10 +40,10 @@ static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block) struct buffer_desc *desc; unsigned int i; - desc = &iter->buffer_desc[block & 0x01]; + desc = exfat_de_iter_get_buffer(iter, block); for (i = 0; i < iter->read_size / iter->write_size; i++) { - if (desc->dirty[i]) { + if (BITMAP_GET(desc->dirty, i)) { device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset; if (exfat_write(exfat->blk_dev->dev_fd, @@ -46,7 +52,7 @@ static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block) device_offset + i * iter->write_size) != (ssize_t)iter->write_size) return -EIO; - desc->dirty[i] = 0; + BITMAP_CLEAR(desc->dirty, i); } } return 0; @@ -169,7 +175,7 @@ static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block) off_t device_offset; ssize_t ret; - desc = &iter->buffer_desc[block & 0x01]; + desc = exfat_de_iter_get_buffer(iter, block); if (block == 0) { desc->p_clus = iter->parent->first_clus; desc->offset = 0; @@ -183,7 +189,7 @@ static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block) if (block > iter->parent->size / iter->read_size) return EOF; - prev_desc = &iter->buffer_desc[(block-1) & 0x01]; + prev_desc = exfat_de_iter_get_buffer(iter, block - 1); if (prev_desc->offset + 2 * iter->read_size <= exfat->clus_size) { desc->p_clus = prev_desc->p_clus; @@ -225,7 +231,7 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, iter->exfat = exfat; iter->parent = dir; iter->write_size = exfat->sect_size; - iter->read_size = exfat->clus_size <= 4*KB ? exfat->clus_size : 4*KB; + iter->read_size = exfat_get_read_size(exfat); if (exfat->clus_size <= 32 * KB) iter->ra_partial_size = MAX(4 * KB, exfat->clus_size / 2); else @@ -257,6 +263,7 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, off_t next_de_file_offset; ssize_t ret; unsigned int block; + struct buffer_desc *bd; next_de_file_offset = iter->de_file_offset + ith * sizeof(struct exfat_dentry); @@ -265,9 +272,6 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, if (next_de_file_offset + sizeof(struct exfat_dentry) > iter->parent->size) return EOF; - /* the dentry must be in current, or next block which will be read */ - if (block > iter->de_file_offset / iter->read_size + 1) - return -ERANGE; /* read next cluster if needed */ if (next_de_file_offset >= iter->next_read_offset) { @@ -280,8 +284,8 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, if (ith + 1 > iter->max_skip_dentries) iter->max_skip_dentries = ith + 1; - *dentry = (struct exfat_dentry *) - (iter->buffer_desc[block & 0x01].buffer + + bd = exfat_de_iter_get_buffer(iter, block); + *dentry = (struct exfat_dentry *)(bd->buffer + next_de_file_offset % iter->read_size); return 0; } @@ -292,6 +296,7 @@ int exfat_de_iter_get_dirty(struct exfat_de_iter *iter, off_t next_file_offset; unsigned int block; int ret, sect_idx; + struct buffer_desc *bd; ret = exfat_de_iter_get(iter, ith, dentry); if (!ret) { @@ -300,7 +305,8 @@ int exfat_de_iter_get_dirty(struct exfat_de_iter *iter, block = (unsigned int)(next_file_offset / iter->read_size); sect_idx = (int)((next_file_offset % iter->read_size) / iter->write_size); - iter->buffer_desc[block & 0x01].dirty[sect_idx] = 1; + bd = exfat_de_iter_get_buffer(iter, block); + BITMAP_SET(bd->dirty, sect_idx); } return ret; @@ -308,8 +314,11 @@ int exfat_de_iter_get_dirty(struct exfat_de_iter *iter, int exfat_de_iter_flush(struct exfat_de_iter *iter) { - if (write_block(iter, 0) || write_block(iter, 1)) - return -EIO; + unsigned int i; + + for (i = 0; i < iter->exfat->buffer_count; i++) + if (write_block(iter, i)) + return -EIO; return 0; } @@ -333,7 +342,7 @@ off_t exfat_de_iter_device_offset(struct exfat_de_iter *iter) return EOF; block = iter->de_file_offset / iter->read_size; - bd = &iter->buffer_desc[block & 0x01]; + bd = exfat_de_iter_get_buffer(iter, block); return exfat_c2o(iter->exfat, bd->p_clus) + bd->offset + iter->de_file_offset % iter->read_size; } @@ -359,9 +368,12 @@ int exfat_lookup_dentry_set(struct exfat *exfat, struct exfat_inode *parent, int dentry_count, empty_dentry_count = 0; int retval; - bd = exfat_alloc_buffer(2, exfat->clus_size, exfat->sect_size); - if (!bd) - return -ENOMEM; + if (!exfat->lookup_buffer) { + exfat->lookup_buffer = exfat_alloc_buffer(exfat); + if (!exfat->lookup_buffer) + return -ENOMEM; + } + bd = exfat->lookup_buffer; retval = exfat_de_iter_init(&de_iter, exfat, parent, bd); if (retval == EOF || retval) @@ -441,8 +453,6 @@ out: filter->out.file_offset = exfat_de_iter_file_offset(&de_iter); filter->out.dev_offset = EOF; } - if (bd) - exfat_free_buffer(bd, 2); return retval; } @@ -613,7 +623,7 @@ int exfat_build_file_dentry_set(struct exfat *exfat, const char *name, name_len = retval / 2; dcount = 2 + DIV_ROUND_UP(name_len, ENTRY_NAME_MAX); - dset = calloc(1, dcount * DENTRY_SIZE); + dset = calloc(dcount, DENTRY_SIZE); if (!dset) return -ENOMEM; @@ -841,9 +851,8 @@ static int exfat_alloc_cluster(struct exfat *exfat, struct exfat_inode *inode, return -EIO; /* zero out the new cluster */ - if (exfat_write(exfat->blk_dev->dev_fd, exfat->zero_cluster, - exfat->clus_size, exfat_c2o(exfat, *new_clu)) != - (ssize_t)exfat->clus_size) { + if (exfat_write_zero(exfat->blk_dev->dev_fd, exfat->clus_size, + exfat_c2o(exfat, *new_clu))) { exfat_err("failed to fill new cluster with zeroes\n"); return -EIO; } diff --git a/lib/exfat_fs.c b/lib/exfat_fs.c index d563c61..be76e59 100644 --- a/lib/exfat_fs.c +++ b/lib/exfat_fs.c @@ -22,7 +22,7 @@ struct exfat_inode *exfat_alloc_inode(__u16 attr) int size; size = offsetof(struct exfat_inode, name) + NAME_BUFFER_SIZE; - node = (struct exfat_inode *)calloc(1, size); + node = calloc(1, size); if (!node) { exfat_err("failed to allocate exfat_node\n"); return NULL; @@ -117,8 +117,8 @@ void exfat_free_exfat(struct exfat *exfat) free(exfat->upcase_table); if (exfat->root) exfat_free_inode(exfat->root); - if (exfat->zero_cluster) - free(exfat->zero_cluster); + if (exfat->lookup_buffer) + free(exfat->lookup_buffer); free(exfat); } } @@ -127,7 +127,7 @@ struct exfat *exfat_alloc_exfat(struct exfat_blk_dev *blk_dev, struct pbr *bs) { struct exfat *exfat; - exfat = (struct exfat *)calloc(1, sizeof(*exfat)); + exfat = calloc(1, sizeof(*exfat)); if (!exfat) return NULL; @@ -139,32 +139,26 @@ struct exfat *exfat_alloc_exfat(struct exfat_blk_dev *blk_dev, struct pbr *bs) exfat->sect_size = EXFAT_SECTOR_SIZE(bs); /* TODO: bitmap could be very large. */ - exfat->alloc_bitmap = (char *)calloc(1, - EXFAT_BITMAP_SIZE(exfat->clus_count)); + exfat->alloc_bitmap = calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); if (!exfat->alloc_bitmap) { exfat_err("failed to allocate bitmap\n"); goto err; } - exfat->ohead_bitmap = - calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); + exfat->ohead_bitmap = calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); if (!exfat->ohead_bitmap) { exfat_err("failed to allocate bitmap\n"); goto err; } - exfat->disk_bitmap = - calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); + exfat->disk_bitmap = calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); if (!exfat->disk_bitmap) { exfat_err("failed to allocate bitmap\n"); goto err; } - exfat->zero_cluster = calloc(1, exfat->clus_size); - if (!exfat->zero_cluster) { - exfat_err("failed to allocate a zero-filled cluster buffer\n"); - goto err; - } + exfat->buffer_count = ((MAX_EXT_DENTRIES + 1) * DENTRY_SIZE) / + exfat_get_read_size(exfat) + 1; exfat->start_clu = EXFAT_FIRST_CLUSTER; return exfat; @@ -173,39 +167,36 @@ err: return NULL; } -struct buffer_desc *exfat_alloc_buffer(int count, - unsigned int clu_size, unsigned int sect_size) +struct buffer_desc *exfat_alloc_buffer(struct exfat *exfat) { struct buffer_desc *bd; - int i; + unsigned int i; + unsigned int read_size = exfat_get_read_size(exfat); - bd = (struct buffer_desc *)calloc(sizeof(*bd), count); + bd = calloc(exfat->buffer_count, sizeof(*bd)); if (!bd) return NULL; - for (i = 0; i < count; i++) { - bd[i].buffer = (char *)malloc(clu_size); + for (i = 0; i < exfat->buffer_count; i++) { + bd[i].buffer = malloc(read_size); if (!bd[i].buffer) goto err; - bd[i].dirty = (char *)calloc(clu_size / sect_size, 1); - if (!bd[i].dirty) - goto err; + + memset(&bd[i].dirty, 0, sizeof(bd[i].dirty)); } return bd; err: - exfat_free_buffer(bd, count); + exfat_free_buffer(exfat, bd); return NULL; } -void exfat_free_buffer(struct buffer_desc *bd, int count) +void exfat_free_buffer(const struct exfat *exfat, struct buffer_desc *bd) { - int i; + unsigned int i; - for (i = 0; i < count; i++) { + for (i = 0; i < exfat->buffer_count; i++) { if (bd[i].buffer) free(bd[i].buffer); - if (bd[i].dirty) - free(bd[i].dirty); } free(bd); } diff --git a/lib/libexfat.c b/lib/libexfat.c index d7b8344..0bcb4a4 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -187,7 +187,9 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, if (!ui->boundary_align) ui->boundary_align = DEFAULT_BOUNDARY_ALIGNMENT; - if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0) + if (ui->sector_size) + bd->sector_size = ui->sector_size; + else if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0) bd->sector_size = DEFAULT_SECTOR_SIZE; bd->sector_size_bits = sector_size_bits(bd->sector_size); bd->num_sectors = blk_dev_size / bd->sector_size; @@ -218,6 +220,24 @@ ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset) return pwrite(fd, buf, size, offset); } +ssize_t exfat_write_zero(int fd, size_t size, off_t offset) +{ + const char zero_buf[4 * KB] = {0}; + + lseek(fd, offset, SEEK_SET); + + while (size > 0) { + int iter_size = MIN(size, sizeof(zero_buf)); + + if (iter_size != write(fd, zero_buf, iter_size)) + return -EIO; + + size -= iter_size; + } + + return 0; +} + size_t exfat_utf16_len(const __le16 *str, size_t max_size) { size_t i = 0; @@ -355,7 +375,7 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) unsigned int cluster_size, sector_size; off_t root_clu_off; - bs = (struct pbr *)malloc(EXFAT_MAX_SECTOR_SIZE); + bs = malloc(EXFAT_MAX_SECTOR_SIZE); if (!bs) { exfat_err("failed to allocate memory\n"); return -ENOMEM; @@ -464,7 +484,7 @@ int exfat_set_volume_label(struct exfat *exfat, char *label_input) dcount = filter.out.dentry_count; memset(pvol->vol_label, 0, sizeof(pvol->vol_label)); } else { - pvol = calloc(sizeof(struct exfat_dentry), 1); + pvol = calloc(1, sizeof(struct exfat_dentry)); if (!pvol) return -ENOMEM; @@ -509,7 +529,7 @@ static int set_guid(__u8 *guid, const char *input) int i, j, zero_len = 0; int len = strlen(input); - if (len != VOLUME_GUID_LEN * 2 && len != VOLUME_GUID_LEN * 2 + 4) { + if (len != EXFAT_GUID_LEN * 2 && len != EXFAT_GUID_LEN * 2 + 4) { exfat_err("invalid format for volume guid\n"); return -EINVAL; } @@ -523,7 +543,7 @@ static int set_guid(__u8 *guid, const char *input) ch -= 'a' - 0xA; else if (ch >= 'A' && ch <= 'F') ch -= 'A' - 0xA; - else if (ch == '-' && len == VOLUME_GUID_LEN * 2 + 4 && + else if (ch == '-' && len == EXFAT_GUID_LEN * 2 + 4 && (i == 8 || i == 13 || i == 18 || i == 23)) continue; else { @@ -542,7 +562,7 @@ static int set_guid(__u8 *guid, const char *input) zero_len++; } - if (zero_len == VOLUME_GUID_LEN * 2) { + if (zero_len == EXFAT_GUID_LEN * 2) { exfat_err("%s is invalid for volume GUID\n", input); return -EINVAL; } @@ -814,7 +834,7 @@ int exfat_set_volume_serial(struct exfat_blk_dev *bd, } bd->sector_size = 1 << ppbr->bsx.sect_size_bits; - ppbr->bsx.vol_serial = ui->volume_serial; + ppbr->bsx.vol_serial = cpu_to_le32(ui->volume_serial); /* update main boot sector */ ret = exfat_write_sector(bd, (char *)ppbr, BOOT_SEC_IDX); @@ -981,6 +1001,10 @@ int read_boot_sect(struct exfat_blk_dev *bdev, struct pbr **bs) unsigned int sect_size, clu_size; pbr = malloc(sizeof(struct pbr)); + if (!pbr) { + exfat_err("failed to allocate memory\n"); + return -ENOMEM; + } if (exfat_read(bdev->dev_fd, pbr, sizeof(*pbr), 0) != (ssize_t)sizeof(*pbr)) { @@ -1017,3 +1041,18 @@ err: free(pbr); return err; } + +int exfat_parse_ulong(const char *s, unsigned long *out) +{ + char *endptr; + + *out = strtoul(s, &endptr, 0); + + if (errno) + return -errno; + + if (s == endptr || *endptr != '\0') + return -EINVAL; + + return 0; +} |