-/* vfs_lookup.c 4.5 81/03/09 */
+/* vfs_lookup.c 4.10 82/02/27 */
#include "../h/param.h"
#include "../h/systm.h"
/*
* 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
* 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 *
-namei(func, flag)
-int (*func)();
+namei(func, flag, follow)
+ int (*func)(), flag, follow;
{
register struct inode *dp;
- register c;
register char *cp;
- struct buf *bp;
+ register struct buf *bp, *nbp;
register struct direct *ep;
- int i;
+ struct inode *pdp;
+ int i, nlink;
dev_t d;
+ ino_t ino;
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++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
+ 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.
*/
-
dp = u.u_cdir;
- if((c=(*func)()) == '/')
+ if (*cp == '/') {
+ while (*cp == '/')
+ cp++;
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 (flag==1 && c == ('/'|0200)) {
- u.u_error = ENOENT;
- goto out;
- }
- 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.
+ * 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);
- if(u.u_error)
+ for (i=0; *cp!='\0' && *cp!='/'; i++) {
+ if (i >= DIRSIZ) {
+ u.u_error = ENOENT;
+ break;
+ }
+ u.u_dbuf[i] = *cp++;
+ }
+ if (u.u_error)
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;
- eo = 0;
+ eo = -1;
bp = NULL;
- if (dp == u.u_rdir && u.u_dent.d_name[0] == '.' &&
- u.u_dent.d_name[1] == '.' && u.u_dent.d_name[2] == 0)
- goto cloop;
-
-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;
- 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;
+ ino = dp->i_number;
+ 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, 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);
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);
- if(flag==2 && c=='\0') {
- if(access(dp, IWRITE))
+ if (flag==1 && *cp=='\0' && dp->i_nlink) {
+ if (access(dp, IWRITE))
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);
- return(NULL);
+ dp = NULL;
+out1:
+ brelse(nbp);
+ return (dp);
}
/*
schar()
{
- return(*u.u_dirp++ & 0377);
+ return (*u.u_dirp++ & 0377);
}
/*
register c;
c = fubyte(u.u_dirp++);
- if(c == -1)
+ if (c == -1) {
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