Browse Source

Modify LFN direntries when file is renamed or deleted, see
Debian bug #596329.

Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>

Alexander Korolkov 13 years ago
parent
commit
ea41797c7a
4 changed files with 39 additions and 3 deletions
  1. 20 1
      src/check.c
  2. 1 0
      src/dosfsck.h
  3. 15 1
      src/lfn.c
  4. 3 1
      src/lfn.h

+ 20 - 1
src/check.c

@@ -311,12 +311,29 @@ static int bad_name(DOS_FILE *file)
     return 0;
 }
 
+static void lfn_remove(loff_t from, loff_t to)
+{
+    int i;
+    DIR_ENT empty;
+
+    /* New dir entry is zeroed except first byte, which is set to 0xe5.
+     * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading
+     * a directory at the first zero entry...
+     */
+    memset( &empty, 0, sizeof(empty) );
+    empty.name[0] = DELETED_FLAG;
+
+    for( ; from < to; from += sizeof(empty) ) {
+	fs_write( from, sizeof(DIR_ENT), &empty );
+    }
+}
 
 static void drop_file(DOS_FS *fs,DOS_FILE *file)
 {
     unsigned long cluster;
 
     MODIFY(file,name[0],DELETED_FLAG);
+    if (file->lfn) lfn_remove(file->lfn_offset, file->offset);
     for (cluster = FSTART(file,fs); cluster > 0 && cluster <
       fs->clusters+2; cluster = next_cluster(fs,cluster))
 	set_owner(fs,cluster,NULL);
@@ -361,6 +378,7 @@ static void auto_rename(DOS_FILE *file)
 	      name,MSDOS_NAME)) break;
 	if (!walk) {
 	    fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);
+	    if (file->lfn) lfn_fix_checksum(file->lfn_offset, file->offset, file->dir_ent.name);
 	    return;
 	}
 	number++;
@@ -392,6 +410,7 @@ static void rename_file(DOS_FILE *file)
 	    for (walk = name; *walk == ' ' || *walk == '\t'; walk++);
 	    if (file_cvt(walk,file->dir_ent.name)) {
 		fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);
+		if (file->lfn) lfn_fix_checksum(file->lfn_offset, file->offset, file->dir_ent.name);
 		return;
 	    }
 	}
@@ -862,7 +881,7 @@ static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,
 	return;
     }
     new = qalloc(&mem_queue,sizeof(DOS_FILE));
-    new->lfn = lfn_get(&de);
+    new->lfn = lfn_get(&de, &new->lfn_offset);
     new->offset = offset;
     memcpy(&new->dir_ent,&de,sizeof(de));
     new->next = new->first = NULL;

+ 1 - 0
src/dosfsck.h

@@ -155,6 +155,7 @@ typedef struct _dos_file {
     DIR_ENT dir_ent;
     char *lfn;
     loff_t offset;
+    loff_t lfn_offset;
     struct _dos_file *parent; /* parent directory */
     struct _dos_file *next; /* next entry */
     struct _dos_file *first; /* first entry (directory only) */

+ 15 - 1
src/lfn.c

@@ -148,6 +148,18 @@ static void clear_lfn_slots( int start, int end )
     }
 }
 
+void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name)
+{
+    int i;
+    __u8 sum;
+    for (sum = 0, i = 0; i < 11; i++)
+	sum = (((sum&1) << 7) | ((sum&0xfe) >> 1)) + short_name[i];
+
+    for( ; from < to; from += sizeof(LFN_ENT) ) {
+	fs_write( from + offsetof(LFN_ENT,alias_checksum), sizeof(sum), &sum );
+    }
+}
+
 void lfn_reset( void )
 {
     if (lfn_unicode)
@@ -374,12 +386,13 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
 
 /* This function is always called when de->attr != VFAT_LN_ATTR is found, to
  * retrieve the previously constructed LFN. */
-char *lfn_get( DIR_ENT *de )
+char *lfn_get( DIR_ENT *de, loff_t *lfn_offset )
 {
     char *lfn;
     __u8 sum;
     int i;
 
+    *lfn_offset = 0;
     if (de->attr == VFAT_LN_ATTR)
 	die("lfn_get called with LFN directory entry");
 
@@ -467,6 +480,7 @@ char *lfn_get( DIR_ENT *de )
 	}
     }
 
+    *lfn_offset = lfn_offsets[0];
     lfn = cnv_unicode( lfn_unicode, UNTIL_0, 1 );
     lfn_reset();
     return( lfn );

+ 3 - 1
src/lfn.h

@@ -28,9 +28,11 @@ void lfn_reset( void );
 void lfn_add_slot( DIR_ENT *de, loff_t dir_offset );
 /* Process a dir slot that is a VFAT LFN entry. */
 
-char *lfn_get( DIR_ENT *de );
+char *lfn_get( DIR_ENT *de, loff_t *lfn_offset );
 /* Retrieve the long name for the proper dir entry. */
 
 void lfn_check_orphaned(void);
 
+void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name);
+
 #endif