📄 vfs_syscalls.c
字号:
struct chown_args { char *path; int uid; int gid;};/* ARGSUSED */chown(p, uap, retval) struct proc *p; register struct chown_args *uap; int *retval;{ register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else { VATTR_NULL(&vattr); vattr.va_uid = uap->uid; vattr.va_gid = uap->gid; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); return (error);}/* * Set ownership given a file descriptor. */struct fchown_args { int fd; int uid; int gid;};/* ARGSUSED */fchown(p, uap, retval) struct proc *p; register struct fchown_args *uap; int *retval;{ struct vattr vattr; struct vnode *vp; struct file *fp; int error; if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); vp = (struct vnode *)fp->f_data; LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else { VATTR_NULL(&vattr); vattr.va_uid = uap->uid; vattr.va_gid = uap->gid; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } VOP_UNLOCK(vp); return (error);}/* * Set the access and modification times of a file. */struct utimes_args { char *path; struct timeval *tptr;};/* ARGSUSED */utimes(p, uap, retval) struct proc *p; register struct utimes_args *uap; int *retval;{ register struct vnode *vp; struct timeval tv[2]; struct vattr vattr; int error; struct nameidata nd; VATTR_NULL(&vattr); if (uap->tptr == NULL) { microtime(&tv[0]); tv[1] = tv[0]; vattr.va_vaflags |= VA_UTIMES_NULL; } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) return (error); NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else { vattr.va_atime.ts_sec = tv[0].tv_sec; vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; vattr.va_mtime.ts_sec = tv[1].tv_sec; vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); return (error);}/* * Truncate a file given its path name. */struct truncate_args { char *path; int pad; off_t length;};/* ARGSUSED */truncate(p, uap, retval) struct proc *p; register struct truncate_args *uap; int *retval;{ register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; LEASE_CHECK(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 = uap->length; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); return (error);}/* * Truncate a file given a file descriptor. */struct ftruncate_args { int fd; int pad; off_t length;};/* ARGSUSED */ftruncate(p, uap, retval) struct proc *p; register struct ftruncate_args *uap; int *retval;{ struct vattr vattr; struct vnode *vp; struct file *fp; int error; if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); if ((fp->f_flag & FWRITE) == 0) return (EINVAL); vp = (struct vnode *)fp->f_data; LEASE_CHECK(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 = uap->length; error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); } VOP_UNLOCK(vp); return (error);}#if defined(COMPAT_43) || defined(COMPAT_SUNOS)/* * Truncate a file given its path name. */struct otruncate_args { char *path; long length;};/* ARGSUSED */otruncate(p, uap, retval) struct proc *p; register struct otruncate_args *uap; int *retval;{ struct truncate_args nuap; nuap.path = uap->path; nuap.length = uap->length; return (truncate(p, &nuap, retval));}/* * Truncate a file given a file descriptor. */struct oftruncate_args { int fd; long length;};/* ARGSUSED */oftruncate(p, uap, retval) struct proc *p; register struct oftruncate_args *uap; int *retval;{ struct ftruncate_args nuap; nuap.fd = uap->fd; nuap.length = uap->length; return (ftruncate(p, &nuap, retval));}#endif /* COMPAT_43 || COMPAT_SUNOS *//* * Sync an open file. */struct fsync_args { int fd;};/* ARGSUSED */fsync(p, uap, retval) struct proc *p; struct fsync_args *uap; int *retval;{ register struct vnode *vp; struct file *fp; int error; if (error = getvnode(p->p_fd, uap->fd, &fp)) 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. */struct rename_args { char *from; char *to;};/* ARGSUSED */rename(p, uap, retval) struct proc *p; register struct rename_args *uap; int *retval;{ register struct vnode *tvp, *fvp, *tdvp; struct nameidata fromnd, tond; int error; NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, uap->from, p); if (error = namei(&fromnd)) return (error); fvp = fromnd.ni_vp; NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, UIO_USERSPACE, uap->to, p); if (error = namei(&tond)) { 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) { LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); if (fromnd.ni_dvp != tdvp) LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); if (tvp) LEASE_CHECK(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. */struct mkdir_args { char *path; int mode;};/* ARGSUSED */mkdir(p, uap, retval) struct proc *p; register struct mkdir_args *uap; int *retval;{ register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) 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 = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; LEASE_CHECK(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. */struct rmdir_args { char *path;};/* ARGSUSED */rmdir(p, uap, retval) struct proc *p; struct rmdir_args *uap; int *retval;{ register struct vnode *vp; int error; struct nameidata nd; NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) 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) { LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); LEASE_CHECK(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);}#ifdef COMPAT_43/* * Read a block of directory entries in a file system independent format. */struct ogetdirentries_args { int fd; char *buf; u_int count; long *basep;};ogetdirentries(p, uap, retval) struct proc *p; register struct ogetdirentries_args *uap; int *retval;{ register struct vnode *vp; struct file *fp; struct uio auio, kuio; struct iovec aiov, kiov; struct dirent *dp, *edp; caddr_t dirbuf; int error, readcnt; long loff; if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); if ((fp->f_flag & FREAD) == 0) return (EBADF); vp = (struct vnode *)fp->f_data; if (vp->v_type != VDIR) return (EINVAL); aiov.iov_base = uap->buf; aiov.iov_len = 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 = uap->count; VOP_LOCK(vp); loff = auio.uio_offset = fp->f_offset;# if (BYTE_ORDER != LITTLE_ENDIAN) if (vp->v_mount->mnt_maxsymlinklen <= 0) { error = VOP_READDIR(vp, &auio, fp->f_cred); fp->f_offset = auio.uio_offset; } else# endif { kuio = auio; kuio.uio_iov = &kiov; kuio.uio_segflg = UIO_SYSSPACE; kiov.iov_len = uap->count; MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); kiov.iov_base = dirbuf; error = VOP_READDIR(vp, &kuio, fp->f_cred); fp->f_offset = kuio.uio_offset; if (error == 0) { readcnt = uap->count - kuio.uio_resid; edp = (struct dirent *)&dirbuf[readcnt]; for (dp = (struct dirent *)dirbuf; dp < edp; ) {# if (BYTE_ORDER == LITTLE_ENDIAN) /* * The expected low byte of * dp->d_namlen is our dp->d_type. * The high MBZ byte of dp->d_namlen * is our dp->d_namlen. */ dp->d_type = dp->d_namlen; dp->d_namlen = 0;# else /* * The dp->d_type is the high byte * of the expected dp->d_namlen, * so must be zero'ed. */ dp->d_type = 0;# endif if (dp->d_reclen > 0) { dp = (struct dirent *) ((char *)dp + dp->d_reclen); } else { error = EIO; break; } } if (dp >= edp) error = uiomove(dirbuf, readcnt, &auio); } FREE(dirbuf, M_TEMP); } VOP_UNLOCK(vp); if (error) return (error); error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); *retval = uap->count - auio.uio_resid; return (error);}#endif/* * Read a block of directory entries in a file system independent format. */struct getdirentries_args { int fd; char *buf; u_int count; long *basep;};getdirentries(p, uap, retval) struct proc *p; register struct getdirentries_args *uap; int *retval;{ register struct vnode *vp; struct file *fp; struct uio auio; struct iovec aiov; long loff; int error; if (error = getvnode(p->p_fd, uap->fd, &fp)) 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 = uap->buf; aiov.iov_len = 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 = uap->count; VOP_LOCK(vp); loff = auio.uio_offset = fp->f_offset; error = VOP_READDIR(vp, &auio, fp->f_cred); fp->f_offset = auio.uio_offset; VOP_UNLOCK(vp); if (error) return (error);#ifdef UNION{ extern int (**union_vnodeop_p)(); extern struct vnode *union_lowervp __P((struct vnode *)); if ((uap->count == auio.uio_resid) && (vp->v_op == union_vnodeop_p)) { struct vnode *tvp = vp; vp = union_lowervp(vp); if (vp != NULLVP) { VOP_LOCK(vp); error = VOP_OPEN(vp, FREAD); VOP_UNLOCK(vp); if (error) { vrele(vp); return (error); } fp->f_data = (caddr_t) vp; fp->f_offset = 0; error = vn_close(tvp, FREAD, fp->f_cred, p); if (error) return (error); goto unionread; } }}#endif if ((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)uap->basep, sizeof(long)); *retval = uap->count - auio.uio_resid; return (error);}/* * Set the mode mask for creation of filesystem nodes. */struct umask_args { int newmask;};mode_t /* XXX */umask(p, uap, retval) struct proc *p; struct umask_args *uap; int *retval;{ register struct filedesc *fdp; fdp = p->p_fd; *retval = fdp->fd_cmask; fdp->fd_cmask = uap->newmask & ALLPERMS; return (0);}/* * Void all references to file by ripping underlying filesystem * away from vnode. */struct revoke_args { char *path;};/* ARGSUSED */revoke(p, uap, retval) struct proc *p; register struct revoke_args *uap; int *retval;{ register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) 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)) 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. */getvnode(fdp, fd, fpp) struct filedesc *fdp; struct file **fpp; int fd;{ 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); *fpp = fp; return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -