xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 6384)
1*6384Swnj /*	vfs_lookup.c	4.14	82/03/31	*/
230Sbill 
330Sbill #include "../h/param.h"
430Sbill #include "../h/systm.h"
530Sbill #include "../h/inode.h"
630Sbill #include "../h/mount.h"
730Sbill #include "../h/dir.h"
830Sbill #include "../h/user.h"
930Sbill #include "../h/buf.h"
102275Swnj #include "../h/conf.h"
1130Sbill 
1230Sbill /*
1330Sbill  * Convert a pathname into a pointer to
145972Swnj  * a locked inode.
1530Sbill  *
1630Sbill  * func = function called to get next char of name
1730Sbill  *	&uchar if name is in user space
1830Sbill  *	&schar if name is in system space
1930Sbill  * flag = 0 if name is sought
2030Sbill  *	1 if name is to be created
2130Sbill  *	2 if name is to be deleted
225972Swnj  * follow = 1 if links are to be followed at the end of the name
2330Sbill  */
2430Sbill struct inode *
255972Swnj namei(func, flag, follow)
265972Swnj 	int (*func)(), flag, follow;
2730Sbill {
2830Sbill 	register struct inode *dp;
2930Sbill 	register char *cp;
305972Swnj 	register struct buf *bp, *nbp;
31194Sbill 	register struct direct *ep;
325990Swnj 	struct inode *pdp;
335972Swnj 	int i, nlink;
3430Sbill 	dev_t d;
3530Sbill 	off_t eo;
3630Sbill 
3730Sbill 	/*
385972Swnj 	 * allocate name buffer; copy name
395972Swnj 	 */
405972Swnj 	nbp = geteblk();
415972Swnj 	nlink = 0;
425972Swnj 	for (i=0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) {
436066Sroot 		if ((*cp&0377) == ('/'|0200)) {
446066Sroot 			u.u_error = EPERM;
456066Sroot 			break;
466066Sroot 		}
476066Sroot #ifdef notdef
485972Swnj 		if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
496066Sroot #else
506066Sroot 		cp++;
516066Sroot 		if (cp >= nbp->b_un.b_addr+BSIZE) {
526066Sroot #endif
535972Swnj 			u.u_error = ENOENT;
545972Swnj 			break;
555972Swnj 		}
565972Swnj 	}
575972Swnj 	if (u.u_error) {
585972Swnj 		dp = NULL;
595972Swnj 		goto out1;
605972Swnj 	}
615972Swnj 	cp = nbp->b_un.b_addr;
625972Swnj 	/*
6330Sbill 	 * If name starts with '/' start from
6430Sbill 	 * root; otherwise start from current dir.
6530Sbill 	 */
6630Sbill 	dp = u.u_cdir;
675972Swnj 	if (*cp == '/') {
685972Swnj 		while (*cp == '/')
695972Swnj 			cp++;
7030Sbill 		if ((dp = u.u_rdir) == NULL)
7130Sbill 			dp = rootdir;
7230Sbill 	}
735972Swnj 	ilock(dp);
745972Swnj 	dp->i_count++;
7530Sbill 
7630Sbill 	/*
7730Sbill 	 * dp must be a directory and
7830Sbill 	 * must have X permission.
795972Swnj 	 * cp is a path name relative to that directory.
8030Sbill 	 */
8130Sbill 
825972Swnj dirloop:
834823Swnj 	if ((dp->i_mode&IFMT) != IFDIR)
8430Sbill 		u.u_error = ENOTDIR;
85194Sbill 	(void) access(dp, IEXEC);
86*6384Swnj dirloop2:
875972Swnj 	for (i=0; *cp!='\0' && *cp!='/'; i++) {
886066Sroot #ifdef notdef
895972Swnj 		if (i >= DIRSIZ) {
905972Swnj 			u.u_error = ENOENT;
915972Swnj 			break;
925972Swnj 		}
935972Swnj 		u.u_dbuf[i] = *cp++;
946066Sroot #else
956066Sroot 		if (i < DIRSIZ)
966066Sroot 			u.u_dbuf[i] = *cp;
976066Sroot 		cp++;
986066Sroot #endif
995972Swnj 	}
1004823Swnj 	if (u.u_error)
10130Sbill 		goto out;
1025990Swnj 	u.u_pdir = dp;
1035972Swnj 	while (i < DIRSIZ)
1045972Swnj 		u.u_dbuf[i++] = '\0';
1055972Swnj 	if (u.u_dbuf[0] == '\0') {		/* null name, e.g. "/" or "" */
1065972Swnj 		if (flag) {
1075972Swnj 			u.u_error = ENOENT;
1085972Swnj 			goto out;
1095972Swnj 		}
1105972Swnj 		goto out1;
1115972Swnj 	}
11230Sbill 	u.u_segflg = 1;
1135972Swnj 	eo = -1;
11430Sbill 	bp = NULL;
11530Sbill 
1165972Swnj 	for (u.u_offset=0; u.u_offset < dp->i_size;
1175972Swnj 	   u.u_offset += sizeof(struct direct), ep++) {
1185972Swnj 		/*
1195972Swnj 		 * If offset is on a block boundary,
1205972Swnj 		 * read the next directory block.
1215972Swnj 		 * Release previous if it exists.
1225972Swnj 		 */
1235972Swnj 		if ((u.u_offset&BMASK) == 0) {
1245972Swnj 			if (bp != NULL)
1255972Swnj 				brelse(bp);
1265972Swnj 			bp = bread(dp->i_dev,
1275972Swnj 				bmap(dp,(daddr_t)(u.u_offset>>BSHIFT), B_READ));
1285972Swnj 			if (bp->b_flags & B_ERROR) {
1295972Swnj 				brelse(bp);
1305972Swnj 				goto out;
1315972Swnj 			}
1325972Swnj 			ep = (struct direct *)bp->b_un.b_addr;
1335972Swnj 		}
1345972Swnj 		/*
1355972Swnj 		 * Note first empty directory slot
1365972Swnj 		 * in eo for possible creat.
1375972Swnj 		 * String compare the directory entry
1385972Swnj 		 * and the current component.
1395972Swnj 		 */
1405972Swnj 		if (ep->d_ino == 0) {
1415972Swnj 			if (eo < 0)
1425972Swnj 				eo = u.u_offset;
1435972Swnj 			continue;
1445972Swnj 		}
1455972Swnj 		if (strncmp(u.u_dbuf, ep->d_name, DIRSIZ) != 0)
1465972Swnj 			continue;
1475972Swnj 		/*
1485972Swnj 		 * Here a component matched in a directory.
1495972Swnj 		 * If there is more pathname, go back to
1505972Swnj 		 * dirloop, otherwise return.
1515972Swnj 		 */
1525972Swnj 		bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
1535972Swnj 		brelse(bp);
1545972Swnj 		if (flag==2 && *cp=='\0') {
1554823Swnj 			if (access(dp, IWRITE))
15630Sbill 				goto out;
1575972Swnj 			/* should fix unlink */
1585972Swnj 			u.u_offset += sizeof(struct direct);
1595972Swnj 			goto out1;
16030Sbill 		}
1615972Swnj 		/*
1625972Swnj 		 * Special handling for ".."
1635972Swnj 		 */
1645972Swnj 		if (u.u_dent.d_name[0]=='.' && u.u_dent.d_name[1]=='.' &&
1655972Swnj 		    u.u_dent.d_name[2]=='\0') {
1665972Swnj 			if (dp == u.u_rdir)
1675972Swnj 				u.u_dent.d_ino = dp->i_number;
1685972Swnj 			else if (u.u_dent.d_ino==ROOTINO &&
1695972Swnj 			   dp->i_number == ROOTINO) {
1705972Swnj 				for(i=1; i<NMOUNT; i++)
1715972Swnj 					if (mount[i].m_bufp != NULL &&
1725972Swnj 					   mount[i].m_dev == dp->i_dev) {
1735972Swnj 						iput(dp);
1745972Swnj 						dp = mount[i].m_inodp;
1755972Swnj 						ilock(dp);
1765972Swnj 						dp->i_count++;
1775972Swnj 						cp -= 2;     /* back over .. */
178*6384Swnj 						goto dirloop2;
1795972Swnj 					}
1805972Swnj 			}
1815972Swnj 		}
1825972Swnj 		d = dp->i_dev;
1835990Swnj 		irele(dp);
1845990Swnj 		pdp = dp;
1855972Swnj 		dp = iget(d, u.u_dent.d_ino);
1865990Swnj 		if (dp == NULL)  {
1875990Swnj 			iput(pdp);
1885972Swnj 			goto out1;
1895990Swnj 		}
1905972Swnj 		/*
1915972Swnj 		 * Check for symbolic link
1925972Swnj 		 */
1935972Swnj 		if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
1945972Swnj 			char *ocp;
19530Sbill 
1965972Swnj 			ocp = cp;
1975972Swnj 			while (*cp++)
1985972Swnj 				;
1995972Swnj 			if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
2005972Swnj 				u.u_error = ELOOP;
2015990Swnj 				iput(pdp);
2025972Swnj 				goto out;
2035972Swnj 			}
2046164Ssam 			bcopy(ocp, nbp->b_un.b_addr+dp->i_size,
2056164Ssam 			  (unsigned)(cp-ocp));
2065972Swnj 			bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
2075972Swnj 			if (bp->b_flags & B_ERROR) {
2085972Swnj 				brelse(bp);
2095990Swnj 				iput(pdp);
2105972Swnj 				goto out;
2115972Swnj 			}
2126164Ssam 			bcopy(bp->b_un.b_addr, nbp->b_un.b_addr,
2136164Ssam 			  (unsigned)dp->i_size);
21430Sbill 			brelse(bp);
2155972Swnj 			cp = nbp->b_un.b_addr;
2165972Swnj 			iput(dp);
2175972Swnj 			if (*cp == '/') {
2185990Swnj 				iput(pdp);
2195972Swnj 				while (*cp == '/')
2205972Swnj 					cp++;
2215972Swnj 				if ((dp = u.u_rdir) == NULL)
2225972Swnj 					dp = rootdir;
2235972Swnj 				ilock(dp);
2245972Swnj 				dp->i_count++;
2255972Swnj 			} else {
2265990Swnj 				dp = pdp;
2275990Swnj 				ilock(dp);
2285972Swnj 			}
2295972Swnj 			goto dirloop;
23030Sbill 		}
2315990Swnj 		iput(pdp);
2325972Swnj 		if (*cp == '/') {
2335972Swnj 			while (*cp == '/')
2345972Swnj 				cp++;
2355972Swnj 			goto dirloop;
2365972Swnj 		}
2375972Swnj 		goto out1;
23830Sbill 	}
23930Sbill 	/*
2405972Swnj 	 * Search failed.
24130Sbill 	 */
2424823Swnj 	if (bp != NULL)
24330Sbill 		brelse(bp);
2445972Swnj 	if (flag==1 && *cp=='\0' && dp->i_nlink) {
2454823Swnj 		if (access(dp, IWRITE))
24630Sbill 			goto out;
2475972Swnj 		if (eo>=0)
2485972Swnj 			u.u_offset = eo;
2495972Swnj 		dp->i_flag |= IUPD|ICHG;
2505972Swnj 		dp = NULL;
2515972Swnj 		goto out1;
25230Sbill 	}
2535972Swnj 	u.u_error = ENOENT;
25430Sbill out:
25530Sbill 	iput(dp);
2565972Swnj 	dp = NULL;
2575972Swnj out1:
2585972Swnj 	brelse(nbp);
2595972Swnj 	return (dp);
26030Sbill }
26130Sbill 
26230Sbill /*
26330Sbill  * Return the next character from the
26430Sbill  * kernel string pointed at by dirp.
26530Sbill  */
26630Sbill schar()
26730Sbill {
26830Sbill 
2695972Swnj 	return (*u.u_dirp++ & 0377);
27030Sbill }
27130Sbill 
27230Sbill /*
27330Sbill  * Return the next character from the
27430Sbill  * user string pointed at by dirp.
27530Sbill  */
27630Sbill uchar()
27730Sbill {
27830Sbill 	register c;
27930Sbill 
28030Sbill 	c = fubyte(u.u_dirp++);
2815972Swnj 	if (c == -1) {
28230Sbill 		u.u_error = EFAULT;
2835972Swnj 		c = 0;
2845972Swnj 	}
2855972Swnj 	return (c);
28630Sbill }
2875972Swnj 
2885972Swnj #ifndef vax
2895972Swnj strncmp(s1, s2, len)
2905972Swnj 	register char *s1, *s2;
2915972Swnj 	register len;
2925972Swnj {
2935972Swnj 
2945972Swnj 	do {
2955972Swnj 		if (*s1 != *s2++)
2965972Swnj 			return (1);
2975972Swnj 		if (*s1++ == '\0')
2985972Swnj 			return (0);
2995972Swnj 	} while (--len);
3005972Swnj 	return (0);
3015972Swnj }
3025972Swnj #endif
303