fs: fat: deletion of long file names
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Thu, 19 Nov 2020 06:31:18 +0000 (07:31 +0100)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Thu, 10 Dec 2020 08:15:00 +0000 (09:15 +0100)
Long file names are stored in multiple directory entries. When deleting a
file we must delete all of them.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
fs/fat/fat_write.c

index c403d7d..20a54a2 100644 (file)
@@ -1445,27 +1445,91 @@ exit:
        return count;
 }
 
-static int delete_dentry(fat_itr *itr)
+/**
+ * delete_single_dentry() - delete a single directory entry
+ *
+ * @itr:       directory iterator
+ * Return:     0 for success
+ */
+static int delete_single_dentry(fat_itr *itr)
+{
+       struct dir_entry *dent = itr->dent;
+
+       memset(dent, 0, sizeof(*dent));
+       dent->name[0] = DELETED_FLAG;
+
+       if (!itr->remaining) {
+               if (flush_dir(itr)) {
+                       printf("error: writing directory entry\n");
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+/**
+ * delete_long_name() - delete long name directory entries
+ *
+ * @itr:       directory iterator
+ * Return:     0 for success
+ */
+static int delete_long_name(fat_itr *itr)
+{
+       struct dir_entry *dent = itr->dent;
+       int seqn = itr->dent->name[0] & ~LAST_LONG_ENTRY_MASK;
+
+       while (seqn--) {
+               int ret;
+
+               ret = delete_single_dentry(itr);
+               if (ret)
+                       return ret;
+               dent = next_dent(itr);
+               if (!dent)
+                       return -EIO;
+       }
+       return 0;
+}
+
+/**
+ * delete_dentry_long() - remove directory entry
+ *
+ * @itr:       directory iterator
+ * Return:     0 for success
+ */
+static int delete_dentry_long(fat_itr *itr)
 {
        fsdata *mydata = itr->fsdata;
-       dir_entry *dentptr = itr->dent;
+       dir_entry *dent = itr->dent;
 
        /* free cluster blocks */
-       clear_fatent(mydata, START(dentptr));
+       clear_fatent(mydata, START(dent));
        if (flush_dirty_fat_buffer(mydata) < 0) {
                printf("Error: flush fat buffer\n");
                return -EIO;
        }
+       /* Position to first directory entry for long name */
+       if (itr->clust != itr->dent_clust) {
+               int ret;
 
-       /*
-        * update a directory entry
-        * TODO:
-        *  - long file name support
-        *  - find and mark the "new" first invalid entry as name[0]=0x00
-        */
-       memset(dentptr, 0, sizeof(*dentptr));
-       dentptr->name[0] = DELETED_FLAG;
+               ret = fat_move_to_cluster(itr, itr->dent_clust);
+               if (ret)
+                       return ret;
+       }
+       itr->dent = itr->dent_start;
+       itr->remaining = itr->dent_rem;
+       dent = itr->dent_start;
+       /* Delete long name */
+       if ((dent->attr & ATTR_VFAT) == ATTR_VFAT &&
+           (dent->name[0] & LAST_LONG_ENTRY_MASK)) {
+               int ret;
 
+               ret = delete_long_name(itr);
+               if (ret)
+                       return ret;
+       }
+       /* Delete short name */
+       delete_single_dentry(itr);
        if (flush_dir(itr)) {
                printf("error: writing directory entry\n");
                return -EIO;
@@ -1535,7 +1599,7 @@ int fat_unlink(const char *filename)
                }
        }
 
-       ret = delete_dentry(itr);
+       ret = delete_dentry_long(itr);
 
 exit:
        free(fsdata.fatbuf);