[CIFS] Finish up of case-insensitive dentry handling for cifs. This
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)
This commit is contained in:
parent
a5a2b489ba
commit
b92327fe6b
5 changed files with 64 additions and 6 deletions
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue