summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 02:56:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 02:56:46 +0000
commit38da4eee80f4b01610d38c264cb03cb28048131f (patch)
tree1ef86b5dd7f73f7d756985339dc1d6bff16233aa /lib
parentAdding upstream version 1.2.2. (diff)
downloadexfatprogs-upstream.tar.xz
exfatprogs-upstream.zip
Adding upstream version 1.2.3.upstream/1.2.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/exfat_dir.c57
-rw-r--r--lib/exfat_fs.c51
-rw-r--r--lib/libexfat.c53
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;
+}