[CIFS] Finish up of case-insensitive dentry handling for cifs. This
authorSteve French <sfrench@us.ibm.com>
Tue, 23 Aug 2005 03:09:43 +0000 (20:09 -0700)
committerSteve French <sfrench@us.ibm.com>
Tue, 23 Aug 2005 03:09:43 +0000 (20:09 -0700)
will eventually (or should eventually) be common code for jfs, smbfs,
etc. but in the meantime is small enough and necessary when mounting
case insensitive to Windows (nocase).

Signed-off-by: Shaggy (shaggy@austin.ibm.com)
Signed-off-by: Steve French (sfrench@us.ibm.com)
fs/cifs/cifsfs.h
fs/cifs/dir.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/readdir.c

index d5fb344..bb3404a 100644 (file)
@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg);
 
 /* Functions related to dir entries */
 extern struct dentry_operations cifs_dentry_ops;
+extern struct dentry_operations cifs_ci_dentry_ops;
 
 /* Functions related to symlinks */
 extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
index c619d45..5311c50 100644 (file)
@@ -230,7 +230,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                             ("Create worked but get_inode_info failed rc = %d",
                              rc));
                } else {
-                       direntry->d_op = &cifs_dentry_ops;
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
                        d_instantiate(direntry, newinode);
                }
                if((nd->flags & LOOKUP_OPEN) == FALSE) {
@@ -322,7 +325,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
                if(!rc) {
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
                                                inode->i_sb,xid);
-                       direntry->d_op = &cifs_dentry_ops;
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
                        if(rc == 0)
                                d_instantiate(direntry, newinode);
                }
@@ -418,7 +424,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
                                         parent_dir_inode->i_sb,xid);
 
        if ((rc == 0) && (newInode != NULL)) {
-               direntry->d_op = &cifs_dentry_ops;
+               if (pTcon->nocase)
+                       direntry->d_op = &cifs_ci_dentry_ops;
+               else
+                       direntry->d_op = &cifs_dentry_ops;
                d_add(direntry, newInode);
 
                /* since paths are not looked up by component - the parent directories are presumed to be good here */
@@ -477,3 +486,42 @@ struct dentry_operations cifs_dentry_ops = {
 /* d_delete:       cifs_d_delete,       *//* not needed except for debugging */
        /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
 };
+
+static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
+{
+       struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+       unsigned long hash;
+       int i;
+
+       hash = init_name_hash();
+       for (i = 0; i < q->len; i++)
+               hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
+                                        hash);
+       q->hash = end_name_hash(hash);
+
+       return 0;
+}
+
+static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
+                          struct qstr *b)
+{
+       struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+
+       if ((a->len == b->len) &&
+           (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
+               /*
+                * To preserve case, don't let an existing negative dentry's
+                * case take precedence.  If a is not a negative dentry, this
+                * should have no side effects
+                */
+               memcpy((unsigned char *)a->name, b->name, a->len);
+               return 0;
+       }
+       return 1;
+}
+
+struct dentry_operations cifs_ci_dentry_ops = {
+       .d_revalidate = cifs_d_revalidate,
+       .d_hash = cifs_ci_hash,
+       .d_compare = cifs_ci_compare,
+};
index ed3e920..2d50b35 100644 (file)
@@ -591,7 +591,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
                                                 inode->i_sb,xid);
 
-               direntry->d_op = &cifs_dentry_ops;
+               if (pTcon->nocase)
+                       direntry->d_op = &cifs_ci_dentry_ops;
+               else
+                       direntry->d_op = &cifs_dentry_ops;
                d_instantiate(direntry, newinode);
                if (direntry->d_inode)
                        direntry->d_inode->i_nlink = 2;
index da420e8..b8ec664 100644 (file)
@@ -199,7 +199,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                             ("Create symlink worked but get_inode_info failed with rc = %d ",
                              rc));
                } else {
-                       direntry->d_op = &cifs_dentry_ops;
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
                        d_instantiate(direntry, newinode);
                }
        }
index ef5eb80..f769292 100644 (file)
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
                }
 
                *ptmp_inode = new_inode(file->f_dentry->d_sb);
-               tmp_dentry->d_op = &cifs_dentry_ops;
+               if (pTcon->nocase)
+                       tmp_dentry->d_op = &cifs_ci_dentry_ops;
+               else
+                       tmp_dentry->d_op = &cifs_dentry_ops;
                if(*ptmp_inode == NULL)
                        return rc;
                rc = 1;