Пример #1
0
int
affs_rename(struct inode *old_dir, struct dentry *old_dentry,
	    struct inode *new_dir, struct dentry *new_dentry)
{
	struct super_block *sb = old_dir->i_sb;
	struct buffer_head *bh = NULL;
	int retval;

	pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
		 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);

	retval = affs_check_name(new_dentry->d_name.name,
				 new_dentry->d_name.len,
				 affs_nofilenametruncate(old_dentry));

	if (retval)
		return retval;

	/* Unlink destination if it already exists */
	if (new_dentry->d_inode) {
		retval = affs_remove_header(new_dentry);
		if (retval)
			return retval;
	}

	bh = affs_bread(sb, old_dentry->d_inode->i_ino);
	if (!bh)
		return -EIO;

	/* Remove header from its parent directory. */
	affs_lock_dir(old_dir);
	retval = affs_remove_hash(old_dir, bh);
	affs_unlock_dir(old_dir);
	if (retval)
		goto done;

	/* And insert it into the new directory with the new name. */
	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
	affs_fix_checksum(sb, bh);
	affs_lock_dir(new_dir);
	retval = affs_insert_hash(new_dir, bh);
	affs_unlock_dir(new_dir);
	/* TODO: move it back to old_dir, if error? */

done:
	mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
	affs_brelse(bh);
	return retval;
}
Пример #2
0
int
affs_remove_header(struct dentry *dentry)
{
    struct super_block *sb;
    struct inode *inode, *dir;
    struct buffer_head *bh = NULL;
    int retval;

    dir = dentry->d_parent->d_inode;
    sb = dir->i_sb;

    retval = -ENOENT;
    inode = dentry->d_inode;
    if (!inode)
        goto done;

    pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino);
    retval = -EIO;
    bh = affs_bread(sb, (u32)(long)dentry->d_fsdata);
    if (!bh)
        goto done;

    affs_lock_link(inode);
    affs_lock_dir(dir);
    switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
    case ST_USERDIR:
        /* if we ever want to support links to dirs
         * i_hash_lock of the inode must only be
         * taken after some checks
         */
        affs_lock_dir(inode);
        retval = affs_empty_dir(inode);
        affs_unlock_dir(inode);
        if (retval)
            goto done_unlock;
        break;
    default:
        break;
    }

    retval = affs_remove_hash(dir, bh);
    if (retval)
        goto done_unlock;
    mark_buffer_dirty_inode(bh, inode);

    affs_unlock_dir(dir);

    if (inode->i_nlink > 1)
        retval = affs_remove_link(dentry);
    else
        inode->i_nlink = 0;
    affs_unlock_link(inode);
    inode->i_ctime = CURRENT_TIME_SEC;
    mark_inode_dirty(inode);

done:
    affs_brelse(bh);
    return retval;

done_unlock:
    affs_unlock_dir(dir);
    affs_unlock_link(inode);
    goto done;
}
Пример #3
0
int
affs_rename(struct inode *old_dir, struct dentry *old_dentry,
	    struct inode *new_dir, struct dentry *new_dentry)
{
	struct inode		*old_inode = old_dentry->d_inode;
	struct inode		*new_inode = new_dentry->d_inode;
	struct buffer_head	*old_bh;
	struct buffer_head	*new_bh;
	unsigned long		 old_ino;
	unsigned long		 new_ino;
	int			 retval;

	pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n",
		 old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode,
		 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)))
		goto out;

	new_bh = NULL;
	retval = -ENOENT;
	old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
	if (!old_bh)
		goto end_rename;

	new_bh = affs_find_entry(new_dir,new_dentry,&new_ino);
	if (new_bh && !new_inode) {
		affs_error(old_inode->i_sb,"affs_rename",
			   "No inode for entry found (key=%lu)\n",new_ino);
		goto end_rename;
	}
	if (S_ISDIR(old_inode->i_mode)) {
		if (new_inode) {
			retval = -ENOTEMPTY;
			if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
				goto end_rename;
		}

		retval = -ENOENT;
		if (affs_parent_ino(old_inode) != old_dir->i_ino)
			goto end_rename;
	}
	/* Unlink destination if it already exists */
	if (new_inode) {
		if ((retval = affs_remove_header(new_bh,new_dir)) < 0)
			goto end_rename;
		new_inode->i_nlink = retval;
		mark_inode_dirty(new_inode);
		if (new_inode->i_ino == new_ino)
			new_inode->i_nlink = 0;
	}
	/* Remove header from its parent directory. */
	if ((retval = affs_remove_hash(old_bh,old_dir)))
		goto end_rename;
	/* And insert it into the new directory with the new name. */
	affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
	if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
		goto end_rename;
	affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);

	new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
			   = old_dir->i_mtime = CURRENT_TIME;
	new_dir->i_version = ++event;
	old_dir->i_version = ++event;
	retval             = 0;
	mark_inode_dirty(new_dir);
	mark_inode_dirty(old_dir);
	mark_buffer_dirty(old_bh,1);
	
end_rename:
	affs_brelse(old_bh);
	affs_brelse(new_bh);
out:
	return retval;
}
Пример #4
0
static int
affs_remove_link(struct dentry *dentry)
{
    struct inode *dir, *inode = dentry->d_inode;
    struct super_block *sb = inode->i_sb;
    struct buffer_head *bh = NULL, *link_bh = NULL;
    u32 link_ino, ino;
    int retval;

    pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
    retval = -EIO;
    bh = affs_bread(sb, inode->i_ino);
    if (!bh)
        goto done;

    link_ino = (u32)(long)dentry->d_fsdata;
    if (inode->i_ino == link_ino) {
        /* we can't remove the head of the link, as its blocknr is still used as ino,
         * so we remove the block of the first link instead.
         */
        link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
        link_bh = affs_bread(sb, link_ino);
        if (!link_bh)
            goto done;

        dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
        if (IS_ERR(dir)) {
            retval = PTR_ERR(dir);
            goto done;
        }

        affs_lock_dir(dir);
        affs_fix_dcache(dentry, link_ino);
        retval = affs_remove_hash(dir, link_bh);
        if (retval) {
            affs_unlock_dir(dir);
            goto done;
        }
        mark_buffer_dirty_inode(link_bh, inode);

        memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
        retval = affs_insert_hash(dir, bh);
        if (retval) {
            affs_unlock_dir(dir);
            goto done;
        }
        mark_buffer_dirty_inode(bh, inode);

        affs_unlock_dir(dir);
        iput(dir);
    } else {
        link_bh = affs_bread(sb, link_ino);
        if (!link_bh)
            goto done;
    }

    while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
        if (ino == link_ino) {
            __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
            AFFS_TAIL(sb, bh)->link_chain = ino2;
            affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
            mark_buffer_dirty_inode(bh, inode);
            retval = 0;
            /* Fix the link count, if bh is a normal header block without links */
            switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
            case ST_LINKDIR:
            case ST_LINKFILE:
                break;
            default:
                if (!AFFS_TAIL(sb, bh)->link_chain)
                    inode->i_nlink = 1;
            }
            affs_free_block(sb, link_ino);
            goto done;
        }
        affs_brelse(bh);
        bh = affs_bread(sb, ino);
        if (!bh)
            goto done;
    }
    retval = -ENOENT;
done:
    affs_brelse(link_bh);
    affs_brelse(bh);
    return retval;
}