Exemplo n.º 1
0
//int vfs_symlink(char *oldpath, char *newpath);
uint32_t sys_symlink(uint32_t param[4], uint32_t param_size[4])
{
	char *oldpath;
	char *newpath;
	int status;
	if ((param_size[0] > CONFIG_FILE_MAX_NAME_LENGTH) || (param_size[1] > CONFIG_FILE_MAX_NAME_LENGTH)) {
		syscall_errno = EFAULT;
		return (uint32_t) -1;
	}
	oldpath = heapmm_alloc(param_size[0]);
	if (!copy_user_to_kern((void *)param[0], oldpath, param_size[0])) {
		syscall_errno = EFAULT;
		heapmm_free(oldpath, param_size[0]);
		return (uint32_t) -1;
	}
	newpath = heapmm_alloc(param_size[1]);
	if (!copy_user_to_kern((void *)param[1], newpath, param_size[1])) {
		syscall_errno = EFAULT;
		heapmm_free(oldpath, param_size[0]);
		heapmm_free(newpath, param_size[1]);
		return (uint32_t) -1;
	}	
	status = vfs_symlink(oldpath, newpath);
	if (status != 0) {
		syscall_errno = status;
		status = -1;
	}
	heapmm_free(oldpath, param_size[0]);
	heapmm_free(newpath, param_size[1]);
	return (uint32_t) status;
}
static int wrapfs_symlink(struct inode *dir, struct dentry *dentry,
			  const char *symname)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
	if (err)
		goto out;
	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
}
Exemplo n.º 3
0
static int sdcardfskk_symlink(struct inode *dir, struct dentry *dentry,
			  const char *symname)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	OVERRIDE_CRED(SDCARDFSKK_SB(dir->i_sb));

	sdcardfskk_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
	if (err)
		goto out;
	err = sdcardfskk_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, sdcardfskk_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	sdcardfskk_put_lower_path(dentry, &lower_path);
	REVERT_CRED();
	return err;
}
Exemplo n.º 4
0
int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
{
	int err;
	struct dentry *d;

	IMustLock(dir);

	d = path->dentry;
	path->dentry = d->d_parent;
	err = security_path_symlink(path, d, symname);
	path->dentry = d;
	if (unlikely(err))
		goto out;

	err = vfs_symlink(dir, path->dentry, symname);
	if (!err) {
		struct path tmp = *path;
		int did;

		vfsub_update_h_iattr(&tmp, &did);
		if (did) {
			tmp.dentry = path->dentry->d_parent;
			vfsub_update_h_iattr(&tmp, /*did*/NULL);
		}
		/*ignore*/
	}

out:
	return err;
}
Exemplo n.º 5
0
static int ccfs_symlink(struct inode *dir, struct dentry *dentry,
			    const char *symname)
{
	int rc;
	struct dentry *lower_dentry;
	struct dentry *lower_dir_dentry;
	umode_t mode;
// TODO: Update cached link
	lower_dentry = ccfs_get_nested_dentry(dentry);		
	dget(lower_dentry);
	
	mdbg(INFO3,"Symlink w/ lower_dentry->d_name.name = [%s] Link = [%s]", lower_dentry->d_name.name, symname);
	lower_dir_dentry = lock_parent(lower_dentry);
	mode = S_IALLUGO;

	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
			 symname);
	
	if (rc || !lower_dentry->d_inode)
		goto out_lock;
	rc = ccfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
	if (rc)
		goto out_lock;
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out_lock:
	unlock_dir(lower_dir_dentry);
	dput(lower_dentry);
	if (!dentry->d_inode)
		d_drop(dentry);
	return rc;
}
void __u2fs_symlink(struct work_struct *work)
{
	struct sioq_args *args = container_of(work, struct sioq_args, work);
	struct symlink_args *s = &args->symlink;

	args->err = vfs_symlink(s->parent, s->dentry, s->symbuf);
	complete(&args->comp);
}
Exemplo n.º 7
0
static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry)
{
	int err;
	struct dentry *newdentry;
	const struct cred *old_cred;
	struct cred *override_cred;

	/* FIXME: recheck lower dentry to see if whiteout is really needed */

	err = -ENOMEM;
	override_cred = ovl_prepare_creds(dentry->d_sb);
	if (!override_cred)
		goto out;

	override_cred->fsuid = make_kuid(override_cred->user_ns, 0);
	if (!uid_valid(override_cred->fsuid))
		override_cred->fsuid = GLOBAL_ROOT_UID;
	override_cred->fsgid = make_kgid(override_cred->user_ns, 0);
	if (!gid_valid(override_cred->fsgid))
		override_cred->fsgid = GLOBAL_ROOT_GID;
	old_cred = override_creds(override_cred);

	newdentry = lookup_one_len(dentry->d_name.name, upperdir,
				   dentry->d_name.len);
	err = PTR_ERR(newdentry);
	if (IS_ERR(newdentry))
		goto out_put_cred;

	/* Just been removed within the same locked region */
	WARN_ON(newdentry->d_inode);

	err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink);
	if (err)
		goto out_dput;

	ovl_dentry_version_inc(dentry->d_parent);

	err = ovl_do_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0);
	if (err)
		vfs_unlink(upperdir->d_inode, newdentry, NULL);

out_dput:
	dput(newdentry);
out_put_cred:
	revert_creds(old_cred);
	put_cred(override_cred);
out:
	if (err) {
		/*
		 * There's no way to recover from failure to whiteout.
		 * What should we do?  Log a big fat error and... ?
		 */
		pr_err("overlayfs: ERROR - failed to whiteout '%s'\n",
		       dentry->d_name.name);
	}

	return err;
}
static int u2fs_symlink(struct inode *dir, struct dentry *dentry,
			  const char *symname)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;
	struct dentry *ret = NULL;
	
	/* creating parent directories if destination is read-only */
	if((U2FS_D(dentry)->lower_path[LEFT].dentry == NULL) &&
	(U2FS_D(dentry)->lower_path[LEFT].mnt == NULL)){

		ret = create_parents(dir, dentry, 
					dentry->d_name.name);

		if (!ret || IS_ERR(ret)) {
					err = PTR_ERR(ret);
					if (!IS_COPYUP_ERR(err))
						printk(KERN_ERR
					      	 "u2fs: create_parents for "
				     		  "u2fs_symlink failed"
					      	 "err=%d\n", err);
					goto out_copyup;
		}
		u2fs_postcopyup_setmnt(dentry);
		u2fs_put_reset_lower_path(dentry, RIGHT);
		
		if(err)
			goto out_copyup;	

	}

	u2fs_get_lower_path(dentry, &lower_path, LEFT);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
	if (err)
		goto out;

	err = u2fs_interpose(dentry, dir->i_sb, &lower_path, LEFT);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, u2fs_lower_inode(dir, LEFT));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	u2fs_put_lower_path(dentry, &lower_path);
out_copyup:
	return err;
}
Exemplo n.º 9
0
int do_vfsub_symlink(struct inode *dir, struct dentry *dentry,
		     const char *symname, int mode)
{
	int err;

	LKTRTrace("i%lu, %.*s, %s, 0x%x\n",
		  dir->i_ino, AuDLNPair(dentry), symname, mode);
	IMustLock(dir);

	err = vfs_symlink(dir, dentry, symname, mode);
	if (!err) {
		/* dir inode is locked */
		au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/
		au_update_fuse_h_inode(NULL, dentry); /*ignore*/
	}
	return err;
}
Exemplo n.º 10
0
static int amfs_symlink(struct inode *dir, struct dentry *dentry,
			  const char *symname)
{
	int err;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;
/*	char* value = NULL;
	value = kzalloc(5,__GFP_WAIT);
	if(value==NULL){
		err = -ENOMEM;
		goto out_err;
	}
	if(amfs_getxattr(dentry, AMFS_XATTR_NAME , value,5) > 0){
		if(!strncmp(value,AMFS_BADFILE,3)){
			err = -EPERM;
			goto freevalue;
		}
	}else if(amfs_getxattr(dentry, AMFS_XATTR_NAME, value, 5)
			!= -ENODATA){
		err = amfs_getxattr(dentry, AMFS_XATTR_NAME, value, 5);
		goto freevalue;
	}
*/
	amfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
	if (err)
		goto out;
	err = amfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, amfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	unlock_dir(lower_parent_dentry);
	amfs_put_lower_path(dentry, &lower_path);
	return err;
}
Exemplo n.º 11
0
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
			    const char *symname)
{
	int rc;
	struct dentry *lower_dentry;
	struct vfsmount *lower_mnt;
	struct dentry *lower_dir_dentry;
	umode_t mode;
	char *encoded_symname;
	int encoded_symlen;
	struct ecryptfs_crypt_stat *crypt_stat = NULL;

	lower_dentry = ecryptfs_dentry_to_lower(dentry);
	dget(lower_dentry);
	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
	lower_dir_dentry = lock_parent(lower_dentry);
	mode = S_IALLUGO;
	encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
						  strlen(symname),
						  &encoded_symname);
	if (encoded_symlen < 0) {
		rc = encoded_symlen;
		goto out_lock;
	}
	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
			 encoded_symname, mode);
	kfree(encoded_symname);
	if (rc || !lower_dentry->d_inode)
		goto out_lock;
	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
	if (rc)
		goto out_lock;
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out_lock:
	unlock_dir(lower_dir_dentry);
	dput(lower_dentry);
	if (!dentry->d_inode)
		d_drop(dentry);
	return rc;
}
Exemplo n.º 12
0
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
			    const char *symname)
{
	int rc;
	struct dentry *lower_dentry;
	struct dentry *lower_dir_dentry;
	char *encoded_symname;
	size_t encoded_symlen;
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;

	lower_dentry = ecryptfs_dentry_to_lower(dentry);
	dget(lower_dentry);
	lower_dir_dentry = lock_parent(lower_dentry);
	mount_crypt_stat = &ecryptfs_superblock_to_private(
		dir->i_sb)->mount_crypt_stat;
	rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname,
						  &encoded_symlen,
						  NULL,
						  mount_crypt_stat, symname,
						  strlen(symname));
	if (rc)
		goto out_lock;
	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
			 encoded_symname);
	kfree(encoded_symname);
	if (rc || !lower_dentry->d_inode)
		goto out_lock;
	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
	if (rc)
		goto out_lock;
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out_lock:
	unlock_dir(lower_dir_dentry);
	dput(lower_dentry);
	if (!dentry->d_inode)
		d_drop(dentry);
	return rc;
}
Exemplo n.º 13
0
int	do_symlink (struct inode *dir_i, const char *name, int len,
	            const char *link_tgt)
{
#if USE_DENTRY_F
	struct dentry	*dent;
#endif
	int	ret;

	ret = 0;

	DOWN(&(dir_i->i_sem));

#if USE_DENTRY_F

	ret = ovlfs_inode_get_child_dentry(dir_i, name, len, &dent,
	                                   OVLFS_DENT_GET_NEGATIVE);

	if ( ret == 0 )
	{
			/* Create the entry using vfs_create to do all the */
			/*  "dirty work".                                  */

		ret = vfs_symlink(dir_i, dent, link_tgt);

		dput(dent);
	}

#else
	IMARK(dir_i);
        ret = dir_i->i_op->symlink(dir_i, name, len, sym_name);
#endif

	UP(&(dir_i->i_sem));

	return	ret;
}
Exemplo n.º 14
0
int ovl_do_whiteout_v1(struct inode *workdir,
			      struct dentry *dentry)
{
	int err;

	err = vfs_symlink(workdir, dentry, ovl_whiteout_symlink);
	if (err)
		return err;

	err = vfs_setxattr(dentry, ovl_whiteout_xattr, "y", 1, 0);
	if (err)
		vfs_unlink(workdir, dentry, NULL);

	if (err) {
		/*
		 * There's no way to recover from failure to whiteout.
		 * What should we do?  Log a big fat error and... ?
		 */
		pr_err("overlayfs: ERROR - failed to whiteout '%s'\n",
		       dentry->d_name.name);
	}

	return err;
}
Exemplo n.º 15
0
int
hwgfs_mk_symlink(
	hwgfs_handle_t		dir,
	const char		*name,
	unsigned int		flags,
	const char		*link,
	hwgfs_handle_t		*handle,
	void			*info)
{
	struct inode		*parent_inode;
	struct dentry		*dentry;
	int			error;

	error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry);
	if (likely(!error)) {
		error = vfs_symlink(parent_inode, dentry, link, S_IALLUGO);
		dentry->d_fsdata = info;
		if (handle)
			*handle = dentry;
		up(&parent_inode->i_sem);
		/* dput(dentry); */
	}
	return error;
}
Exemplo n.º 16
0
static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry)
{
	int err;
	struct dentry *newdentry;
	const struct cred *old_cred;
	struct cred *override_cred;

	/* FIXME: recheck lower dentry to see if whiteout is really needed */

	err = -ENOMEM;
	override_cred = prepare_creds();
	if (!override_cred)
		goto out;

	/*
	 * CAP_SYS_ADMIN for setxattr
	 * CAP_DAC_OVERRIDE for symlink creation
	 * CAP_FOWNER for unlink in sticky directory
	 */
	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
	cap_raise(override_cred->cap_effective, CAP_FOWNER);
	override_cred->fsuid = GLOBAL_ROOT_UID;
	override_cred->fsgid = GLOBAL_ROOT_GID;
	old_cred = override_creds(override_cred);

	newdentry = lookup_one_len(dentry->d_name.name, upperdir,
				   dentry->d_name.len);
	err = PTR_ERR(newdentry);
	if (IS_ERR(newdentry))
		goto out_put_cred;

	/* Just been removed within the same locked region */
	WARN_ON(newdentry->d_inode);

	err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink);
	if (err)
		goto out_dput;

	ovl_dentry_version_inc(dentry->d_parent);

	err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0);
	if (err)
		vfs_unlink(upperdir->d_inode, newdentry);

out_dput:
	dput(newdentry);
out_put_cred:
	revert_creds(old_cred);
	put_cred(override_cred);
out:
	if (err) {
		/*
		 * There's no way to recover from failure to whiteout.
		 * What should we do?  Log a big fat error and... ?
		 */
		pr_err("overlayfs: ERROR - failed to whiteout '%s'\n",
		       dentry->d_name.name);
	}

	return err;
}
Exemplo n.º 17
0
int copyup_named_dentry(struct inode *dir, struct dentry *dentry,
			int bstart, int new_bindex, char *name,
			int namelen, struct file **copyup_file, int len)
{
	struct dentry *new_hidden_dentry;
	struct dentry *old_hidden_dentry = NULL;
	struct super_block *sb;
	struct file *input_file = NULL;
	struct file *output_file = NULL;
	ssize_t read_bytes, write_bytes;
	mm_segment_t old_fs;
	int err = 0;
	char *buf;
	int old_bindex;
	int got_branch_input = -1;
	int got_branch_output = -1;
	int old_bstart;
	int old_bend;
	int size = len;
	struct dentry *new_hidden_parent_dentry;
	mm_segment_t oldfs;
	char *symbuf = NULL;
	uid_t saved_uid = current->fsuid;
	gid_t saved_gid = current->fsgid;

	print_entry_location();
	verify_locked(dentry);
	fist_print_dentry("IN: copyup_named_dentry", dentry);

	old_bindex = bstart;
	old_bstart = dbstart(dentry);
	old_bend = dbend(dentry);

	ASSERT(new_bindex >= 0);
	ASSERT(new_bindex < old_bindex);
	PASSERT(dir);
	PASSERT(dentry);

	sb = dir->i_sb;

	if ((err = is_robranch_super(sb, new_bindex)))
		goto out;

	/* Create the directory structure above this dentry. */
	new_hidden_dentry = create_parents_named(dir, dentry, name, new_bindex);
	PASSERT(new_hidden_dentry);
	if (IS_ERR(new_hidden_dentry)) {
		err = PTR_ERR(new_hidden_dentry);
		goto out;
	}

	fist_print_generic_dentry("Copyup Object", new_hidden_dentry);

	/* Now we actually create the object. */
	old_hidden_dentry = dtohd_index(dentry, old_bindex);
	PASSERT(old_hidden_dentry);
	PASSERT(old_hidden_dentry->d_inode);
	DGET(old_hidden_dentry);

	/* For symlinks, we must read the link before we lock the directory. */
	if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) {
		PASSERT(old_hidden_dentry->d_inode->i_op);
		PASSERT(old_hidden_dentry->d_inode->i_op->readlink);

		symbuf = KMALLOC(PATH_MAX, GFP_UNIONFS);
		if (!symbuf) {
			err = -ENOMEM;
			goto copyup_readlink_err;
		}

		oldfs = get_fs();
		set_fs(KERNEL_DS);
		err =
		    old_hidden_dentry->d_inode->i_op->
		    readlink(old_hidden_dentry, symbuf, PATH_MAX);
		set_fs(oldfs);
		if (err < 0)
			goto copyup_readlink_err;
		symbuf[err] = '\0';
	}

	/* Now we lock the parent, and create the object in the new branch. */
	new_hidden_parent_dentry = lock_parent(new_hidden_dentry);
	current->fsuid = new_hidden_parent_dentry->d_inode->i_uid;
	current->fsgid = new_hidden_parent_dentry->d_inode->i_gid;
	if (S_ISDIR(old_hidden_dentry->d_inode->i_mode)) {
		err = vfs_mkdir(new_hidden_parent_dentry->d_inode,
				new_hidden_dentry, S_IRWXU);
	} else if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		err = vfs_symlink(new_hidden_parent_dentry->d_inode,
				  new_hidden_dentry, symbuf);
#else
		err = vfs_symlink(new_hidden_parent_dentry->d_inode,
				  new_hidden_dentry, symbuf, S_IRWXU);
#endif
	} else if (S_ISBLK(old_hidden_dentry->d_inode->i_mode)
		   || S_ISCHR(old_hidden_dentry->d_inode->i_mode)
		   || S_ISFIFO(old_hidden_dentry->d_inode->i_mode)
		   || S_ISSOCK(old_hidden_dentry->d_inode->i_mode)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		err = vfs_mknod(new_hidden_parent_dentry->d_inode,
				new_hidden_dentry,
				old_hidden_dentry->d_inode->i_mode,
				kdev_t_to_nr(old_hidden_dentry->d_inode->
					     i_rdev));
#else
		err = vfs_mknod(new_hidden_parent_dentry->d_inode,
				new_hidden_dentry,
				old_hidden_dentry->d_inode->i_mode,
				old_hidden_dentry->d_inode->i_rdev);
#endif
	} else if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		err = vfs_create(new_hidden_parent_dentry->d_inode,
				 new_hidden_dentry, S_IRWXU);
#else
		err = vfs_create(new_hidden_parent_dentry->d_inode,
				 new_hidden_dentry, S_IRWXU, NULL);
#endif
	} else {
		char diemsg[100];
		snprintf(diemsg, sizeof(diemsg), "Unknown inode type %d\n",
			 old_hidden_dentry->d_inode->i_mode);
		FISTBUG(diemsg);
	}
	current->fsuid = saved_uid;
	current->fsgid = saved_gid;
	unlock_dir(new_hidden_parent_dentry);
      copyup_readlink_err:
	KFREE(symbuf);
	if (err) {
		/* get rid of the hidden dentry and all its traces */
		DPUT(new_hidden_dentry);
		set_dtohd_index(dentry, new_bindex, NULL);
		set_dbstart(dentry, old_bstart);
		set_dbend(dentry, old_bend);
		goto out;
	}

	/* We actually copyup the file here. */
	if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) {
		mntget(stohiddenmnt_index(sb, old_bindex));
		branchget(sb, old_bindex);
		got_branch_input = old_bindex;
		input_file =
		    DENTRY_OPEN(old_hidden_dentry,
				stohiddenmnt_index(sb, old_bindex), O_RDONLY);
		if (IS_ERR(input_file)) {
			err = PTR_ERR(input_file);
			goto out;
		}
		if (!input_file->f_op || !input_file->f_op->read) {
			err = -EINVAL;
			goto out;
		}

		/* copy the new file */
		DGET(new_hidden_dentry);
		mntget(stohiddenmnt_index(sb, new_bindex));
		branchget(sb, new_bindex);
		got_branch_output = new_bindex;
		output_file =
		    DENTRY_OPEN(new_hidden_dentry,
				stohiddenmnt_index(sb, new_bindex), O_WRONLY);
		if (IS_ERR(output_file)) {
			err = PTR_ERR(output_file);
			goto out;
		}
		if (!output_file->f_op || !output_file->f_op->write) {
			err = -EINVAL;
			goto out;
		}

		/* allocating a buffer */
		buf = (char *)KMALLOC(PAGE_SIZE, GFP_UNIONFS);
		if (!buf) {
			err = -ENOMEM;
			goto out;
		}

		/* now read PAGE_SIZE bytes from offset 0 in a loop */
		old_fs = get_fs();

		input_file->f_pos = 0;
		output_file->f_pos = 0;

		set_fs(KERNEL_DS);
		do {
			if (len >= PAGE_SIZE)
				size = PAGE_SIZE;
			else if ((len < PAGE_SIZE) && (len > 0))
				size = len;

			len -= PAGE_SIZE;

			read_bytes =
			    input_file->f_op->read(input_file, buf, size,
						   &input_file->f_pos);
			if (read_bytes <= 0) {
				err = read_bytes;
				break;
			}

			write_bytes =
			    output_file->f_op->write(output_file, buf,
						     read_bytes,
						     &output_file->f_pos);
			if (write_bytes < 0 || (write_bytes < read_bytes)) {
				err = -EIO;
				break;
			}
		} while ((read_bytes > 0) && (len > 0));
		set_fs(old_fs);
		KFREE(buf);
	}

	/* Set permissions. */
	if ((err =
	     copyup_permissions(sb, old_hidden_dentry, new_hidden_dentry)))
		goto out;
	/* Selinux uses extended attributes for permissions. */
#if defined(UNIONFS_XATTR) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20))
	if ((err = copyup_xattrs(old_hidden_dentry, new_hidden_dentry)))
		goto out;
#endif

	/* do not allow files getting deleted to be reinterposed */
	if (!d_deleted(dentry))
		unionfs_reinterpose(dentry);

      out:
	if (input_file && !IS_ERR(input_file)) {
		fput(input_file);
	} else {
		/* since input file was not opened, we need to explicitly
		 * dput the old_hidden_dentry
		 */
		DPUT(old_hidden_dentry);
	}

	/* in any case, we have to branchput */
	if (got_branch_input >= 0)
		branchput(sb, got_branch_input);

	if (output_file) {
		if (copyup_file && !err) {
			*copyup_file = output_file;
		} else {
			fput(output_file);
			branchput(sb, got_branch_output);
		}
	}

	fist_print_dentry("OUT: copyup_dentry", dentry);
	fist_print_inode("OUT: copyup_dentry", dentry->d_inode);

	print_exit_status(err);
	return err;
}
Exemplo n.º 18
0
static int unionfs_symlink(struct inode *dir, struct dentry *dentry,
			   const char *symname)
{
	int err = 0;
	struct dentry *lower_dentry = NULL;
	struct dentry *wh_dentry = NULL;
	struct dentry *lower_parent_dentry = NULL;
	struct dentry *parent;
	char *name = NULL;
	int valid = 0;
	umode_t mode;

	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
	parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
	unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);

	valid = __unionfs_d_revalidate(dentry, parent, false, 0);
	if (unlikely(!valid)) {
		err = -ESTALE;
		goto out;
	}

	/*
	 * It's only a bug if this dentry was not negative and couldn't be
	 * revalidated (shouldn't happen).
	 */
	BUG_ON(!valid && dentry->d_inode);

	lower_dentry = find_writeable_branch(dir, dentry);
	if (IS_ERR(lower_dentry)) {
		err = PTR_ERR(lower_dentry);
		goto out;
	}

	lower_parent_dentry = lock_parent(lower_dentry);
	if (IS_ERR(lower_parent_dentry)) {
		err = PTR_ERR(lower_parent_dentry);
		goto out_unlock;
	}

	mode = S_IALLUGO;
	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
	if (!err) {
		err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
		if (!err) {
			unionfs_copy_attr_times(dir);
			fsstack_copy_inode_size(dir,
						lower_parent_dentry->d_inode);
			/* update no. of links on parent directory */
			set_nlink(dir, unionfs_get_nlinks(dir));
		}
	}

out_unlock:
	unlock_dir(lower_parent_dentry);
out:
	dput(wh_dentry);
	kfree(name);

	if (!err) {
		unionfs_postcopyup_setmnt(dentry);
		unionfs_check_inode(dir);
		unionfs_check_dentry(dentry);
	}
	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(dentry->d_sb);
	return err;
}
Exemplo n.º 19
0
SYSCALL_HANDLER3(sys_symlink, const char *target, const char *linkpath, int *ret) {
	*ret = vfs_symlink(target, linkpath);
}
Exemplo n.º 20
0
static int unionfs_symlink(struct inode *dir, struct dentry *dentry,
			   const char *symname)
{
	int err = 0;
	struct dentry *hidden_dentry = NULL;
	struct dentry *whiteout_dentry = NULL;
	struct dentry *hidden_dir_dentry = NULL;
	umode_t mode;
	int bindex = 0, bstart;
	char *name = NULL;

	print_entry_location();
	lock_dentry(dentry);
	fist_print_dentry("IN unionfs_symlink", dentry);

	/* We start out in the leftmost branch. */
	bstart = dbstart(dentry);

	hidden_dentry = dtohd(dentry);

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

	whiteout_dentry =
	    LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
			   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_symlink() */
		hidden_dir_dentry = lock_parent(whiteout_dentry);

		fist_print_generic_dentry("HDD", hidden_dir_dentry);
		fist_print_generic_dentry("WD", whiteout_dentry);

		if (!(err = is_robranch_super(dentry->d_sb, bstart))) {
			err =
			    vfs_unlink(hidden_dir_dentry->d_inode,
				       whiteout_dentry);
		}
		DPUT(whiteout_dentry);

		fist_copy_attr_times(dir, hidden_dir_dentry->d_inode);
		/* propagate number of hard-links */
		dir->i_nlink = get_nlinks(dir);

		unlock_dir(hidden_dir_dentry);

		if (err) {
			/* exit if the error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				goto out;
			/* should now try to create symlink in the another branch */
			bstart--;
		}
	}

	/* deleted whiteout if it was present, now do a normal vfs_symlink() with
	   possible recursive directory creation */
	for (bindex = bstart; bindex >= 0; bindex--) {
		hidden_dentry = dtohd_index(dentry, bindex);
		if (!hidden_dentry) {
			/* if hidden_dentry is NULL, create the entire
			 * dentry directory structure in branch 'bindex'. hidden_dentry will NOT be null when
			 * bindex == bstart because lookup passed as a negative unionfs dentry pointing to a
			 * lone negative underlying dentry */
			hidden_dentry = create_parents(dir, dentry, bindex);
			if (!hidden_dentry || IS_ERR(hidden_dentry)) {
				if (IS_ERR(hidden_dentry)) {
					err = PTR_ERR(hidden_dentry);
				}
				fist_dprint(8,
					    "hidden dentry NULL (or error) for bindex = %d\n",
					    bindex);
				continue;
			}
		}

		hidden_dir_dentry = lock_parent(hidden_dentry);

		if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
			mode = S_IALLUGO;
			err =
			    vfs_symlink(hidden_dir_dentry->d_inode,
					hidden_dentry, symname, mode);
		}
		unlock_dir(hidden_dir_dentry);

		if (err || !hidden_dentry->d_inode) {
			/* break out of for loop if error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				break;
		} else {
			err = unionfs_interpose(dentry, dir->i_sb, 0);
			if (!err) {
				fist_copy_attr_timesizes(dir,
							 hidden_dir_dentry->
							 d_inode);
				/* update number of links on parent directory */
				dir->i_nlink = get_nlinks(dir);
			}
			break;
		}
	}

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

	KFREE(name);
	fist_print_dentry("OUT unionfs_symlink :", dentry);
	unlock_dentry(dentry);
	print_exit_status(err);
	return err;
}