patch-2.1.89 linux/fs/affs/namei.c
Next file: linux/fs/affs/super.c
Previous file: linux/fs/affs/inode.c
Back to the patch index
Back to the overall index
- Lines: 571
- Date:
Mon Feb 23 22:01:26 1998
- Orig file:
v2.1.88/linux/fs/affs/namei.c
- Orig date:
Thu Feb 12 20:56:10 1998
diff -u --recursive --new-file v2.1.88/linux/fs/affs/namei.c linux/fs/affs/namei.c
@@ -21,23 +21,17 @@
#include <linux/errno.h>
-/* Simple toupper()/tolower() for DOS\1 */
+/* Simple toupper() for DOS\1 */
-static inline unsigned int
+static unsigned int
affs_toupper(unsigned int ch)
{
return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
}
-static inline unsigned int
-affs_tolower(unsigned int ch)
-{
- return ch >= 'A' && ch <= 'Z' ? ch + ('a' - 'A') : ch;
-}
+/* International toupper() for DOS\3 ("international") */
-/* International toupper()/tolower() for DOS\3 ("international") */
-
-static inline unsigned int
+static unsigned int
affs_intl_toupper(unsigned int ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
@@ -45,23 +39,8 @@
ch - ('a' - 'A') : ch;
}
-static inline unsigned int
-affs_intl_tolower(unsigned int ch)
-{
- return (ch >= 'A' && ch <= 'Z') || (ch >= 0xC0
- && ch <= 0xDE && ch != 0xD7) ?
- ch + ('a' - 'A') : ch;
-}
-
-/* We need 2 sets of dentry operations, since we cannot
- * determine the fs flavour in the callback routines.
- */
-
static int affs_hash_dentry(struct dentry *, struct qstr *);
static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-static int affs_hash_dentry_intl(struct dentry *, struct qstr *);
-static int affs_compare_dentry_intl(struct dentry *, struct qstr *, struct qstr *);
-
struct dentry_operations affs_dentry_operations = {
NULL, /* d_validate */
affs_hash_dentry, /* d_hash */
@@ -69,24 +48,25 @@
NULL /* d_delete */
};
-struct dentry_operations affs_dentry_operations_intl = {
- NULL, /* d_validate */
- affs_hash_dentry_intl, /* d_hash */
- affs_compare_dentry_intl, /* d_compare */
- NULL /* d_delete */
-};
-
+/*
+ * Note: the dentry argument is the parent dentry.
+ */
static int
affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
{
+ unsigned int (*toupper)(unsigned int) = affs_toupper;
unsigned long hash;
int i;
if ((i = affs_check_name(qstr->name,qstr->len)))
return i;
+
+ /* Check whether to use the international 'toupper' routine */
+ if (AFFS_I2FSTYPE(dentry->d_inode))
+ toupper = affs_intl_toupper;
hash = init_name_hash();
for (i = 0; i < qstr->len && i < 30; i++)
- hash = partial_name_hash(affs_tolower(qstr->name[i]),hash);
+ hash = partial_name_hash(toupper(qstr->name[i]), hash);
qstr->hash = end_name_hash(hash);
return 0;
@@ -95,6 +75,9 @@
static int
affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
+ unsigned int (*toupper)(unsigned int) = affs_toupper;
+ int alen = a->len;
+ int blen = b->len;
int i;
/* 'a' is the qstr of an already existing dentry, so the name
@@ -107,45 +90,19 @@
/* If the names are longer than the allowed 30 chars,
* the excess is ignored, so their length may differ.
*/
-
- if ((a->len < 30 || b->len < 30) && a->len != b->len)
+ if (alen > 30)
+ alen = 30;
+ if (blen > 30)
+ blen = 30;
+ if (alen != blen)
return 1;
- for (i = 0; i < a->len && i < 30; i++)
- if (affs_tolower(a->name[i]) != affs_tolower(b->name[i]))
- return 1;
-
- return 0;
-}
-
-static int
-affs_hash_dentry_intl(struct dentry *dentry, struct qstr *qstr)
-{
- unsigned long hash;
- int i;
+ /* Check whether to use the international 'toupper' routine */
+ if (AFFS_I2FSTYPE(dentry->d_inode))
+ toupper = affs_intl_toupper;
- if ((i = affs_check_name(qstr->name,qstr->len)))
- return i;
- hash = init_name_hash();
- for (i = 0; i < qstr->len && i < 30; i++)
- hash = partial_name_hash(affs_intl_tolower(qstr->name[i]),hash);
- qstr->hash = end_name_hash(hash);
-
- return 0;
-}
-
-static int
-affs_compare_dentry_intl(struct dentry *dentry, struct qstr *a, struct qstr *b)
-{
- int i;
-
- if (affs_check_name(b->name,b->len))
- return 1;
- if ((a->len < 30 || b->len < 30) && a->len != b->len)
- return 1;
-
- for (i = 0; i < a->len && i < 30; i++)
- if (affs_intl_tolower(a->name[i]) != affs_intl_tolower(b->name[i]))
+ for (i = 0; i < alen; i++)
+ if (toupper(a->name[i]) != toupper(b->name[i]))
return 1;
return 0;
@@ -158,6 +115,9 @@
static int
affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
{
+ unsigned int (*toupper)(unsigned int) = intl ? affs_intl_toupper : affs_toupper;
+ int i;
+
if (!compare)
return 0;
@@ -171,21 +131,9 @@
return 1;
if (dlen != len)
return 0;
- if (intl) {
- while (dlen--) {
- if (affs_intl_toupper(*name) != affs_intl_toupper(*compare))
- return 0;
- name++;
- compare++;
- }
- } else {
- while (dlen--) {
- if (affs_toupper(*name) != affs_toupper(*compare))
- return 0;
- name++;
- compare++;
- }
- }
+ for (i = 0; i < len; i++)
+ if (toupper(name[i]) != toupper(compare[i]))
+ return 0;
return 1;
}
@@ -211,23 +159,22 @@
affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
{
struct buffer_head *bh;
- int intl;
+ int intl = AFFS_I2FSTYPE(dir);
s32 key;
const char *name = dentry->d_name.name;
int namelen = dentry->d_name.len;
pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
- intl = AFFS_I2FSTYPE(dir);
- bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+ bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
if (!bh)
return NULL;
- if (affs_match(name,namelen,".",1,intl)) {
+ if (namelen == 1 && name[0] == '.') {
*ino = dir->i_ino;
return bh;
}
- if (affs_match(name,namelen,"..",2,intl)) {
+ if (namelen == 2 && name[0] == '.' && name[1] == '.') {
*ino = affs_parent_ino(dir);
return bh;
}
@@ -239,10 +186,9 @@
int cnamelen;
affs_brelse(bh);
- if (key == 0) {
- bh = NULL;
+ bh = NULL;
+ if (key == 0)
break;
- }
bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
if (!bh)
break;
@@ -274,8 +220,7 @@
if (!inode)
return -EACCES;
}
- dentry->d_op = AFFS_I2FSTYPE(dir) ? &affs_dentry_operations_intl
- : &affs_dentry_operations;
+ dentry->d_op = &affs_dentry_operations;
d_add(dentry,inode);
return 0;
}
@@ -291,10 +236,7 @@
pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name);
- bh = NULL;
retval = -ENOENT;
- if (!dir)
- goto unlink_done;
if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto unlink_done;
@@ -312,8 +254,10 @@
inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
- retval = 0;
d_delete(dentry);
+ mark_inode_dirty(dir);
+ retval = 0;
+
unlink_done:
affs_brelse(bh);
return retval;
@@ -328,11 +272,10 @@
pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
dentry->d_name.name,mode);
- if (!dir)
- return -ENOENT;
+ error = -ENOSPC;
inode = affs_new_inode(dir);
if (!inode)
- return -ENOSPC;
+ goto out;
pr_debug(" -- ino=%lu\n",inode->i_ino);
if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
@@ -341,19 +284,22 @@
inode->i_op = &affs_file_inode_operations;
error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
- if (error) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- return error;
- }
+ if (error)
+ goto out_iput;
inode->i_mode = mode;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ d_instantiate(dentry,inode);
+ mark_inode_dirty(inode);
dir->i_version = ++event;
mark_inode_dirty(dir);
- d_instantiate(dentry,inode);
+out:
+ return error;
- return 0;
+out_iput:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
int
@@ -365,25 +311,29 @@
pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name,mode);
+ error = -ENOSPC;
inode = affs_new_inode(dir);
if (!inode)
- return -ENOSPC;
+ goto out;
inode->i_op = &affs_dir_inode_operations;
error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
- if (error) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- return error;
- }
+ if (error)
+ goto out_iput;
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ d_instantiate(dentry,inode);
+ mark_inode_dirty(inode);
dir->i_version = ++event;
mark_inode_dirty(dir);
- d_instantiate(dentry,inode);
+out:
+ return error;
- return 0;
+out_iput:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
static int
@@ -399,24 +349,18 @@
int
affs_rmdir(struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode = dentry->d_inode;
int retval;
unsigned long ino;
- struct inode *inode;
struct buffer_head *bh;
pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name);
- inode = NULL;
- bh = NULL;
retval = -ENOENT;
- if (!dir)
- goto rmdir_done;
if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto rmdir_done;
- inode = dentry->d_inode;
-
retval = -EPERM;
if (current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid && !fsuser())
@@ -425,31 +369,31 @@
goto rmdir_done;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto rmdir_done;
- if (!S_ISDIR(inode->i_mode)) {
- retval = -ENOTDIR;
+ retval = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
goto rmdir_done;
- }
- down(&inode->i_sem);
- if (dentry->d_count > 1) {
+ /*
+ * Make sure the directory is empty and the dentry isn't busy.
+ */
+ if (dentry->d_count > 1)
shrink_dcache_parent(dentry);
- }
- up(&inode->i_sem);
- if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
- retval = -ENOTEMPTY;
+ retval = -ENOTEMPTY;
+ if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
goto rmdir_done;
- }
- if (inode->i_count > 1) {
- retval = -EBUSY;
+ retval = -EBUSY;
+ if (dentry->d_count > 1)
goto rmdir_done;
- }
+
if ((retval = affs_remove_header(bh,inode)) < 0)
goto rmdir_done;
inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
retval = 0;
+ mark_inode_dirty(dir);
mark_inode_dirty(inode);
d_delete(dentry);
+
rmdir_done:
affs_brelse(bh);
return retval;
@@ -462,27 +406,25 @@
struct inode *inode;
char *p;
unsigned long tmp;
- int i, maxlen;
+ int i, maxlen, error;
char c, lc;
pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name,symname);
maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
+ error = -ENOSPC;
inode = affs_new_inode(dir);
if (!inode)
- return -ENOSPC;
+ goto out;
inode->i_op = &affs_symlink_inode_operations;
inode->i_mode = S_IFLNK | 0777;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ error = -EIO;
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- if (!bh) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- return -EIO;
- }
+ if (!bh)
+ goto out_iput;
i = 0;
p = ((struct slink_front *)bh->b_data)->symname;
lc = '/';
@@ -514,25 +456,30 @@
mark_buffer_dirty(bh,1);
affs_brelse(bh);
mark_inode_dirty(inode);
+
+ /* N.B. This test shouldn't be necessary ... dentry must be negative */
+ error = -EEXIST;
bh = affs_find_entry(dir,dentry,&tmp);
- if (bh) {
- inode->i_nlink = 0;
- iput(inode);
- affs_brelse(bh);
- return -EEXIST;
- }
- i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
- if (i) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- affs_brelse(bh);
- return i;
- }
- dir->i_version = ++event;
+ if (bh)
+ goto out_release;
+ /* N.B. Shouldn't we add the entry before dirtying the buffer? */
+ error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
+ if (error)
+ goto out_release;
d_instantiate(dentry,inode);
-
- return 0;
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+
+out:
+ return error;
+
+out_release:
+ affs_brelse(bh);
+out_iput:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
int
@@ -547,6 +494,7 @@
pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name);
+ /* N.B. Do we need this test? The dentry must be negative ... */
bh = affs_find_entry(dir,dentry,&i);
if (bh) {
affs_brelse(bh);
@@ -556,8 +504,9 @@
affs_warning(dir->i_sb,"link","Impossible link to link");
return -EINVAL;
}
+ error = -ENOSPC;
if (!(inode = affs_new_inode(dir)))
- return -ENOSPC;
+ goto out;
inode->i_op = oldinode->i_op;
inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode);
@@ -573,6 +522,7 @@
inode->i_nlink = 0;
else {
dir->i_version = ++event;
+ mark_inode_dirty(dir);
mark_inode_dirty(oldinode);
oldinode->i_count++;
d_instantiate(dentry,oldinode);
@@ -580,6 +530,7 @@
mark_inode_dirty(inode);
iput(inode);
+out:
return error;
}
@@ -600,7 +551,7 @@
new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
- return retval;
+ goto out;
new_bh = NULL;
retval = -ENOENT;
@@ -630,8 +581,10 @@
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (is_subdir(new_dentry,old_dentry))
+ if (is_subdir(new_dentry, old_dentry))
goto end_rename;
+ if (new_dentry->d_count > 1)
+ shrink_dcache_parent(new_dentry);
retval = -ENOTEMPTY;
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
@@ -644,7 +597,7 @@
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (is_subdir(new_dentry,old_dentry))
+ if (is_subdir(new_dentry, old_dentry))
goto end_rename;
if (affs_parent_ino(old_inode) != old_dir->i_ino)
goto end_rename;
@@ -681,6 +634,6 @@
end_rename:
affs_brelse(old_bh);
affs_brelse(new_bh);
-
+out:
return retval;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov