Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validsize #194

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion libexfat/cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,14 @@ int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,

if (erase)
{
rc = erase_range(ef, node, node->size, size);
rc = erase_range(ef, node, node->valid_size, size);
if (rc != 0)
return rc;
node->valid_size = size;
}
else
{
node->valid_size = MIN(node->valid_size, size);
}

exfat_update_mtime(node);
Expand Down
1 change: 1 addition & 0 deletions libexfat/exfat.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct exfat_node
bool is_cached : 1;
bool is_dirty : 1;
bool is_unlinked : 1;
uint64_t valid_size;
uint64_t size;
time_t mtime, atime;
le16_t name[EXFAT_NAME_MAX + 1];
Expand Down
44 changes: 31 additions & 13 deletions libexfat/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,27 +390,44 @@ ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
void* buffer, size_t size, off_t offset)
{
uint64_t newsize = offset;
uint64_t uoffset = offset;
cluster_t cluster;
char* bufp = buffer;
off_t lsize, loffset, remainder;

if (offset < 0)
return -EINVAL;
if (newsize >= node->size)
if (uoffset >= node->size)
return 0;
if (size == 0)
return 0;

cluster = exfat_advance_cluster(ef, node, newsize / CLUSTER_SIZE(*ef->sb));
if (uoffset + size > node->valid_size)
{
ssize_t bytes = 0;

exfat_debug("Read %ld %zu from %lu %lu file", offset, size, node->valid_size, node->size);
if (uoffset < node->valid_size)
{
bytes = exfat_generic_pread(ef, node, buffer,
node->valid_size - uoffset, offset);
if (bytes < 0 || (size_t) bytes < node->valid_size - uoffset)
return bytes;
}
memset(buffer + bytes, 0,
MIN(size - bytes, node->size - node->valid_size));
return MIN(size, node->size - uoffset);
}

cluster = exfat_advance_cluster(ef, node, uoffset / CLUSTER_SIZE(*ef->sb));
if (CLUSTER_INVALID(*ef->sb, cluster))
{
exfat_error("invalid cluster 0x%x while reading", cluster);
return -EIO;
}

loffset = newsize % CLUSTER_SIZE(*ef->sb);
remainder = MIN(size, node->size - newsize);
loffset = uoffset % CLUSTER_SIZE(*ef->sb);
remainder = MIN(size, node->size - uoffset);
while (remainder > 0)
{
if (CLUSTER_INVALID(*ef->sb, cluster))
Expand All @@ -432,43 +449,43 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
}
if (!(node->attrib & EXFAT_ATTRIB_DIR) && !ef->ro && !ef->noatime)
exfat_update_atime(node);
return MIN(size, node->size - newsize) - remainder;
return MIN(size, node->size - uoffset) - remainder;
}

ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
const void* buffer, size_t size, off_t offset)
{
uint64_t newsize = offset;
uint64_t uoffset = offset;
int rc;
cluster_t cluster;
const char* bufp = buffer;
off_t lsize, loffset, remainder;

if (offset < 0)
return -EINVAL;
if (newsize > node->size)
if (uoffset > node->size)
{
rc = exfat_truncate(ef, node, newsize, true);
rc = exfat_truncate(ef, node, uoffset, true);
if (rc != 0)
return rc;
}
if (newsize + size > node->size)
if (uoffset + size > node->size)
{
rc = exfat_truncate(ef, node, newsize + size, false);
rc = exfat_truncate(ef, node, uoffset + size, false);
if (rc != 0)
return rc;
}
if (size == 0)
return 0;

cluster = exfat_advance_cluster(ef, node, newsize / CLUSTER_SIZE(*ef->sb));
cluster = exfat_advance_cluster(ef, node, uoffset / CLUSTER_SIZE(*ef->sb));
if (CLUSTER_INVALID(*ef->sb, cluster))
{
exfat_error("invalid cluster 0x%x while writing", cluster);
return -EIO;
}

loffset = newsize % CLUSTER_SIZE(*ef->sb);
loffset = uoffset % CLUSTER_SIZE(*ef->sb);
remainder = size;
while (remainder > 0)
{
Expand All @@ -487,6 +504,7 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
bufp += lsize;
loffset = 0;
remainder -= lsize;
node->valid_size = MAX(node->valid_size, uoffset + size - remainder);
cluster = exfat_next_cluster(ef, node, cluster);
}
if (!(node->attrib & EXFAT_ATTRIB_DIR))
Expand Down
2 changes: 1 addition & 1 deletion libexfat/mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)
ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
ef->root->fptr_cluster = ef->root->start_cluster;
ef->root->name[0] = cpu_to_le16('\0');
ef->root->size = rootdir_size(ef);
ef->root->valid_size = ef->root->size = rootdir_size(ef);
if (ef->root->size == 0)
{
exfat_free(ef);
Expand Down
14 changes: 7 additions & 7 deletions libexfat/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ static void init_node_meta1(struct exfat_node* node,
static void init_node_meta2(struct exfat_node* node,
const struct exfat_entry_meta2* meta2)
{
node->valid_size = le64_to_cpu(meta2->valid_size);
node->size = le64_to_cpu(meta2->size);
node->start_cluster = le32_to_cpu(meta2->start_cluster);
node->fptr_cluster = node->start_cluster;
Expand Down Expand Up @@ -206,8 +207,7 @@ static bool check_entries(const struct exfat_entry* entry, int n)
}

static bool check_node(const struct exfat* ef, struct exfat_node* node,
le16_t actual_checksum, const struct exfat_entry_meta1* meta1,
const struct exfat_entry_meta2* meta2)
le16_t actual_checksum, const struct exfat_entry_meta1* meta1)
{
int cluster_size = CLUSTER_SIZE(*ef->sb);
uint64_t clusters_heap_size =
Expand All @@ -234,12 +234,11 @@ static bool check_node(const struct exfat* ef, struct exfat_node* node,
cannot be greater than file size. See SetFileValidData() function
description in MSDN.
*/
if (le64_to_cpu(meta2->valid_size) > node->size)
if (node->valid_size > node->size)
{
exfat_get_name(node, buffer);
exfat_error("'%s' has valid size (%"PRIu64") greater than size "
"(%"PRIu64")", buffer, le64_to_cpu(meta2->valid_size),
node->size);
"(%"PRIu64")", buffer, node->valid_size, node->size);
ret = false;
}

Expand Down Expand Up @@ -328,7 +327,7 @@ static int parse_file_entries(struct exfat* ef, struct exfat_node* node,
init_node_meta2(node, meta2);
init_node_name(node, entries + 2, mandatory_entries - 2);

if (!check_node(ef, node, exfat_calc_checksum(entries, n), meta1, meta2))
if (!check_node(ef, node, exfat_calc_checksum(entries, n), meta1))
return -EIO;

return 0;
Expand Down Expand Up @@ -659,7 +658,8 @@ int exfat_flush_node(struct exfat* ef, struct exfat_node* node)
NULL, &meta1->atime_tzo);
meta1->adate = edate;
meta1->atime = etime;
meta2->size = meta2->valid_size = cpu_to_le64(node->size);
meta2->valid_size = cpu_to_le64(node->valid_size);
meta2->size = cpu_to_le64(node->size);
meta2->start_cluster = cpu_to_le32(node->start_cluster);
meta2->flags = EXFAT_FLAG_ALWAYS1;
/* empty files must not be marked as contiguous */
Expand Down