X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ec54f0ccd696d01fc91f90190c10d52bf8cbb317..13f48dee70ec0b79753383e9734854a57464d8fa:/usr/src/sys/kern/vfs_syscalls.c diff --git a/usr/src/sys/kern/vfs_syscalls.c b/usr/src/sys/kern/vfs_syscalls.c index 422191252a..4063304af6 100644 --- a/usr/src/sys/kern/vfs_syscalls.c +++ b/usr/src/sys/kern/vfs_syscalls.c @@ -1,10 +1,15 @@ /* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 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. * * %sccs.include.redist.c% * - * @(#)vfs_syscalls.c 8.1 (Berkeley) %G% + * @(#)vfs_syscalls.c 8.28 (Berkeley) %G% */ #include @@ -24,6 +29,8 @@ #include #include +static int change_dir __P((struct nameidata *ndp, struct proc *p)); + #ifdef REF_DIAGNOSTIC #define CURCOUNT (curproc ? curproc->p_spare[0] : 0) #define CHECKPOINTREF int oldrefcount = CURCOUNT; @@ -39,11 +46,11 @@ */ /* - * Mount system call. + * Mount a file system. */ struct mount_args { int type; - char *dir; + char *path; int flags; caddr_t data; }; @@ -56,17 +63,13 @@ mount(p, uap, retval) register struct vnode *vp; register struct mount *mp; int error, flag; + struct vattr va; struct nameidata nd; - /* - * Must be super user - */ - if (error = suser(p->p_ucred, &p->p_acflag)) - return (error); /* * Get vnode to be covered */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; @@ -88,12 +91,49 @@ mount(p, uap, retval) } mp->mnt_flag |= uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); + /* + * Only root, or the user that did the original mount is + * permitted to update it. + */ + if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (uap->flags & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + uap->flags |= MNT_NOSUID | MNT_NODEV; + } VOP_UNLOCK(vp); goto update; } - if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) { + /* + * If the user is not root, ensure that they own the directory + * onto which we are attempting to mount. + */ + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || + (va.va_uid != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag)))) { vput(vp); - return (EBUSY); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (uap->flags & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + uap->flags |= MNT_NOSUID | MNT_NODEV; } if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) return (error); @@ -101,11 +141,14 @@ mount(p, uap, retval) vput(vp); return (ENOTDIR); } - if ((unsigned long)uap->type > MOUNT_MAXTYPE || - vfssw[uap->type] == (struct vfsops *)0) { + if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { vput(vp); return (ENODEV); } + if (vp->v_mountedhere != NULL) { + vput(vp); + return (EBUSY); + } /* * Allocate and initialize the file system. @@ -119,14 +162,9 @@ mount(p, uap, retval) vput(vp); return (error); } - if (vp->v_mountedhere != (struct mount *)0) { - vfs_unlock(mp); - free((caddr_t)mp, M_MOUNT); - vput(vp); - return (EBUSY); - } vp->v_mountedhere = mp; mp->mnt_vnodecovered = vp; + mp->mnt_stat.f_owner = p->p_ucred->cr_uid; update: /* * Set the mount level flags. @@ -135,14 +173,14 @@ update: mp->mnt_flag |= MNT_RDONLY; else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_flag |= MNT_WANTRDWR; - mp->mnt_flag &=~ - (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); - mp->mnt_flag |= uap->flags & - (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); + mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | + MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); + mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | + MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); /* * Mount the filesystem. */ - error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); + error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); if (mp->mnt_flag & MNT_UPDATE) { vrele(vp); if (mp->mnt_flag & MNT_WANTRDWR) @@ -156,17 +194,16 @@ update: /* * Put the new filesystem on the mount list after root. */ - mp->mnt_next = rootfs->mnt_next; - mp->mnt_prev = rootfs; - rootfs->mnt_next = mp; - mp->mnt_next->mnt_prev = mp; cache_purge(vp); if (!error) { + TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); + checkdirs(vp); VOP_UNLOCK(vp); vfs_unlock(mp); error = VFS_START(mp, 0, p); } else { - vfs_remove(mp); + mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; + vfs_unlock(mp); free((caddr_t)mp, M_MOUNT); vput(vp); } @@ -174,13 +211,50 @@ update: } /* - * Unmount system call. + * Scan all active processes to see if any of them have a current + * or root directory onto which the new filesystem has just been + * mounted. If so, replace them with the new mount point. + */ +checkdirs(olddp) + struct vnode *olddp; +{ + struct filedesc *fdp; + struct vnode *newdp; + struct proc *p; + + if (olddp->v_usecount == 1) + return; + if (VFS_ROOT(olddp->v_mountedhere, &newdp)) + panic("mount: lost mount"); + for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { + fdp = p->p_fd; + if (fdp->fd_cdir == olddp) { + vrele(fdp->fd_cdir); + VREF(newdp); + fdp->fd_cdir = newdp; + } + if (fdp->fd_rdir == olddp) { + vrele(fdp->fd_rdir); + VREF(newdp); + fdp->fd_rdir = newdp; + } + } + if (rootvnode == olddp) { + vrele(rootvnode); + VREF(newdp); + rootvnode = newdp; + } + vput(newdp); +} + +/* + * Unmount a file system. * * Note: unmount takes a path to the vnode mounted on as argument, * not special file (as before). */ struct unmount_args { - char *pathp; + char *path; int flags; }; /* ARGSUSED */ @@ -194,16 +268,22 @@ unmount(p, uap, retval) int error; struct nameidata nd; + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); + if (error = namei(&nd)) + return (error); + vp = nd.ni_vp; + mp = vp->v_mount; + /* - * Must be super user + * Only root, or the user that did the original mount is + * permitted to unmount this filesystem. */ - if (error = suser(p->p_ucred, &p->p_acflag)) + if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && + (error = suser(p->p_ucred, &p->p_acflag))) { + vput(vp); return (error); + } - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); - if (error = namei(&nd)) - return (error); - vp = nd.ni_vp; /* * Must be the root of the filesystem */ @@ -211,13 +291,12 @@ unmount(p, uap, retval) vput(vp); return (EINVAL); } - mp = vp->v_mount; vput(vp); return (dounmount(mp, uap->flags, p)); } /* - * Do an unmount. + * Do the actual file system unmount. */ dounmount(mp, flags, p) register struct mount *mp; @@ -234,6 +313,7 @@ dounmount(mp, flags, p) if (error = vfs_lock(mp)) return (error); + mp->mnt_flag &=~ MNT_ASYNC; vnode_pager_umount(mp); /* release cached vnodes */ cache_purgevfs(mp); /* remove cache entries for this file sys */ if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || @@ -245,8 +325,10 @@ dounmount(mp, flags, p) vfs_unlock(mp); } else { vrele(coveredvp); - vfs_remove(mp); - if (mp->mnt_mounth != NULL) + TAILQ_REMOVE(&mountlist, mp, mnt_list); + mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; + vfs_unlock(mp); + if (mp->mnt_vnodelist.lh_first != NULL) panic("unmount: dangling vnode"); free((caddr_t)mp, M_MOUNT); } @@ -254,10 +336,9 @@ dounmount(mp, flags, p) } /* - * Sync system call. * Sync each mounted filesystem. */ -#ifdef DIAGNOSTIC +#ifdef DEBUG int syncprt = 0; struct ctldebug debug0 = { "syncprt", &syncprt }; #endif @@ -271,24 +352,34 @@ sync(p, uap, retval) struct sync_args *uap; int *retval; { - register struct mount *mp; - struct mount *omp; + register struct mount *mp, *nmp; + int asyncflag; - mp = rootfs; - do { + for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { + /* + * Get the next pointer in case we hang on vfs_busy + * while we are being unmounted. + */ + nmp = mp->mnt_list.tqe_next; /* * The lock check below is to avoid races with mount * and unmount. */ if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && !vfs_busy(mp)) { + asyncflag = mp->mnt_flag & MNT_ASYNC; + mp->mnt_flag &= ~MNT_ASYNC; VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); - omp = mp; - mp = mp->mnt_next; - vfs_unbusy(omp); - } else - mp = mp->mnt_next; - } while (mp != rootfs); + if (asyncflag) + mp->mnt_flag |= MNT_ASYNC; + /* + * Get the next pointer again, as the next filesystem + * might have been unmounted while we were sync'ing. + */ + nmp = mp->mnt_list.tqe_next; + vfs_unbusy(mp); + } + } #ifdef DIAGNOSTIC if (syncprt) vfs_bufstats(); @@ -297,7 +388,7 @@ sync(p, uap, retval) } /* - * Operate on filesystem quotas. + * Change filesystem quotas. */ struct quotactl_args { char *path; @@ -394,16 +485,15 @@ getfsstat(p, uap, retval) register struct getfsstat_args *uap; int *retval; { - register struct mount *mp; + register struct mount *mp, *nmp; register struct statfs *sp; caddr_t sfsp; long count, maxcount, error; maxcount = uap->bufsize / sizeof(struct statfs); sfsp = (caddr_t)uap->buf; - mp = rootfs; - count = 0; - do { + for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { + nmp = mp->mnt_list.tqe_next; if (sfsp && count < maxcount && ((mp->mnt_flag & MNT_MLOCK) == 0)) { sp = &mp->mnt_stat; @@ -413,18 +503,15 @@ getfsstat(p, uap, retval) */ if (((uap->flags & MNT_NOWAIT) == 0 || (uap->flags & MNT_WAIT)) && - (error = VFS_STATFS(mp, sp, p))) { - mp = mp->mnt_prev; + (error = VFS_STATFS(mp, sp, p))) continue; - } sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) return (error); sfsp += sizeof(*sp); } count++; - mp = mp->mnt_prev; - } while (mp != rootfs); + } if (sfsp && count > maxcount) *retval = maxcount; else @@ -445,22 +532,36 @@ fchdir(p, uap, retval) int *retval; { register struct filedesc *fdp = p->p_fd; - register struct vnode *vp; + struct vnode *vp, *tdp; + struct mount *mp; struct file *fp; int error; if (error = getvnode(fdp, uap->fd, &fp)) return (error); vp = (struct vnode *)fp->f_data; + VREF(vp); VOP_LOCK(vp); if (vp->v_type != VDIR) error = ENOTDIR; else error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); + while (!error && (mp = vp->v_mountedhere) != NULL) { + if (mp->mnt_flag & MNT_MLOCK) { + mp->mnt_flag |= MNT_MWAIT; + sleep((caddr_t)mp, PVFS); + continue; + } + if (error = VFS_ROOT(mp, &tdp)) + break; + vput(vp); + vp = tdp; + } VOP_UNLOCK(vp); - if (error) + if (error) { + vrele(vp); return (error); - VREF(vp); + } vrele(fdp->fd_cdir); fdp->fd_cdir = vp; return (0); @@ -470,7 +571,7 @@ fchdir(p, uap, retval) * Change current working directory (``.''). */ struct chdir_args { - char *fname; + char *path; }; /* ARGSUSED */ chdir(p, uap, retval) @@ -482,8 +583,8 @@ chdir(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); - if (error = chdirec(&nd, p)) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); + if (error = change_dir(&nd, p)) return (error); vrele(fdp->fd_cdir); fdp->fd_cdir = nd.ni_vp; @@ -494,7 +595,7 @@ chdir(p, uap, retval) * Change notion of root (``/'') directory. */ struct chroot_args { - char *fname; + char *path; }; /* ARGSUSED */ chroot(p, uap, retval) @@ -508,8 +609,8 @@ chroot(p, uap, retval) if (error = suser(p->p_ucred, &p->p_acflag)) return (error); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); - if (error = chdirec(&nd, p)) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); + if (error = change_dir(&nd, p)) return (error); if (fdp->fd_rdir != NULL) vrele(fdp->fd_rdir); @@ -520,7 +621,8 @@ chroot(p, uap, retval) /* * Common routine for chroot and chdir. */ -chdirec(ndp, p) +static int +change_dir(ndp, p) register struct nameidata *ndp; struct proc *p; { @@ -541,14 +643,13 @@ chdirec(ndp, p) } /* - * Open system call. * Check permissions, allocate an open file structure, * and call the device open routine if any. */ struct open_args { - char *fname; + char *path; + int flags; int mode; - int crtmode; }; open(p, uap, retval) struct proc *p; @@ -558,7 +659,7 @@ open(p, uap, retval) register struct filedesc *fdp = p->p_fd; register struct file *fp; register struct vnode *vp; - int fmode, cmode; + int flags, cmode; struct file *nfp; int type, indx, error; struct flock lf; @@ -568,16 +669,16 @@ open(p, uap, retval) if (error = falloc(p, &nfp, &indx)) return (error); fp = nfp; - fmode = FFLAGS(uap->mode); - cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); + flags = FFLAGS(uap->flags); + cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); p->p_dupfd = -indx - 1; /* XXX check for fdopen */ - if (error = vn_open(&nd, fmode, cmode)) { + if (error = vn_open(&nd, flags, cmode)) { ffree(fp); if ((error == ENODEV || error == ENXIO) && p->p_dupfd >= 0 && /* XXX from fdopen */ - (error = dupfdopen(fdp, indx, p->p_dupfd, - fmode, error)) == 0) { + (error = + dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { *retval = indx; return (0); } @@ -588,28 +689,29 @@ open(p, uap, retval) } p->p_dupfd = 0; vp = nd.ni_vp; - fp->f_flag = fmode & FMASK; + fp->f_flag = flags & FMASK; fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; fp->f_data = (caddr_t)vp; - if (fmode & (O_EXLOCK | O_SHLOCK)) { + if (flags & (O_EXLOCK | O_SHLOCK)) { lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; - if (fmode & O_EXLOCK) + if (flags & O_EXLOCK) lf.l_type = F_WRLCK; else lf.l_type = F_RDLCK; type = F_FLOCK; - if ((fmode & FNONBLOCK) == 0) + if ((flags & FNONBLOCK) == 0) type |= F_WAIT; + VOP_UNLOCK(vp); if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { - VOP_UNLOCK(vp); (void) vn_close(vp, fp->f_flag, fp->f_cred, p); ffree(fp); fdp->fd_ofiles[indx] = NULL; return (error); } + VOP_LOCK(vp); fp->f_flag |= FHASLOCK; } VOP_UNLOCK(vp); @@ -619,11 +721,11 @@ open(p, uap, retval) #ifdef COMPAT_43 /* - * Creat system call. + * Create a file. */ struct ocreat_args { - char *fname; - int fmode; + char *path; + int mode; }; ocreat(p, uap, retval) struct proc *p; @@ -632,19 +734,19 @@ ocreat(p, uap, retval) { struct open_args openuap; - openuap.fname = uap->fname; - openuap.crtmode = uap->fmode; - openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; + openuap.path = uap->path; + openuap.mode = uap->mode; + openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; return (open(p, &openuap, retval)); } #endif /* COMPAT_43 */ /* - * Mknod system call. + * Create a special file. */ struct mknod_args { - char *fname; - int fmode; + char *path; + int mode; int dev; }; /* ARGSUSED */ @@ -656,41 +758,53 @@ mknod(p, uap, retval) register struct vnode *vp; struct vattr vattr; int error; + int whiteout; struct nameidata nd; CHECKPOINTREF; if (error = suser(p->p_ucred, &p->p_acflag)) return (error); - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (vp != NULL) { + if (vp != NULL) error = EEXIST; - goto out; - } - VATTR_NULL(&vattr); - switch (uap->fmode & S_IFMT) { - - case S_IFMT: /* used by badsect to flag bad sectors */ - vattr.va_type = VBAD; - break; - case S_IFCHR: - vattr.va_type = VCHR; - break; - case S_IFBLK: - vattr.va_type = VBLK; - break; - default: - error = EINVAL; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; + vattr.va_rdev = uap->dev; + whiteout = 0; + + switch (uap->mode & S_IFMT) { + case S_IFMT: /* used by badsect to flag bad sectors */ + vattr.va_type = VBAD; + break; + case S_IFCHR: + vattr.va_type = VCHR; + break; + case S_IFBLK: + vattr.va_type = VBLK; + break; + case S_IFWHT: + whiteout = 1; + break; + default: + error = EINVAL; + break; + } } - vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; - vattr.va_rdev = uap->dev; -out: if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (whiteout) { + error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); + if (error) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + } else { + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, + &nd.ni_cnd, &vattr); + } } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == vp) @@ -705,11 +819,11 @@ out: } /* - * Mkfifo system call. + * Create named pipe. */ struct mkfifo_args { - char *fname; - int fmode; + char *path; + int mode; }; /* ARGSUSED */ mkfifo(p, uap, retval) @@ -724,7 +838,7 @@ mkfifo(p, uap, retval) #ifndef FIFO return (EOPNOTSUPP); #else - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); if (nd.ni_vp != NULL) { @@ -738,18 +852,18 @@ mkfifo(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_type = VFIFO; - vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); #endif /* FIFO */ } /* - * Link system call. + * Make a hard file link. */ struct link_args { - char *target; - char *linkname; + char *path; + char *link; }; /* ARGSUSED */ link(p, uap, retval) @@ -757,44 +871,39 @@ link(p, uap, retval) register struct link_args *uap; int *retval; { - register struct vnode *vp, *xp; - int error; + register struct vnode *vp; struct nameidata nd; + int error; CHECKPOINTREF; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (vp->v_type == VDIR && - (error = suser(p->p_ucred, &p->p_acflag))) - goto out1; - nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT; - nd.ni_dirp = (caddr_t)uap->linkname; - if (error = namei(&nd)) - goto out1; - xp = nd.ni_vp; - if (xp != NULL) { - error = EEXIST; - goto out; - } - xp = nd.ni_dvp; -out: - if (!error) { - LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); - } else { - VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (nd.ni_vp) - vrele(nd.ni_vp); + if (vp->v_type != VDIR || + (error = suser(p->p_ucred, &p->p_acflag)) == 0) { + nd.ni_cnd.cn_nameiop = CREATE; + nd.ni_cnd.cn_flags = LOCKPARENT; + nd.ni_dirp = uap->link; + if ((error = namei(&nd)) == 0) { + if (nd.ni_vp != NULL) + error = EEXIST; + if (!error) { + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, + LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); + } else { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp) + vrele(nd.ni_vp); + } + } } -out1: vrele(vp); CHECKREFS("link"); return (error); @@ -804,8 +913,8 @@ out1: * Make a symbolic link. */ struct symlink_args { - char *target; - char *linkname; + char *path; + char *link; }; /* ARGSUSED */ symlink(p, uap, retval) @@ -814,15 +923,15 @@ symlink(p, uap, retval) int *retval; { struct vattr vattr; - char *target; + char *path; int error; struct nameidata nd; CHECKPOINTREF; - MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); - if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) + MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) goto out; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); if (error = namei(&nd)) goto out; if (nd.ni_vp) { @@ -836,20 +945,58 @@ symlink(p, uap, retval) goto out; } VATTR_NULL(&vattr); - vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); + vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); out: - FREE(target, M_NAMEI); + FREE(path, M_NAMEI); CHECKREFS("symlink"); return (error); } +/* + * Delete a whiteout from the filesystem. + */ +struct undelete_args { + char *path; +}; +/* ARGSUSED */ +undelete(p, uap, retval) + struct proc *p; + struct undelete_args *uap; + int *retval; +{ + int error; + struct nameidata nd; + + NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p); + error = namei(&nd); + if (error) + return (error); + + if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp) + vrele(nd.ni_vp); + return (EEXIST); + } + + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + return (error); +} + /* * Delete a name from the filesystem. */ struct unlink_args { - char *name; + char *path; }; /* ARGSUSED */ unlink(p, uap, retval) @@ -862,26 +1009,26 @@ unlink(p, uap, retval) struct nameidata nd; CHECKPOINTREF; - NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p); + NDINIT(&nd, DELETE, LOCKPARENT, 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_type == VDIR && - (error = suser(p->p_ucred, &p->p_acflag))) - goto out; - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (vp->v_flag & VROOT) { - error = EBUSY; - goto out; + + if (vp->v_type != VDIR || + (error = suser(p->p_ucred, &p->p_acflag)) == 0) { + /* + * The root of a mounted filesystem cannot be deleted. + */ + if (vp->v_flag & VROOT) + error = EBUSY; + else + (void)vnode_pager_uncache(vp); } - (void) vnode_pager_uncache(vp); -out: + if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -889,22 +1036,22 @@ out: vrele(nd.ni_dvp); else vput(nd.ni_dvp); - vput(vp); + if (vp != NULLVP) + vput(vp); } CHECKREFS("unlink"); return (error); } +/* + * Reposition read/write file offset. + */ struct lseek_args { - int fdes; + int fd; int pad; - off_t off; - int sbase; + off_t offset; + int whence; }; - -/* - * Seek system call. - */ lseek(p, uap, retval) struct proc *p; register struct lseek_args *uap; @@ -916,28 +1063,24 @@ lseek(p, uap, retval) struct vattr vattr; int error; - if ((unsigned)uap->fdes >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fdes]) == NULL) + if ((u_int)uap->fd >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[uap->fd]) == NULL) return (EBADF); if (fp->f_type != DTYPE_VNODE) return (ESPIPE); - switch (uap->sbase) { - + switch (uap->whence) { case L_INCR: - fp->f_offset += uap->off; + fp->f_offset += uap->offset; break; - case L_XTND: - if (error = VOP_GETATTR((struct vnode *)fp->f_data, - &vattr, cred, p)) + if (error = + VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) return (error); - fp->f_offset = uap->off + vattr.va_size; + fp->f_offset = uap->offset + vattr.va_size; break; - case L_SET: - fp->f_offset = uap->off; + fp->f_offset = uap->offset; break; - default: return (EINVAL); } @@ -947,12 +1090,12 @@ lseek(p, uap, retval) #if defined(COMPAT_43) || defined(COMPAT_SUNOS) /* - * Old lseek system call. + * Reposition read/write file offset. */ struct olseek_args { - int fdes; - long off; - int sbase; + int fd; + long offset; + int whence; }; olseek(p, uap, retval) struct proc *p; @@ -963,9 +1106,9 @@ olseek(p, uap, retval) off_t qret; int error; - nuap.fdes = uap->fdes; - nuap.off = uap->off; - nuap.sbase = uap->sbase; + nuap.fd = uap->fd; + nuap.offset = uap->offset; + nuap.whence = uap->whence; error = lseek(p, &nuap, &qret); *(long *)retval = qret; return (error); @@ -975,57 +1118,54 @@ olseek(p, uap, retval) /* * Check access permissions. */ -struct saccess_args { - char *fname; - int fmode; +struct access_args { + char *path; + int flags; }; -/* ARGSUSED */ -saccess(p, uap, retval) +access(p, uap, retval) struct proc *p; - register struct saccess_args *uap; + register struct access_args *uap; int *retval; { register struct ucred *cred = p->p_ucred; register struct vnode *vp; - int error, mode, svuid, svgid; + int error, flags, t_gid, t_uid; struct nameidata nd; - svuid = cred->cr_uid; - svgid = cred->cr_groups[0]; + t_uid = cred->cr_uid; + t_gid = cred->cr_groups[0]; cred->cr_uid = p->p_cred->p_ruid; cred->cr_groups[0] = p->p_cred->p_rgid; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) goto out1; vp = nd.ni_vp; - /* - * fmode == 0 means only check for exist - */ - if (uap->fmode) { - mode = 0; - if (uap->fmode & R_OK) - mode |= VREAD; - if (uap->fmode & W_OK) - mode |= VWRITE; - if (uap->fmode & X_OK) - mode |= VEXEC; - if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) - error = VOP_ACCESS(vp, mode, cred, p); + + /* Flags == 0 means only check for existence. */ + if (uap->flags) { + flags = 0; + if (uap->flags & R_OK) + flags |= VREAD; + if (uap->flags & W_OK) + flags |= VWRITE; + if (uap->flags & X_OK) + flags |= VEXEC; + if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) + error = VOP_ACCESS(vp, flags, cred, p); } vput(vp); out1: - cred->cr_uid = svuid; - cred->cr_groups[0] = svgid; + cred->cr_uid = t_uid; + cred->cr_groups[0] = t_gid; return (error); } #if defined(COMPAT_43) || defined(COMPAT_SUNOS) /* - * Stat system call. - * This version follows links. + * Get file status; this version follows links. */ struct ostat_args { - char *fname; + char *path; struct ostat *ub; }; /* ARGSUSED */ @@ -1039,7 +1179,7 @@ ostat(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); error = vn_stat(nd.ni_vp, &sb, p); @@ -1052,11 +1192,10 @@ ostat(p, uap, retval) } /* - * Lstat system call. - * This version does not follow links. + * Get file status; this version does not follow links. */ struct olstat_args { - char *fname; + char *path; struct ostat *ub; }; /* ARGSUSED */ @@ -1065,25 +1204,55 @@ olstat(p, uap, retval) register struct olstat_args *uap; int *retval; { - struct stat sb; + struct vnode *vp, *dvp; + struct stat sb, sb1; struct ostat osb; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, + uap->path, p); if (error = namei(&nd)) return (error); - error = vn_stat(nd.ni_vp, &sb, p); - vput(nd.ni_vp); - if (error) - return (error); + /* + * For symbolic links, always return the attributes of its + * containing directory, except for mode, size, and links. + */ + vp = nd.ni_vp; + dvp = nd.ni_dvp; + if (vp->v_type != VLNK) { + if (dvp == vp) + vrele(dvp); + else + vput(dvp); + error = vn_stat(vp, &sb, p); + vput(vp); + if (error) + return (error); + } else { + error = vn_stat(dvp, &sb, p); + vput(dvp); + if (error) { + vput(vp); + return (error); + } + error = vn_stat(vp, &sb1, p); + vput(vp); + if (error) + return (error); + sb.st_mode &= ~S_IFDIR; + sb.st_mode |= S_IFLNK; + sb.st_nlink = sb1.st_nlink; + sb.st_size = sb1.st_size; + sb.st_blocks = sb1.st_blocks; + } cvtstat(&sb, &osb); error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); return (error); } /* - * convert from an old to a new stat structure. + * Convert from an old to a new stat structure. */ cvtstat(st, ost) struct stat *st; @@ -1112,11 +1281,10 @@ cvtstat(st, ost) #endif /* COMPAT_43 || COMPAT_SUNOS */ /* - * Stat system call. - * This version follows links. + * Get file status; this version follows links. */ struct stat_args { - char *fname; + char *path; struct stat *ub; }; /* ARGSUSED */ @@ -1129,7 +1297,7 @@ stat(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); error = vn_stat(nd.ni_vp, &sb, p); @@ -1141,11 +1309,10 @@ stat(p, uap, retval) } /* - * Lstat system call. - * This version does not follow links. + * Get file status; this version does not follow links. */ struct lstat_args { - char *fname; + char *path; struct stat *ub; }; /* ARGSUSED */ @@ -1160,7 +1327,7 @@ lstat(p, uap, retval) struct nameidata nd; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, - uap->fname, p); + uap->path, p); if (error = namei(&nd)) return (error); /* @@ -1200,10 +1367,10 @@ lstat(p, uap, retval) } /* - * Pathconf system call. + * Get configurable pathname variables. */ struct pathconf_args { - char *fname; + char *path; int name; }; /* ARGSUSED */ @@ -1215,7 +1382,7 @@ pathconf(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); @@ -1227,7 +1394,7 @@ pathconf(p, uap, retval) * Return target name of a symbolic link. */ struct readlink_args { - char *name; + char *path; char *buf; int count; }; @@ -1244,25 +1411,24 @@ readlink(p, uap, retval) struct nameidata nd; CHECKPOINTREF; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); + NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (vp->v_type != VLNK) { + if (vp->v_type != VLNK) error = EINVAL; - goto out; + else { + aiov.iov_base = uap->buf; + aiov.iov_len = uap->count; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + auio.uio_resid = uap->count; + error = VOP_READLINK(vp, &auio, p->p_ucred); } - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = p; - auio.uio_resid = uap->count; - error = VOP_READLINK(vp, &auio, p->p_ucred); -out: vput(vp); *retval = uap->count - auio.uio_resid; CHECKREFS("readlink"); @@ -1270,10 +1436,10 @@ out: } /* - * Change flags of a file given path name. + * Change flags of a file given a path name. */ struct chflags_args { - char *fname; + char *path; int flags; }; /* ARGSUSED */ @@ -1287,20 +1453,19 @@ chflags(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); + 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_flags = uap->flags; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } - VATTR_NULL(&vattr); - vattr.va_flags = uap->flags; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: vput(vp); return (error); } @@ -1326,16 +1491,15 @@ fchflags(p, uap, retval) 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_flags = uap->flags; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } - VATTR_NULL(&vattr); - vattr.va_flags = uap->flags; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: VOP_UNLOCK(vp); return (error); } @@ -1344,8 +1508,8 @@ out: * Change mode of a file given path name. */ struct chmod_args { - char *fname; - int fmode; + char *path; + int mode; }; /* ARGSUSED */ chmod(p, uap, retval) @@ -1358,20 +1522,19 @@ chmod(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); + 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_mode = uap->mode & ALLPERMS; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } - VATTR_NULL(&vattr); - vattr.va_mode = uap->fmode & 07777; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: vput(vp); return (error); } @@ -1381,7 +1544,7 @@ out: */ struct fchmod_args { int fd; - int fmode; + int mode; }; /* ARGSUSED */ fchmod(p, uap, retval) @@ -1397,16 +1560,15 @@ fchmod(p, uap, retval) 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_mode = uap->mode & ALLPERMS; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } - VATTR_NULL(&vattr); - vattr.va_mode = uap->fmode & 07777; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: VOP_UNLOCK(vp); return (error); } @@ -1415,7 +1577,7 @@ out: * Set ownership given a path name. */ struct chown_args { - char *fname; + char *path; int uid; int gid; }; @@ -1430,21 +1592,20 @@ chown(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p); + 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_uid = uap->uid; + vattr.va_gid = uap->gid; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } - VATTR_NULL(&vattr); - vattr.va_uid = uap->uid; - vattr.va_gid = uap->gid; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: vput(vp); return (error); } @@ -1471,17 +1632,16 @@ fchown(p, uap, retval) 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + else { + VATTR_NULL(&vattr); + vattr.va_uid = uap->uid; + vattr.va_gid = uap->gid; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } - VATTR_NULL(&vattr); - vattr.va_uid = uap->uid; - vattr.va_gid = uap->gid; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: VOP_UNLOCK(vp); return (error); } @@ -1490,7 +1650,7 @@ out: * Set the access and modification times of a file. */ struct utimes_args { - char *fname; + char *path; struct timeval *tptr; }; /* ARGSUSED */ @@ -1512,35 +1672,33 @@ utimes(p, uap, retval) 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->fname, p); + 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_mount->mnt_flag & MNT_RDONLY) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; - goto out; + 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); } - 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); -out: vput(vp); return (error); } +/* + * Truncate a file given its path name. + */ struct truncate_args { - char *fname; + char *path; int pad; off_t length; }; - -/* - * Truncate a file given its path name. - */ /* ARGSUSED */ truncate(p, uap, retval) struct proc *p; @@ -1552,36 +1710,32 @@ truncate(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); + 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_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_type == VDIR) { + if (vp->v_type == VDIR) error = EISDIR; - goto out; + 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); } - if ((error = vn_writechk(vp)) || - (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) - goto out; - VATTR_NULL(&vattr); - vattr.va_size = uap->length; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); -out: vput(vp); return (error); } +/* + * Truncate a file given a file descriptor. + */ struct ftruncate_args { int fd; int pad; off_t length; }; - -/* - * Truncate a file given a file descriptor. - */ /* ARGSUSED */ ftruncate(p, uap, retval) struct proc *p; @@ -1598,18 +1752,15 @@ ftruncate(p, uap, retval) if ((fp->f_flag & FWRITE) == 0) return (EINVAL); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); - if (vp->v_type == VDIR) { + if (vp->v_type == VDIR) error = EISDIR; - goto out; + else if ((error = vn_writechk(vp)) == 0) { + VATTR_NULL(&vattr); + vattr.va_size = uap->length; + error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); } - if (error = vn_writechk(vp)) - goto out; - VATTR_NULL(&vattr); - vattr.va_size = uap->length; - error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); -out: VOP_UNLOCK(vp); return (error); } @@ -1619,7 +1770,7 @@ out: * Truncate a file given its path name. */ struct otruncate_args { - char *fname; + char *path; long length; }; /* ARGSUSED */ @@ -1630,7 +1781,7 @@ otruncate(p, uap, retval) { struct truncate_args nuap; - nuap.fname = uap->fname; + nuap.path = uap->path; nuap.length = uap->length; return (truncate(p, &nuap, retval)); } @@ -1657,7 +1808,7 @@ oftruncate(p, uap, retval) #endif /* COMPAT_43 || COMPAT_SUNOS */ /* - * Synch an open file. + * Sync an open file. */ struct fsync_args { int fd; @@ -1682,10 +1833,8 @@ fsync(p, uap, retval) } /* - * Rename system call. - * - * Source and destination must either both be directories, or both - * not be directories. If target is a directory, it must be empty. + * 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; @@ -1740,11 +1889,11 @@ rename(p, uap, retval) error = -1; out: if (!error) { - LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); if (fromnd.ni_dvp != tdvp) - LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); if (tvp) - LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); + 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 { @@ -1764,7 +1913,8 @@ out: FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); out1: p->p_spare[1]--; - vrele(fromnd.ni_startdir); + if (fromnd.ni_startdir) + vrele(fromnd.ni_startdir); FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); CHECKREFS("rename"); if (error == -1) @@ -1773,11 +1923,11 @@ out1: } /* - * Mkdir system call. + * Make a directory file. */ struct mkdir_args { - char *name; - int dmode; + char *path; + int mode; }; /* ARGSUSED */ mkdir(p, uap, retval) @@ -1791,7 +1941,7 @@ mkdir(p, uap, retval) struct nameidata nd; CHECKPOINTREF; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; @@ -1807,8 +1957,8 @@ mkdir(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_type = VDIR; - vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + vattr.va_mode = (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); @@ -1817,10 +1967,10 @@ mkdir(p, uap, retval) } /* - * Rmdir system call. + * Remove a directory file. */ struct rmdir_args { - char *name; + char *path; }; /* ARGSUSED */ rmdir(p, uap, retval) @@ -1833,7 +1983,7 @@ rmdir(p, uap, retval) struct nameidata nd; CHECKPOINTREF; - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); + NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; @@ -1855,8 +2005,8 @@ rmdir(p, uap, retval) 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); + 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); @@ -1877,7 +2027,7 @@ out: struct ogetdirentries_args { int fd; char *buf; - unsigned count; + u_int count; long *basep; }; ogetdirentries(p, uap, retval) @@ -1891,7 +2041,7 @@ ogetdirentries(p, uap, retval) struct iovec aiov, kiov; struct dirent *dp, *edp; caddr_t dirbuf; - int error, readcnt; + int error, eofflag, readcnt; long loff; if (error = getvnode(p->p_fd, uap->fd, &fp)) @@ -1899,6 +2049,7 @@ ogetdirentries(p, uap, retval) 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; @@ -1913,7 +2064,8 @@ ogetdirentries(p, uap, retval) 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); + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, + (u_long *)0, 0); fp->f_offset = auio.uio_offset; } else # endif @@ -1924,7 +2076,8 @@ ogetdirentries(p, uap, retval) 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); + error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, + (u_long *)0, 0); fp->f_offset = kuio.uio_offset; if (error == 0) { readcnt = uap->count - kuio.uio_resid; @@ -1963,11 +2116,67 @@ ogetdirentries(p, uap, retval) VOP_UNLOCK(vp); if (error) return (error); + +#ifdef UNION +{ + extern int (**union_vnodeop_p)(); + extern struct vnode *union_dircache __P((struct vnode *)); + + if ((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 ((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); } -#endif +#endif /* COMPAT_43 */ /* * Read a block of directory entries in a file system independent format. @@ -1975,7 +2184,7 @@ ogetdirentries(p, uap, retval) struct getdirentries_args { int fd; char *buf; - unsigned count; + u_int count; long *basep; }; getdirentries(p, uap, retval) @@ -1988,7 +2197,7 @@ getdirentries(p, uap, retval) struct uio auio; struct iovec aiov; long loff; - int error; + int error, eofflag; if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); @@ -2008,11 +2217,56 @@ unionread: auio.uio_resid = uap->count; VOP_LOCK(vp); loff = auio.uio_offset = fp->f_offset; - error = VOP_READDIR(vp, &auio, fp->f_cred); + 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)(); + extern struct vnode *union_dircache __P((struct vnode *)); + + if ((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 + if ((uap->count == auio.uio_resid) && (vp->v_flag & VROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) { @@ -2033,7 +2287,7 @@ unionread: * Set the mode mask for creation of filesystem nodes. */ struct umask_args { - int mask; + int newmask; }; mode_t /* XXX */ umask(p, uap, retval) @@ -2041,10 +2295,11 @@ umask(p, uap, retval) struct umask_args *uap; int *retval; { - register struct filedesc *fdp = p->p_fd; + register struct filedesc *fdp; + fdp = p->p_fd; *retval = fdp->fd_cmask; - fdp->fd_cmask = uap->mask & 07777; + fdp->fd_cmask = uap->newmask & ALLPERMS; return (0); } @@ -2053,7 +2308,7 @@ umask(p, uap, retval) * away from vnode. */ struct revoke_args { - char *fname; + char *path; }; /* ARGSUSED */ revoke(p, uap, retval) @@ -2066,7 +2321,7 @@ revoke(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); vp = nd.ni_vp; @@ -2089,15 +2344,15 @@ out: /* * Convert a user file descriptor to a kernel file entry. */ -getvnode(fdp, fdes, fpp) +getvnode(fdp, fd, fpp) struct filedesc *fdp; struct file **fpp; - int fdes; + int fd; { struct file *fp; - if ((unsigned)fdes >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fdes]) == NULL) + if ((u_int)fd >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[fd]) == NULL) return (EBADF); if (fp->f_type != DTYPE_VNODE) return (EINVAL);