lkml.org 
[lkml]   [1997]   [Aug]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectMsdos name alias patch for 2.1.48
Date
From

The following patch is another attempt to fix name aliases. It is
done against 2.1.48. The name aliasing problem can be shown as
follows:

# mount -t msdos /dev/fd0 /mnt
# echo xyz >/mnt/abc
# cat /mnt/Abc
xyz
# rm /mnt/abc
# cat /mnt/Abc
xyz


The solution that I tried this time involves a scheme similar to the
one outlined by the original xlate_name_char code. However, it is
also combined with a filesystem specific name comparison function. By
default (i.e. non-msdos), the name comparison function is memcmp; and
for msdos it is a new function which formats names using
msdos_format_name before comparing them.

I notices that with the original xlate_name_char code, the presence
of a filesystem specific translation function would have to be checked
for each character of the name. I optimized this by introducing a
function which calculates the hash of the whole name at once. As a
side effect, this also allows for more flexibility.

All calls to msdos_format_name use strings allocated on the stack,
hence no unclean calls to kmalloc are needed. The customized name
comparison function is only called when the hash value of the names to
be compared is equal, and hence it is not on the critical path.

Regards,

Alain

diff -ur 2.1.48/linux/fs/dcache.c linux/fs/dcache.c
--- 2.1.48/linux/fs/dcache.c Tue Aug 5 20:56:09 1997
+++ linux/fs/dcache.c Tue Aug 5 21:01:14 1997
@@ -218,8 +218,19 @@
continue;
if (dentry->d_parent != parent)
continue;
- if (memcmp(dentry->d_name.name, str, len))
- continue;
+ {
+ struct inode *inode;
+ inode = parent->d_inode;
+ if(inode && inode->i_op && inode->i_op->namecmp) {
+ if(inode->i_op->namecmp(inode,
+ dentry->d_name.name,
+ str, len))
+ continue;
+ } else {
+ if (memcmp(dentry->d_name.name, str, len))
+ continue;
+ }
+ }
return dentry;
}
return NULL;
diff -ur 2.1.48/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- 2.1.48/linux/fs/msdos/namei.c Tue Aug 5 20:56:09 1997
+++ linux/fs/msdos/namei.c Tue Aug 5 21:50:54 1997
@@ -201,10 +201,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 +237,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 +257,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;
@@ -583,7 +595,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 +743,57 @@
return error;
}

+static int msdos_calc_hash(struct inode *inode,
+ const char *name, int len,
+ unsigned long *arg_hash)
+{
+ unsigned long hash;
+ char msdos_name[MSDOS_NAME];
+ int error;
+ int i;
+
+#if 0
+ hash = *arg_hash;
+ if( len >= 1 && name[0] == '.' &&
+ (len == 1 || (len == 2 && name[1] == '.'))) {
+ printk("reserved %s\n", name);
+ *arg_hash = 0;
+ return 0;
+ }
+#endif
+
+ error = msdos_format_name(MSDOS_SB(inode->i_sb)->options.name_check,
+ name, len, msdos_name,1,
+ MSDOS_SB(inode->i_sb)->options.dotsOK);
+ if(error)
+ return error;
+
+ hash = init_name_hash();
+ for(i=0; i< MSDOS_NAME; i++)
+ hash = partial_name_hash(msdos_name[i], hash);
+ *arg_hash = hash;
+ return 0;
+}
+
+
+static int msdos_cmp(struct inode * inode, const char *a, const char *b, int n)
+{
+ char a_msdos_name[MSDOS_NAME],b_msdos_name[MSDOS_NAME];
+ int error;
+
+ error = msdos_format_name(MSDOS_SB(inode->i_sb)->options.name_check,
+ a, n, a_msdos_name,1,
+ MSDOS_SB(inode->i_sb)->options.dotsOK);
+ if(error)
+ return error;
+ error = msdos_format_name(MSDOS_SB(inode->i_sb)->options.name_check,
+ a, n, a_msdos_name,1,
+ MSDOS_SB(inode->i_sb)->options.dotsOK);
+ if(error)
+ return error;
+
+ return memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
+}

/* The public inode operations for the msdos fs */
struct inode_operations msdos_dir_inode_operations = {
@@ -750,7 +813,12 @@
NULL, /* writepage */
fat_bmap, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL, /* revalidate */
+ msdos_calc_hash, /* canonize */
+ msdos_cmp /* name compare */
};


diff -ur 2.1.48/linux/fs/namei.c linux/fs/namei.c
--- 2.1.48/linux/fs/namei.c Tue Aug 5 20:56:09 1997
+++ linux/fs/namei.c Tue Aug 5 21:45:25 1997
@@ -352,16 +352,6 @@
}

/*
- * 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.
*
* This is the basic name resolution function, turning a pathname
@@ -411,12 +401,28 @@
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 != '/'));
+ if(base->d_inode && base->d_inode->i_op &&
+ base->d_inode->i_op->namehash) {
+ const char *name_start = name;
+ int error;
+ do {
+ len++; name++;
+ c = *name;
+ } while (c && (c != '/'));
+ error = base->d_inode->i_op->namehash(base->d_inode,
+ name_start, len,
+ &hash);
+ if(error<0) {
+ dentry = ERR_PTR(error);
+ break;
+ }
+ } else {
+ do {
+ len++; name++;
+ hash = partial_name_hash(c, hash);
+ c = *name;
+ } while (c && (c != '/'));
+ }

this.len = len;
this.hash = end_name_hash(hash);
diff -ur 2.1.48/linux/include/linux/fs.h linux/include/linux/fs.h
--- 2.1.48/linux/include/linux/fs.h Tue Aug 5 20:56:10 1997
+++ linux/include/linux/fs.h Tue Aug 5 21:03:01 1997
@@ -564,6 +564,9 @@
int (*updatepage) (struct inode *, struct page *, const char *,
unsigned long, unsigned int, int);
int (*revalidate) (struct inode *);
+ int (*namehash) (struct inode *, const char *name, int len,
+ unsigned long *hash);
+ int (*namecmp) (struct inode *,const char *, const char *, int);
};

struct super_operations {

\
 
 \ /
  Last update: 2005-03-22 13:40    [W:0.093 / U:2.992 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site