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 + -
显示快捷键?