fix olstat to give the correct symlink info
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
index deb34b9..f33db2e 100644 (file)
@@ -9,7 +9,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)vfs_syscalls.c      8.21 (Berkeley) %G%
+ *     @(#)vfs_syscalls.c      8.23 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -744,12 +744,17 @@ mknod(p, uap, retval)
                        break;
                }
        }
                        break;
                }
        }
-       if (whiteout) {
-               error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
-               vput(nd.ni_dvp);
-       } else if (!error) {
+       if (!error) {
                VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
                VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
-               error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+               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)
        } else {
                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                if (nd.ni_dvp == vp)
@@ -931,8 +936,7 @@ unwhiteout(p, uap, retval)
        }
 
        VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
        }
 
        VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
-       error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
-       if (error != 0)
+       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);
                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
        vput(nd.ni_dvp);
        return (error);
@@ -1150,18 +1154,48 @@ olstat(p, uap, retval)
        register struct olstat_args *uap;
        int *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;
 
        struct ostat osb;
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
+       NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
+           uap->path, p);
        if (error = namei(&nd))
                return (error);
        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);
        cvtstat(&sb, &osb);
        error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
        return (error);