vfs_syscalls.c

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

C
2,115
字号
	vput(vp);	return (error);}/* * Set the access and modification times given a file descriptor. *//* ARGSUSED */intsys_futimes(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_futimes_args /* {		syscallarg(int) fd;		syscallarg(struct timeval *) tptr;	} */ *uap = v;	register struct vnode *vp;	struct timeval tv[2];	struct vattr vattr;	int error;	struct file *fp;	VATTR_NULL(&vattr);	if (SCARG(uap, tptr) == NULL) {		microtime(&tv[0]);		tv[1] = tv[0];		vattr.va_vaflags |= VA_UTIMES_NULL;	} else {		error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,			       sizeof (tv));		if (error)			return (error);	}	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)		return (error);	vp = (struct vnode *)fp->f_data;	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);	VOP_LOCK(vp);	if (vp->v_mount->mnt_flag & MNT_RDONLY)		error = EROFS;	else {		vattr.va_atime.tv_sec = tv[0].tv_sec;		vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;		vattr.va_mtime.tv_sec = tv[1].tv_sec;		vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);	}	VOP_UNLOCK(vp);	return (error);}/* * Truncate a file given its path name. *//* ARGSUSED */intsys_truncate(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_truncate_args /* {		syscallarg(char *) path;		syscallarg(int) pad;		syscallarg(off_t) length;	} */ *uap = v;	register struct vnode *vp;	struct vattr vattr;	int error;	struct nameidata nd;	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);	if ((error = namei(&nd)) != 0)		return (error);	vp = nd.ni_vp;	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);	VOP_LOCK(vp);	if (vp->v_type == VDIR)		error = EISDIR;	else if ((error = vn_writechk(vp)) == 0 &&	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {		VATTR_NULL(&vattr);		vattr.va_size = SCARG(uap, length);		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);	}	vput(vp);	return (error);}/* * Truncate a file given a file descriptor. *//* ARGSUSED */intsys_ftruncate(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_ftruncate_args /* {		syscallarg(int) fd;		syscallarg(int) pad;		syscallarg(off_t) length;	} */ *uap = v;	struct vattr vattr;	struct vnode *vp;	struct file *fp;	int error;	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)		return (error);	if ((fp->f_flag & FWRITE) == 0)		return (EINVAL);	vp = (struct vnode *)fp->f_data;	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);	VOP_LOCK(vp);	if (vp->v_type == VDIR)		error = EISDIR;	else if ((error = vn_writechk(vp)) == 0) {		VATTR_NULL(&vattr);		vattr.va_size = SCARG(uap, length);		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);	}	VOP_UNLOCK(vp);	return (error);}/* * Sync an open file. *//* ARGSUSED */intsys_fsync(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	struct sys_fsync_args /* {		syscallarg(int) fd;	} */ *uap = v;	register struct vnode *vp;	struct file *fp;	int error;	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)		return (error);	vp = (struct vnode *)fp->f_data;	VOP_LOCK(vp);	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);	VOP_UNLOCK(vp);	return (error);}/* * Rename files.  Source and destination must either both be directories, * or both not be directories.  If target is a directory, it must be empty. *//* ARGSUSED */intsys_rename(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_rename_args /* {		syscallarg(char *) from;		syscallarg(char *) to;	} */ *uap = v;	register struct vnode *tvp, *fvp, *tdvp;	struct nameidata fromnd, tond;	int error;	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,	    SCARG(uap, from), p);	if ((error = namei(&fromnd)) != 0)		return (error);	fvp = fromnd.ni_vp;	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,	    UIO_USERSPACE, SCARG(uap, to), p);	if ((error = namei(&tond)) != 0) {		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);		vrele(fromnd.ni_dvp);		vrele(fvp);		goto out1;	}	tdvp = tond.ni_dvp;	tvp = tond.ni_vp;	if (tvp != NULL) {		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {			error = ENOTDIR;			goto out;		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {			error = EISDIR;			goto out;		}	}	if (fvp == tdvp)		error = EINVAL;	/*	 * If source is the same as the destination (that is the	 * same inode number with the same name in the same directory),	 * then there is nothing to do.	 */	if (fvp == tvp && fromnd.ni_dvp == tdvp &&	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,	      fromnd.ni_cnd.cn_namelen))		error = -1;out:	if (!error) {		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);		if (fromnd.ni_dvp != tdvp)			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);		if (tvp)			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);	} else {		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);		if (tdvp == tvp)			vrele(tdvp);		else			vput(tdvp);		if (tvp)			vput(tvp);		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);		vrele(fromnd.ni_dvp);		vrele(fvp);	}	vrele(tond.ni_startdir);	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);out1:	if (fromnd.ni_startdir)		vrele(fromnd.ni_startdir);	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);	if (error == -1)		return (0);	return (error);}/* * Make a directory file. *//* ARGSUSED */intsys_mkdir(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_mkdir_args /* {		syscallarg(char *) path;		syscallarg(int) mode;	} */ *uap = v;	register struct vnode *vp;	struct vattr vattr;	int error;	struct nameidata nd;	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);	if ((error = namei(&nd)) != 0)		return (error);	vp = nd.ni_vp;	if (vp != NULL) {		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);		if (nd.ni_dvp == vp)			vrele(nd.ni_dvp);		else			vput(nd.ni_dvp);		vrele(vp);		return (EEXIST);	}	VATTR_NULL(&vattr);	vattr.va_type = VDIR;	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);	if (!error)		vput(nd.ni_vp);	return (error);}/* * Remove a directory file. *//* ARGSUSED */intsys_rmdir(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	struct sys_rmdir_args /* {		syscallarg(char *) path;	} */ *uap = v;	register struct vnode *vp;	int error;	struct nameidata nd;	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,	    SCARG(uap, path), p);	if ((error = namei(&nd)) != 0)		return (error);	vp = nd.ni_vp;	if (vp->v_type != VDIR) {		error = ENOTDIR;		goto out;	}	/*	 * No rmdir "." please.	 */	if (nd.ni_dvp == vp) {		error = EINVAL;		goto out;	}	/*	 * The root of a mounted filesystem cannot be deleted.	 */	if (vp->v_flag & VROOT)		error = EBUSY;out:	if (!error) {		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);	} else {		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);		if (nd.ni_dvp == vp)			vrele(nd.ni_dvp);		else			vput(nd.ni_dvp);		vput(vp);	}	return (error);}/* * Read a block of directory entries in a file system independent format. */intsys_getdirentries(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_getdirentries_args /* {		syscallarg(int) fd;		syscallarg(char *) buf;		syscallarg(u_int) count;		syscallarg(long *) basep;	} */ *uap = v;	register struct vnode *vp;	struct file *fp;	struct uio auio;	struct iovec aiov;	long loff;	int error, eofflag;	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)		return (error);	if ((fp->f_flag & FREAD) == 0)		return (EBADF);	vp = (struct vnode *)fp->f_data;unionread:	if (vp->v_type != VDIR)		return (EINVAL);	aiov.iov_base = SCARG(uap, buf);	aiov.iov_len = SCARG(uap, count);	auio.uio_iov = &aiov;	auio.uio_iovcnt = 1;	auio.uio_rw = UIO_READ;	auio.uio_segflg = UIO_USERSPACE;	auio.uio_procp = p;	auio.uio_resid = SCARG(uap, count);	VOP_LOCK(vp);	loff = auio.uio_offset = fp->f_offset;	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);	fp->f_offset = auio.uio_offset;	VOP_UNLOCK(vp);	if (error)		return (error);#ifdef UNION{	extern int (**union_vnodeop_p) __P((void *));	extern struct vnode *union_dircache __P((struct vnode *));	if ((SCARG(uap, count) == auio.uio_resid) &&	    (vp->v_op == union_vnodeop_p)) {		struct vnode *lvp;		lvp = union_dircache(vp);		if (lvp != NULLVP) {			struct vattr va;			/*			 * If the directory is opaque,			 * then don't show lower entries			 */			error = VOP_GETATTR(vp, &va, fp->f_cred, p);			if (va.va_flags & OPAQUE) {				vput(lvp);				lvp = NULL;			}		}				if (lvp != NULLVP) {			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);			VOP_UNLOCK(lvp);			if (error) {				vrele(lvp);				return (error);			}			fp->f_data = (caddr_t) lvp;			fp->f_offset = 0;			error = vn_close(vp, FREAD, fp->f_cred, p);			if (error)				return (error);			vp = lvp;			goto unionread;		}	}}#endif /* UNION */	if ((SCARG(uap, count) == auio.uio_resid) &&	    (vp->v_flag & VROOT) &&	    (vp->v_mount->mnt_flag & MNT_UNION)) {		struct vnode *tvp = vp;		vp = vp->v_mount->mnt_vnodecovered;		VREF(vp);		fp->f_data = (caddr_t) vp;		fp->f_offset = 0;		vrele(tvp);		goto unionread;	}	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),	    sizeof(long));	*retval = SCARG(uap, count) - auio.uio_resid;	return (error);}/* * Set the mode mask for creation of filesystem nodes. */intsys_umask(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	struct sys_umask_args /* {		syscallarg(int) newmask;	} */ *uap = v;	register struct filedesc *fdp;	fdp = p->p_fd;	*retval = fdp->fd_cmask;	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;	return (0);}/* * Void all references to file by ripping underlying filesystem * away from vnode. *//* ARGSUSED */intsys_revoke(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	register struct sys_revoke_args /* {		syscallarg(char *) path;	} */ *uap = v;	register struct vnode *vp;	struct vattr vattr;	int error;	struct nameidata nd;	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);	if ((error = namei(&nd)) != 0)		return (error);	vp = nd.ni_vp;	if (vp->v_type != VCHR && vp->v_type != VBLK) {		error = EINVAL;		goto out;	}	if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)		goto out;	if (p->p_ucred->cr_uid != vattr.va_uid &&	    (error = suser(p->p_ucred, &p->p_acflag)))		goto out;	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))		vgoneall(vp);out:	vrele(vp);	return (error);}/* * Convert a user file descriptor to a kernel file entry. */intgetvnode(fdp, fd, fpp)	struct filedesc *fdp;	int fd;	struct file **fpp;{	struct vnode *vp;	struct file *fp;	if ((u_int)fd >= fdp->fd_nfiles ||	    (fp = fdp->fd_ofiles[fd]) == NULL)		return (EBADF);	if (fp->f_type != DTYPE_VNODE)		return (EINVAL);	vp = (struct vnode *)fp->f_data;	if (vp->v_type == VBAD)		return (EBADF);	*fpp = fp;	return (0);}

⌨️ 快捷键说明

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