summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Skadorov <philipp.skadorov@savoirfairelinux.com>2016-12-15 15:52:53 -0500
committerTom Rini <trini@konsulko.com>2016-12-27 11:24:13 -0500
commit49abbd9cc309235895c9ff7ccb6ad75c40fca4a9 (patch)
treecde9103347ae17a2bbae256f1c591f2d366e31e7
parent43db3e3b3d7d24c080ee04605a0f045939137b19 (diff)
downloadu-boot-imx-49abbd9cc309235895c9ff7ccb6ad75c40fca4a9.zip
u-boot-imx-49abbd9cc309235895c9ff7ccb6ad75c40fca4a9.tar.gz
u-boot-imx-49abbd9cc309235895c9ff7ccb6ad75c40fca4a9.tar.bz2
fat: fatwrite: fix the command for FAT12
The u-boot command fatwrite empties FAT clusters from the beginning till the end of the file. Specifically for FAT12 it fails to detect the end of the file and goes beyond the file bounds thus corrupting the file system. Additionally, FAT entry chaining-up into a file is not implemented for FAT12. The users normally workaround this by re-formatting the partition as FAT16/FAT32, like here: https://github.com/FEDEVEL/openrex-uboot-v2015.10/issues/1 The patch fixes the bounds of a file and FAT12 entries chaining into a file, including EOF markup. Signed-off-by: Philipp Skadorov <philipp.skadorov@savoirfairelinux.com>
-rw-r--r--fs/fat/fat_write.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 40a3860..aab0b0e 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -467,11 +467,12 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
}
/*
- * Set the entry at index 'entry' in a FAT (16/32) table.
+ * Set the entry at index 'entry' in a FAT (12/16/32) table.
*/
static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
{
- __u32 bufnum, offset;
+ __u32 bufnum, offset, off16;
+ __u16 val1, val2;
switch (mydata->fatsize) {
case 32:
@@ -482,6 +483,10 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
bufnum = entry / FAT16BUFSIZE;
offset = entry - bufnum * FAT16BUFSIZE;
break;
+ case 12:
+ bufnum = entry / FAT12BUFSIZE;
+ offset = entry - bufnum * FAT12BUFSIZE;
+ break;
default:
/* Unsupported FAT size */
return -1;
@@ -521,6 +526,45 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
case 16:
((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
break;
+ case 12:
+ off16 = (offset * 3) / 4;
+
+ switch (offset & 0x3) {
+ case 0:
+ val1 = cpu_to_le16(entry_value) & 0xfff;
+ ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
+ ((__u16 *)mydata->fatbuf)[off16] |= val1;
+ break;
+ case 1:
+ val1 = cpu_to_le16(entry_value) & 0xf;
+ val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
+
+ ((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
+ ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
+
+ ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
+ ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
+ break;
+ case 2:
+ val1 = cpu_to_le16(entry_value) & 0xff;
+ val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
+
+ ((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
+ ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
+
+ ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
+ ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
+ break;
+ case 3:
+ val1 = cpu_to_le16(entry_value) & 0xfff;
+ ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
+ ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
+ break;
+ default:
+ break;
+ }
+
+ break;
default:
return -1;
}
@@ -529,7 +573,7 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
}
/*
- * Determine the next free cluster after 'entry' in a FAT (16/32) table
+ * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
* and link it to 'entry'. EOC marker is not set on returned entry.
*/
static __u32 determine_fatent(fsdata *mydata, __u32 entry)
@@ -651,6 +695,8 @@ static void flush_dir_table(fsdata *mydata, dir_entry **dentptr)
set_fatent_value(mydata, dir_newclust, 0xffffff8);
else if (mydata->fatsize == 16)
set_fatent_value(mydata, dir_newclust, 0xfff8);
+ else if (mydata->fatsize == 12)
+ set_fatent_value(mydata, dir_newclust, 0xff8);
dir_curclust = dir_newclust;
@@ -670,16 +716,13 @@ static int clear_fatent(fsdata *mydata, __u32 entry)
{
__u32 fat_val;
- while (1) {
+ while (!CHECK_CLUST(entry, mydata->fatsize)) {
fat_val = get_fatent_value(mydata, entry);
if (fat_val != 0)
set_fatent_value(mydata, entry, 0);
else
break;
- if (fat_val == 0xfffffff || fat_val == 0xffff)
- break;
-
entry = fat_val;
}
@@ -750,7 +793,9 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
*gotsize += actsize;
/* Mark end of file in FAT */
- if (mydata->fatsize == 16)
+ if (mydata->fatsize == 12)
+ newclust = 0xfff;
+ else if (mydata->fatsize == 16)
newclust = 0xffff;
else if (mydata->fatsize == 32)
newclust = 0xfffffff;