diff options
Diffstat (limited to 'fs/sysv')
-rw-r--r-- | fs/sysv/namei.c | 188 |
1 files changed, 80 insertions, 108 deletions
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index b3586b58f..bb8828efa 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -10,6 +10,11 @@ * sysv/namei.c * Copyright (C) 1993 Bruno Haible */ +/* + 7 Dec 1997 - updated to use dentries by Krzysztof G. Baranowski + <kgb@manjak.knm.org.pl> + */ + #include <linux/sched.h> #include <linux/kernel.h> @@ -100,31 +105,29 @@ static struct buffer_head * sysv_find_entry(struct inode * dir, return NULL; } -int sysv_lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +int sysv_lookup(struct inode * dir, struct dentry * dentry) { int ino; + struct inode * inode = NULL; struct sysv_dir_entry * de; struct buffer_head * bh; - *result = NULL; if (!dir) return -ENOENT; if (!S_ISDIR(dir->i_mode)) { - iput(dir); return -ENOENT; } - if (!(bh = sysv_find_entry(dir,name,len,&de))) { - iput(dir); + if (!(bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de))) { return -ENOENT; } ino = de->inode; brelse(bh); - if (!(*result = iget(dir->i_sb,ino))) { - iput(dir); + inode = iget(dir->i_sb,ino); + + if (!inode) return -EACCES; - } - iput(dir); + d_add(dentry, inode); return 0; } @@ -201,42 +204,37 @@ static int sysv_add_entry(struct inode * dir, return 0; } -int sysv_create(struct inode * dir,const char * name, int len, int mode, - struct inode ** result) +int sysv_create(struct inode * dir, struct dentry * dentry, int mode) { int error; struct inode * inode; struct buffer_head * bh; struct sysv_dir_entry * de; - *result = NULL; if (!dir) return -ENOENT; inode = sysv_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_op = &sysv_file_inode_operations; inode->i_mode = mode; mark_inode_dirty(inode); - error = sysv_add_entry(dir,name,len, &bh ,&de); + error = sysv_add_entry(dir,dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (error) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - iput(dir); return error; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - *result = inode; + d_instantiate(dentry, inode); return 0; } -int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) { int error; struct inode * inode; @@ -245,17 +243,15 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde if (!dir) return -ENOENT; - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir,dentry->d_name.name, + dentry->d_name.len,&de); if (bh) { brelse(bh); - iput(dir); return -EEXIST; } inode = sysv_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_uid = current->fsuid; inode->i_mode = mode; inode->i_op = NULL; @@ -277,53 +273,45 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde if (S_ISBLK(mode) || S_ISCHR(mode)) inode->i_rdev = to_kdev_t(rdev); mark_inode_dirty(inode); - error = sysv_add_entry(dir, name, len, &bh, &de); + error = sysv_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de); if (error) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - iput(dir); return error; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - iput(inode); + d_instantiate(dentry, inode); return 0; } -int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) +int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) { int error; struct inode * inode; struct buffer_head * bh, *dir_block; struct sysv_dir_entry * de; - if (!dir) { - iput(dir); + if (!dir) return -EINVAL; - } - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); return -EEXIST; } if (dir->i_nlink >= dir->i_sb->sv_link_max) { - iput(dir); return -EMLINK; } inode = sysv_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_op = &sysv_dir_inode_operations; inode->i_size = 2 * SYSV_DIRSIZE; dir_block = sysv_file_bread(inode,0,1); if (!dir_block) { - iput(dir); inode->i_nlink--; mark_inode_dirty(inode); iput(inode); @@ -342,9 +330,9 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); - error = sysv_add_entry(dir, name, len, &bh, &de); - if (error) { - iput(dir); + error = sysv_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); + if (error) { inode->i_nlink=0; iput(inode); return error; @@ -353,10 +341,9 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) mark_buffer_dirty(bh, 1); dir->i_nlink++; mark_inode_dirty(dir); - iput(dir); - iput(inode); brelse(bh); - return 0; + d_instantiate(dentry, inode); + return 0; } /* @@ -419,7 +406,7 @@ bad_dir: return 1; } -int sysv_rmdir(struct inode * dir, const char * name, int len) +int sysv_rmdir(struct inode * dir, struct dentry * dentry) { int retval; struct inode * inode; @@ -427,13 +414,14 @@ int sysv_rmdir(struct inode * dir, const char * name, int len) struct sysv_dir_entry * de; inode = NULL; - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); retval = -ENOENT; if (!bh) goto end_rmdir; retval = -EPERM; - if (!(inode = iget(dir->i_sb, de->inode))) - goto end_rmdir; + inode = dentry->d_inode; + if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) @@ -467,15 +455,14 @@ int sysv_rmdir(struct inode * dir, const char * name, int len) dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); + d_delete(dentry); retval = 0; end_rmdir: - iput(dir); - iput(inode); brelse(bh); return retval; } -int sysv_unlink(struct inode * dir, const char * name, int len) +int sysv_unlink(struct inode * dir, struct dentry * dentry) { int retval; struct inode * inode; @@ -485,16 +472,16 @@ int sysv_unlink(struct inode * dir, const char * name, int len) repeat: retval = -ENOENT; inode = NULL; - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (!bh) goto end_unlink; - if (!(inode = iget(dir->i_sb, de->inode))) - goto end_unlink; + inode = dentry->d_inode; + retval = -EPERM; if (S_ISDIR(inode->i_mode)) goto end_unlink; if (de->inode != inode->i_ino) { - iput(inode); brelse(bh); current->counter = 0; schedule(); @@ -510,7 +497,7 @@ repeat: } if (!inode->i_nlink) { printk("Deleting nonexistent file (%s:%lu), %d\n", - kdevname(inode->i_dev), + kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); inode->i_nlink=1; } @@ -521,15 +508,15 @@ repeat: inode->i_nlink--; inode->i_ctime = dir->i_ctime; mark_inode_dirty(inode); + d_delete(dentry); retval = 0; end_unlink: brelse(bh); - iput(inode); - iput(dir); return retval; } -int sysv_symlink(struct inode * dir, const char * name, int len, const char * symname) +int sysv_symlink(struct inode * dir, struct dentry * dentry, + const char * symname) { struct sysv_dir_entry * de; struct inode * inode; @@ -540,15 +527,13 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy char c; struct buffer_head * bh; - if (!(inode = sysv_new_inode(dir))) { - iput(dir); + if (!(inode = sysv_new_inode(dir))) return -ENOSPC; - } + inode->i_mode = S_IFLNK | 0777; inode->i_op = &sysv_symlink_inode_operations; name_block = sysv_file_bread(inode,0,1); if (!name_block) { - iput(dir); inode->i_nlink--; mark_inode_dirty(inode); iput(inode); @@ -564,94 +549,81 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy brelse(name_block); inode->i_size = i; mark_inode_dirty(inode); - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); brelse(bh); - iput(dir); return -EEXIST; } - i = sysv_add_entry(dir, name, len, &bh, &de); + i = sysv_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (i) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - iput(dir); return i; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - iput(inode); + d_instantiate(dentry, inode); return 0; } -int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +int sysv_link(struct inode * oldinode, struct inode * dir, + struct dentry * dentry) { int error; struct sysv_dir_entry * de; struct buffer_head * bh; if (S_ISDIR(oldinode->i_mode)) { - iput(oldinode); - iput(dir); return -EPERM; } if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) { - iput(oldinode); - iput(dir); return -EMLINK; } - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); - iput(oldinode); return -EEXIST; } - error = sysv_add_entry(dir, name, len, &bh, &de); + error = sysv_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (error) { - iput(dir); - iput(oldinode); return error; } de->inode = oldinode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); oldinode->i_nlink++; oldinode->i_ctime = CURRENT_TIME; mark_inode_dirty(oldinode); - iput(oldinode); + d_instantiate(dentry, oldinode); return 0; } /* return 1 if `new' is a subdir of `old' on the same device */ -static int subdir(struct inode * new_inode, struct inode * old_inode) +static int subdir(struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; - int result; - - new_inode->i_count++; - result = 0; - for (;;) { - if (new_inode == old_inode) { - result = 1; - break; - } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (sysv_lookup(new_inode,"..",2,&new_inode)) - break; - if (new_inode->i_ino == ino) /* root dir reached ? */ - break; - } - iput(new_inode); - return result; + int result = 0; + + for (;;) { + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; + } + result = 1; + break; + } + return result; } #define PARENT_INO(buffer) \ @@ -716,7 +688,7 @@ start_up: if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) @@ -735,7 +707,7 @@ start_up: if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -EIO; dir_bh = sysv_file_bread(old_inode,0,0); |