예제 #1
0
/*
 * smb_vop_link(target-dir-vp, source-file-vp, target-name)
 *
 * Create a link - same tree (identical TID) only.
 */
int
smb_vop_link(vnode_t *to_dvp, vnode_t *from_vp, char *to_name,
    int flags, cred_t *cr)
{
	int option_flags = 0;
	char *np, *buf;
	int rc;

	if (flags & SMB_IGNORE_CASE)
		option_flags = FIGNORECASE;

	if (flags & SMB_CATIA) {
		buf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
		np = smb_vop_catia_v5tov4(to_name, buf, MAXNAMELEN);
		if (strchr(np, '/') != NULL) {
			kmem_free(buf, MAXNAMELEN);
			return (EILSEQ);
		}

		rc = VOP_LINK(to_dvp, from_vp, np, cr, &smb_ct, option_flags);
		kmem_free(buf, MAXNAMELEN);
		return (rc);
	}

	rc = VOP_LINK(to_dvp, from_vp, to_name, cr, &smb_ct, option_flags);
	return (rc);
}
예제 #2
0
STATIC int
linvfs_link(
	struct dentry	*old_dentry,
	struct inode	*dir,
	struct dentry	*dentry)
{
	struct inode	*ip;	/* inode of guy being linked to */
	vnode_t		*tdvp;	/* target directory for new name/link */
	vnode_t		*vp;	/* vp of name being linked */
	int		error;

	ip = old_dentry->d_inode;	/* inode being linked to */
	if (S_ISDIR(ip->i_mode))
		return -EPERM;

	tdvp = LINVFS_GET_VP(dir);
	vp = LINVFS_GET_VP(ip);

	VOP_LINK(tdvp, vp, dentry, NULL, error);
	if (!error) {
		VMODIFY(tdvp);
		VN_HOLD(vp);
		validate_fields(ip);
		d_instantiate(dentry, ip);
	}
	return -error;
}
예제 #3
0
static int
zfs_replay_link(void *arg1, char *arg2, boolean_t byteswap)
{
	zfsvfs_t *zfsvfs = (zfsvfs_t *)arg1;
	lr_link_t *lr = (lr_link_t *)arg2;
	char *name = (char *)(lr + 1);	/* name follows lr_link_t */
	znode_t *dzp, *zp;
	int error;
	int vflg = 0;

	if (byteswap)
		byteswap_uint64_array(lr, sizeof (*lr));

	if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
		return (error);

	if ((error = zfs_zget(zfsvfs, lr->lr_link_obj, &zp)) != 0) {
		VN_RELE(ZTOV(dzp));
		return (error);
	}

	if (lr->lr_common.lrc_txtype & TX_CI)
		vflg |= FIGNORECASE;

	error = VOP_LINK(ZTOV(dzp), ZTOV(zp), name, kcred, NULL, vflg);

	VN_RELE(ZTOV(zp));
	VN_RELE(ZTOV(dzp));

	return (error);
}
예제 #4
0
파일: vfspath.c 프로젝트: Mr-Grieves/os161
/* Does most of the work for link(). */
int
vfs_link(char *oldpath, char *newpath)
{
	struct vnode *oldfile;
	struct vnode *newdir;
	char newname[NAME_MAX+1];
	int result;

	result = vfs_lookup(oldpath, &oldfile);
	if (result) {
		return result;
	}
	result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname));
	if (result) {
		VOP_DECREF(oldfile);
		return result;
	}

	if (oldfile->vn_fs==NULL || newdir->vn_fs==NULL ||
	    oldfile->vn_fs != newdir->vn_fs) {
		VOP_DECREF(newdir);
		VOP_DECREF(oldfile);
		return EXDEV;
	}

	result = VOP_LINK(newdir, newname, oldfile);

	VOP_DECREF(newdir);
	VOP_DECREF(oldfile);

	return result;
}
예제 #5
0
static int
unionfs_link(void *v)
{
#if 0
	struct vop_link_args *ap = v;
	int		error;
	int		needrelookup;
	struct unionfs_node *dunp;
	struct unionfs_node *unp;
	struct vnode   *udvp;
	struct vnode   *uvp;
	struct componentname *cnp;

	UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");

	error = 0;
	needrelookup = 0;
	dunp = VTOUNIONFS(ap->a_tdvp);
	unp = NULL;
	udvp = dunp->un_uppervp;
	uvp = NULLVP;
	cnp = ap->a_cnp;

	if (udvp == NULLVP)
		return (EROFS);

	if (ap->a_vp->v_op != unionfs_vnodeop_p)
		uvp = ap->a_vp;
	else {
		unp = VTOUNIONFS(ap->a_vp);

		if (unp->un_uppervp == NULLVP) {
			if (ap->a_vp->v_type != VREG)
				return (EOPNOTSUPP);

			error = unionfs_copyfile(unp, 1, cnp->cn_cred);
			if (error != 0)
				return (error);
			needrelookup = 1;
		}
		uvp = unp->un_uppervp;
	}

	if (needrelookup != 0)
		error = unionfs_relookup_for_create(ap->a_tdvp, cnp);

	if (error == 0)
		error = VOP_LINK(udvp, uvp, cnp);

	UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);

	return (error);
#else
	panic("XXXAD");
	return 0;
#endif
}
예제 #6
0
int
RUMP_VOP_LINK(struct vnode *dvp,
    struct vnode *vp,
    struct componentname *cnp)
{
	int error;

	rump_schedule();
	error = VOP_LINK(dvp, vp, cnp);
	rump_unschedule();

	return error;
}
예제 #7
0
static int
auto_link(
	vnode_t *tdvp,
	vnode_t *svp,
	char *nm,
	cred_t *cred,
	caller_context_t *ct,
	int flags)
{
	vnode_t *newvp;
	int error;

	AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp,
	    (void *)svp, nm));

	if (error = auto_trigger_mount(tdvp, cred, &newvp))
		goto done;

	if (newvp == NULL) {
		/*
		 * an autonode can not be a link to another node
		 */
		error = ENOSYS;
		goto done;
	}

	if (vn_is_readonly(newvp)) {
		error = EROFS;
		VN_RELE(newvp);
		goto done;
	}

	if (vn_matchops(svp, auto_vnodeops)) {
		/*
		 * source vp can't be an autonode
		 */
		error = ENOSYS;
		VN_RELE(newvp);
		goto done;
	}

	error = VOP_LINK(newvp, svp, nm, cred, ct, flags);
	VN_RELE(newvp);

done:
	AUTOFS_DPRINT((5, "auto_link error=%d\n", error));
	return (error);
}
예제 #8
0
파일: xattr.c 프로젝트: pcd1193182/openzfs
static int
xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
    caller_context_t *ct, int flags)
{
	vnode_t *pvp;
	int error;

	if (svp->v_flag & V_SYSATTR) {
		return (EINVAL);
	}

	error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct);
	if (error == 0) {
		error = VOP_LINK(pvp, svp, name, cr, ct, flags);
	}
	return (error);
}
예제 #9
0
파일: zfs_replay.c 프로젝트: 151706061/osv
static int
zfs_replay_link(zfsvfs_t *zfsvfs, void *data, boolean_t byteswap)
{
#ifdef __OSV__
	kprintf("TX_LINK not supported on OSv\n");
	return EOPNOTSUPP;
#else
	lr_link_t *lr;
	char *name = (char *)(lr + 1);	/* name follows lr_link_t */
	znode_t *dzp, *zp;
	struct componentname cn;
	int error;
	int vflg = 0;

	if (byteswap)
		byteswap_uint64_array(lr, sizeof (*lr));

	if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
		return (error);

	if ((error = zfs_zget(zfsvfs, lr->lr_link_obj, &zp)) != 0) {
		VN_RELE(ZTOV(dzp));
		return (error);
	}

	if (lr->lr_common.lrc_txtype & TX_CI)
		vflg |= FIGNORECASE;

	cn.cn_nameptr = name;
	cn.cn_cred = kcred;
	cn.cn_thread = curthread;
	cn.cn_flags = SAVENAME;

	vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY);
	vn_lock(ZTOV(zp), LK_EXCLUSIVE | LK_RETRY);
	error = VOP_LINK(ZTOV(dzp), ZTOV(zp), &cn /*,vflg*/);
	VOP_UNLOCK(ZTOV(zp), 0);
	VOP_UNLOCK(ZTOV(dzp), 0);

	VN_RELE(ZTOV(zp));
	VN_RELE(ZTOV(dzp));

	return (error);
#endif
}
예제 #10
0
static int
zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
{
	char *name = (char *)(lr + 1);	/* name follows lr_link_t */
	znode_t *dzp, *zp;
	struct componentname cn;
	int error;
	int vflg = 0;

	if (byteswap)
		byteswap_uint64_array(lr, sizeof (*lr));

	if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
		return (error);

	if ((error = zfs_zget(zfsvfs, lr->lr_link_obj, &zp)) != 0) {
		VN_RELE(ZTOV(dzp));
		return (error);
	}

	if (lr->lr_common.lrc_txtype & TX_CI)
		vflg |= FIGNORECASE;
	cn.cn_nameptr = name;
	cn.cn_cred = kcred;
	cn.cn_flags = 0;

	vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY);
	vn_lock(ZTOV(zp), LK_EXCLUSIVE | LK_RETRY);
	error = VOP_LINK(ZTOV(dzp), ZTOV(zp), &cn /*,vflg*/);
	VOP_UNLOCK(ZTOV(zp));
	VOP_UNLOCK(ZTOV(dzp));

	VN_RELE(ZTOV(zp));
	VN_RELE(ZTOV(dzp));

	return (error);
}
예제 #11
0
static int zfsfuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
{
	if(strlen(newname) >= MAXNAMELEN)
		return ENAMETOOLONG;

	vfs_t *vfs = (vfs_t *) fuse_req_userdata(req);
	zfsvfs_t *zfsvfs = vfs->vfs_data;

	ZFS_ENTER(zfsvfs);

	znode_t *td_znode, *s_znode;

	int error = zfs_zget(zfsvfs, ino, &s_znode, B_FALSE);
	if(error) {
		ZFS_EXIT(zfsvfs);
		/* If the inode we are trying to get was recently deleted
		   dnode_hold_impl will return EEXIST instead of ENOENT */
		return error == EEXIST ? ENOENT : error;
	}

	ASSERT(s_znode != NULL);

	error = zfs_zget(zfsvfs, newparent, &td_znode, B_FALSE);
	if(error) {
		VN_RELE(ZTOV(s_znode));
		ZFS_EXIT(zfsvfs);
		/* If the inode we are trying to get was recently deleted
		   dnode_hold_impl will return EEXIST instead of ENOENT */
		return error == EEXIST ? ENOENT : error;
	}

	vnode_t *svp = ZTOV(s_znode);
	vnode_t *tdvp = ZTOV(td_znode);
	ASSERT(svp != NULL);
	ASSERT(tdvp != NULL);

	cred_t cred;
	zfsfuse_getcred(req, &cred);

	error = VOP_LINK(tdvp, svp, (char *) newname, &cred, NULL, 0);

	vnode_t *vp = NULL;

	if(error)
		goto out;

	error = VOP_LOOKUP(tdvp, (char *) newname, &vp, NULL, 0, NULL, &cred, NULL, NULL, NULL);
	if(error)
		goto out;

	ASSERT(vp != NULL);

	struct fuse_entry_param e = { 0 };

	e.attr_timeout = 0.0;
	e.entry_timeout = 0.0;

	e.ino = VTOZ(vp)->z_id;
	if(e.ino == 3)
		e.ino = 1;

	e.generation = VTOZ(vp)->z_phys->zp_gen;

	error = zfsfuse_stat(vp, &e.attr, &cred);

out:
	if(vp != NULL)
		VN_RELE(vp);
	VN_RELE(tdvp);
	VN_RELE(svp);

	ZFS_EXIT(zfsvfs);

	if(!error)
		fuse_reply_entry(req, &e);

	return error;
}
예제 #12
0
extern int
vnode_iop_link(
    DENT_T * olddent,
    INODE_T * parent,
    DENT_T * newdent
)
{
    int err = 0;
    struct link_ctx ctx;
    VATTR_T *vap;
    VNODE_T *parentvp;

    ASSERT_I_SEM_MINE(olddent->d_inode);
    ASSERT_I_SEM_MINE(parent);
    ASSERT(MDKI_INOISMVFS(parent));

    if (!vnlayer_link_eligible(olddent))
        return -EXDEV;

    /* VOP_REALVP will check that the parent is a loopback directory and
     * return EINVAL if it isn't.
     */
    if (VOP_REALVP(ITOV(parent), &parentvp) == 0) {
        /* We are creating a shadow link so bypass the mvfs for the rest */
        err = vnlayer_do_linux_link(parentvp, olddent, parent, newdent);
        err = mdki_errno_unix_to_linux(err);
    } else {
        /* This needs to be passed on to the mvfs to deal with */
        CALL_DATA_T cd;
        INODE_T *inode;
        if (!MDKI_INOISOURS(olddent->d_inode))
            return -EXDEV;
        ctx.parent = parent;
        ctx.newdent = newdent;
        ctx.olddent = olddent;
        ctx.done = FALSE;

        mdki_linux_init_call_data(&cd);
	if (MDKI_INOISMVFS(olddent->d_inode)) {
            err = VOP_LINK(ITOV(parent), ITOV(olddent->d_inode),
                           (char *)newdent->d_name.name, &cd, &ctx);
            err = mdki_errno_unix_to_linux(err);
            if (err == 0 && !ctx.done) {
                /* Again, a heavy handed way of bumping the inode count and
                 * handling the locking (This will use the inode lock)
                 */
                inode = igrab(olddent->d_inode);
                VNODE_D_INSTANTIATE(newdent, inode);
                if ((vap = VATTR_ALLOC()) != NULL) {
                    VATTR_SET_MASK(vap, AT_ALL);
                    if (VOP_GETATTR(ITOV(inode), vap, 0, &cd) == 0)
                        mdki_linux_vattr_pullup(ITOV(inode), vap, AT_ALL);
                    VATTR_FREE(vap);
		}
            }
	} else {
	    err = -EXDEV;
	}
        mdki_linux_destroy_call_data(&cd);
    }
    return err;
}
예제 #13
0
/*
 *	union_link:
 *
 *	tdvp will be locked on entry, vp will not be locked on entry.
 *	tdvp should remain locked on return and vp should remain unlocked
 *	on return.
 *
 * union_link(struct vnode *a_tdvp, struct vnode *a_vp,
 *	      struct componentname *a_cnp)
 */
static int
union_link(struct vop_old_link_args *ap)
{
	struct componentname *cnp = ap->a_cnp;
	struct thread *td = cnp->cn_td;
	struct union_node *dun = VTOUNION(ap->a_tdvp);
	struct vnode *vp;
	struct vnode *tdvp;
	int error = 0;

	if (ap->a_tdvp->v_ops != ap->a_vp->v_ops) {
		vp = ap->a_vp;
	} else {
		struct union_node *tun = VTOUNION(ap->a_vp);

		if (tun->un_uppervp == NULLVP) {
			vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
#if 0
			if (dun->un_uppervp == tun->un_dirvp) {
				if (dun->un_flags & UN_ULOCK) {
					dun->un_flags &= ~UN_ULOCK;
					vn_unlock(dun->un_uppervp);
				}
			}
#endif
			error = union_copyup(tun, 1, cnp->cn_cred, td);
#if 0
			if (dun->un_uppervp == tun->un_dirvp) {
				vn_lock(dun->un_uppervp, 
					LK_EXCLUSIVE | LK_RETRY);
				dun->un_flags |= UN_ULOCK;
			}
#endif
			vn_unlock(ap->a_vp);
		}
		vp = tun->un_uppervp;
	}

	if (error)
		return (error);

	/*
	 * Make sure upper is locked, then unlock the union directory we were 
	 * called with to avoid a deadlock while we are calling VOP_LINK on 
	 * the upper (with tdvp locked and vp not locked).  Our ap->a_tdvp
	 * is expected to be locked on return.
	 */

	if ((tdvp = union_lock_upper(dun, td)) == NULLVP)
		return (EROFS);

	vn_unlock(ap->a_tdvp);	/* unlock calling node */
	error = VOP_LINK(tdvp, vp, cnp); /* call link on upper */

	/*
	 * We have to unlock tdvp prior to relocking our calling node in
	 * order to avoid a deadlock.
	 */
	union_unlock_upper(tdvp, td);
	vn_lock(ap->a_tdvp, LK_EXCLUSIVE | LK_RETRY);
	return (error);
}