add UNION support to ogetdirentries; add cookies and eofflag to VOP_READDIR
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
index 2e8cd85..67e05d1 100644 (file)
@@ -9,7 +9,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)vfs_syscalls.c      8.10 (Berkeley) %G%
+ *     @(#)vfs_syscalls.c      8.15 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -194,16 +194,21 @@ unmount(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       /*
-        * Must be super user
-        */
-       if (error = suser(p->p_ucred, &p->p_acflag))
-               return (error);
-
        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+
+       /*
+        * Unless this is a user mount, then must
+        * have suser privilege.
+        */
+       if (((vp->v_mount->mnt_flag & MNT_USER) == 0) &&
+           (error = suser(p->p_ucred, &p->p_acflag))) {
+               vput(vp);
+               return (error);
+       }
+
        /*
         * Must be the root of the filesystem
         */
        /*
         * Must be the root of the filesystem
         */
@@ -1409,7 +1414,7 @@ chown(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
@@ -1730,7 +1735,8 @@ out:
        FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
 out1:
        p->p_spare[1]--;
        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)
        FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
        CHECKREFS("rename");
        if (error == -1)
@@ -1857,7 +1863,7 @@ ogetdirentries(p, uap, retval)
        struct iovec aiov, kiov;
        struct dirent *dp, *edp;
        caddr_t dirbuf;
        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))
        long loff;
 
        if (error = getvnode(p->p_fd, uap->fd, &fp))
@@ -1865,6 +1871,7 @@ ogetdirentries(p, uap, retval)
        if ((fp->f_flag & FREAD) == 0)
                return (EBADF);
        vp = (struct vnode *)fp->f_data;
        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;
        if (vp->v_type != VDIR)
                return (EINVAL);
        aiov.iov_base = uap->buf;
@@ -1879,7 +1886,8 @@ ogetdirentries(p, uap, retval)
        loff = auio.uio_offset = fp->f_offset;
 #      if (BYTE_ORDER != LITTLE_ENDIAN)
                if (vp->v_mount->mnt_maxsymlinklen <= 0) {
        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
                        fp->f_offset = auio.uio_offset;
                } else
 #      endif
@@ -1890,7 +1898,8 @@ ogetdirentries(p, uap, retval)
                kiov.iov_len = uap->count;
                MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
                kiov.iov_base = dirbuf;
                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;
                fp->f_offset = kuio.uio_offset;
                if (error == 0) {
                        readcnt = uap->count - kuio.uio_resid;
@@ -1929,11 +1938,54 @@ ogetdirentries(p, uap, retval)
        VOP_UNLOCK(vp);
        if (error)
                return (error);
        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 *lvp;
+
+               lvp = union_lowervp(vp);
+               if (lvp != NULLVP) {
+                       VOP_LOCK(lvp);
+                       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);
 }
        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.
 
 /*
  * Read a block of directory entries in a file system independent format.
@@ -1954,7 +2006,7 @@ getdirentries(p, uap, retval)
        struct uio auio;
        struct iovec aiov;
        long loff;
        struct uio auio;
        struct iovec aiov;
        long loff;
-       int error;
+       int error, eofflag;
 
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
 
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
@@ -1974,7 +2026,7 @@ unionread:
        auio.uio_resid = uap->count;
        VOP_LOCK(vp);
        loff = auio.uio_offset = fp->f_offset;
        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)
        fp->f_offset = auio.uio_offset;
        VOP_UNLOCK(vp);
        if (error)
@@ -1987,23 +2039,24 @@ unionread:
 
        if ((uap->count == auio.uio_resid) &&
            (vp->v_op == union_vnodeop_p)) {
 
        if ((uap->count == auio.uio_resid) &&
            (vp->v_op == union_vnodeop_p)) {
-               struct vnode *tvp = vp;
+               struct vnode *lvp;
 
 
-               vp = union_lowervp(vp);
-               if (vp != NULLVP) {
-                       VOP_LOCK(vp);
-                       error = VOP_OPEN(vp, FREAD);
-                       VOP_UNLOCK(vp);
+               lvp = union_lowervp(vp);
+               if (lvp != NULLVP) {
+                       VOP_LOCK(lvp);
+                       error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
+                       VOP_UNLOCK(lvp);
 
                        if (error) {
 
                        if (error) {
-                               vrele(vp);
+                               vrele(lvp);
                                return (error);
                        }
                                return (error);
                        }
-                       fp->f_data = (caddr_t) vp;
+                       fp->f_data = (caddr_t) lvp;
                        fp->f_offset = 0;
                        fp->f_offset = 0;
-                       error = vn_close(tvp, FREAD, fp->f_cred, p);
+                       error = vn_close(vp, FREAD, fp->f_cred, p);
                        if (error)
                                return (error);
                        if (error)
                                return (error);
+                       vp = lvp;
                        goto unionread;
                }
        }
                        goto unionread;
                }
        }