/*
 * simple tests for rename.
 * following the checks in vfs, plus the parent-child relationship.
 */
static int au_may_ren(struct au_ren_args *a)
{
	int err, isdir;
	struct inode *h_inode;

	if (a->src_bstart == a->btgt) {
		err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent,
				 au_ftest_ren(a->flags, ISDIR));
		if (unlikely(err))
			goto out;
		err = -EINVAL;
		if (unlikely(a->src_h_dentry == a->h_trap))
			goto out;
	}

	err = 0;
	if (a->dst_bstart != a->btgt)
		goto out;

	err = -ENOTEMPTY;
	if (unlikely(a->dst_h_dentry == a->h_trap))
		goto out;

	err = -EIO;
	h_inode = a->dst_h_dentry->d_inode;
	isdir = !!au_ftest_ren(a->flags, ISDIR);
	if (!a->dst_dentry->d_inode) {
		if (unlikely(h_inode))
			goto out;
		err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent,
				 isdir);
	} else {
		if (unlikely(!h_inode || !h_inode->i_nlink))
			goto out;
		err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent,
				 isdir);
		if (unlikely(err))
			goto out;
	}

out:
	if (unlikely(err == -ENOENT || err == -EEXIST))
		err = -EIO;
	AuTraceErr(err);
	return err;
}
Ejemplo n.º 2
0
/*
 * decide the branch where we operate for @dentry. the branch index will be set
 * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent
 * dir for reverting.
 * when a new whiteout is necessary, create it.
 */
static struct dentry*
lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup,
		    struct au_dtime *dt, struct au_pin *pin)
{
	struct dentry *wh_dentry;
	struct super_block *sb;
	struct path h_path;
	int err, need_wh;
	unsigned int udba;
	aufs_bindex_t bcpup;

	need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup);
	wh_dentry = ERR_PTR(need_wh);
	if (unlikely(need_wh < 0))
		goto out;

	sb = dentry->d_sb;
	udba = au_opt_udba(sb);
	bcpup = *rbcpup;
	err = au_pin(pin, dentry, bcpup, udba,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	wh_dentry = ERR_PTR(err);
	if (unlikely(err))
		goto out;

	h_path.dentry = au_pinned_h_parent(pin);
	if (udba != AuOpt_UDBA_NONE
	    && au_dbstart(dentry) == bcpup) {
		err = au_may_del(dentry, bcpup, h_path.dentry, isdir);
		wh_dentry = ERR_PTR(err);
		if (unlikely(err))
			goto out_unpin;
	}

	h_path.mnt = au_sbr_mnt(sb, bcpup);
	au_dtime_store(dt, au_pinned_parent(pin), &h_path);
	wh_dentry = NULL;
	if (!need_wh)
		goto out; /* success, no need to create whiteout */

	wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry);
	if (IS_ERR(wh_dentry))
		goto out_unpin;

	/* returns with the parent is locked and wh_dentry is dget-ed */
	goto out; /* success */

out_unpin:
	au_unpin(pin);
out:
	return wh_dentry;
}