summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAKASHI Takahiro <takahiro.akashi@linaro.org>2019-05-24 14:10:36 +0900
committerTom Rini <trini@konsulko.com>2019-05-28 18:55:08 -0400
commit9c709c7b4177d063733070c7256f0b8635996d65 (patch)
treefe97738ca54b3d0d4057ec6978321c3b57a842b6 /fs
parenta9f6706cf0ba330281ae7d6a0af65cc26ffb7d25 (diff)
downloadu-boot-9c709c7b4177d063733070c7256f0b8635996d65.tar.gz
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/fat/fat_write.c33
1 files changed, 14 insertions, 19 deletions
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 11b85d35ed..5ea15fab3a 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -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;