ufs_vnops.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,066 行 · 第 1/4 页

C
2,066
字号
/*	$NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $	*//* * Copyright (c) 1982, 1986, 1989, 1993 *	The Regents of the University of California.  All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)ufs_vnops.c	8.14 (Berkeley) 10/26/94 */#include <sys/param.h>#include <sys/systm.h>#include <sys/namei.h>#include <sys/resourcevar.h>#include <sys/kernel.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/buf.h>#include <sys/proc.h>#include <sys/conf.h>#include <sys/mount.h>#include <sys/vnode.h>#include <sys/malloc.h>#include <sys/dirent.h>#include <sys/lockf.h>#include <vm/vm.h>#include <miscfs/specfs/specdev.h>#include <miscfs/fifofs/fifo.h>#include <ufs/ufs/quota.h>#include <ufs/ufs/inode.h>#include <ufs/ufs/dir.h>#include <ufs/ufs/ufsmount.h>#include <ufs/ufs/ufs_extern.h>static int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *));static int ufs_chown	__P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *));union _qcvt {	int64_t	qcvt;	int32_t val[2];};#define SETHIGH(q, h) { \	union _qcvt tmp; \	tmp.qcvt = (q); \	tmp.val[_QUAD_HIGHWORD] = (h); \	(q) = tmp.qcvt; \}#define SETLOW(q, l) { \	union _qcvt tmp; \	tmp.qcvt = (q); \	tmp.val[_QUAD_LOWWORD] = (l); \	(q) = tmp.qcvt; \}/* * Create a regular file */intufs_create(v)	void *v;{	struct vop_create_args /* {		struct vnode *a_dvp;		struct vnode **a_vpp;		struct componentname *a_cnp;		struct vattr *a_vap;	} */ *ap = v;	return	    ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),			  ap->a_dvp, ap->a_vpp, ap->a_cnp);}/* * Mknod vnode call *//* ARGSUSED */intufs_mknod(v)	void *v;{	struct vop_mknod_args /* {		struct vnode *a_dvp;		struct vnode **a_vpp;		struct componentname *a_cnp;		struct vattr *a_vap;	} */ *ap = v;	register struct vattr *vap = ap->a_vap;	register struct vnode **vpp = ap->a_vpp;	register struct inode *ip;	int error;	if ((error =	    ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),	    ap->a_dvp, vpp, ap->a_cnp)) != 0)		return (error);	ip = VTOI(*vpp);	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;	if (vap->va_rdev != VNOVAL) {		/*		 * Want to be able to use this to make badblock		 * inodes, so don't truncate the dev number.		 */		ip->i_rdev = vap->va_rdev;	}	/*	 * Remove inode so that it will be reloaded by VFS_VGET and	 * checked to see if it is an alias of an existing entry in	 * the inode cache.	 */	vput(*vpp);	(*vpp)->v_type = VNON;	vgone(*vpp);	*vpp = 0;	return (0);}/* * Open called. * * Nothing to do. *//* ARGSUSED */intufs_open(v)	void *v;{	struct vop_open_args /* {		struct vnode *a_vp;		int  a_mode;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap = v;	/*	 * Files marked append-only must be opened for appending.	 */	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)		return (EPERM);	return (0);}/* * Close called. * * Update the times on the inode. *//* ARGSUSED */intufs_close(v)	void *v;{	struct vop_close_args /* {		struct vnode *a_vp;		int  a_fflag;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap = v;	register struct vnode *vp = ap->a_vp;	register struct inode *ip = VTOI(vp);	if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))		ITIMES(ip, &time, &time);	return (0);}intufs_access(v)	void *v;{	struct vop_access_args /* {		struct vnode *a_vp;		int  a_mode;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap = v;	register struct vnode *vp = ap->a_vp;	register struct inode *ip = VTOI(vp);	mode_t mode = ap->a_mode;#ifdef DIAGNOSTIC	if (!VOP_ISLOCKED(vp)) {		vprint("ufs_access: not locked", vp);		panic("ufs_access: not locked");	}#endif#ifdef QUOTA	if (mode & VWRITE)		switch (vp->v_type) {			int error;		case VDIR:		case VLNK:		case VREG:			if ((error = getinoquota(ip)) != 0)				return (error);			break;		case VBAD:		case VBLK:		case VCHR:		case VSOCK:		case VFIFO:		case VNON:			break;		}#endif	/* If immutable bit set, nobody gets to write it. */	if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))		return (EPERM);	return (vaccess(ip->i_mode, ip->i_uid, ip->i_gid, mode, ap->a_cred));}/* ARGSUSED */intufs_getattr(v)	void *v;{	struct vop_getattr_args /* {		struct vnode *a_vp;		struct vattr *a_vap;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap = v;	register struct vnode *vp = ap->a_vp;	register struct inode *ip = VTOI(vp);	register struct vattr *vap = ap->a_vap;	ITIMES(ip, &time, &time);	/*	 * Copy from inode table	 */	vap->va_fsid = ip->i_dev;	vap->va_fileid = ip->i_number;	vap->va_mode = ip->i_mode & ~IFMT;	vap->va_nlink = ip->i_nlink;	vap->va_uid = ip->i_uid;	vap->va_gid = ip->i_gid;	vap->va_rdev = (dev_t)ip->i_rdev;	vap->va_size = ip->i_din.di_size;	vap->va_atime.tv_sec = ip->i_atime;	vap->va_atime.tv_nsec = ip->i_atimensec;	vap->va_mtime.tv_sec = ip->i_mtime;	vap->va_mtime.tv_nsec = ip->i_mtimensec;	vap->va_ctime.tv_sec = ip->i_ctime;	vap->va_ctime.tv_nsec = ip->i_ctimensec;	vap->va_flags = ip->i_flags;	vap->va_gen = ip->i_gen;	/* this doesn't belong here */	if (vp->v_type == VBLK)		vap->va_blocksize = BLKDEV_IOSIZE;	else if (vp->v_type == VCHR)		vap->va_blocksize = MAXBSIZE;	else		vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;	vap->va_bytes = dbtob(ip->i_blocks);	vap->va_type = vp->v_type;	vap->va_filerev = ip->i_modrev;	return (0);}/* * Set attribute vnode op. called from several syscalls */intufs_setattr(v)	void *v;{	struct vop_setattr_args /* {		struct vnode *a_vp;		struct vattr *a_vap;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap = v;	register struct vattr *vap = ap->a_vap;	register struct vnode *vp = ap->a_vp;	register struct inode *ip = VTOI(vp);	register struct ucred *cred = ap->a_cred;	register struct proc *p = ap->a_p;	int error;	/*	 * Check for unsettable attributes.	 */	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {		return (EINVAL);	}	if (vap->va_flags != VNOVAL) {		if (cred->cr_uid != ip->i_uid &&		    (error = suser(cred, &p->p_acflag)))			return (error);		if (cred->cr_uid == 0) {			if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&			    securelevel > 0)				return (EPERM);			ip->i_flags = vap->va_flags;		} else {			if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND))				return (EPERM);			ip->i_flags &= SF_SETTABLE;			ip->i_flags |= (vap->va_flags & UF_SETTABLE);		}		ip->i_flag |= IN_CHANGE;		if (vap->va_flags & (IMMUTABLE | APPEND))			return (0);	}	if (ip->i_flags & (IMMUTABLE | APPEND))		return (EPERM);	/*	 * Go through the fields and update iff not VNOVAL.	 */	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {		error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p);		if (error)			return (error);	}	if (vap->va_size != VNOVAL) {		if (vp->v_type == VDIR)			return (EISDIR);		error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p);		if (error)			return (error);	}	ip = VTOI(vp);	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {		if (cred->cr_uid != ip->i_uid &&		    (error = suser(cred, &p->p_acflag)) &&		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 		    (error = VOP_ACCESS(vp, VWRITE, cred, p))))			return (error);		if (vap->va_atime.tv_sec != VNOVAL)			ip->i_flag |= IN_ACCESS;		if (vap->va_mtime.tv_sec != VNOVAL)			ip->i_flag |= IN_CHANGE | IN_UPDATE;		error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 1);		if (error)			return (error);	}	error = 0;	if (vap->va_mode != (mode_t)VNOVAL)		error = ufs_chmod(vp, (int)vap->va_mode, cred, p);	return (error);}/* * Change the mode on a file. * Inode must be locked before calling. */static intufs_chmod(vp, mode, cred, p)	register struct vnode *vp;	register int mode;	register struct ucred *cred;	struct proc *p;{	register struct inode *ip = VTOI(vp);	int error;	if (cred->cr_uid != ip->i_uid &&	    (error = suser(cred, &p->p_acflag)))		return (error);	if (cred->cr_uid) {		if (vp->v_type != VDIR && (mode & S_ISTXT))			return (EFTYPE);		if (!groupmember(ip->i_gid, cred) && (mode & ISGID))			return (EPERM);	}	ip->i_mode &= ~ALLPERMS;	ip->i_mode |= (mode & ALLPERMS);	ip->i_flag |= IN_CHANGE;	if ((vp->v_flag & VTEXT) && (ip->i_mode & S_ISTXT) == 0)		(void) vnode_pager_uncache(vp);	return (0);}/* * Perform chown operation on inode ip; * inode must be locked prior to call. */static intufs_chown(vp, uid, gid, cred, p)	register struct vnode *vp;	uid_t uid;	gid_t gid;	struct ucred *cred;	struct proc *p;{	register struct inode *ip = VTOI(vp);	uid_t ouid;	gid_t ogid;	int error = 0;#ifdef QUOTA	register int i;	long change;#endif	if (uid == (uid_t)VNOVAL)		uid = ip->i_uid;	if (gid == (gid_t)VNOVAL)		gid = ip->i_gid;	/*	 * If we don't own the file, are trying to change the owner	 * of the file, or are not a member of the target group,	 * the caller must be superuser or the call fails.	 */	if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||	    (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) &&	    (error = suser(cred, &p->p_acflag)))		return (error);	ogid = ip->i_gid;	ouid = ip->i_uid;#ifdef QUOTA	if ((error = getinoquota(ip)) != 0)		return (error);	if (ouid == uid) {		dqrele(vp, ip->i_dquot[USRQUOTA]);		ip->i_dquot[USRQUOTA] = NODQUOT;	}	if (ogid == gid) {		dqrele(vp, ip->i_dquot[GRPQUOTA]);		ip->i_dquot[GRPQUOTA] = NODQUOT;	}	change = ip->i_blocks;	(void) chkdq(ip, -change, cred, CHOWN);	(void) chkiq(ip, -1, cred, CHOWN);	for (i = 0; i < MAXQUOTAS; i++) {		dqrele(vp, ip->i_dquot[i]);		ip->i_dquot[i] = NODQUOT;	}#endif	ip->i_gid = gid;	ip->i_uid = uid;#ifdef QUOTA	if ((error = getinoquota(ip)) == 0) {		if (ouid == uid) {			dqrele(vp, ip->i_dquot[USRQUOTA]);			ip->i_dquot[USRQUOTA] = NODQUOT;		}		if (ogid == gid) {			dqrele(vp, ip->i_dquot[GRPQUOTA]);			ip->i_dquot[GRPQUOTA] = NODQUOT;		}		if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {			if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)				goto good;			else				(void) chkdq(ip, -change, cred, CHOWN|FORCE);		}		for (i = 0; i < MAXQUOTAS; i++) {			dqrele(vp, ip->i_dquot[i]);			ip->i_dquot[i] = NODQUOT;		}	}	ip->i_gid = ogid;	ip->i_uid = ouid;	if (getinoquota(ip) == 0) {		if (ouid == uid) {			dqrele(vp, ip->i_dquot[USRQUOTA]);			ip->i_dquot[USRQUOTA] = NODQUOT;		}		if (ogid == gid) {			dqrele(vp, ip->i_dquot[GRPQUOTA]);			ip->i_dquot[GRPQUOTA] = NODQUOT;		}		(void) chkdq(ip, change, cred, FORCE|CHOWN);		(void) chkiq(ip, 1, cred, FORCE|CHOWN);		(void) getinoquota(ip);	}	return (error);good:	if (getinoquota(ip))		panic("chown: lost quota");#endif /* QUOTA */	if (ouid != uid || ogid != gid)		ip->i_flag |= IN_CHANGE;	if (ouid != uid && cred->cr_uid != 0)		ip->i_mode &= ~ISUID;	if (ogid != gid && cred->cr_uid != 0)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?