fs/fat/fat_write: Fix management of empty files
authorBenoît Thébaudeau <benoit@wsystem.com>
Mon, 28 Sep 2015 13:45:32 +0000 (15:45 +0200)
committerTom Rini <trini@konsulko.com>
Sun, 11 Oct 2015 21:12:08 +0000 (17:12 -0400)
Overwriting an empty file not created by U-Boot did not work, and it
could even corrupt the FAT. Moreover, creating empty files or emptying
existing files allocated a cluster, which is not standard.

Fix this by always keeping empty files clusterless as specified by
Microsoft (the start cluster must be set to 0 in the directory entry in
that case), and by supporting overwriting such files.

Signed-off-by: Benoît Thébaudeau <benoit@wsystem.com>
fs/fat/fat_write.c

index 2d032ee5ec92774c49f06aa9db3b51c7cca32a83..af828d07bd0a7377b3a783550756ff9242e1a08a 100644 (file)
@@ -710,6 +710,14 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
 
        debug("%llu bytes\n", filesize);
 
+       if (!curclust) {
+               if (filesize) {
+                       debug("error: nonempty clusterless file!\n");
+                       return -1;
+               }
+               return 0;
+       }
+
        actsize = bytesperclust;
        endclust = curclust;
        do {
@@ -765,15 +773,24 @@ getit:
 }
 
 /*
- * Fill dir_entry
+ * Set start cluster in directory entry
  */
-static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
-       const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
+static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
+                               __u32 start_cluster)
 {
        if (mydata->fatsize == 32)
                dentptr->starthi =
                        cpu_to_le16((start_cluster & 0xffff0000) >> 16);
        dentptr->start = cpu_to_le16(start_cluster & 0xffff);
+}
+
+/*
+ * Fill dir_entry
+ */
+static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
+       const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
+{
+       set_start_cluster(mydata, dentptr, start_cluster);
        dentptr->size = cpu_to_le32(size);
 
        dentptr->attr = attr;
@@ -1030,32 +1047,58 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,
                retdent->size = cpu_to_le32(size);
                start_cluster = START(retdent);
 
-               ret = check_overflow(mydata, start_cluster, size);
-               if (ret) {
-                       printf("Error: %llu overflow\n", size);
-                       goto exit;
-               }
+               if (start_cluster) {
+                       if (size) {
+                               ret = check_overflow(mydata, start_cluster,
+                                                       size);
+                               if (ret) {
+                                       printf("Error: %llu overflow\n", size);
+                                       goto exit;
+                               }
+                       }
+
+                       ret = clear_fatent(mydata, start_cluster);
+                       if (ret) {
+                               printf("Error: clearing FAT entries\n");
+                               goto exit;
+                       }
 
-               ret = clear_fatent(mydata, start_cluster);
-               if (ret) {
-                       printf("Error: clearing FAT entries\n");
-                       goto exit;
+                       if (!size)
+                               set_start_cluster(mydata, retdent, 0);
+               } else if (size) {
+                       ret = start_cluster = find_empty_cluster(mydata);
+                       if (ret < 0) {
+                               printf("Error: finding empty cluster\n");
+                               goto exit;
+                       }
+
+                       ret = check_overflow(mydata, start_cluster, size);
+                       if (ret) {
+                               printf("Error: %llu overflow\n", size);
+                               goto exit;
+                       }
+
+                       set_start_cluster(mydata, retdent, start_cluster);
                }
        } else {
                /* Set short name to set alias checksum field in dir_slot */
                set_name(empty_dentptr, filename);
                fill_dir_slot(mydata, &empty_dentptr, filename);
 
-               ret = start_cluster = find_empty_cluster(mydata);
-               if (ret < 0) {
-                       printf("Error: finding empty cluster\n");
-                       goto exit;
-               }
+               if (size) {
+                       ret = start_cluster = find_empty_cluster(mydata);
+                       if (ret < 0) {
+                               printf("Error: finding empty cluster\n");
+                               goto exit;
+                       }
 
-               ret = check_overflow(mydata, start_cluster, size);
-               if (ret) {
-                       printf("Error: %llu overflow\n", size);
-                       goto exit;
+                       ret = check_overflow(mydata, start_cluster, size);
+                       if (ret) {
+                               printf("Error: %llu overflow\n", size);
+                               goto exit;
+                       }
+               } else {
+                       start_cluster = 0;
                }
 
                /* Set attribute as archieve for regular file */