symbolic links
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Sun, 28 Feb 1982 06:56:17 +0000 (22:56 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Sun, 28 Feb 1982 06:56:17 +0000 (22:56 -0800)
SCCS-vsn: sys/kern/kern_resource.c 4.6
SCCS-vsn: sys/kern/vfs_vnops.c 4.22
SCCS-vsn: sys/ufs/ffs/ffs_inode.c 4.9
SCCS-vsn: sys/ufs/ffs/ufs_inode.c 4.9
SCCS-vsn: sys/ufs/lfs/lfs_inode.c 4.9
SCCS-vsn: sys/ufs/ufs/ufs_inode.c 4.9
SCCS-vsn: sys/kern/vfs_lookup.c 4.10
SCCS-vsn: sys/ufs/ffs/ufs_lookup.c 4.10
SCCS-vsn: sys/ufs/ufs/ufs_lookup.c 4.10
SCCS-vsn: sys/kern/kern_proc.c 4.23
SCCS-vsn: sys/kern/vfs_syscalls.c 4.18
SCCS-vsn: sys/ufs/ffs/ffs_vnops.c 4.18
SCCS-vsn: sys/ufs/ffs/ufs_vnops.c 4.18
SCCS-vsn: sys/ufs/lfs/lfs_vnops.c 4.18
SCCS-vsn: sys/ufs/ufs/ufs_vnops.c 4.18
SCCS-vsn: sys/ufs/ffs/dinode.h 4.10
SCCS-vsn: sys/ufs/ffs/inode.h 4.10
SCCS-vsn: sys/ufs/ufs/dinode.h 4.10
SCCS-vsn: sys/ufs/ufs/inode.h 4.10
SCCS-vsn: sys/sys/stat.h 4.3

20 files changed:
usr/src/sys/kern/kern_proc.c
usr/src/sys/kern/kern_resource.c
usr/src/sys/kern/vfs_lookup.c
usr/src/sys/kern/vfs_syscalls.c
usr/src/sys/kern/vfs_vnops.c
usr/src/sys/sys/stat.h
usr/src/sys/ufs/ffs/dinode.h
usr/src/sys/ufs/ffs/ffs_inode.c
usr/src/sys/ufs/ffs/ffs_vnops.c
usr/src/sys/ufs/ffs/inode.h
usr/src/sys/ufs/ffs/ufs_inode.c
usr/src/sys/ufs/ffs/ufs_lookup.c
usr/src/sys/ufs/ffs/ufs_vnops.c
usr/src/sys/ufs/lfs/lfs_inode.c
usr/src/sys/ufs/lfs/lfs_vnops.c
usr/src/sys/ufs/ufs/dinode.h
usr/src/sys/ufs/ufs/inode.h
usr/src/sys/ufs/ufs/ufs_inode.c
usr/src/sys/ufs/ufs/ufs_lookup.c
usr/src/sys/ufs/ufs/ufs_vnops.c

index 300be30..583af04 100644 (file)
@@ -1,4 +1,4 @@
-/*     kern_proc.c     4.22    82/02/15        */
+/*     kern_proc.c     4.23    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -49,7 +49,7 @@ exece()
        char cfname[DIRSIZ];
        char cfarg[SHSIZE];
 
        char cfname[DIRSIZ];
        char cfarg[SHSIZE];
 
-       if ((ip = namei(uchar, 0)) == NULL)
+       if ((ip = namei(uchar, 0, 1)) == NULL)
                return;
        bno = 0;
        bp = 0;
                return;
        bno = 0;
        bp = 0;
@@ -154,7 +154,7 @@ exece()
                bcopy((caddr_t)u.u_dbuf, (caddr_t)cfname, DIRSIZ);
                indir = 1;
                iput(ip);
                bcopy((caddr_t)u.u_dbuf, (caddr_t)cfname, DIRSIZ);
                indir = 1;
                iput(ip);
-               ip = namei(schar, 0);
+               ip = namei(schar, 0, 1);
                if (ip == NULL)
                        return;
                goto again;
                if (ip == NULL)
                        return;
                goto again;
index e5cf063..e1d8d93 100644 (file)
@@ -1,4 +1,4 @@
-/*     kern_resource.c 4.5     81/11/08        */
+/*     kern_resource.c 4.6     82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -35,7 +35,7 @@ sysacct()
                        u.u_error = EBUSY;
                        return;
                }
                        u.u_error = EBUSY;
                        return;
                }
-               ip = namei(uchar, 0);
+               ip = namei(uchar, 0, 1);
                if(ip == NULL)
                        return;
                if((ip->i_mode & IFMT) != IFREG) {
                if(ip == NULL)
                        return;
                if((ip->i_mode & IFMT) != IFREG) {
index bffb0c7..28a2c1e 100644 (file)
@@ -1,4 +1,4 @@
-/*     vfs_lookup.c    4.9     82/02/26        */
+/*     vfs_lookup.c    4.10    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -29,6 +29,7 @@ namei(func, flag, follow)
        register char *cp;
        register struct buf *bp, *nbp;
        register struct direct *ep;
        register char *cp;
        register struct buf *bp, *nbp;
        register struct direct *ep;
+       struct inode *pdp;
        int i, nlink;
        dev_t d;
        ino_t ino;
        int i, nlink;
        dev_t d;
        ino_t ino;
@@ -83,6 +84,7 @@ dirloop:
        }
        if (u.u_error)
                goto out;
        }
        if (u.u_error)
                goto out;
+       u.u_pdir = dp;
        while (i < DIRSIZ)
                u.u_dbuf[i++] = '\0';
        if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
        while (i < DIRSIZ)
                u.u_dbuf[i++] = '\0';
        if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
@@ -164,10 +166,13 @@ dirloop:
                }
                d = dp->i_dev;
                ino = dp->i_number;
                }
                d = dp->i_dev;
                ino = dp->i_number;
-               iput(dp);
+               irele(dp);
+               pdp = dp;
                dp = iget(d, u.u_dent.d_ino);
                dp = iget(d, u.u_dent.d_ino);
-               if (dp == NULL)
+               if (dp == NULL)  {
+                       iput(pdp);
                        goto out1;
                        goto out1;
+               }
                /*
                 * Check for symbolic link
                 */
                /*
                 * Check for symbolic link
                 */
@@ -179,12 +184,14 @@ dirloop:
                                ;
                        if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
                                u.u_error = ELOOP;
                                ;
                        if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
                                u.u_error = ELOOP;
+                               iput(pdp);
                                goto out;
                        }
                        bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
                        bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
                        if (bp->b_flags & B_ERROR) {
                                brelse(bp);
                                goto out;
                        }
                        bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
                        bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
                        if (bp->b_flags & B_ERROR) {
                                brelse(bp);
+                               iput(pdp);
                                goto out;
                        }
                        bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
                                goto out;
                        }
                        bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
@@ -192,6 +199,7 @@ dirloop:
                        cp = nbp->b_un.b_addr;
                        iput(dp);
                        if (*cp == '/') {
                        cp = nbp->b_un.b_addr;
                        iput(dp);
                        if (*cp == '/') {
+                               iput(pdp);
                                while (*cp == '/')
                                        cp++;
                                if ((dp = u.u_rdir) == NULL)
                                while (*cp == '/')
                                        cp++;
                                if ((dp = u.u_rdir) == NULL)
@@ -199,12 +207,12 @@ dirloop:
                                ilock(dp);
                                dp->i_count++;
                        } else {
                                ilock(dp);
                                dp->i_count++;
                        } else {
-                               dp = iget(d, ino);      /* retrieve directory */
-                               if (dp == NULL)
-                                       goto out1;
+                               dp = pdp;
+                               ilock(dp);
                        }
                        goto dirloop;
                }
                        }
                        goto dirloop;
                }
+               iput(pdp);
                if (*cp == '/') {
                        while (*cp == '/')
                                cp++;
                if (*cp == '/') {
                        while (*cp == '/')
                                cp++;
@@ -220,7 +228,6 @@ dirloop:
        if (flag==1 && *cp=='\0' && dp->i_nlink) {
                if (access(dp, IWRITE))
                        goto out;
        if (flag==1 && *cp=='\0' && dp->i_nlink) {
                if (access(dp, IWRITE))
                        goto out;
-               u.u_pdir = dp;
                if (eo>=0)
                        u.u_offset = eo;
                dp->i_flag |= IUPD|ICHG;
                if (eo>=0)
                        u.u_offset = eo;
                dp->i_flag |= IUPD|ICHG;
index c8ad364..944dc66 100644 (file)
@@ -1,4 +1,4 @@
-/*     vfs_syscalls.c  4.17    82/01/19        */
+/*     vfs_syscalls.c  4.18    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -39,7 +39,7 @@ fstat()
 }
 
 /*
 }
 
 /*
- * Stat system call.
+ * Stat system call.  This version does not follow links.
  */
 stat()
 {
  */
 stat()
 {
@@ -50,13 +50,32 @@ stat()
        } *uap;
 
        uap = (struct a *)u.u_ap;
        } *uap;
 
        uap = (struct a *)u.u_ap;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 0);
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
+/*
+ * Lstat system call.  This version does follow links.
+ */
+lstat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0, 1);
+       if (ip == NULL)
+               return;
+       stat1(ip, uap->sb, (off_t)0);
+       iput(ip);
+}
+
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
@@ -82,7 +101,7 @@ stat1(ip, ub)
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
-        * Next the dates in the disk
+        * next the dates in the disk
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
@@ -96,7 +115,79 @@ stat1(ip, ub)
 }
 
 /*
 }
 
 /*
- * Dup system call.
+ * Return target name of a symbolic link
+ */
+readlink()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *name;
+               char    *buf;
+               int     count;
+       } *uap;
+
+       ip = namei(uchar, 0, 0);
+       if (ip == NULL)
+               return;
+       if ((ip->i_mode&IFMT) != IFLNK) {
+               u.u_error = ENXIO;
+               goto out;
+       }
+       uap = (struct a *)u.u_ap;
+       u.u_offset = 0;
+       u.u_base = uap->buf;
+       u.u_count = uap->count;
+       u.u_segflg = 0;
+       readi(ip);
+out:
+       iput(ip);
+       u.u_r.r_val1 = uap->count - u.u_count;
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+symlink()
+{
+       register struct a {
+               char    *target;
+               char    *linkname;
+       } *uap;
+       register struct inode *ip;
+       register char *tp;
+       register c, nc;
+
+       uap = (struct a *)u.u_ap;
+       tp = uap->target;
+       nc = 0;
+       while (c = fubyte(tp)) {
+               if (c < 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               tp++;
+               nc++;
+       }
+       u.u_dirp = uap->linkname;
+       ip = namei(uchar, 1, 0);
+       if (ip) {
+               iput(ip);
+               u.u_error = EEXIST;
+               return;
+       }
+       ip = maknode(IFLNK | 0777);
+       if (ip == NULL)
+               return;
+       u.u_base = uap->target;
+       u.u_count = nc;
+       u.u_offset = 0;
+       u.u_segflg = 0;
+       writei(ip);
+       iput(ip);
+}
+
+/*
+ * the dup system call.
  */
 dup()
 {
  */
 dup()
 {
@@ -157,7 +248,7 @@ smount()
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
@@ -272,7 +363,7 @@ getmdev()
 
        if (!suser())
                return(NODEV);
 
        if (!suser())
                return(NODEV);
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
index 9cb79f6..67693a4 100644 (file)
@@ -1,4 +1,4 @@
-/*     vfs_vnops.c     4.21    82/02/15        */
+/*     vfs_vnops.c     4.22    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -203,11 +203,12 @@ access(ip, mode)
  * return inode pointer.
  */
 struct inode *
  * return inode pointer.
  */
 struct inode *
-owner()
+owner(follow)
+       int follow;
 {
        register struct inode *ip;
 
 {
        register struct inode *ip;
 
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, follow);
        if (ip == NULL)
                return (NULL);
        if (u.u_uid == ip->i_uid)
        if (ip == NULL)
                return (NULL);
        if (u.u_uid == ip->i_uid)
index 46f388e..dc00dcd 100644 (file)
@@ -1,4 +1,4 @@
-/*     stat.h  4.2     81/02/19        */
+/*     stat.h  4.3     82/02/27        */
 
 struct stat
 {
 
 struct stat
 {
@@ -20,8 +20,7 @@ struct        stat
 #define                S_IFCHR 0020000 /* character special */
 #define                S_IFBLK 0060000 /* block special */
 #define                S_IFREG 0100000 /* regular */
 #define                S_IFCHR 0020000 /* character special */
 #define                S_IFBLK 0060000 /* block special */
 #define                S_IFREG 0100000 /* regular */
-#define                S_IFMPC 0030000 /* multiplexed char special */
-#define                S_IFMPB 0070000 /* multiplexed block special */
+#define                S_IFLNK 0120000 /* symbolic link */
 #define        S_ISUID 0004000         /* set user id on execution */
 #define        S_ISGID 0002000         /* set group id on execution */
 #define        S_ISVTX 0001000         /* save swapped text even after use */
 #define        S_ISUID 0004000         /* set user id on execution */
 #define        S_ISGID 0002000         /* set group id on execution */
 #define        S_ISVTX 0001000         /* save swapped text even after use */
index ebd13e3..1f2d849 100644 (file)
@@ -1,4 +1,4 @@
-/*     dinode.h        4.9     81/11/14        */
+/*     dinode.h        4.10    82/02/27        */
 
 /*
  * The I node is the focus of all file activity in UNIX.
 
 /*
  * The I node is the focus of all file activity in UNIX.
@@ -71,8 +71,7 @@ struct        inode *namei();
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
-#define                IFSYMREG        0110000         /* regular symbolic link */
-#define                IFSYMDIR        0130000         /* directory symbolic link */
+#define                IFLNK           0120000         /* symbolic link */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
index 64b0029..0592361 100644 (file)
@@ -1,4 +1,4 @@
-/*     ffs_inode.c     4.8     82/02/15        */
+/*     ffs_inode.c     4.9     82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -276,7 +276,7 @@ itrunc(ip)
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
-       if (i!=IFREG && i!=IFDIR)
+       if (i!=IFREG && i!=IFDIR && i!=IFLNK)
                return;
 
        /*
                return;
 
        /*
index df1f9d6..8394259 100644 (file)
@@ -1,4 +1,4 @@
-/*     ffs_vnops.c     4.17    82/01/19        */
+/*     ffs_vnops.c     4.18    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -39,7 +39,7 @@ fstat()
 }
 
 /*
 }
 
 /*
- * Stat system call.
+ * Stat system call.  This version does not follow links.
  */
 stat()
 {
  */
 stat()
 {
@@ -50,13 +50,32 @@ stat()
        } *uap;
 
        uap = (struct a *)u.u_ap;
        } *uap;
 
        uap = (struct a *)u.u_ap;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 0);
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
+/*
+ * Lstat system call.  This version does follow links.
+ */
+lstat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0, 1);
+       if (ip == NULL)
+               return;
+       stat1(ip, uap->sb, (off_t)0);
+       iput(ip);
+}
+
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
@@ -82,7 +101,7 @@ stat1(ip, ub)
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
-        * Next the dates in the disk
+        * next the dates in the disk
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
@@ -96,7 +115,79 @@ stat1(ip, ub)
 }
 
 /*
 }
 
 /*
- * Dup system call.
+ * Return target name of a symbolic link
+ */
+readlink()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *name;
+               char    *buf;
+               int     count;
+       } *uap;
+
+       ip = namei(uchar, 0, 0);
+       if (ip == NULL)
+               return;
+       if ((ip->i_mode&IFMT) != IFLNK) {
+               u.u_error = ENXIO;
+               goto out;
+       }
+       uap = (struct a *)u.u_ap;
+       u.u_offset = 0;
+       u.u_base = uap->buf;
+       u.u_count = uap->count;
+       u.u_segflg = 0;
+       readi(ip);
+out:
+       iput(ip);
+       u.u_r.r_val1 = uap->count - u.u_count;
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+symlink()
+{
+       register struct a {
+               char    *target;
+               char    *linkname;
+       } *uap;
+       register struct inode *ip;
+       register char *tp;
+       register c, nc;
+
+       uap = (struct a *)u.u_ap;
+       tp = uap->target;
+       nc = 0;
+       while (c = fubyte(tp)) {
+               if (c < 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               tp++;
+               nc++;
+       }
+       u.u_dirp = uap->linkname;
+       ip = namei(uchar, 1, 0);
+       if (ip) {
+               iput(ip);
+               u.u_error = EEXIST;
+               return;
+       }
+       ip = maknode(IFLNK | 0777);
+       if (ip == NULL)
+               return;
+       u.u_base = uap->target;
+       u.u_count = nc;
+       u.u_offset = 0;
+       u.u_segflg = 0;
+       writei(ip);
+       iput(ip);
+}
+
+/*
+ * the dup system call.
  */
 dup()
 {
  */
 dup()
 {
@@ -157,7 +248,7 @@ smount()
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
@@ -272,7 +363,7 @@ getmdev()
 
        if (!suser())
                return(NODEV);
 
        if (!suser())
                return(NODEV);
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
index 89df7d8..15efb10 100644 (file)
@@ -1,4 +1,4 @@
-/*     inode.h 4.9     81/11/14        */
+/*     inode.h 4.10    82/02/27        */
 
 /*
  * The I node is the focus of all file activity in UNIX.
 
 /*
  * The I node is the focus of all file activity in UNIX.
@@ -71,8 +71,7 @@ struct        inode *namei();
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
-#define                IFSYMREG        0110000         /* regular symbolic link */
-#define                IFSYMDIR        0130000         /* directory symbolic link */
+#define                IFLNK           0120000         /* symbolic link */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
index 5098b76..bac9d12 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_inode.c     4.8     82/02/15        */
+/*     ufs_inode.c     4.9     82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -276,7 +276,7 @@ itrunc(ip)
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
-       if (i!=IFREG && i!=IFDIR)
+       if (i!=IFREG && i!=IFDIR && i!=IFLNK)
                return;
 
        /*
                return;
 
        /*
index ed44b11..244bb4a 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_lookup.c    4.9     82/02/26        */
+/*     ufs_lookup.c    4.10    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -29,6 +29,7 @@ namei(func, flag, follow)
        register char *cp;
        register struct buf *bp, *nbp;
        register struct direct *ep;
        register char *cp;
        register struct buf *bp, *nbp;
        register struct direct *ep;
+       struct inode *pdp;
        int i, nlink;
        dev_t d;
        ino_t ino;
        int i, nlink;
        dev_t d;
        ino_t ino;
@@ -83,6 +84,7 @@ dirloop:
        }
        if (u.u_error)
                goto out;
        }
        if (u.u_error)
                goto out;
+       u.u_pdir = dp;
        while (i < DIRSIZ)
                u.u_dbuf[i++] = '\0';
        if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
        while (i < DIRSIZ)
                u.u_dbuf[i++] = '\0';
        if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
@@ -164,10 +166,13 @@ dirloop:
                }
                d = dp->i_dev;
                ino = dp->i_number;
                }
                d = dp->i_dev;
                ino = dp->i_number;
-               iput(dp);
+               irele(dp);
+               pdp = dp;
                dp = iget(d, u.u_dent.d_ino);
                dp = iget(d, u.u_dent.d_ino);
-               if (dp == NULL)
+               if (dp == NULL)  {
+                       iput(pdp);
                        goto out1;
                        goto out1;
+               }
                /*
                 * Check for symbolic link
                 */
                /*
                 * Check for symbolic link
                 */
@@ -179,12 +184,14 @@ dirloop:
                                ;
                        if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
                                u.u_error = ELOOP;
                                ;
                        if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
                                u.u_error = ELOOP;
+                               iput(pdp);
                                goto out;
                        }
                        bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
                        bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
                        if (bp->b_flags & B_ERROR) {
                                brelse(bp);
                                goto out;
                        }
                        bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
                        bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
                        if (bp->b_flags & B_ERROR) {
                                brelse(bp);
+                               iput(pdp);
                                goto out;
                        }
                        bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
                                goto out;
                        }
                        bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
@@ -192,6 +199,7 @@ dirloop:
                        cp = nbp->b_un.b_addr;
                        iput(dp);
                        if (*cp == '/') {
                        cp = nbp->b_un.b_addr;
                        iput(dp);
                        if (*cp == '/') {
+                               iput(pdp);
                                while (*cp == '/')
                                        cp++;
                                if ((dp = u.u_rdir) == NULL)
                                while (*cp == '/')
                                        cp++;
                                if ((dp = u.u_rdir) == NULL)
@@ -199,12 +207,12 @@ dirloop:
                                ilock(dp);
                                dp->i_count++;
                        } else {
                                ilock(dp);
                                dp->i_count++;
                        } else {
-                               dp = iget(d, ino);      /* retrieve directory */
-                               if (dp == NULL)
-                                       goto out1;
+                               dp = pdp;
+                               ilock(dp);
                        }
                        goto dirloop;
                }
                        }
                        goto dirloop;
                }
+               iput(pdp);
                if (*cp == '/') {
                        while (*cp == '/')
                                cp++;
                if (*cp == '/') {
                        while (*cp == '/')
                                cp++;
@@ -220,7 +228,6 @@ dirloop:
        if (flag==1 && *cp=='\0' && dp->i_nlink) {
                if (access(dp, IWRITE))
                        goto out;
        if (flag==1 && *cp=='\0' && dp->i_nlink) {
                if (access(dp, IWRITE))
                        goto out;
-               u.u_pdir = dp;
                if (eo>=0)
                        u.u_offset = eo;
                dp->i_flag |= IUPD|ICHG;
                if (eo>=0)
                        u.u_offset = eo;
                dp->i_flag |= IUPD|ICHG;
index f92f1e6..f3ef98d 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_vnops.c     4.17    82/01/19        */
+/*     ufs_vnops.c     4.18    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -39,7 +39,7 @@ fstat()
 }
 
 /*
 }
 
 /*
- * Stat system call.
+ * Stat system call.  This version does not follow links.
  */
 stat()
 {
  */
 stat()
 {
@@ -50,13 +50,32 @@ stat()
        } *uap;
 
        uap = (struct a *)u.u_ap;
        } *uap;
 
        uap = (struct a *)u.u_ap;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 0);
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
+/*
+ * Lstat system call.  This version does follow links.
+ */
+lstat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0, 1);
+       if (ip == NULL)
+               return;
+       stat1(ip, uap->sb, (off_t)0);
+       iput(ip);
+}
+
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
@@ -82,7 +101,7 @@ stat1(ip, ub)
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
-        * Next the dates in the disk
+        * next the dates in the disk
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
@@ -96,7 +115,79 @@ stat1(ip, ub)
 }
 
 /*
 }
 
 /*
- * Dup system call.
+ * Return target name of a symbolic link
+ */
+readlink()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *name;
+               char    *buf;
+               int     count;
+       } *uap;
+
+       ip = namei(uchar, 0, 0);
+       if (ip == NULL)
+               return;
+       if ((ip->i_mode&IFMT) != IFLNK) {
+               u.u_error = ENXIO;
+               goto out;
+       }
+       uap = (struct a *)u.u_ap;
+       u.u_offset = 0;
+       u.u_base = uap->buf;
+       u.u_count = uap->count;
+       u.u_segflg = 0;
+       readi(ip);
+out:
+       iput(ip);
+       u.u_r.r_val1 = uap->count - u.u_count;
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+symlink()
+{
+       register struct a {
+               char    *target;
+               char    *linkname;
+       } *uap;
+       register struct inode *ip;
+       register char *tp;
+       register c, nc;
+
+       uap = (struct a *)u.u_ap;
+       tp = uap->target;
+       nc = 0;
+       while (c = fubyte(tp)) {
+               if (c < 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               tp++;
+               nc++;
+       }
+       u.u_dirp = uap->linkname;
+       ip = namei(uchar, 1, 0);
+       if (ip) {
+               iput(ip);
+               u.u_error = EEXIST;
+               return;
+       }
+       ip = maknode(IFLNK | 0777);
+       if (ip == NULL)
+               return;
+       u.u_base = uap->target;
+       u.u_count = nc;
+       u.u_offset = 0;
+       u.u_segflg = 0;
+       writei(ip);
+       iput(ip);
+}
+
+/*
+ * the dup system call.
  */
 dup()
 {
  */
 dup()
 {
@@ -157,7 +248,7 @@ smount()
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
@@ -272,7 +363,7 @@ getmdev()
 
        if (!suser())
                return(NODEV);
 
        if (!suser())
                return(NODEV);
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
index ef7d828..67ed51b 100644 (file)
@@ -1,4 +1,4 @@
-/*     lfs_inode.c     4.8     82/02/15        */
+/*     lfs_inode.c     4.9     82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -276,7 +276,7 @@ itrunc(ip)
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
-       if (i!=IFREG && i!=IFDIR)
+       if (i!=IFREG && i!=IFDIR && i!=IFLNK)
                return;
 
        /*
                return;
 
        /*
index b858a87..c1244b0 100644 (file)
@@ -1,4 +1,4 @@
-/*     lfs_vnops.c     4.17    82/01/19        */
+/*     lfs_vnops.c     4.18    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -39,7 +39,7 @@ fstat()
 }
 
 /*
 }
 
 /*
- * Stat system call.
+ * Stat system call.  This version does not follow links.
  */
 stat()
 {
  */
 stat()
 {
@@ -50,13 +50,32 @@ stat()
        } *uap;
 
        uap = (struct a *)u.u_ap;
        } *uap;
 
        uap = (struct a *)u.u_ap;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 0);
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
+/*
+ * Lstat system call.  This version does follow links.
+ */
+lstat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0, 1);
+       if (ip == NULL)
+               return;
+       stat1(ip, uap->sb, (off_t)0);
+       iput(ip);
+}
+
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
@@ -82,7 +101,7 @@ stat1(ip, ub)
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
-        * Next the dates in the disk
+        * next the dates in the disk
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
@@ -96,7 +115,79 @@ stat1(ip, ub)
 }
 
 /*
 }
 
 /*
- * Dup system call.
+ * Return target name of a symbolic link
+ */
+readlink()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *name;
+               char    *buf;
+               int     count;
+       } *uap;
+
+       ip = namei(uchar, 0, 0);
+       if (ip == NULL)
+               return;
+       if ((ip->i_mode&IFMT) != IFLNK) {
+               u.u_error = ENXIO;
+               goto out;
+       }
+       uap = (struct a *)u.u_ap;
+       u.u_offset = 0;
+       u.u_base = uap->buf;
+       u.u_count = uap->count;
+       u.u_segflg = 0;
+       readi(ip);
+out:
+       iput(ip);
+       u.u_r.r_val1 = uap->count - u.u_count;
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+symlink()
+{
+       register struct a {
+               char    *target;
+               char    *linkname;
+       } *uap;
+       register struct inode *ip;
+       register char *tp;
+       register c, nc;
+
+       uap = (struct a *)u.u_ap;
+       tp = uap->target;
+       nc = 0;
+       while (c = fubyte(tp)) {
+               if (c < 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               tp++;
+               nc++;
+       }
+       u.u_dirp = uap->linkname;
+       ip = namei(uchar, 1, 0);
+       if (ip) {
+               iput(ip);
+               u.u_error = EEXIST;
+               return;
+       }
+       ip = maknode(IFLNK | 0777);
+       if (ip == NULL)
+               return;
+       u.u_base = uap->target;
+       u.u_count = nc;
+       u.u_offset = 0;
+       u.u_segflg = 0;
+       writei(ip);
+       iput(ip);
+}
+
+/*
+ * the dup system call.
  */
 dup()
 {
  */
 dup()
 {
@@ -157,7 +248,7 @@ smount()
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
@@ -272,7 +363,7 @@ getmdev()
 
        if (!suser())
                return(NODEV);
 
        if (!suser())
                return(NODEV);
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
index ebd13e3..1f2d849 100644 (file)
@@ -1,4 +1,4 @@
-/*     dinode.h        4.9     81/11/14        */
+/*     dinode.h        4.10    82/02/27        */
 
 /*
  * The I node is the focus of all file activity in UNIX.
 
 /*
  * The I node is the focus of all file activity in UNIX.
@@ -71,8 +71,7 @@ struct        inode *namei();
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
-#define                IFSYMREG        0110000         /* regular symbolic link */
-#define                IFSYMDIR        0130000         /* directory symbolic link */
+#define                IFLNK           0120000         /* symbolic link */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
index 89df7d8..15efb10 100644 (file)
@@ -1,4 +1,4 @@
-/*     inode.h 4.9     81/11/14        */
+/*     inode.h 4.10    82/02/27        */
 
 /*
  * The I node is the focus of all file activity in UNIX.
 
 /*
  * The I node is the focus of all file activity in UNIX.
@@ -71,8 +71,7 @@ struct        inode *namei();
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
 #define                IFDIR           0040000         /* directory */
 #define                IFBLK           0060000         /* block special */
 #define                IFREG           0100000         /* regular */
-#define                IFSYMREG        0110000         /* regular symbolic link */
-#define                IFSYMDIR        0130000         /* directory symbolic link */
+#define                IFLNK           0120000         /* symbolic link */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
 #define                IFPORTAL        0140000         /* portal */
 #define        ISUID   04000           /* set user id on execution */
 #define        ISGID   02000           /* set group id on execution */
index 5098b76..bac9d12 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_inode.c     4.8     82/02/15        */
+/*     ufs_inode.c     4.9     82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -276,7 +276,7 @@ itrunc(ip)
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
        struct inode itmp;
 
        i = ip->i_mode & IFMT;
-       if (i!=IFREG && i!=IFDIR)
+       if (i!=IFREG && i!=IFDIR && i!=IFLNK)
                return;
 
        /*
                return;
 
        /*
index ed44b11..244bb4a 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_lookup.c    4.9     82/02/26        */
+/*     ufs_lookup.c    4.10    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -29,6 +29,7 @@ namei(func, flag, follow)
        register char *cp;
        register struct buf *bp, *nbp;
        register struct direct *ep;
        register char *cp;
        register struct buf *bp, *nbp;
        register struct direct *ep;
+       struct inode *pdp;
        int i, nlink;
        dev_t d;
        ino_t ino;
        int i, nlink;
        dev_t d;
        ino_t ino;
@@ -83,6 +84,7 @@ dirloop:
        }
        if (u.u_error)
                goto out;
        }
        if (u.u_error)
                goto out;
+       u.u_pdir = dp;
        while (i < DIRSIZ)
                u.u_dbuf[i++] = '\0';
        if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
        while (i < DIRSIZ)
                u.u_dbuf[i++] = '\0';
        if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
@@ -164,10 +166,13 @@ dirloop:
                }
                d = dp->i_dev;
                ino = dp->i_number;
                }
                d = dp->i_dev;
                ino = dp->i_number;
-               iput(dp);
+               irele(dp);
+               pdp = dp;
                dp = iget(d, u.u_dent.d_ino);
                dp = iget(d, u.u_dent.d_ino);
-               if (dp == NULL)
+               if (dp == NULL)  {
+                       iput(pdp);
                        goto out1;
                        goto out1;
+               }
                /*
                 * Check for symbolic link
                 */
                /*
                 * Check for symbolic link
                 */
@@ -179,12 +184,14 @@ dirloop:
                                ;
                        if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
                                u.u_error = ELOOP;
                                ;
                        if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
                                u.u_error = ELOOP;
+                               iput(pdp);
                                goto out;
                        }
                        bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
                        bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
                        if (bp->b_flags & B_ERROR) {
                                brelse(bp);
                                goto out;
                        }
                        bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
                        bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
                        if (bp->b_flags & B_ERROR) {
                                brelse(bp);
+                               iput(pdp);
                                goto out;
                        }
                        bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
                                goto out;
                        }
                        bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
@@ -192,6 +199,7 @@ dirloop:
                        cp = nbp->b_un.b_addr;
                        iput(dp);
                        if (*cp == '/') {
                        cp = nbp->b_un.b_addr;
                        iput(dp);
                        if (*cp == '/') {
+                               iput(pdp);
                                while (*cp == '/')
                                        cp++;
                                if ((dp = u.u_rdir) == NULL)
                                while (*cp == '/')
                                        cp++;
                                if ((dp = u.u_rdir) == NULL)
@@ -199,12 +207,12 @@ dirloop:
                                ilock(dp);
                                dp->i_count++;
                        } else {
                                ilock(dp);
                                dp->i_count++;
                        } else {
-                               dp = iget(d, ino);      /* retrieve directory */
-                               if (dp == NULL)
-                                       goto out1;
+                               dp = pdp;
+                               ilock(dp);
                        }
                        goto dirloop;
                }
                        }
                        goto dirloop;
                }
+               iput(pdp);
                if (*cp == '/') {
                        while (*cp == '/')
                                cp++;
                if (*cp == '/') {
                        while (*cp == '/')
                                cp++;
@@ -220,7 +228,6 @@ dirloop:
        if (flag==1 && *cp=='\0' && dp->i_nlink) {
                if (access(dp, IWRITE))
                        goto out;
        if (flag==1 && *cp=='\0' && dp->i_nlink) {
                if (access(dp, IWRITE))
                        goto out;
-               u.u_pdir = dp;
                if (eo>=0)
                        u.u_offset = eo;
                dp->i_flag |= IUPD|ICHG;
                if (eo>=0)
                        u.u_offset = eo;
                dp->i_flag |= IUPD|ICHG;
index f92f1e6..f3ef98d 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_vnops.c     4.17    82/01/19        */
+/*     ufs_vnops.c     4.18    82/02/27        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -39,7 +39,7 @@ fstat()
 }
 
 /*
 }
 
 /*
- * Stat system call.
+ * Stat system call.  This version does not follow links.
  */
 stat()
 {
  */
 stat()
 {
@@ -50,13 +50,32 @@ stat()
        } *uap;
 
        uap = (struct a *)u.u_ap;
        } *uap;
 
        uap = (struct a *)u.u_ap;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 0);
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
        if (ip == NULL)
                return;
        stat1(ip, uap->sb);
        iput(ip);
 }
 
+/*
+ * Lstat system call.  This version does follow links.
+ */
+lstat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0, 1);
+       if (ip == NULL)
+               return;
+       stat1(ip, uap->sb, (off_t)0);
+       iput(ip);
+}
+
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
 /*
  * The basic routine for fstat and stat:
  * get the inode and pass appropriate parts back.
@@ -82,7 +101,7 @@ stat1(ip, ub)
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
        ds.st_rdev = (dev_t)ip->i_un.i_rdev;
        ds.st_size = ip->i_size;
        /*
-        * Next the dates in the disk
+        * next the dates in the disk
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
         */
        bp = bread(ip->i_dev, itod(ip->i_number));
        dp = bp->b_un.b_dino;
@@ -96,7 +115,79 @@ stat1(ip, ub)
 }
 
 /*
 }
 
 /*
- * Dup system call.
+ * Return target name of a symbolic link
+ */
+readlink()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *name;
+               char    *buf;
+               int     count;
+       } *uap;
+
+       ip = namei(uchar, 0, 0);
+       if (ip == NULL)
+               return;
+       if ((ip->i_mode&IFMT) != IFLNK) {
+               u.u_error = ENXIO;
+               goto out;
+       }
+       uap = (struct a *)u.u_ap;
+       u.u_offset = 0;
+       u.u_base = uap->buf;
+       u.u_count = uap->count;
+       u.u_segflg = 0;
+       readi(ip);
+out:
+       iput(ip);
+       u.u_r.r_val1 = uap->count - u.u_count;
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+symlink()
+{
+       register struct a {
+               char    *target;
+               char    *linkname;
+       } *uap;
+       register struct inode *ip;
+       register char *tp;
+       register c, nc;
+
+       uap = (struct a *)u.u_ap;
+       tp = uap->target;
+       nc = 0;
+       while (c = fubyte(tp)) {
+               if (c < 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               tp++;
+               nc++;
+       }
+       u.u_dirp = uap->linkname;
+       ip = namei(uchar, 1, 0);
+       if (ip) {
+               iput(ip);
+               u.u_error = EEXIST;
+               return;
+       }
+       ip = maknode(IFLNK | 0777);
+       if (ip == NULL)
+               return;
+       u.u_base = uap->target;
+       u.u_count = nc;
+       u.u_offset = 0;
+       u.u_segflg = 0;
+       writei(ip);
+       iput(ip);
+}
+
+/*
+ * the dup system call.
  */
 dup()
 {
  */
 dup()
 {
@@ -157,7 +248,7 @@ smount()
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
        if (u.u_error)
                return;
        u.u_dirp = (caddr_t)uap->freg;
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
        if (ip == NULL)
                return;
        if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR)
@@ -272,7 +363,7 @@ getmdev()
 
        if (!suser())
                return(NODEV);
 
        if (!suser())
                return(NODEV);
-       ip = namei(uchar, 0);
+       ip = namei(uchar, 0, 1);
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)
        if (ip == NULL)
                return(NODEV);
        if ((ip->i_mode&IFMT) != IFBLK)