exfat: support handle zero-size directory
[ Upstream commit dab48b8f2fe7264d51ec9eed0adea0fe3c78830a ] After repairing a corrupted file system with exfatprogs' fsck.exfat, zero-size directories may result. It is also possible to create zero-size directories in other exFAT implementation, such as Paragon ufsd dirver. As described in the specification, the lower directory size limits is 0 bytes. Without this commit, sub-directories and files cannot be created under a zero-size directory, and it cannot be removed. Signed-off-by: Yuezhang Mo <Yuezhang.Mo@sony.com> Reviewed-by: Andy Wu <Andy.Wu@sony.com> Reviewed-by: Aoyama Wataru <wataru.aoyama@sony.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
24e222a54e
commit
b469227b1d
@ -338,14 +338,20 @@ static int exfat_find_empty_entry(struct inode *inode,
|
|||||||
if (exfat_check_max_dentries(inode))
|
if (exfat_check_max_dentries(inode))
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
/* we trust p_dir->size regardless of FAT type */
|
|
||||||
if (exfat_find_last_cluster(sb, p_dir, &last_clu))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate new cluster to this directory
|
* Allocate new cluster to this directory
|
||||||
*/
|
*/
|
||||||
exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags);
|
if (ei->start_clu != EXFAT_EOF_CLUSTER) {
|
||||||
|
/* we trust p_dir->size regardless of FAT type */
|
||||||
|
if (exfat_find_last_cluster(sb, p_dir, &last_clu))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags);
|
||||||
|
} else {
|
||||||
|
/* This directory is empty */
|
||||||
|
exfat_chain_set(&clu, EXFAT_EOF_CLUSTER, 0,
|
||||||
|
ALLOC_NO_FAT_CHAIN);
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate a cluster */
|
/* allocate a cluster */
|
||||||
ret = exfat_alloc_cluster(inode, 1, &clu, IS_DIRSYNC(inode));
|
ret = exfat_alloc_cluster(inode, 1, &clu, IS_DIRSYNC(inode));
|
||||||
@ -355,6 +361,11 @@ static int exfat_find_empty_entry(struct inode *inode,
|
|||||||
if (exfat_zeroed_cluster(inode, clu.dir))
|
if (exfat_zeroed_cluster(inode, clu.dir))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
if (ei->start_clu == EXFAT_EOF_CLUSTER) {
|
||||||
|
ei->start_clu = clu.dir;
|
||||||
|
p_dir->dir = clu.dir;
|
||||||
|
}
|
||||||
|
|
||||||
/* append to the FAT chain */
|
/* append to the FAT chain */
|
||||||
if (clu.flags != p_dir->flags) {
|
if (clu.flags != p_dir->flags) {
|
||||||
/* no-fat-chain bit is disabled,
|
/* no-fat-chain bit is disabled,
|
||||||
@ -644,7 +655,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
|
|||||||
info->type = exfat_get_entry_type(ep);
|
info->type = exfat_get_entry_type(ep);
|
||||||
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
||||||
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
||||||
if ((info->type == TYPE_FILE) && (info->size == 0)) {
|
if (info->size == 0) {
|
||||||
info->flags = ALLOC_NO_FAT_CHAIN;
|
info->flags = ALLOC_NO_FAT_CHAIN;
|
||||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
} else {
|
} else {
|
||||||
@ -888,6 +899,9 @@ static int exfat_check_dir_empty(struct super_block *sb,
|
|||||||
|
|
||||||
dentries_per_clu = sbi->dentries_per_clu;
|
dentries_per_clu = sbi->dentries_per_clu;
|
||||||
|
|
||||||
|
if (p_dir->dir == EXFAT_EOF_CLUSTER)
|
||||||
|
return 0;
|
||||||
|
|
||||||
exfat_chain_dup(&clu, p_dir);
|
exfat_chain_dup(&clu, p_dir);
|
||||||
|
|
||||||
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
||||||
@ -1262,7 +1276,8 @@ static int __exfat_rename(struct inode *old_parent_inode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
|
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
|
||||||
if (new_entry_type == TYPE_DIR) {
|
if (new_entry_type == TYPE_DIR &&
|
||||||
|
new_ei->start_clu != EXFAT_EOF_CLUSTER) {
|
||||||
/* new_ei, new_clu_to_free */
|
/* new_ei, new_clu_to_free */
|
||||||
struct exfat_chain new_clu_to_free;
|
struct exfat_chain new_clu_to_free;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user