Messages in this thread Patch in this message | | | From | alknaff@innet ... | Subject | Msdos patch for aliased names | Date | Mon, 28 Jul 1997 22:51:17 +0200 |
| |
The following patch repairs the problem with aliased names in the Msdos filesystem. I.e. the following bug:
$ echo test >/mnt/xyz $ cat /xyz test $ cat /Xyz test $ rm /xyz $ cat /Xyz test
The last cat /Xyz still finds the file, even though it has been removed.
In order to avoid these problems, the filenames are not transformed into "canonic" filenames, which allow only one representation per valid MSDOS directory entry. Unfortunately, the name_translate_char mechanism was not enough for that, because canonizing an MSDOS filename may change its length (if for instance the basename was longer than 8 characters, but also when using names without extension, which can be represented with or without a trailing dot).
Moreover, the patch cleans up some instances of returning ENOENT instead of transforming the dentry into a negative dentry
It also adds init_private_file which is needed for the binfmt modules (unrelated to msdos)
Regards,
Alain
diff -ur 2.1.47/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c --- 2.1.47/linux/fs/fat/fatfs_syms.c Fri Jul 25 22:45:50 1997 +++ linux/fs/fat/fatfs_syms.c Fri Jul 25 22:45:59 1997 @@ -47,6 +47,7 @@ EXPORT_SYMBOL(fat_uni2code); EXPORT_SYMBOL(fat_unlock_creation); EXPORT_SYMBOL(fat_write_inode); +EXPORT_SYMBOL(fat_delete_inode); int init_fat_fs(void) { diff -ur 2.1.47/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- 2.1.47/linux/fs/msdos/namei.c Fri Jul 25 22:53:11 1997 +++ linux/fs/msdos/namei.c Mon Jul 28 22:38:35 1997 @@ -16,6 +16,8 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/stat.h> +#include <linux/mm.h> +#include <linux/malloc.h> #include <asm/uaccess.h> @@ -201,10 +203,18 @@ PRINTK (("msdos_lookup\n")); - if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,&bh,&de,&ino)) < 0) { + if(!dir) { d_add(dentry, NULL); return 0; } + + if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,&bh,&de,&ino)) < 0) { + if(res == -ENOENT) { + d_add(dentry, NULL); + res = 0; + } + return res; + } PRINTK (("msdos_lookup 4\n")); if (bh) fat_brelse(sb, bh); @@ -229,6 +239,7 @@ iput(inode); if (!(inode = iget(next->i_sb,next->i_ino))) { fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen"); + d_add(dentry, NULL); return -ENOENT; } } @@ -248,6 +259,9 @@ struct msdos_dir_entry *de; int res,ino; + if(!dir) + return -ENOENT; + *result = NULL; if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) { if (res != -ENOENT) return res; @@ -383,7 +397,7 @@ if (!S_ISDIR(inode->i_mode)) goto rmdir_done; res = -EBUSY; if (dir->i_dev != inode->i_dev || dir == inode) - goto rmdir_done; + goto rmdir_done; res = msdos_empty(inode); if (res) goto rmdir_done; @@ -583,7 +597,7 @@ struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode; struct dentry *walk; int new_ino,free_ino,dotdot_ino; - int error,exists,ino; + int error,exists; if (old_dir->i_dev != new_dir->i_dev) return -EINVAL; if (old_ino == new_dir->i_ino) return -EINVAL; @@ -731,6 +745,52 @@ return error; } +static inline char toupper(char c) +{ + return (c >= 'a' && c <= 'z') ? c-32 : c; +} + +#define NAME_ALLOC_LEN(len) ((len+16) & ~15) + +static int msdos_canonize(struct inode *inode, struct qstr *name) +{ + char *target, *newName; + const char *src, *end; + int i; + + src = name->name; + end = name->name + name->len; + + target = newName = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL); + if(!target) + return -ENOSPC; + + /* "hidden" dot */ + if(*src == '.') + *target++ = *src++; + + /* basename */ + for(i=0; i<8; i++) { + if(src == end || !*src || *src == '.') + break; + *target++ = toupper(*src++); + } + /* skip everything until dot */ + while(src != end && *src && *src != '.') + src++; + + *target++='.'; + + /* extension */ + for(i=0; i<3; i++) { + if(src == end || !*src || *src == '.') + break; + *target++ = toupper(*src++); + } + *target = '\0'; + name->name = newName; + return 0; +} /* The public inode operations for the msdos fs */ struct inode_operations msdos_dir_inode_operations = { @@ -750,7 +810,11 @@ NULL, /* writepage */ fat_bmap, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL, /* revalidate */ + msdos_canonize /* canonize */ }; diff -ur 2.1.47/linux/fs/namei.c linux/fs/namei.c --- 2.1.47/linux/fs/namei.c Fri Jul 25 22:51:31 1997 +++ linux/fs/namei.c Mon Jul 28 22:14:29 1997 @@ -308,6 +308,28 @@ return result; } +static char calc_hash(struct dentry *base, struct qstr *this) +{ + int len; + unsigned long hash; + char c; + const char *name; + + name = this->name; + hash = init_name_hash(); + len = 0; + c = *name; + do { + len++; name++; + hash = partial_name_hash(c, hash); + c = *name; + } while (c && (c != '/')); + + this->len = len; + this->hash = end_name_hash(hash); + return c; +} + /* In difference to the former version, lookup() no longer eats the dir. */ static struct dentry * lookup(struct dentry * dir, struct qstr * name) { @@ -324,6 +346,15 @@ if (result) goto done_noerror; + if(dir->d_inode && dir->d_inode->i_op->canonize_name) { + err = dir->d_inode->i_op->canonize_name(dir->d_inode, + name); + result = ERR_PTR(err); + if (err) + goto done_error; + calc_hash(dir, name); + } + result = cached_lookup(dir, name); if (result) goto done_noerror; @@ -360,15 +391,6 @@ return dentry; } -/* - * Allow a filesystem to translate the character set of - * a file name. This allows for filesystems that are not - * case-sensitive, for example. - * - * This is only a dummy define right now, but eventually - * it might become something like "(parent)->d_charmap[c]" - */ -#define name_translate_char(parent, c) (c) /* * Name resolution. @@ -397,6 +419,7 @@ /* At this point we know we have a real path component. */ for(;;) { int len; + const unsigned char *oname; unsigned long hash; struct qstr this; char c, follow; @@ -404,13 +427,12 @@ dentry = ERR_PTR(-ENOENT); if (!base->d_inode) break; - this.name = name; + this.name = oname = name; hash = init_name_hash(); len = 0; c = *name; do { len++; name++; - c = name_translate_char(base, c); hash = partial_name_hash(c, hash); c = *name; } while (c && (c != '/')); @@ -428,6 +450,10 @@ } dentry = lookup(base, &this); + + if(this.name != oname) + kfree(this.name); + if (IS_ERR(dentry)) break; diff -ur 2.1.47/linux/include/linux/fs.h linux/include/linux/fs.h --- 2.1.47/linux/include/linux/fs.h Fri Jul 25 22:52:47 1997 +++ linux/include/linux/fs.h Mon Jul 28 22:14:11 1997 @@ -564,6 +564,7 @@ int (*updatepage) (struct inode *, struct page *, const char *, unsigned long, unsigned int, int); int (*revalidate) (struct inode *); + int (*canonize_name) (struct inode *, struct qstr *); }; struct super_operations { diff -ur 2.1.47/linux/kernel/ksyms.c linux/kernel/ksyms.c --- 2.1.47/linux/kernel/ksyms.c Fri Jul 25 22:48:20 1997 +++ linux/kernel/ksyms.c Fri Jul 25 22:47:43 1997 @@ -241,6 +241,7 @@ EXPORT_SYMBOL(search_binary_handler); EXPORT_SYMBOL(prepare_binprm); EXPORT_SYMBOL(remove_arg_zero); +EXPORT_SYMBOL(init_private_file); /* execution environment registration */ EXPORT_SYMBOL(lookup_exec_domain);
| |