Beispiel #1
0
/*
 * Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
		  struct inode * new_dir, struct dentry * new_dentry)
{
	struct inode * old_inode, * new_inode;
	struct buffer_head * old_bh, * new_bh, * dir_bh;
	struct sysv_dir_entry * old_de, * new_de;
	int retval;

	old_inode = old_dentry->d_inode;
	new_inode = new_dentry->d_inode;
	new_bh = dir_bh = NULL;
	old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name,
				old_dentry->d_name.len, &old_de);
	retval = -ENOENT;
	if (!old_bh || old_de->inode != old_inode->i_ino)
		goto end_rename;
	retval = -EPERM;
	new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
				new_dentry->d_name.len, &new_de);
	if (new_bh) {
		if (!new_inode) {
			brelse(new_bh);
			new_bh = NULL;
		}
	}
	if (S_ISDIR(old_inode->i_mode)) {
		if (new_inode) {
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
				goto end_rename;
		}
		retval = -EIO;
		dir_bh = sysv_file_bread(old_inode, 0, 0);
		if (!dir_bh)
			goto end_rename;
		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
			goto end_rename;
		retval = -EMLINK;
		if (!new_inode && new_dir != old_dir &&
				new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
			goto end_rename;
	}
	if (!new_bh) {
		retval = sysv_add_entry(new_dir, new_dentry->d_name.name,
					new_dentry->d_name.len, &new_bh, &new_de);
		if (retval)
			goto end_rename;
	}
	new_de->inode = old_inode->i_ino;
	old_de->inode = 0;
	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(old_dir);
	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(new_dir);
	if (new_inode) {
		new_inode->i_nlink--;
		new_inode->i_ctime = CURRENT_TIME;
		mark_inode_dirty(new_inode);
	}
	mark_buffer_dirty(old_bh);
	mark_buffer_dirty(new_bh);
	if (dir_bh) {
		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
		mark_buffer_dirty(dir_bh);
		old_dir->i_nlink--;
		mark_inode_dirty(old_dir);
		if (new_inode) {
			new_inode->i_nlink--;
			mark_inode_dirty(new_inode);
		} else {
			new_dir->i_nlink++;
			mark_inode_dirty(new_dir);
		}
	}
	retval = 0;
end_rename:
	brelse(dir_bh);
	brelse(old_bh);
	brelse(new_bh);
	return retval;
}
Beispiel #2
0
/*
 * rename uses retry to avoid race-conditions: at least they should be minimal.
 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 * checks fail, it tries to restart itself again. Very practical - no changes
 * are done until we know everything works ok.. and then all the changes can be
 * done in one fell swoop when we have claimed all the buffers needed.
 *
 * Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int do_xiafs_rename(struct inode * old_dir, const char * old_name, 
			 int old_len, struct inode * new_dir, 
			 const char * new_name, int new_len,
			 int must_be_dir)
{
    struct inode * old_inode, * new_inode;
    struct buffer_head * old_bh, * new_bh, * dir_bh;
    struct xiafs_direct * old_de, * old_de_pre, * new_de, * new_de_pre;
    int retval;

try_again:
    old_inode = new_inode = NULL;
    old_bh = new_bh = dir_bh = NULL;
    old_bh = xiafs_find_entry(old_dir, old_name, old_len, &old_de, &old_de_pre);
    retval = -ENOENT;
    if (!old_bh)
        goto end_rename;
    old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
    if (!old_inode)
        goto end_rename;
    if (must_be_dir && !S_ISDIR(old_inode->i_mode))
	goto end_rename;
    retval = -EPERM;
    if ((old_dir->i_mode & S_ISVTX) && 
	    current->fsuid != old_inode->i_uid &&
	    current->fsuid != old_dir->i_uid && !fsuser())
        goto end_rename;
    new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL);
    if (new_bh) {
        new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0);
	if (!new_inode) {
	    brelse(new_bh);
	    new_bh = NULL;
	}
    }
    if (new_inode == old_inode) {
        retval = 0;
	goto end_rename;
    }
    if (new_inode && S_ISDIR(new_inode->i_mode)) {
        retval = -EEXIST;
	goto end_rename;
    }
    retval = -EPERM;
    if (new_inode && (new_dir->i_mode & S_ISVTX) && 
	    current->fsuid != new_inode->i_uid &&
 	    current->fsuid != new_dir->i_uid && !fsuser())
        goto end_rename;
    if (S_ISDIR(old_inode->i_mode)) {
        retval = -EEXIST;
	if (new_bh)
	    goto end_rename;
	if ((retval = permission(old_inode, MAY_WRITE)) != 0)
	    goto end_rename;
	retval = -EINVAL;
	if (subdir(new_dir, old_inode))
	    goto end_rename;
	retval = -EIO;
	dir_bh = xiafs_bread(old_inode,0,0);
	if (!dir_bh)
	    goto end_rename;
	if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
	    goto end_rename;
	retval = -EMLINK;
	if (new_dir->i_nlink > 64000)
	    goto end_rename;
    }
    if (!new_bh)
        new_bh = xiafs_add_entry(new_dir, new_name, new_len, &new_de, &new_de_pre);
    retval = -ENOSPC;
    if (!new_bh) 
        goto end_rename;
    /* sanity checking */
    if ( (new_inode && (new_de->d_ino != new_inode->i_ino))
	    || (new_de->d_ino && !new_inode)
	    || (old_de->d_ino != old_inode->i_ino)) {
        xiafs_rm_entry(new_de, new_de_pre);
        brelse(old_bh);
	brelse(new_bh);
	brelse(dir_bh);
	iput(old_inode);
	iput(new_inode);
	current->counter=0;
	schedule();
	goto try_again;
    }
    xiafs_rm_entry(old_de, old_de_pre);
    new_de->d_ino = old_inode->i_ino;
    if (new_inode) {
        new_inode->i_nlink--;
	new_inode->i_dirt = 1;
    }
    mark_buffer_dirty(old_bh, 1);
    mark_buffer_dirty(new_bh, 1);
    if (dir_bh) {
        PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
	mark_buffer_dirty(dir_bh, 1);
	old_dir->i_nlink--;
	new_dir->i_nlink++;
	old_dir->i_dirt = 1;
	new_dir->i_dirt = 1;
    }
    retval = 0;
end_rename:
    brelse(dir_bh);
    brelse(old_bh);
    brelse(new_bh);
    iput(old_inode);
    iput(new_inode);
    iput(old_dir);
    iput(new_dir);
    return retval;
}
Beispiel #3
0
/*
 * rename uses retrying to avoid race-conditions: at least they should be minimal.
 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 * checks fail, it tries to restart itself again. Very practical - no changes
 * are done until we know everything works ok.. and then all the changes can be
 * done in one fell swoop when we have claimed all the buffers needed.
 *
 * Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
			   struct inode * new_dir, struct dentry *new_dentry)
{
	struct inode * old_inode, * new_inode;
	struct buffer_head * old_bh, * new_bh, * dir_bh;
	struct minix_dir_entry * old_de, * new_de;
	struct minix_sb_info * info;
	int retval;

	info = &old_dir->i_sb->u.minix_sb;
	goto start_up;
try_again:
	brelse(old_bh);
	brelse(new_bh);
	brelse(dir_bh);
	current->counter = 0;
	schedule();
start_up:
	old_inode = new_inode = NULL;
	old_bh = new_bh = dir_bh = NULL;
	old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
				  old_dentry->d_name.len, &old_de);
	retval = -ENOENT;
	if (!old_bh)
		goto end_rename;
	old_inode = old_dentry->d_inode;
	retval = -EPERM;
	new_inode = new_dentry->d_inode;
	new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
				  new_dentry->d_name.len, &new_de);
	if (new_bh) {
		if (!new_inode) {
			brelse(new_bh);
			new_bh = NULL;
		}
	}
	if (new_inode == old_inode) {
		retval = 0;
		goto end_rename;
	}
	if (S_ISDIR(old_inode->i_mode)) {
		retval = -EINVAL;
		if (is_subdir(new_dentry, old_dentry))
			goto end_rename;
		if (new_inode) {
			/* Prune any children before testing for busy */
			if (new_dentry->d_count > 1)
				shrink_dcache_parent(new_dentry);
			retval = -EBUSY;
			if (new_dentry->d_count > 1)
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
				goto end_rename;
			retval = -EBUSY;
		}
		retval = -EIO;
		dir_bh = minix_bread(old_inode,0,0);
		if (!dir_bh)
			goto end_rename;
		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
			goto end_rename;
		retval = -EMLINK;
		if (!new_inode && new_dir->i_nlink >= info->s_link_max)
			goto end_rename;
	}
	if (!new_bh) {
		retval = minix_add_entry(new_dir,
					 new_dentry->d_name.name,
					 new_dentry->d_name.len,
					 &new_bh, &new_de);
		if (retval)
			goto end_rename;
	}
/* sanity checking before doing the rename - avoid races */
	if (new_inode && (new_de->inode != new_inode->i_ino))
		goto try_again;
	if (new_de->inode && !new_inode)
		goto try_again;
	if (old_de->inode != old_inode->i_ino)
		goto try_again;
/* ok, that's it */
	old_de->inode = 0;
	new_de->inode = old_inode->i_ino;
	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(old_dir);
	old_dir->i_version = ++event;
	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(new_dir);
	new_dir->i_version = ++event;
	if (new_inode) {
		new_inode->i_nlink--;
		new_inode->i_ctime = CURRENT_TIME;
		mark_inode_dirty(new_inode);
	}
	mark_buffer_dirty(old_bh, 1);
	mark_buffer_dirty(new_bh, 1);
	if (dir_bh) {
		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
		mark_buffer_dirty(dir_bh, 1);
		old_dir->i_nlink--;
		mark_inode_dirty(old_dir);
		if (new_inode) {
			new_inode->i_nlink--;
			mark_inode_dirty(new_inode);
		} else {
			new_dir->i_nlink++;
			mark_inode_dirty(new_dir);
		}
	}
	/* Update the dcache */
	d_move(old_dentry, new_dentry);
	retval = 0;
end_rename:
	brelse(dir_bh);
	brelse(old_bh);
	brelse(new_bh);
	return retval;
}
Beispiel #4
0
/*
 * rename uses retrying to avoid race-conditions: at least they should be minimal.
 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 * checks fail, it tries to restart itself again. Very practical - no changes
 * are done until we know everything works ok.. and then all the changes can be
 * done in one fell swoop when we have claimed all the buffers needed.
 *
 * Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int do_sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
			  struct inode * new_dir, struct dentry * new_dentry)
{
	struct inode * old_inode, * new_inode;
	struct buffer_head * old_bh, * new_bh, * dir_bh;
	struct sysv_dir_entry * old_de, * new_de;
	int retval;

	goto start_up;
try_again:
	brelse(old_bh);
	brelse(new_bh);
	brelse(dir_bh);
	current->counter = 0;
	schedule();
start_up:
	old_inode = new_inode = NULL;
	old_bh = new_bh = dir_bh = NULL;
	old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name,
				old_dentry->d_name.len, &old_de);
	retval = -ENOENT;
	if (!old_bh)
		goto end_rename;
	old_inode = old_dentry->d_inode;	/* don't cross mnt-points */
	retval = -EPERM;
	new_inode = new_dentry->d_inode;
	new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
				new_dentry->d_name.len, &new_de);
	if (new_bh) {
		if (!new_inode) {
			brelse(new_bh);
			new_bh = NULL;
		}
	}
	if (new_inode == old_inode) {
		retval = 0;
		goto end_rename;
	}
	if (S_ISDIR(old_inode->i_mode)) {
		retval = -EINVAL;
		if (is_subdir(new_dentry, old_dentry))
			goto end_rename;
		if (new_inode) {
			if (new_dentry->d_count > 1)
				shrink_dcache_parent(new_dentry);
			retval = -EBUSY;
			if (new_dentry->d_count > 1)
				goto end_rename;
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
				goto end_rename;
		}
		retval = -EIO;
		dir_bh = sysv_file_bread(old_inode, 0, 0);
		if (!dir_bh)
			goto end_rename;
		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
			goto end_rename;
		retval = -EMLINK;
		if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
			goto end_rename;
	}
	if (!new_bh) {
		retval = sysv_add_entry(new_dir, new_dentry->d_name.name,
					new_dentry->d_name.len, &new_bh, &new_de);
		if (retval)
			goto end_rename;
	}
/* sanity checking before doing the rename - avoid races */
	if (new_inode && (new_de->inode != new_inode->i_ino))
		goto try_again;
	if (new_de->inode && !new_inode)
		goto try_again;
	if (old_de->inode != old_inode->i_ino)
		goto try_again;
/* ok, that's it */
	old_de->inode = 0;
	new_de->inode = old_inode->i_ino;
	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(old_dir);
	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
	mark_inode_dirty(new_dir);
	if (new_inode) {
		new_inode->i_nlink--;
		new_inode->i_ctime = CURRENT_TIME;
		mark_inode_dirty(new_inode);
	}
	mark_buffer_dirty(old_bh, 1);
	mark_buffer_dirty(new_bh, 1);
	if (dir_bh) {
		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
		mark_buffer_dirty(dir_bh, 1);
		old_dir->i_nlink--;
		mark_inode_dirty(old_dir);
		if (new_inode) {
			new_inode->i_nlink--;
			mark_inode_dirty(new_inode);
		} else {
			new_dir->i_nlink++;
			mark_inode_dirty(new_dir);
		}
	}
	d_move(old_dentry, new_dentry);
	retval = 0;
end_rename:
	brelse(dir_bh);
	brelse(old_bh);
	brelse(new_bh);
	return retval;
}