Skip to content

Commit

Permalink
exfat: fix appending discontinuous clusters to empty file
Browse files Browse the repository at this point in the history
Eric Hong found that when using ftruncate to expand an empty file,
exfat_ent_set() will fail if discontinuous clusters are allocated.
The reason is that the empty file does not have a cluster chain,
but exfat_ent_set() attempts to append the newly allocated cluster
to the cluster chain. In addition, exfat_find_last_cluster() only
supports finding the last cluster in a non-empty file.

So this commit adds a check whether the file is empty. If the file
is empty, exfat_find_last_cluster() and exfat_ent_set() are no longer
called as they do not need to be called.

Fixes: f55c096f62f1 ("exfat: do not zero the extended part")
Reported-by: Eric Hong <[email protected]>
Signed-off-by: Yuezhang Mo <[email protected]>
Signed-off-by: Namjae Jeon <[email protected]>
  • Loading branch information
YuezhangMo authored and namjaejeon committed Feb 18, 2024
1 parent b918344 commit 7ea2d84
Showing 1 changed file with 22 additions and 15 deletions.
37 changes: 22 additions & 15 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
if (new_num_clusters == num_clusters)
goto out;

exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
ret = exfat_find_last_cluster(sb, &clu, &last_clu);
if (ret)
return ret;
if (num_clusters) {
exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
ret = exfat_find_last_cluster(sb, &clu, &last_clu);
if (ret)
return ret;

clu.dir = last_clu + 1;
} else {
last_clu = EXFAT_EOF_CLUSTER;
clu.dir = EXFAT_EOF_CLUSTER;
}

clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
EXFAT_EOF_CLUSTER : last_clu + 1;
clu.size = 0;
clu.flags = ei->flags;

Expand All @@ -53,17 +58,19 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
return ret;

/* Append new clusters to chain */
if (clu.flags != ei->flags) {
exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters);
ei->flags = ALLOC_FAT_CHAIN;
}
if (clu.flags == ALLOC_FAT_CHAIN)
if (exfat_ent_set(sb, last_clu, clu.dir))
goto free_clu;

if (num_clusters == 0)
if (num_clusters) {
if (clu.flags != ei->flags)
if (exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters))
goto free_clu;

if (clu.flags == ALLOC_FAT_CHAIN)
if (exfat_ent_set(sb, last_clu, clu.dir))
goto free_clu;
} else
ei->start_clu = clu.dir;

ei->flags = clu.flags;

out:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
Expand Down

0 comments on commit 7ea2d84

Please sign in to comment.