fdesc_vnops.c

来自「早期freebsd实现」· C语言 代码 · 共 975 行 · 第 1/2 页

C
975
字号
/* * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * 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. * *	@(#)fdesc_vnops.c	8.9 (Berkeley) 1/21/94 * * $Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp $ *//* * /dev/fd Filesystem */#include <sys/param.h>#include <sys/systm.h>#include <sys/types.h>#include <sys/time.h>#include <sys/proc.h>#include <sys/kernel.h>	/* boottime */#include <sys/resourcevar.h>#include <sys/filedesc.h>#include <sys/vnode.h>#include <sys/malloc.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/mount.h>#include <sys/namei.h>#include <sys/buf.h>#include <sys/dirent.h>#include <miscfs/fdesc/fdesc.h>#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)#define FDL_WANT	0x01#define FDL_LOCKED	0x02static int fdcache_lock;dev_t devctty;#if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2#endif#define	NFDCACHE 3#define	FD_NHASH(ix) ((ix) & NFDCACHE)/* * Cache head */struct fdcache {	struct fdescnode	*fc_forw;	struct fdescnode	*fc_back;};static struct fdcache fdcache[NFDCACHE];/* * Initialise cache headers */fdesc_init(){	struct fdcache *fc;	devctty = makedev(nchrdev, 0);	for (fc = fdcache; fc < fdcache + NFDCACHE; fc++)		fc->fc_forw = fc->fc_back = (struct fdescnode *) fc;}/* * Compute hash list for given target vnode */static struct fdcache *fdesc_hash(ix)	int ix;{	return (&fdcache[FD_NHASH(ix)]);}intfdesc_allocvp(ftype, ix, mp, vpp)	fdntype ftype;	int ix;	struct mount *mp;	struct vnode **vpp;{	struct fdcache *fc;	struct fdescnode *fd;	int error = 0;loop:	fc = fdesc_hash(ix);	for (fd = fc->fc_forw; fd != (struct fdescnode *) fc; fd = fd->fd_forw) {		if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {			if (vget(fd->fd_vnode, 0))				goto loop;			*vpp = fd->fd_vnode;			return (error);		}	}	/*	 * otherwise lock the array while we call getnewvnode	 * since that can block.	 */ 	if (fdcache_lock & FDL_LOCKED) {		fdcache_lock |= FDL_WANT;		sleep((caddr_t) &fdcache_lock, PINOD);		goto loop;	}	fdcache_lock |= FDL_LOCKED;	error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);	if (error)		goto out;	MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);	(*vpp)->v_data = fd;	fd->fd_vnode = *vpp;	fd->fd_type = ftype;	fd->fd_fd = -1;	fd->fd_link = 0;	fd->fd_ix = ix;	fc = fdesc_hash(ix);	insque(fd, fc);out:;	fdcache_lock &= ~FDL_LOCKED;	if (fdcache_lock & FDL_WANT) {		fdcache_lock &= ~FDL_WANT;		wakeup((caddr_t) &fdcache_lock);	}	return (error);}/* * vp is the current namei directory * ndp is the name to locate in that directory... */intfdesc_lookup(ap)	struct vop_lookup_args /* {		struct vnode * a_dvp;		struct vnode ** a_vpp;		struct componentname * a_cnp;	} */ *ap;{	struct vnode **vpp = ap->a_vpp;	struct vnode *dvp = ap->a_dvp;	char *pname;	struct proc *p;	int nfiles;	unsigned fd;	int error;	struct vnode *fvp;	char *ln;	pname = ap->a_cnp->cn_nameptr;	if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {		*vpp = dvp;		VREF(dvp);			VOP_LOCK(dvp);		return (0);	}	p = ap->a_cnp->cn_proc;	nfiles = p->p_fd->fd_nfiles;	switch (VTOFDESC(dvp)->fd_type) {	default:	case Flink:	case Fdesc:	case Fctty:		error = ENOTDIR;		goto bad;	case Froot:		if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {			error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);			if (error)				goto bad;			*vpp = fvp;			fvp->v_type = VDIR;			VOP_LOCK(fvp);			return (0);		}		if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {			struct vnode *ttyvp = cttyvp(p);			if (ttyvp == NULL) {				error = ENXIO;				goto bad;			}			error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);			if (error)				goto bad;			*vpp = fvp;			fvp->v_type = VFIFO;			VOP_LOCK(fvp);			return (0);		}		ln = 0;		switch (ap->a_cnp->cn_namelen) {		case 5:			if (bcmp(pname, "stdin", 5) == 0) {				ln = "fd/0";				fd = FD_STDIN;			}			break;		case 6:			if (bcmp(pname, "stdout", 6) == 0) {				ln = "fd/1";				fd = FD_STDOUT;			} else			if (bcmp(pname, "stderr", 6) == 0) {				ln = "fd/2";				fd = FD_STDERR;			}			break;		}		if (ln) {			error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);			if (error)				goto bad;			VTOFDESC(fvp)->fd_link = ln;			*vpp = fvp;			fvp->v_type = VLNK;			VOP_LOCK(fvp);			return (0);		} else {			error = ENOENT;			goto bad;		}		/* FALL THROUGH */	case Fdevfd:		if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {			error = fdesc_root(dvp->v_mount, vpp);			return (error);		}		fd = 0;		while (*pname >= '0' && *pname <= '9') {			fd = 10 * fd + *pname++ - '0';			if (fd >= nfiles)				break;		}		if (*pname != '\0') {			error = ENOENT;			goto bad;		}		if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) {			error = EBADF;			goto bad;		}		error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);		if (error)			goto bad;		VTOFDESC(fvp)->fd_fd = fd;		*vpp = fvp;		return (0);	}bad:;	*vpp = NULL;	return (error);}intfdesc_open(ap)	struct vop_open_args /* {		struct vnode *a_vp;		int  a_mode;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct vnode *vp = ap->a_vp;	int error = 0;	switch (VTOFDESC(vp)->fd_type) {	case Fdesc:		/*		 * XXX Kludge: set p->p_dupfd to contain the value of the		 * the file descriptor being sought for duplication. The error 		 * return ensures that the vnode for this device will be		 * released by vn_open. Open will detect this special error and		 * take the actions in dupfdopen.  Other callers of vn_open or		 * VOP_OPEN will simply report the error.		 */		ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd;	/* XXX */		error = ENODEV;		break;	case Fctty:		error = cttyopen(devctty, ap->a_mode, 0, ap->a_p);		break;	}	return (error);}static intfdesc_attr(fd, vap, cred, p)	int fd;	struct vattr *vap;	struct ucred *cred;	struct proc *p;{	struct filedesc *fdp = p->p_fd;	struct file *fp;	struct stat stb;	int error;	if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)		return (EBADF);	switch (fp->f_type) {	case DTYPE_VNODE:		error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);		if (error == 0 && vap->va_type == VDIR) {			/*			 * don't allow directories to show up because			 * that causes loops in the namespace.			 */			vap->va_type = VFIFO;		}		break;	case DTYPE_SOCKET:		error = soo_stat((struct socket *)fp->f_data, &stb);		if (error == 0) {			vattr_null(vap);			vap->va_type = VSOCK;			vap->va_mode = stb.st_mode;			vap->va_nlink = stb.st_nlink;			vap->va_uid = stb.st_uid;			vap->va_gid = stb.st_gid;			vap->va_fsid = stb.st_dev;			vap->va_fileid = stb.st_ino;			vap->va_size = stb.st_size;			vap->va_blocksize = stb.st_blksize;			vap->va_atime = stb.st_atimespec;			vap->va_mtime = stb.st_mtimespec;			vap->va_ctime = stb.st_ctimespec;			vap->va_gen = stb.st_gen;			vap->va_flags = stb.st_flags;			vap->va_rdev = stb.st_rdev;			vap->va_bytes = stb.st_blocks * stb.st_blksize;		}		break;	default:		panic("fdesc attr");		break;	}	return (error);}intfdesc_getattr(ap)	struct vop_getattr_args /* {		struct vnode *a_vp;		struct vattr *a_vap;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct vnode *vp = ap->a_vp;	struct vattr *vap = ap->a_vap;	unsigned fd;	int error = 0;	switch (VTOFDESC(vp)->fd_type) {	case Froot:	case Fdevfd:	case Flink:	case Fctty:		bzero((caddr_t) vap, sizeof(*vap));		vattr_null(vap);		vap->va_fileid = VTOFDESC(vp)->fd_ix;		switch (VTOFDESC(vp)->fd_type) {		case Flink:			vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;			vap->va_type = VLNK;			vap->va_nlink = 1;			vap->va_size = strlen(VTOFDESC(vp)->fd_link);			break;		case Fctty:			vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;			vap->va_type = VFIFO;			vap->va_nlink = 1;			vap->va_size = 0;			break;		default:			vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;			vap->va_type = VDIR;			vap->va_nlink = 2;			vap->va_size = DEV_BSIZE;			break;		}		vap->va_uid = 0;		vap->va_gid = 0;		vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];		vap->va_blocksize = DEV_BSIZE;		vap->va_atime.ts_sec = boottime.tv_sec;		vap->va_atime.ts_nsec = 0;		vap->va_mtime = vap->va_atime;		vap->va_ctime = vap->va_mtime;		vap->va_gen = 0;		vap->va_flags = 0;		vap->va_rdev = 0;		vap->va_bytes = 0;		break;	case Fdesc:		fd = VTOFDESC(vp)->fd_fd;		error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);		break;	default:		panic("fdesc_getattr");		break;		}	if (error == 0)		vp->v_type = vap->va_type;	return (error);}intfdesc_setattr(ap)	struct vop_setattr_args /* {		struct vnode *a_vp;		struct vattr *a_vap;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct filedesc *fdp = ap->a_p->p_fd;	struct file *fp;	unsigned fd;	int error;

⌨️ 快捷键说明

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