lint
[unix-history] / usr / src / sys / ufs / ffs / ufs_lookup.c
index 1b55c4d..e959eed 100644 (file)
@@ -1,4 +1,4 @@
-/*     ufs_lookup.c    3.4     %G%     */
+/*     ufs_lookup.c    4.13    82/03/13        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -7,10 +7,11 @@
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/buf.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/buf.h"
+#include "../h/conf.h"
 
 /*
  * Convert a pathname into a pointer to
 
 /*
  * Convert a pathname into a pointer to
- * an inode. Note that the inode is locked.
+ * a locked inode.
  *
  * func = function called to get next char of name
  *     &uchar if name is in user space
  *
  * func = function called to get next char of name
  *     &uchar if name is in user space
  * flag = 0 if name is sought
  *     1 if name is to be created
  *     2 if name is to be deleted
  * flag = 0 if name is sought
  *     1 if name is to be created
  *     2 if name is to be deleted
+ * follow = 1 if links are to be followed at the end of the name
  */
 struct inode *
  */
 struct inode *
-namei(func, flag)
-int (*func)();
+namei(func, flag, follow)
+       int (*func)(), flag, follow;
 {
        register struct inode *dp;
 {
        register struct inode *dp;
-       register c;
        register char *cp;
        register char *cp;
-       struct buf *bp;
+       register struct buf *bp, *nbp;
        register struct direct *ep;
        register struct direct *ep;
-       int i;
+       struct inode *pdp;
+       int i, nlink;
        dev_t d;
        off_t eo;
 
        dev_t d;
        off_t eo;
 
+       /*
+        * allocate name buffer; copy name
+        */
+       nbp = geteblk();
+       nlink = 0;
+       for (i=0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) {
+               if ((*cp&0377) == ('/'|0200)) {
+                       u.u_error = EPERM;
+                       break;
+               }
+#ifdef notdef
+               if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
+#else
+               cp++;
+               if (cp >= nbp->b_un.b_addr+BSIZE) {
+#endif
+                       u.u_error = ENOENT;
+                       break;
+               }
+       }
+       if (u.u_error) {
+               dp = NULL;
+               goto out1;
+       }
+       cp = nbp->b_un.b_addr;
        /*
         * If name starts with '/' start from
         * root; otherwise start from current dir.
         */
        /*
         * If name starts with '/' start from
         * root; otherwise start from current dir.
         */
-
        dp = u.u_cdir;
        dp = u.u_cdir;
-       if((c=(*func)()) == '/')
+       if (*cp == '/') {
+               while (*cp == '/')
+                       cp++;
                if ((dp = u.u_rdir) == NULL)
                        dp = rootdir;
                if ((dp = u.u_rdir) == NULL)
                        dp = rootdir;
-       (void) iget(dp->i_dev, dp->i_number);
-       while(c == '/')
-               c = (*func)();
-       if(c == '\0' && flag != 0)
-               u.u_error = ENOENT;
-
-cloop:
-       /*
-        * Here dp contains pointer
-        * to last component matched.
-        */
-
-       if(u.u_error)
-               goto out;
-       if(c == '\0')
-               return(dp);
-
-       /*
-        * If there is another component,
-        * Gather up name into
-        * users' dir buffer.
-        */
-
-       cp = &u.u_dbuf[0];
-       while (c != '/' && c != '\0' && u.u_error == 0 ) {
-               if (mpxip!=NULL && c=='!')
-                       break;
-               if (cp < &u.u_dbuf[DIRSIZ])
-                       *cp++ = c;
-               c = (*func)();
-       }
-       while(cp < &u.u_dbuf[DIRSIZ])
-               *cp++ = '\0';
-       while(c == '/')
-               c = (*func)();
-       if (c == '!' && mpxip != NULL) {
-               iput(dp);
-               plock(mpxip);
-               mpxip->i_count++;
-               return(mpxip);
        }
        }
+       ilock(dp);
+       dp->i_count++;
 
 
-seloop:
        /*
         * dp must be a directory and
         * must have X permission.
        /*
         * dp must be a directory and
         * must have X permission.
+        * cp is a path name relative to that directory.
         */
 
         */
 
-       if((dp->i_mode&IFMT) != IFDIR)
+dirloop:
+       if ((dp->i_mode&IFMT) != IFDIR)
                u.u_error = ENOTDIR;
        (void) access(dp, IEXEC);
                u.u_error = ENOTDIR;
        (void) access(dp, IEXEC);
-       if(u.u_error)
+       for (i=0; *cp!='\0' && *cp!='/'; i++) {
+#ifdef notdef
+               if (i >= DIRSIZ) {
+                       u.u_error = ENOENT;
+                       break;
+               }
+               u.u_dbuf[i] = *cp++;
+#else
+               if (i < DIRSIZ)
+                       u.u_dbuf[i] = *cp;
+               cp++;
+#endif
+       }
+       if (u.u_error)
                goto out;
                goto out;
-
-       /*
-        * set up to search a directory
-        */
-       u.u_offset = 0;
+       u.u_pdir = dp;
+       while (i < DIRSIZ)
+               u.u_dbuf[i++] = '\0';
+       if (u.u_dbuf[0] == '\0') {              /* null name, e.g. "/" or "" */
+               if (flag) {
+                       u.u_error = ENOENT;
+                       goto out;
+               }
+               goto out1;
+       }
        u.u_segflg = 1;
        u.u_segflg = 1;
-       eo = 0;
+       eo = -1;
        bp = NULL;
 
        bp = NULL;
 
-eloop:
-
-       /*
-        * If at the end of the directory,
-        * the search failed. Report what
-        * is appropriate as per flag.
-        */
-
-       if(u.u_offset >= dp->i_size) {
-               if(bp != NULL)
-                       brelse(bp);
-               if(flag==1 && c=='\0' && dp->i_nlink) {
-                       if(access(dp, IWRITE))
+       for (u.u_offset=0; u.u_offset < dp->i_size;
+          u.u_offset += sizeof(struct direct), ep++) {
+               /*
+                * If offset is on a block boundary,
+                * read the next directory block.
+                * Release previous if it exists.
+                */
+               if ((u.u_offset&BMASK) == 0) {
+                       if (bp != NULL)
+                               brelse(bp);
+                       bp = bread(dp->i_dev,
+                               bmap(dp,(daddr_t)(u.u_offset>>BSHIFT), B_READ));
+                       if (bp->b_flags & B_ERROR) {
+                               brelse(bp);
                                goto out;
                                goto out;
-                       u.u_pdir = dp;
-                       if(eo)
-                               u.u_offset = eo-sizeof(struct direct);
-                       else
-                               dp->i_flag |= IUPD|ICHG;
-                       return(NULL);
+                       }
+                       ep = (struct direct *)bp->b_un.b_addr;
                }
                }
-               u.u_error = ENOENT;
-               goto out;
-       }
-
-       /*
-        * If offset is on a block boundary,
-        * read the next directory block.
-        * Release previous if it exists.
-        */
+               /*
+                * Note first empty directory slot
+                * in eo for possible creat.
+                * String compare the directory entry
+                * and the current component.
+                */
+               if (ep->d_ino == 0) {
+                       if (eo < 0)
+                               eo = u.u_offset;
+                       continue;
+               }
+               if (strncmp(u.u_dbuf, ep->d_name, DIRSIZ) != 0)
+                       continue;
+               /*
+                * Here a component matched in a directory.
+                * If there is more pathname, go back to
+                * dirloop, otherwise return.
+                */
+               bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
+               brelse(bp);
+               if (flag==2 && *cp=='\0') {
+                       if (access(dp, IWRITE))
+                               goto out;
+                       /* should fix unlink */
+                       u.u_offset += sizeof(struct direct);
+                       goto out1;
+               }
+               /*
+                * Special handling for ".."
+                */
+               if (u.u_dent.d_name[0]=='.' && u.u_dent.d_name[1]=='.' &&
+                   u.u_dent.d_name[2]=='\0') {
+                       if (dp == u.u_rdir)
+                               u.u_dent.d_ino = dp->i_number;
+                       else if (u.u_dent.d_ino==ROOTINO &&
+                          dp->i_number == ROOTINO) {
+                               for(i=1; i<NMOUNT; i++)
+                                       if (mount[i].m_bufp != NULL &&
+                                          mount[i].m_dev == dp->i_dev) {
+                                               iput(dp);
+                                               dp = mount[i].m_inodp;
+                                               ilock(dp);
+                                               dp->i_count++;
+                                               cp -= 2;     /* back over .. */
+                                               goto dirloop;
+                                       }
+                       }
+               }
+               d = dp->i_dev;
+               irele(dp);
+               pdp = dp;
+               dp = iget(d, u.u_dent.d_ino);
+               if (dp == NULL)  {
+                       iput(pdp);
+                       goto out1;
+               }
+               /*
+                * Check for symbolic link
+                */
+               if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
+                       char *ocp;
 
 
-       if((u.u_offset&BMASK) == 0) {
-               if(bp != NULL)
-                       brelse(bp);
-               bp = bread(dp->i_dev,
-                       bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
-               if (bp->b_flags & B_ERROR) {
+                       ocp = cp;
+                       while (*cp++)
+                               ;
+                       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,
+                         (unsigned)(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,
+                         (unsigned)dp->i_size);
                        brelse(bp);
                        brelse(bp);
-                       goto out;
+                       cp = nbp->b_un.b_addr;
+                       iput(dp);
+                       if (*cp == '/') {
+                               iput(pdp);
+                               while (*cp == '/')
+                                       cp++;
+                               if ((dp = u.u_rdir) == NULL)
+                                       dp = rootdir;
+                               ilock(dp);
+                               dp->i_count++;
+                       } else {
+                               dp = pdp;
+                               ilock(dp);
+                       }
+                       goto dirloop;
                }
                }
-               ep = (struct direct *)bp->b_un.b_addr;
-       } else
-               ep++;
-
-       /*
-        * Note first empty directory slot
-        * in eo for possible creat.
-        * String compare the directory entry
-        * and the current component.
-        * If they do not match, go back to eloop.
-        */
-
-       u.u_offset += sizeof(struct direct);
-       if(ep->d_ino == 0) {
-               if(eo == 0)
-                       eo = u.u_offset;
-               goto eloop;
-       }
-       for(i=0; i<DIRSIZ; i++) {
-               if(u.u_dbuf[i] != ep->d_name[i])
-                       goto eloop;
-               if(u.u_dbuf[i] == 0)
-                       break;
+               iput(pdp);
+               if (*cp == '/') {
+                       while (*cp == '/')
+                               cp++;
+                       goto dirloop;
+               }
+               goto out1;
        }
        }
-
        /*
        /*
-        * Here a component matched in a directory.
-        * If there is more pathname, go back to
-        * cloop, otherwise return.
+        * Search failed.
         */
         */
-       bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
-       if(bp != NULL)
+       if (bp != NULL)
                brelse(bp);
                brelse(bp);
-       if(flag==2 && c=='\0') {
-               if(access(dp, IWRITE))
+       if (flag==1 && *cp=='\0' && dp->i_nlink) {
+               if (access(dp, IWRITE))
                        goto out;
                        goto out;
-               return(dp);
+               if (eo>=0)
+                       u.u_offset = eo;
+               dp->i_flag |= IUPD|ICHG;
+               dp = NULL;
+               goto out1;
        }
        }
-       d = dp->i_dev;
-       if(u.u_dent.d_ino == ROOTINO)
-       if(dp->i_number == ROOTINO)
-       if(u.u_dent.d_name[1] == '.')
-               for(i=1; i<NMOUNT; i++)
-                       if(mount[i].m_bufp != NULL)
-                       if(mount[i].m_dev == d) {
-                               iput(dp);
-                               dp = mount[i].m_inodp;
-                               dp->i_count++;
-                               plock(dp);
-                               goto seloop;
-                       }
-       iput(dp);
-       dp = iget(d, u.u_dent.d_ino);
-       if(dp == NULL)
-               return(NULL);
-       goto cloop;
-
+       u.u_error = ENOENT;
 out:
        iput(dp);
 out:
        iput(dp);
-       return(NULL);
+       dp = NULL;
+out1:
+       brelse(nbp);
+       return (dp);
 }
 
 /*
 }
 
 /*
@@ -212,7 +265,7 @@ out:
 schar()
 {
 
 schar()
 {
 
-       return(*u.u_dirp++ & 0377);
+       return (*u.u_dirp++ & 0377);
 }
 
 /*
 }
 
 /*
@@ -224,7 +277,25 @@ uchar()
        register c;
 
        c = fubyte(u.u_dirp++);
        register c;
 
        c = fubyte(u.u_dirp++);
-       if(c == -1)
+       if (c == -1) {
                u.u_error = EFAULT;
                u.u_error = EFAULT;
-       return(c);
+               c = 0;
+       }
+       return (c);
+}
+
+#ifndef vax
+strncmp(s1, s2, len)
+       register char *s1, *s2;
+       register len;
+{
+
+       do {
+               if (*s1 != *s2++)
+                       return (1);
+               if (*s1++ == '\0')
+                       return (0);
+       } while (--len);
+       return (0);
 }
 }
+#endif