[PATCH] Add d_hash and d_compare operations for case-insensitive names (1 of 1)
[email protected] Mon, 12 Jul 2004 13:39:22 -0500
| Newsgroups | gmane.comp.file-systems.jfs.patches |
|---|---|
| Message-ID | <[email protected]> |
# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/07/12 13:31:38-05:00 [email protected] # JFS: Add d_hash and d_compare operations for case-insensitive names # # JFS supports OS/2-compatibility with case-insensitive file names. # To avoid multiple dentries for these names, jfs needs to provide # the d_hash and d_compare dentry_operations. The operations are # only used when the volume was created in OS/2 or with the -O flag. # diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c --- a/fs/jfs/namei.c 2004-07-12 13:35:34 -05:00 +++ b/fs/jfs/namei.c 2004-07-12 13:35:34 -05:00 @@ -1,5 +1,5 @@ /* - * Copyright (C) International Business Machines Corp., 2000-2003 + * Copyright (C) International Business Machines Corp., 2000-2004 * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -18,6 +18,7 @@ */ #include <linux/fs.h> +#include <linux/ctype.h> #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_inode.h" @@ -43,6 +44,7 @@ */ struct inode_operations jfs_dir_inode_operations; struct file_operations jfs_dir_operations; +struct dentry_operations jfs_ci_dentry_operations; static s64 commitZeroLink(tid_t, struct inode *); @@ -1422,7 +1424,15 @@ return ERR_PTR(-EACCES); } - return d_splice_alias(ip, dentry); + if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2) + dentry->d_op = &jfs_ci_dentry_operations; + + dentry = d_splice_alias(ip, dentry); + + if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) + dentry->d_op = &jfs_ci_dentry_operations; + + return dentry; } struct dentry *jfs_get_parent(struct dentry *dentry) @@ -1475,4 +1485,47 @@ .read = generic_read_dir, .readdir = jfs_readdir, .fsync = jfs_fsync, +}; + +static int jfs_ci_hash(struct dentry *dir, struct qstr *this) +{ + unsigned long hash; + int i; + + hash = init_name_hash(); + for (i=0; i < this->len; i++) + hash = partial_name_hash(tolower(this->name[i]), hash); + this->hash = end_name_hash(hash); + + return 0; +} + +static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b) +{ + int i, result = 1; + + if (a->len != b->len) + goto out; + for (i=0; i < a->len; i++) { + if (tolower(a->name[i]) != tolower(b->name[i])) + goto out; + } + result = 0; + + /* + * We want creates to preserve case. A negative dentry, a, that + * has a different case than b may cause a new entry to be created + * with the wrong case. Since we can't tell if a comes from a negative + * dentry, we blindly replace it with b. This should be harmless if + * a is not a negative dentry. + */ + memcpy((unsigned char *)a->name, b->name, a->len); +out: + return result; +} + +struct dentry_operations jfs_ci_dentry_operations = +{ + .d_hash = jfs_ci_hash, + .d_compare = jfs_ci_compare, }; diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c --- a/fs/jfs/super.c 2004-07-12 13:35:34 -05:00 +++ b/fs/jfs/super.c 2004-07-12 13:35:34 -05:00 @@ -82,6 +82,8 @@ extern struct dentry *jfs_get_parent(struct dentry *dentry); extern int jfs_extendfs(struct super_block *, s64, int); +extern struct dentry_operations jfs_ci_dentry_operations; + #ifdef PROC_FS_JFS /* see jfs_debug.h */ extern void jfs_proc_init(void); extern void jfs_proc_clean(void); @@ -445,6 +447,9 @@ sb->s_root = d_alloc_root(inode); if (!sb->s_root) goto out_no_root; + + if (sbi->mntflag & JFS_OS2) + sb->s_root->d_op = &jfs_ci_dentry_operations; /* logical blocks are represented by 40 bits in pxd_t, etc. */ sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;