Package: dosfstools Version: 3.0.6-1 Severity: important Tags: patch When dosfsck renames a file (automatically or manually), it doesn't update checksums of corresponding LFN entries.
When dosfsck deletes a file, it leaves corresponding LFN entries not deleted. After these actions filesystem still contains errors, so user has to run dosfsck second time to fix them. Patch is attached. -- System Information: Debian Release: squeeze/sid APT prefers testing APT policy: (990, 'testing'), (500, 'stable') Architecture: i386 (i686) Kernel: Linux 2.6.33.2 (SMP w/2 CPU cores) Locale: LANG=ru_RU.UTF-8, LC_CTYPE=ru_RU.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages dosfstools depends on: ii libc6 2.10.1-5 GNU C Library: Shared libraries dosfstools recommends no packages. dosfstools suggests no packages. -- debconf-show failed
commit 3bad011e4c9329befd834218be946240e39b714a Author: Alexander Korolkov <al-...@inbox.ru> Date: Fri Sep 10 14:37:12 2010 +0400 Modify LFN direntries when file is renamed or deleted diff --git a/src/check.c b/src/check.c index b16e794..d6c54c1 100644 --- a/src/check.c +++ b/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; diff --git a/src/dosfsck.h b/src/dosfsck.h index 126056d..25a15ed 100644 --- a/src/dosfsck.h +++ b/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) */ diff --git a/src/lfn.c b/src/lfn.c index 97e91dd..dc17f20 100644 --- a/src/lfn.c +++ b/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 ); diff --git a/src/lfn.h b/src/lfn.h index 8e8f5a1..2da426d 100644 --- a/src/lfn.h +++ b/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