fs: fat: flush a directory cluster properly

When a long name directory entry is created, multiple directory entries
may be occupied across a directory cluster boundary. Since only one
directory cluster is cached in a directory iterator, a first cluster must
be written back to device before switching over a second cluster.

Without this patch, some added files may be lost even if you don't see
any failures on write operation.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
AKASHI Takahiro 2019-05-24 14:10:36 +09:00 committed by Tom Rini
parent a9f6706cf0
commit 9c709c7b41

View File

@ -209,7 +209,8 @@ name11_12:
return 1;
}
static int flush_dir_table(fat_itr *itr);
static int new_dir_table(fat_itr *itr);
static int flush_dir(fat_itr *itr);
/*
* Fill dir_slot entries with appropriate name, id, and attr
@ -242,19 +243,15 @@ fill_dir_slot(fat_itr *itr, const char *l_name)
memcpy(itr->dent, slotptr, sizeof(dir_slot));
slotptr--;
counter--;
if (itr->remaining == 0)
flush_dir(itr);
if (!fat_itr_next(itr))
if (!itr->dent && !itr->is_root && flush_dir_table(itr))
if (!itr->dent && !itr->is_root && new_dir_table(itr))
return -1;
}
if (!itr->dent && !itr->is_root)
/*
* don't care return value here because we have already
* finished completing an entry with name, only ending up
* no more entry left
*/
flush_dir_table(itr);
return 0;
}
@ -621,18 +618,14 @@ static int find_empty_cluster(fsdata *mydata)
}
/*
* Write directory entries in itr's buffer to block device
* Allocate a cluster for additional directory entries
*/
static int flush_dir_table(fat_itr *itr)
static int new_dir_table(fat_itr *itr)
{
fsdata *mydata = itr->fsdata;
int dir_newclust = 0;
unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) {
printf("error: writing directory entry\n");
return -1;
}
dir_newclust = find_empty_cluster(mydata);
set_fatent_value(mydata, itr->clust, dir_newclust);
if (mydata->fatsize == 32)
@ -987,7 +980,7 @@ static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
return itr->dent;
}
if (!itr->dent && !itr->is_root && flush_dir_table(itr))
if (!itr->dent && !itr->is_root && new_dir_table(itr))
/* indicate that allocating dent failed */
itr->dent = NULL;
@ -1164,14 +1157,16 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
memset(itr->dent, 0, sizeof(*itr->dent));
/* Set short name to set alias checksum field in dir_slot */
/* Calculate checksum for short name */
set_name(itr->dent, filename);
/* Set long name entries */
if (fill_dir_slot(itr, filename)) {
ret = -EIO;
goto exit;
}
/* Set attribute as archive for regular file */
/* Set short name entry */
fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
retdent = itr->dent;