diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-03 01:22:27 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-03 01:22:27 +0000 |
commit | f9bbe9da79dbc8557c74efeb158b431cd67ace52 (patch) | |
tree | 3220d014a35f9d88a48668a1468524e988daebff /fs/smbfs/dir.c | |
parent | 3d697109c1ff85ef563aec3d5e113ef225ed2792 (diff) |
Upgrade to 2.1.73.
Diffstat (limited to 'fs/smbfs/dir.c')
-rw-r--r-- | fs/smbfs/dir.c | 174 |
1 files changed, 108 insertions, 66 deletions
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 921aa86e1..5af80e91b 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -85,7 +85,18 @@ find_inode_number(struct dentry *dir, struct qstr *name) struct dentry * dentry; ino_t ino = 0; + /* + * Check for a fs-specific hash function. Note that we must + * calculate the standard hash first, as the d_op->d_hash() + * routine may choose to leave the hash value unchanged. + */ name->hash = full_name_hash(name->name, name->len); + if (dir->d_op && dir->d_op->d_hash) + { + if (dir->d_op->d_hash(dir, name) != 0) + goto out; + } + dentry = d_lookup(dir, name); if (dentry) { @@ -93,6 +104,7 @@ find_inode_number(struct dentry *dir, struct qstr *name) ino = dentry->d_inode->i_ino; dput(dentry); } +out: return ino; } @@ -179,27 +191,51 @@ out: return result; } +/* + * Note: in order to allow the smbclient process to open the + * mount point, we don't revalidate for the connection pid. + */ static int smb_dir_open(struct inode *dir, struct file *file) { + struct dentry *dentry = file->f_dentry; + struct smb_sb_info *server = server_from_dentry(dentry); + int error = 0; #ifdef SMBFS_DEBUG_VERBOSE -printk("smb_dir_open: (%s/%s)\n", file->f_dentry->d_parent->d_name.name, +printk("smb_dir_open: (%s/%s)\n", dentry->d_parent->d_name.name, file->f_dentry->d_name.name); #endif - return smb_revalidate_inode(dir); + /* + * Directory timestamps in the core protocol aren't updated + * when a file is added, so we give them a very short TTL. + */ + if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) + { + unsigned long age = jiffies - dir->u.smbfs_i.oldmtime; + if (age > 2*HZ) + smb_invalid_dir_cache(dir); + } + + if (server->conn_pid) + error = smb_revalidate_inode(dir); + else + printk("smb_dir_open: smbclient process\n"); + return error; } /* * Dentry operations routines */ static int smb_lookup_validate(struct dentry *); +static int smb_hash_dentry(struct dentry *, struct qstr *); +static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *); static void smb_delete_dentry(struct dentry *); static struct dentry_operations smbfs_dentry_operations = { smb_lookup_validate, /* d_validate(struct dentry *) */ - NULL, /* d_hash */ - NULL, /* d_compare */ + smb_hash_dentry, /* d_hash */ + smb_compare_dentry, /* d_compare */ smb_delete_dentry /* d_delete(struct dentry *) */ }; @@ -218,7 +254,7 @@ smb_lookup_validate(struct dentry * dentry) * we believe in dentries for 5 seconds. (But each * successful server lookup renews the timestamp.) */ - valid = (age <= SMBFS_MAX_AGE) || IS_ROOT(dentry); + valid = (age <= SMBFS_MAX_AGE); #ifdef SMBFS_DEBUG_VERBOSE if (!valid) printk("smb_lookup_validate: %s/%s not valid, age=%lu\n", @@ -234,7 +270,8 @@ printk("smb_lookup_validate: %s/%s has dud inode\n", dentry->d_parent->d_name.name, dentry->d_name.name); #endif valid = 0; - } + } else if (!valid) + valid = (smb_revalidate_inode(inode) == 0); } else { /* @@ -245,21 +282,49 @@ dentry->d_parent->d_name.name, dentry->d_name.name); } /* + * XXX: It would be better to use the tolower from linux/ctype.h, + * but _ctype is needed and it is not exported. + */ +#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c)) + +static int +smb_hash_dentry(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 +smb_compare_dentry(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; +out: + return result; +} + +/* * This is the callback from dput() when d_count is going to 0. * We use this to unhash dentries with bad inodes and close files. */ static void smb_delete_dentry(struct dentry * dentry) { - if ((jiffies - dentry->d_time) > SMBFS_MAX_AGE) - { -#ifdef SMBFS_DEBUG_VERBOSE -printk("smb_delete_dentry: %s/%s expired, d_time=%lu, now=%lu\n", -dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_time, jiffies); -#endif - d_drop(dentry); - } - if (dentry->d_inode) { if (is_bad_inode(dentry->d_inode)) @@ -305,7 +370,7 @@ smb_lookup(struct inode *dir, struct dentry *dentry) if (dentry->d_name.len > SMB_MAXNAMELEN) goto out; - error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &finfo); + error = smb_proc_getattr(dentry, &finfo); #ifdef SMBFS_PARANOIA if (error && error != -ENOENT) printk("smb_lookup: find %s/%s failed, error=%d\n", @@ -350,7 +415,7 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id) printk("smb_instantiate: file %s/%s, fileid=%u\n", dentry->d_parent->d_name.name, dentry->d_name.name, fileid); #endif - error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr); + error = smb_proc_getattr(dentry, &fattr); if (error) goto out_close; @@ -402,9 +467,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, mode); goto out; smb_invalid_dir_cache(dir); - error = smb_proc_create(dentry->d_parent, &(dentry->d_name), - 0, CURRENT_TIME, &fileid); - if (!error) { + error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid); + if (!error) + { error = smb_instantiate(dentry, fileid, 1); } else { @@ -428,7 +493,7 @@ smb_mkdir(struct inode *dir, struct dentry *dentry, int mode) goto out; smb_invalid_dir_cache(dir); - error = smb_proc_mkdir(dentry->d_parent, &(dentry->d_name)); + error = smb_proc_mkdir(dentry); if (!error) { error = smb_instantiate(dentry, 0, 0); @@ -440,17 +505,17 @@ out: static int smb_rmdir(struct inode *dir, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; int error; - error = -ENAMETOOLONG; - if (dentry->d_name.len > SMB_MAXNAMELEN) + error = -ENOTDIR; + if (!S_ISDIR(inode->i_mode)) goto out; /* - * Since the dentry is holding an inode, the file - * is in use, so we have to close it first. + * Close the directory if it's open. */ - smb_close(dentry->d_inode); + smb_close(inode); /* * Prune any child dentries so this dentry can become negative. @@ -463,7 +528,7 @@ smb_rmdir(struct inode *dir, struct dentry *dentry) } smb_invalid_dir_cache(dir); - error = smb_proc_rmdir(dentry->d_parent, &(dentry->d_name)); + error = smb_proc_rmdir(dentry); if (!error) { smb_renew_times(dentry); @@ -478,24 +543,18 @@ smb_unlink(struct inode *dir, struct dentry *dentry) { int error; - error = -ENAMETOOLONG; - if (dentry->d_name.len > SMB_MAXNAMELEN) - goto out; - /* - * Since the dentry is holding an inode, the file - * is in use, so we have to close it first. + * Close the file if it's open. */ smb_close(dentry->d_inode); smb_invalid_dir_cache(dir); - error = smb_proc_unlink(dentry->d_parent, &(dentry->d_name)); + error = smb_proc_unlink(dentry); if (!error) { smb_renew_times(dentry); d_delete(dentry); } -out: return error; } @@ -511,50 +570,33 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; /* - * Since the old and new dentries are holding the files open, - * we have to close the files first. + * Close any open files, and check whether to delete the + * target before attempting the rename. */ if (old_dentry->d_inode) smb_close(old_dentry->d_inode); if (new_dentry->d_inode) - smb_close(new_dentry->d_inode); - - smb_invalid_dir_cache(old_dir); - smb_invalid_dir_cache(new_dir); - error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name), - new_dentry->d_parent, &(new_dentry->d_name)); - /* - * If the new file exists, attempt to delete it. - */ - if (error == -EEXIST) { + smb_close(new_dentry->d_inode); + error = smb_proc_unlink(new_dentry); + if (error) + { #ifdef SMBFS_DEBUG_VERBOSE -printk("smb_rename: existing file %s/%s, d_count=%d\n", -new_dentry->d_parent->d_name.name, new_dentry->d_name.name, -new_dentry->d_count); -#endif - error = smb_proc_unlink(new_dentry->d_parent, - &(new_dentry->d_name)); -#ifdef SMBFS_DEBUG_VERBOSE -printk("smb_rename: after unlink error=%d\n", error); +printk("smb_rename: unlink %s/%s, error=%d\n", +new_dentry->d_parent->d_name.name, new_dentry->d_name.name, error); #endif - if (!error) - { - d_delete(new_dentry); - error = smb_proc_mv(old_dentry->d_parent, - &(old_dentry->d_name), - new_dentry->d_parent, - &(new_dentry->d_name)); + goto out; } + d_delete(new_dentry); } - /* - * Update the dcache - */ + smb_invalid_dir_cache(old_dir); + smb_invalid_dir_cache(new_dir); + error = smb_proc_mv(old_dentry, new_dentry); if (!error) { smb_renew_times(old_dentry); - smb_renew_times(new_dentry->d_parent); + smb_renew_times(new_dentry); d_move(old_dentry, new_dentry); } out: |