Esempio n. 1
0
int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		   struct inode *new_dir, struct dentry *new_dentry)
{
	int err = 0;
	struct dentry *wh_dentry;

	double_lock_dentry(old_dentry, new_dentry);

	if (!S_ISDIR(old_dentry->d_inode->i_mode))
		err = unionfs_partial_lookup(old_dentry);
	else
		err = may_rename_dir(old_dentry);

	if (err)
		goto out;

	err = unionfs_partial_lookup(new_dentry);
	if (err)
		goto out;

	/*
	 * if new_dentry is already hidden because of whiteout,
	 * simply override it even if the whiteouted dir is not empty.
	 */
	wh_dentry = lookup_whiteout(new_dentry);
	if (!IS_ERR(wh_dentry))
		dput(wh_dentry);
	else if (new_dentry->d_inode) {
		if (S_ISDIR(old_dentry->d_inode->i_mode) !=
		    S_ISDIR(new_dentry->d_inode->i_mode)) {
			err = S_ISDIR(old_dentry->d_inode->i_mode) ?
					-ENOTDIR : -EISDIR;
			goto out;
		}

		if (S_ISDIR(new_dentry->d_inode->i_mode)) {
			struct unionfs_dir_state *namelist;
			/* check if this unionfs directory is empty or not */
			err = check_empty(new_dentry, &namelist);
			if (err)
				goto out;

			if (!is_robranch(new_dentry))
				err = delete_whiteouts(new_dentry,
						       dbstart(new_dentry),
						       namelist);

			free_rdstate(namelist);

			if (err)
				goto out;
		}
	}
	err = do_unionfs_rename(old_dir, old_dentry, new_dir, new_dentry);

out:
	if (err)
		/* clear the new_dentry stuff created */
		d_drop(new_dentry);
	else
		/* force re-lookup since the dir on ro branch is not renamed,
		   and hidden dentries still indicate the un-renamed ones. */
		if (S_ISDIR(old_dentry->d_inode->i_mode))
			atomic_dec(&UNIONFS_D(old_dentry)->generation);

	unionfs_unlock_dentry(new_dentry);
	unionfs_unlock_dentry(old_dentry);
	return err;
}
Esempio n. 2
0
int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		   struct inode *new_dir, struct dentry *new_dentry)
{
	int err = 0;
	struct dentry *wh_dentry;

	print_entry_location();

	double_lock_dentry(old_dentry, new_dentry);

	fist_checkinode(old_dir, "unionfs_rename-old_dir");
	fist_checkinode(new_dir, "unionfs_rename-new_dir");
	fist_print_dentry("IN: unionfs_rename, old_dentry", old_dentry);
	fist_print_dentry("IN: unionfs_rename, new_dentry", new_dentry);

	if (!S_ISDIR(old_dentry->d_inode->i_mode))
	err = unionfs_partial_lookup(old_dentry);
	else
		err = may_rename_dir(old_dentry);
	if (err)
		goto out;
	err = unionfs_partial_lookup(new_dentry);
	if (err)
		goto out;

	/*
	 * if new_dentry is already hidden because of whiteout,
	 * simply override it even if the whiteouted dir is not empty.
	 */
	wh_dentry = lookup_whiteout(new_dentry);
	if (!IS_ERR(wh_dentry))
		DPUT(wh_dentry);
	else if (new_dentry->d_inode) {
		if (S_ISDIR(old_dentry->d_inode->i_mode) !=
		    S_ISDIR(new_dentry->d_inode->i_mode)) {
			err =
			    S_ISDIR(old_dentry->d_inode->
				    i_mode) ? -ENOTDIR : -EISDIR;
			goto out;
		}

		if (S_ISDIR(old_dentry->d_inode->i_mode)) {
			/* check if this unionfs directory is empty or not */
			err = check_empty(new_dentry, NULL);
			if (err)
				goto out;
			/* Handle the case where we are overwriting directories
			 * that are not really empty because of whiteout or
			 * non-whiteout entries.
			 */
		}
	}
#ifdef UNIONFS_DELETE_ALL
	if (IS_SET(old_dir->i_sb, DELETE_ALL))
		err = unionfs_rename_all(old_dir, old_dentry, new_dir,
					 new_dentry);
	else
#endif
		err = unionfs_rename_whiteout(old_dir, old_dentry, new_dir,
					      new_dentry);

      out:
	fist_checkinode(new_dir, "post unionfs_rename-new_dir");
	fist_print_dentry("OUT: unionfs_rename, old_dentry", old_dentry);

	if (err) {
		/* clear the new_dentry stuff created */
		d_drop(new_dentry);
	} else {
		/* force re-lookup since the dir on ro branch is not renamed,
		   and hidden dentries still indicate the un-renamed ones. */
		if (S_ISDIR(old_dentry->d_inode->i_mode))
			atomic_dec(&dtopd(old_dentry)->udi_generation);
		fist_print_dentry("OUT: unionfs_rename, new_dentry",
				  new_dentry);
	}

	unlock_dentry(new_dentry);
	unlock_dentry(old_dentry);
	print_exit_status(err);
	return err;
}
Esempio n. 3
0
static int unionfs_link(struct dentry *old_dentry, struct inode *dir,
			struct dentry *new_dentry)
{
	int err = 0;
	struct dentry *hidden_old_dentry = NULL;
	struct dentry *hidden_new_dentry = NULL;
	struct dentry *hidden_dir_dentry = NULL;
	struct dentry *whiteout_dentry;
	char *name = NULL;

	print_entry_location();
	double_lock_dentry(new_dentry, old_dentry);

	hidden_new_dentry = dtohd(new_dentry);

	/* check if whiteout exists in the branch of new dentry, i.e. lookup
	 * .wh.foo first. If present, delete it */
	name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len);
	if (IS_ERR(name)) {
		err = PTR_ERR(name);
		goto out;
	}

	whiteout_dentry =
	    LOOKUP_ONE_LEN(name, hidden_new_dentry->d_parent,
			   new_dentry->d_name.len + WHLEN);
	if (IS_ERR(whiteout_dentry)) {
		err = PTR_ERR(whiteout_dentry);
		goto out;
	}

	if (!whiteout_dentry->d_inode) {
		DPUT(whiteout_dentry);
		whiteout_dentry = NULL;
	} else {
		/* found a .wh.foo entry, unlink it and then call vfs_link() */
		hidden_dir_dentry = lock_parent(whiteout_dentry);
		if (!
		    (err =
		     is_robranch_super(new_dentry->d_sb,
				       dbstart(new_dentry)))) {
			err =
			    vfs_unlink(hidden_dir_dentry->d_inode,
				       whiteout_dentry);
		}
		fist_copy_attr_times(dir, hidden_dir_dentry->d_inode);
		dir->i_nlink = get_nlinks(dir);
		unlock_dir(hidden_dir_dentry);
		hidden_dir_dentry = NULL;
		DPUT(whiteout_dentry);
		if (err)
			goto out;
	}

	if (dbstart(old_dentry) != dbstart(new_dentry)) {
		hidden_new_dentry =
		    create_parents(dir, new_dentry, dbstart(old_dentry));
		err = PTR_ERR(hidden_new_dentry);
		if (IS_COPYUP_ERR(err))
			goto docopyup;
		if (!hidden_new_dentry || IS_ERR(hidden_new_dentry))
			goto out;
	}
	hidden_new_dentry = dtohd(new_dentry);
	hidden_old_dentry = dtohd(old_dentry);

	BUG_ON(dbstart(old_dentry) != dbstart(new_dentry));
	hidden_dir_dentry = lock_parent(hidden_new_dentry);
	if (!(err = is_robranch(old_dentry)))
		err =
		    vfs_link(hidden_old_dentry, hidden_dir_dentry->d_inode,
			     hidden_new_dentry);
	unlock_dir(hidden_dir_dentry);

      docopyup:
	if (IS_COPYUP_ERR(err)) {
		int old_bstart = dbstart(old_dentry);
		int bindex;

		for (bindex = old_bstart - 1; bindex >= 0; bindex--) {
			err =
			    copyup_dentry(old_dentry->d_parent->
					  d_inode, old_dentry,
					  old_bstart, bindex, NULL,
					  old_dentry->d_inode->i_size);
			if (!err) {
				hidden_new_dentry =
				    create_parents(dir, new_dentry, bindex);
				hidden_old_dentry = dtohd(old_dentry);
				hidden_dir_dentry =
				    lock_parent(hidden_new_dentry);
				/* do vfs_link */
				err =
				    vfs_link(hidden_old_dentry,
					     hidden_dir_dentry->d_inode,
					     hidden_new_dentry);
				unlock_dir(hidden_dir_dentry);
				goto check_link;
			}
		}
		goto out;
	}
      check_link:
	if (err || !hidden_new_dentry->d_inode)
		goto out;

	/* Its a hard link, so use the same inode */
	new_dentry->d_inode = IGRAB(old_dentry->d_inode);
	d_instantiate(new_dentry, new_dentry->d_inode);
	fist_copy_attr_all(dir, hidden_new_dentry->d_parent->d_inode);
	/* propagate number of hard-links */
	old_dentry->d_inode->i_nlink = get_nlinks(old_dentry->d_inode);

      out:
	if (!new_dentry->d_inode)
		d_drop(new_dentry);

	KFREE(name);

	unlock_dentry(new_dentry);
	unlock_dentry(old_dentry);

	print_exit_status(err);
	return err;
}