示例#1
0
/*
 * genfs_rename_exit: Unlock everything we locked for rename.
 *
 * fdvp and tdvp must be referenced.
 *
 * On entry, everything is locked, and fvp and tvp referenced.
 *
 * On exit, everything is unlocked, and fvp and tvp are released.
 */
static void
genfs_rename_exit(const struct genfs_rename_ops *ops,
    struct mount *mp,
    struct vnode *fdvp, struct vnode *fvp,
    struct vnode *tdvp, struct vnode *tvp)
{

	(void)ops;
	KASSERT(ops != NULL);
	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fvp != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	if ((tvp != NULL) && (tvp != fvp))
		VOP_UNLOCK(tvp);
	VOP_UNLOCK(fvp);
	if (tvp != NULL)
		vrele(tvp);
	if (tdvp != fdvp)
		VOP_UNLOCK(tdvp);
	vrele(fvp);
	VOP_UNLOCK(fdvp);
}
/*
 * udf_gro_remove_check_permitted: check whether a remove is permitted given
 * our credentials.
 */
static int
udf_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred,
    struct vnode *dvp, struct vnode *vp)
{
	struct udf_node *dir_node = VTOI(dvp);
	struct udf_node *udf_node = VTOI(vp);
	mode_t dmode;
	uid_t duid, uid;
	gid_t gdummy;

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != vp);
	KASSERT(dvp->v_type == VDIR);
	KASSERT(vp->v_type != VDIR);
	KASSERT(dvp->v_mount == mp);
	KASSERT(vp->v_mount == mp);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

	DPRINTF(CALL, ("udf_gro_remove_check_permitted called\n"));
	dmode = udf_getaccessmode(dir_node);

	udf_getownership(dir_node, &duid, &gdummy);
	udf_getownership(udf_node, &uid,  &gdummy);

	return genfs_ufslike_remove_check_permitted(cred,
	    dvp, dmode, duid,
	    vp, uid);
}
示例#3
0
static int
tmpfs_open(struct vop_open_args *v)
{
	struct vnode *vp = v->a_vp;
	int mode = v->a_mode;

	int error;
	struct tmpfs_node *node;

	MPASS(VOP_ISLOCKED(vp));

	node = VP_TO_TMPFS_NODE(vp);

	/* The file is still active but all its names have been removed
	 * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
	 * it is about to die. */
	if (node->tn_links < 1)
		return (ENOENT);

	/* If the file is marked append-only, deny write requests. */
	if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
		error = EPERM;
	else {
		error = 0;
		vnode_create_vobject(vp, node->tn_size, v->a_td);
	}

	MPASS(VOP_ISLOCKED(vp));
	return error;
}
/*
 * udf_gro_remove: rename an object over another link to itself, effectively
 * removing just the original link.
 */
static int
udf_gro_remove(struct mount *mp, kauth_cred_t cred,
    struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
{
	struct udf_node *dir_node, *udf_node;

	KASSERT(mp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(cnp != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != vp);
	KASSERT(dvp->v_mount == mp);
	KASSERT(vp->v_mount == mp);
	KASSERT(dvp->v_type == VDIR);
	KASSERT(vp->v_type != VDIR);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

	DPRINTF(CALL, ("udf_gro_remove called\n"));

	dir_node = VTOI(dvp);
	udf_node = VTOI(vp);
	udf_dir_detach(dir_node->ump, dir_node, udf_node, cnp);

	return 0;
}
示例#5
0
/*
 * ulfs_gro_rename_check_possible: Check whether a rename is possible
 * independent of credentials.
 */
static int
ulfs_gro_rename_check_possible(struct mount *mp,
    struct vnode *fdvp, struct vnode *fvp,
    struct vnode *tdvp, struct vnode *tvp)
{

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fvp != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(tdvp != tvp);
	KASSERT(fvp != tvp);
	KASSERT(fdvp->v_type == VDIR);
	KASSERT(tdvp->v_type == VDIR);
	KASSERT(fdvp->v_mount == mp);
	KASSERT(fvp->v_mount == mp);
	KASSERT(tdvp->v_mount == mp);
	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	return genfs_ufslike_rename_check_possible(
	    VTOI(fdvp)->i_flags, VTOI(fvp)->i_flags,
	    VTOI(tdvp)->i_flags, (tvp? VTOI(tvp)->i_flags : 0),
	    (tvp != NULL),
	    IMMUTABLE, APPEND);
}
示例#6
0
/*
 * genfs_ufslike_remove_check_permitted: Check whether a remove is
 * permitted given our credentials, assuming UFS-like permission and
 * ownership semantics.
 *
 * Everything must be locked and referenced.
 */
int
genfs_ufslike_remove_check_permitted(kauth_cred_t cred,
    struct vnode *dvp, mode_t dmode, uid_t duid,
    struct vnode *vp, uid_t uid)
{
	int error;

	KASSERT(dvp != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != vp);
	KASSERT(dvp->v_type == VDIR);
	KASSERT(vp->v_type != VDIR);
	KASSERT(dvp->v_mount == vp->v_mount);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

	/*
	 * We need to write to the directory to remove from it.
	 */
	error = VOP_ACCESS(dvp, VWRITE, cred);
	if (error)
		return error;

	error = genfs_ufslike_check_sticky(cred, dmode, duid, vp, uid);
	if (error)
		return error;

	return 0;
}
示例#7
0
/*
 * ulfs_gro_remove: Rename an object over another link to itself,
 * effectively removing just the original link.
 */
static int
ulfs_gro_remove(struct mount *mp, kauth_cred_t cred,
    struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
{
	struct ulfs_lookup_results *ulr = de;
	int error;

	KASSERT(mp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(cnp != NULL);
	KASSERT(ulr != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != vp);
	KASSERT(dvp->v_mount == mp);
	KASSERT(vp->v_mount == mp);
	KASSERT(dvp->v_type == VDIR);
	KASSERT(vp->v_type != VDIR);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	KASSERT(cnp->cn_nameiop == DELETE);

	/* XXX ulfs_dirremove decrements vp's link count for us.  */
	error = ulfs_dirremove(dvp, ulr, VTOI(vp), cnp->cn_flags, 0);
	if (error)
		goto out1;

	VN_KNOTE(dvp, NOTE_WRITE);
	VN_KNOTE(vp, (VTOI(vp)->i_nlink? NOTE_LINK : NOTE_DELETE));

out1:
	return error;
}
示例#8
0
/*
 * ulfs_gro_rename_check_permitted: Check whether a rename is permitted
 * given our credentials.
 */
static int
ulfs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
    struct vnode *fdvp, struct vnode *fvp,
    struct vnode *tdvp, struct vnode *tvp)
{

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fvp != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(tdvp != tvp);
	KASSERT(fvp != tvp);
	KASSERT(fdvp->v_type == VDIR);
	KASSERT(tdvp->v_type == VDIR);
	KASSERT(fdvp->v_mount == mp);
	KASSERT(fvp->v_mount == mp);
	KASSERT(tdvp->v_mount == mp);
	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	return genfs_ufslike_rename_check_permitted(cred,
	    fdvp, VTOI(fdvp)->i_mode, VTOI(fdvp)->i_uid,
	    fvp, VTOI(fvp)->i_uid,
	    tdvp, VTOI(tdvp)->i_mode, VTOI(tdvp)->i_uid,
	    tvp, (tvp? VTOI(tvp)->i_uid : 0));
}
示例#9
0
/*
 * ext2fs_gro_remove: Rename an object over another link to itself,
 * effectively removing just the original link.
 */
static int
ext2fs_gro_remove(struct mount *mp, kauth_cred_t cred,
    struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
{
	struct ufs_lookup_results *ulr = de;
	int error;

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(cnp != NULL);
	KASSERT(ulr != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != vp);
	KASSERT(dvp->v_mount == mp);
	KASSERT(vp->v_mount == mp);
	KASSERT(dvp->v_type == VDIR);
	KASSERT(vp->v_type != VDIR);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

	error = ext2fs_dirremove(dvp, ulr, cnp);
	if (error)
		return error;

	KASSERT(0 < VTOI(vp)->i_e2fs_nlink);
	VTOI(vp)->i_e2fs_nlink--;
	VTOI(vp)->i_flag |= IN_CHANGE;

	VN_KNOTE(dvp, NOTE_WRITE);
	VN_KNOTE(vp, (VTOI(vp)->i_e2fs_nlink? NOTE_LINK : NOTE_DELETE));

	return 0;
}
/*
 * udf_gro_rename_check_possible: check whether a rename is possible
 * independent of credentials.
 */
static int
udf_gro_rename_check_possible(struct mount *mp,
    struct vnode *fdvp, struct vnode *fvp,
    struct vnode *tdvp, struct vnode *tvp)
{
	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fvp != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(tdvp != tvp);
	KASSERT(fvp != tvp);
	KASSERT(fdvp->v_type == VDIR);
	KASSERT(tdvp->v_type == VDIR);
	KASSERT(fdvp->v_mount == mp);
	KASSERT(fvp->v_mount == mp);
	KASSERT(tdvp->v_mount == mp);
	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	DPRINTF(CALL, ("udf_gro_rename_check_possible called\n"));

	/* flags not implemented since they are not defined (yet) in UDF */
	return 0;
}
/*
 * udf_gro_directory_empty_p: return true if the directory vp is empty. dvp is
 * its parent.
 *
 * vp and dvp must be locked and referenced.
 */
static bool
udf_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
    struct vnode *vp, struct vnode *dvp)
{
	struct udf_node *udf_node = VTOI(vp);
	int error, isempty;

	KASSERT(mp != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(vp != dvp);
	KASSERT(vp->v_mount == mp);
	KASSERT(dvp->v_mount == mp);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);

	DPRINTF(CALL, ("udf_gro_directory_empty_p called\n"));
	/* make sure our `leaf' node's hash is populated */
	dirhash_get(&udf_node->dir_hash);
	error = udf_dirhash_fill(udf_node);
	if (error) {
		dirhash_put(udf_node->dir_hash);
		/* VERY unlikely, answer its not empty */
		return 0;
	}

	/* check to see if the directory is empty */
	isempty = dirhash_dir_isempty(udf_node->dir_hash);
	dirhash_put(udf_node->dir_hash);

	return isempty;
}
示例#12
0
/*
 * lfs_gro_rename: Actually perform the rename operation.  Do a little
 * LFS bookkeeping and then defer to ulfs_gro_rename.
 */
static int
lfs_gro_rename(struct mount *mp, kauth_cred_t cred,
    struct vnode *fdvp, struct componentname *fcnp,
    void *fde, struct vnode *fvp,
    struct vnode *tdvp, struct componentname *tcnp,
    void *tde, struct vnode *tvp)
{
	int error;

	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fcnp != NULL);
	KASSERT(fde != NULL);
	KASSERT(fvp != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(tcnp != NULL);
	KASSERT(tde != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(tdvp != tvp);
	KASSERT(fvp != tvp);
	KASSERT(fdvp->v_mount == mp);
	KASSERT(fvp->v_mount == mp);
	KASSERT(tdvp->v_mount == mp);
	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	error = lfs_set_dirop(tdvp, tvp);
	if (error != 0)
		return error;

	MARK_VNODE(fdvp);
	MARK_VNODE(fvp);

	error = ulfs_gro_rename(mp, cred,
	    fdvp, fcnp, fde, fvp,
	    tdvp, tcnp, tde, tvp);

	UNMARK_VNODE(fdvp);
	UNMARK_VNODE(fvp);
	UNMARK_VNODE(tdvp);
	if (tvp) {
		UNMARK_VNODE(tvp);
	}
	lfs_unset_dirop(VFSTOULFS(mp)->um_lfs, tdvp, "rename");
	vrele(tdvp);
	if (tvp) {
		vrele(tvp);
	}

	return error;
}
示例#13
0
/* XXX Should this operation be atomic?  I think it should, but code in
 * XXX other places (e.g., ufs) doesn't seem to be... */
int
tmpfs_setattr(struct vop_setattr_args *v)
{
	struct vnode *vp = v->a_vp;
	struct vattr *vap = v->a_vap;
	struct ucred *cred = v->a_cred;
	struct thread *td = curthread;

	int error;

	MPASS(VOP_ISLOCKED(vp));

	error = 0;

	/* Abort if any unsettable attribute is given. */
	if (vap->va_type != VNON ||
	    vap->va_nlink != VNOVAL ||
	    vap->va_fsid != VNOVAL ||
	    vap->va_fileid != VNOVAL ||
	    vap->va_blocksize != VNOVAL ||
	    vap->va_gen != VNOVAL ||
	    vap->va_rdev != VNOVAL ||
	    vap->va_bytes != VNOVAL)
		error = EINVAL;

	if (error == 0 && (vap->va_flags != VNOVAL))
		error = tmpfs_chflags(vp, vap->va_flags, cred, td);

	if (error == 0 && (vap->va_size != VNOVAL))
		error = tmpfs_chsize(vp, vap->va_size, cred, td);

	if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
		error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);

	if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
		error = tmpfs_chmod(vp, vap->va_mode, cred, td);

	if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
	    vap->va_atime.tv_nsec != VNOVAL) ||
	    (vap->va_mtime.tv_sec != VNOVAL &&
	    vap->va_mtime.tv_nsec != VNOVAL) ||
	    (vap->va_birthtime.tv_sec != VNOVAL &&
	    vap->va_birthtime.tv_nsec != VNOVAL)))
		error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
			&vap->va_birthtime, vap->va_vaflags, cred, td);

	/* Update the node times.  We give preference to the error codes
	 * generated by this function rather than the ones that may arise
	 * from tmpfs_update. */
	tmpfs_update(vp);

	MPASS(VOP_ISLOCKED(vp));

	return error;
}
示例#14
0
int
tmpfs_access(struct vop_access_args *v)
{
	struct vnode *vp = v->a_vp;
	accmode_t accmode = v->a_accmode;
	struct ucred *cred = v->a_cred;

	int error;
	struct tmpfs_node *node;

	MPASS(VOP_ISLOCKED(vp));

	node = VP_TO_TMPFS_NODE(vp);

	switch (vp->v_type) {
	case VDIR:
		/* FALLTHROUGH */
	case VLNK:
		/* FALLTHROUGH */
	case VREG:
		if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
			error = EROFS;
			goto out;
		}
		break;

	case VBLK:
		/* FALLTHROUGH */
	case VCHR:
		/* FALLTHROUGH */
	case VSOCK:
		/* FALLTHROUGH */
	case VFIFO:
		break;

	default:
		error = EINVAL;
		goto out;
	}

	if (accmode & VWRITE && node->tn_flags & IMMUTABLE) {
		error = EPERM;
		goto out;
	}

	error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
	    node->tn_gid, accmode, cred, NULL);

out:
	MPASS(VOP_ISLOCKED(vp));

	return error;
}
/*
 * udf_gro_rename_check_permitted: check whether a rename is permitted given
 * our credentials.
 */
static int
udf_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
    struct vnode *fdvp, struct vnode *fvp,
    struct vnode *tdvp, struct vnode *tvp)
{
	struct udf_node *fdir_node = VTOI(fdvp);
	struct udf_node *tdir_node = VTOI(tdvp);
	struct udf_node *f_node = VTOI(fvp);
	struct udf_node *t_node = (tvp? VTOI(tvp): NULL);
	mode_t fdmode, tdmode;
	uid_t fduid, tduid, fuid, tuid;
	gid_t gdummy;

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fvp != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(tdvp != tvp);
	KASSERT(fvp != tvp);
	KASSERT(fdvp->v_type == VDIR);
	KASSERT(tdvp->v_type == VDIR);
	KASSERT(fdvp->v_mount == mp);
	KASSERT(fvp->v_mount == mp);
	KASSERT(tdvp->v_mount == mp);
	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	DPRINTF(CALL, ("udf_gro_rename_check_permitted called\n"));
	fdmode = udf_getaccessmode(fdir_node);
	tdmode = udf_getaccessmode(tdir_node);

	udf_getownership(fdir_node, &fduid, &gdummy);
	udf_getownership(tdir_node, &tduid, &gdummy);
	udf_getownership(f_node,    &fuid, &gdummy);

	tuid = 0;
	if (t_node)
		udf_getownership(t_node, &tuid, &gdummy);

	return genfs_ufslike_rename_check_permitted(cred,
	    fdvp, fdmode, fduid,
	    fvp,  fuid,
	    tdvp, tdmode, tduid,
	    tvp,  tuid);
}
示例#16
0
static int
tmpfs_remove(struct vop_remove_args *v)
{
	struct vnode *dvp = v->a_dvp;
	struct vnode *vp = v->a_vp;

	int error;
	struct tmpfs_dirent *de;
	struct tmpfs_mount *tmp;
	struct tmpfs_node *dnode;
	struct tmpfs_node *node;

	MPASS(VOP_ISLOCKED(dvp));
	MPASS(VOP_ISLOCKED(vp));

	if (vp->v_type == VDIR) {
		error = EISDIR;
		goto out;
	}

	dnode = VP_TO_TMPFS_DIR(dvp);
	node = VP_TO_TMPFS_NODE(vp);
	tmp = VFS_TO_TMPFS(vp->v_mount);
	de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
	MPASS(de != NULL);

	/* Files marked as immutable or append-only cannot be deleted. */
	if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
	    (dnode->tn_flags & APPEND)) {
		error = EPERM;
		goto out;
	}

	/* Remove the entry from the directory; as it is a file, we do not
	 * have to change the number of hard links of the directory. */
	tmpfs_dir_detach(dvp, de);
	if (v->a_cnp->cn_flags & DOWHITEOUT)
		tmpfs_dir_whiteout_add(dvp, v->a_cnp);

	/* Free the directory entry we just deleted.  Note that the node
	 * referred by it will not be removed until the vnode is really
	 * reclaimed. */
	tmpfs_free_dirent(tmp, de, TRUE);

	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
	error = 0;

out:

	return error;
}
示例#17
0
int
adosfs_access(void *v)
{
	struct vop_access_args /* {
		struct vnode *a_vp;
		int  a_mode;
		kauth_cred_t a_cred;
	} */ *sp = v;
	struct anode *ap;
	struct vnode *vp = sp->a_vp;
	int error;

#ifdef ADOSFS_DIAGNOSTIC
	advopprint(sp);
#endif

	ap = VTOA(vp);
#ifdef DIAGNOSTIC
	if (!VOP_ISLOCKED(vp)) {
		vprint("adosfs_access: not locked", sp->a_vp);
		panic("adosfs_access: not locked");
	}
#endif

	error = adosfs_check_possible(vp, ap, sp->a_mode);
	if (error)
		return error;

	error = adosfs_check_permitted(vp, ap, sp->a_mode, sp->a_cred);

#ifdef ADOSFS_DIAGNOSTIC
	printf(" %d)", error);
#endif
	return(error);
}
示例#18
0
static int
enforce_rlimit_fsize(struct vnode *vp, struct uio *uio, int ioflag)
{
	struct lwp *l = curlwp;
	off_t testoff;

	if (uio->uio_rw != UIO_WRITE || vp->v_type != VREG)
		return 0;

	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	if (ioflag & IO_APPEND)
		testoff = vp->v_size;
	else
		testoff = uio->uio_offset;

	if (testoff + uio->uio_resid >
	    l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
		mutex_enter(proc_lock);
		psignal(l->l_proc, SIGXFSZ);
		mutex_exit(proc_lock);
		return EFBIG;
	}

	return 0;
}
示例#19
0
/*
 * genfs_rename_knote: Note events about the various vnodes in a
 * rename.  To be called by gro_rename on success.  The only pair of
 * vnodes that may be identical is {fdvp, tdvp}.  deleted_p is true iff
 * the rename overwrote the last link to tvp.
 */
void
genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp,
    struct vnode *tdvp, struct vnode *tvp, bool deleted_p)
{
	long fdvp_events, tdvp_events;
	bool directory_p, reparent_p, replaced_p;

	KASSERT(fdvp != NULL);
	KASSERT(fvp != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(fdvp != fvp);
	KASSERT(fdvp != tvp);
	KASSERT(tdvp != fvp);
	KASSERT(tdvp != tvp);
	KASSERT(fvp != tvp);
	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));

	directory_p = (fvp->v_type == VDIR);
	reparent_p = (fdvp != tdvp);
	replaced_p = (tvp != NULL);

	KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
	KASSERT(!deleted_p || replaced_p);

	fdvp_events = NOTE_WRITE;
	if (directory_p && reparent_p)
		fdvp_events |= NOTE_LINK;
	VN_KNOTE(fdvp, fdvp_events);

	VN_KNOTE(fvp, NOTE_RENAME);

	if (reparent_p) {
		tdvp_events = NOTE_WRITE;
		if (!replaced_p) {
			tdvp_events |= NOTE_EXTEND;
			if (directory_p)
				tdvp_events |= NOTE_LINK;
		}
		VN_KNOTE(tdvp, tdvp_events);
	}

	if (replaced_p)
		VN_KNOTE(tvp, (deleted_p? NOTE_DELETE : NOTE_LINK));
}
示例#20
0
/*
 * ulfs_gro_directory_empty_p: Return true if the directory vp is
 * empty.  dvp is its parent.
 *
 * vp and dvp must be locked and referenced.
 */
static bool
ulfs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
    struct vnode *vp, struct vnode *dvp)
{

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(vp != dvp);
	KASSERT(vp->v_mount == mp);
	KASSERT(dvp->v_mount == mp);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);

	return ulfs_dirempty(VTOI(vp), VTOI(dvp)->i_number, cred);
}
示例#21
0
int VOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
{
	struct vop_rmdir_args a;
	a.a_desc = VDESC(vop_rmdir);
	a.a_dvp = dvp;
#ifdef VFSDEBUG
	if ((dvp->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(dvp))
		panic("vop_rmdir: dvp");
#endif
	a.a_vp = vp;
#ifdef VFSDEBUG
	if ((vp->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(vp))
		panic("vop_rmdir: vp");
#endif
	a.a_cnp = cnp;
	return (VCALL(dvp, VOFFSET(vop_rmdir), &a));
}
示例#22
0
/*
 * Read a symbolic link
 */
static int
pfs_readlink(struct vop_readlink_args *va)
{
	struct vnode *vn = va->a_vp;
	struct pfs_vdata *pvd = vn->v_data;
	struct pfs_node *pn = pvd->pvd_pn;
	struct uio *uio = va->a_uio;
	struct proc *proc = NULL;
	struct thread *td = curthread;
	char buf[PATH_MAX];
	struct sbuf sb;
	int error, locked;

	PFS_TRACE(("%s", pn->pn_name));
	pfs_assert_not_owned(pn);

	if (vn->v_type != VLNK)
		PFS_RETURN (EINVAL);
	KASSERT_PN_IS_LINK(pn);

	if (pn->pn_fill == NULL)
		PFS_RETURN (EIO);

	if (pvd->pvd_pid != NO_PID) {
		if ((proc = pfind(pvd->pvd_pid)) == NULL)
			PFS_RETURN (EIO);
		if (proc->p_flag & P_WEXIT) {
			PROC_UNLOCK(proc);
			PFS_RETURN (EIO);
		}
		_PHOLD(proc);
		PROC_UNLOCK(proc);
	}
	vhold(vn);
	locked = VOP_ISLOCKED(vn, td);
	VOP_UNLOCK(vn, 0, td);

	/* sbuf_new() can't fail with a static buffer */
	sbuf_new(&sb, buf, sizeof buf, 0);

	error = pn_fill(td, proc, pn, &sb, NULL);

	if (proc != NULL)
		PRELE(proc);
	vn_lock(vn, locked | LK_RETRY, td);
	vdrop(vn);

	if (error) {
		sbuf_delete(&sb);
		PFS_RETURN (error);
	}

	sbuf_finish(&sb);
	error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
	sbuf_delete(&sb);
	PFS_RETURN (error);
}
示例#23
0
/*
 * genfs_rename_enter: Look up fcnp in fdvp, and store the lookup
 * results in *fde_ret and the associated vnode in *fvp_ret; fail if
 * not found.  Look up tcnp in tdvp, and store the lookup results in
 * *tde_ret and the associated vnode in *tvp_ret; store null instead if
 * not found.  Fail if anything has been mounted on any of the nodes
 * involved.
 *
 * fdvp and tdvp must be referenced.
 *
 * On entry, nothing is locked.
 *
 * On success, everything is locked, and *fvp_ret, and *tvp_ret if
 * nonnull, are referenced.  The only pairs of vnodes that may be
 * identical are {fdvp, tdvp} and {fvp, tvp}.
 *
 * On failure, everything remains as was.
 *
 * Locking everything including the source and target nodes is
 * necessary to make sure that, e.g., link count updates are OK.  The
 * locking order is, in general, ancestor-first, matching the order you
 * need to use to look up a descendant anyway.
 */
static int
genfs_rename_enter(const struct genfs_rename_ops *ops,
    struct mount *mp, kauth_cred_t cred,
    struct vnode *fdvp, struct componentname *fcnp,
    void *fde_ret, struct vnode **fvp_ret,
    struct vnode *tdvp, struct componentname *tcnp,
    void *tde_ret, struct vnode **tvp_ret)
{
	int error;

	KASSERT(mp != NULL);
	KASSERT(fdvp != NULL);
	KASSERT(fcnp != NULL);
	KASSERT(fvp_ret != NULL);
	KASSERT(tdvp != NULL);
	KASSERT(tcnp != NULL);
	KASSERT(tvp_ret != NULL);
	KASSERT(fvp_ret != tvp_ret);
	KASSERT(fdvp->v_type == VDIR);
	KASSERT(tdvp->v_type == VDIR);
	KASSERT(fdvp->v_mount == mp);
	KASSERT(tdvp->v_mount == mp);

	if (fdvp == tdvp)
		error = genfs_rename_enter_common(ops, mp, cred, fdvp,
		    fcnp, fde_ret, fvp_ret,
		    tcnp, tde_ret, tvp_ret);
	else
		error = genfs_rename_enter_separate(ops, mp, cred,
		    fdvp, fcnp, fde_ret, fvp_ret,
		    tdvp, tcnp, tde_ret, tvp_ret);

	if (error)
		return error;

	KASSERT(*fvp_ret != NULL);
	KASSERT(VOP_ISLOCKED(*fvp_ret) == LK_EXCLUSIVE);
	KASSERT((*tvp_ret == NULL) || (VOP_ISLOCKED(*tvp_ret) == LK_EXCLUSIVE));
	KASSERT(*fvp_ret != fdvp);
	KASSERT(*fvp_ret != tdvp);
	KASSERT(*tvp_ret != fdvp);
	KASSERT(*tvp_ret != tdvp);
	return 0;
}
示例#24
0
static int
unionfs_close(void *v)
{
	struct vop_close_args *ap = v;
	int		error;
	struct unionfs_node *unp;
	struct unionfs_node_status *unsp;
	kauth_cred_t   cred;
	struct vnode   *ovp;

	UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");

	KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
	unp = VTOUNIONFS(ap->a_vp);
	cred = ap->a_cred;

	unionfs_get_node_status(unp, &unsp);

	if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
#ifdef DIAGNOSTIC
		printf("unionfs_close: warning: open count is 0\n");
#endif
		if (unp->un_uppervp != NULLVP)
			ovp = unp->un_uppervp;
		else
			ovp = unp->un_lowervp;
	} else if (unsp->uns_upper_opencnt > 0)
		ovp = unp->un_uppervp;
	else
		ovp = unp->un_lowervp;

	error = VOP_CLOSE(ovp, ap->a_fflag, cred);

	if (error != 0)
		goto unionfs_close_abort;

	if (ovp == unp->un_uppervp) {
		unsp->uns_upper_opencnt--;
		if (unsp->uns_upper_opencnt == 0) {
			if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
				VOP_CLOSE(unp->un_lowervp, FREAD, cred);
				unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
				unsp->uns_lower_opencnt--;
			}
		}
	} else
		unsp->uns_lower_opencnt--;

unionfs_close_abort:
	unionfs_tryrem_node_status(unp, unsp);

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

	return (error);
}
示例#25
0
static int
tmpfs_fsync(struct vop_fsync_args *v)
{
	struct vnode *vp = v->a_vp;

	MPASS(VOP_ISLOCKED(vp));

	tmpfs_update(vp);

	return 0;
}
示例#26
0
/*
 * ulfs_gro_remove_check_permitted: Check whether a remove is permitted
 * given our credentials.
 */
static int
ulfs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred,
    struct vnode *dvp, struct vnode *vp)
{

	(void)mp;
	KASSERT(mp != NULL);
	KASSERT(dvp != NULL);
	KASSERT(vp != NULL);
	KASSERT(dvp != vp);
	KASSERT(dvp->v_type == VDIR);
	KASSERT(vp->v_type != VDIR);
	KASSERT(dvp->v_mount == mp);
	KASSERT(vp->v_mount == mp);
	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

	return genfs_ufslike_remove_check_permitted(cred,
	    dvp, VTOI(dvp)->i_mode, VTOI(dvp)->i_uid, vp, VTOI(vp)->i_uid);
}
示例#27
0
/*
 * ulfs_rmdired_p: Check whether the directory vp has been rmdired.
 *
 * vp must be locked and referenced.
 */
static bool
ulfs_rmdired_p(struct vnode *vp)
{

	KASSERT(vp != NULL);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	KASSERT(vp->v_type == VDIR);

	/* XXX Is this correct?  */
	return (VTOI(vp)->i_size == 0);
}
/*
 * udf_rmdired_p: check whether the directory vp has been rmdired.
 *
 * vp must be locked and referenced.
 */
static bool
udf_rmdired_p(struct vnode *vp)
{
	DPRINTF(CALL, ("udf_rmdired_p called\n"));

	KASSERT(vp != NULL);
	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	KASSERT(vp->v_type == VDIR);

	return (VTOI(vp)->i_flags & IN_DELETED);
}
示例#29
0
int
RUMP_VOP_ISLOCKED(struct vnode *vp)
{
	int error;

	rump_schedule();
	error = VOP_ISLOCKED(vp);
	rump_unschedule();

	return error;
}
int
ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off,
    int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l)
{
	struct iovec iov;
	struct uio uio;
	int error;

	KASSERT(ISSET(ioflg, IO_NODELOCKED));
	KASSERT(VOP_ISLOCKED(vp));
	KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

	iov.iov_base = buf;
	iov.iov_len = len;
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;
	uio.uio_resid = len;
	uio.uio_offset = off;
	uio.uio_rw = rw;
	UIO_SETUP_SYSSPACE(&uio);

	switch (rw) {
	case UIO_READ:
		error = lfs_bufrd(vp, &uio, ioflg, cred);
		break;
	case UIO_WRITE:
		error = lfs_bufwr(vp, &uio, ioflg, cred);
		break;
	default:
		panic("invalid uio rw: %d", (int)rw);
	}

	if (aresid)
		*aresid = uio.uio_resid;
	else if (uio.uio_resid && error == 0)
		error = EIO;

	KASSERT(VOP_ISLOCKED(vp));
	KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
	return error;
}