xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 6066)
1*6066Sroot /*	vfs_lookup.c	4.11	82/03/06	*/
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;
355972Swnj 	ino_t ino;
3630Sbill 	off_t eo;
3730Sbill 
3830Sbill 	/*
395972Swnj 	 * allocate name buffer; copy name
405972Swnj 	 */
415972Swnj 	nbp = geteblk();
425972Swnj 	nlink = 0;
435972Swnj 	for (i=0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) {
44*6066Sroot 		if ((*cp&0377) == ('/'|0200)) {
45*6066Sroot 			u.u_error = EPERM;
46*6066Sroot 			break;
47*6066Sroot 		}
48*6066Sroot #ifdef notdef
495972Swnj 		if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
50*6066Sroot #else
51*6066Sroot 		cp++;
52*6066Sroot 		if (cp >= nbp->b_un.b_addr+BSIZE) {
53*6066Sroot #endif
545972Swnj 			u.u_error = ENOENT;
555972Swnj 			break;
565972Swnj 		}
575972Swnj 	}
585972Swnj 	if (u.u_error) {
595972Swnj 		dp = NULL;
605972Swnj 		goto out1;
615972Swnj 	}
625972Swnj 	cp = nbp->b_un.b_addr;
635972Swnj 	/*
6430Sbill 	 * If name starts with '/' start from
6530Sbill 	 * root; otherwise start from current dir.
6630Sbill 	 */
6730Sbill 	dp = u.u_cdir;
685972Swnj 	if (*cp == '/') {
695972Swnj 		while (*cp == '/')
705972Swnj 			cp++;
7130Sbill 		if ((dp = u.u_rdir) == NULL)
7230Sbill 			dp = rootdir;
7330Sbill 	}
745972Swnj 	ilock(dp);
755972Swnj 	dp->i_count++;
7630Sbill 
7730Sbill 	/*
7830Sbill 	 * dp must be a directory and
7930Sbill 	 * must have X permission.
805972Swnj 	 * cp is a path name relative to that directory.
8130Sbill 	 */
8230Sbill 
835972Swnj dirloop:
844823Swnj 	if ((dp->i_mode&IFMT) != IFDIR)
8530Sbill 		u.u_error = ENOTDIR;
86194Sbill 	(void) access(dp, IEXEC);
875972Swnj 	for (i=0; *cp!='\0' && *cp!='/'; i++) {
88*6066Sroot #ifdef notdef
895972Swnj 		if (i >= DIRSIZ) {
905972Swnj 			u.u_error = ENOENT;
915972Swnj 			break;
925972Swnj 		}
935972Swnj 		u.u_dbuf[i] = *cp++;
94*6066Sroot #else
95*6066Sroot 		if (i < DIRSIZ)
96*6066Sroot 			u.u_dbuf[i] = *cp;
97*6066Sroot 		cp++;
98*6066Sroot #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 .. */
1785972Swnj 						goto dirloop;
1795972Swnj 					}
1805972Swnj 			}
1815972Swnj 		}
1825972Swnj 		d = dp->i_dev;
1835972Swnj 		ino = dp->i_number;
1845990Swnj 		irele(dp);
1855990Swnj 		pdp = dp;
1865972Swnj 		dp = iget(d, u.u_dent.d_ino);
1875990Swnj 		if (dp == NULL)  {
1885990Swnj 			iput(pdp);
1895972Swnj 			goto out1;
1905990Swnj 		}
1915972Swnj 		/*
1925972Swnj 		 * Check for symbolic link
1935972Swnj 		 */
1945972Swnj 		if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
1955972Swnj 			char *ocp;
19630Sbill 
1975972Swnj 			ocp = cp;
1985972Swnj 			while (*cp++)
1995972Swnj 				;
2005972Swnj 			if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
2015972Swnj 				u.u_error = ELOOP;
2025990Swnj 				iput(pdp);
2035972Swnj 				goto out;
2045972Swnj 			}
2055972Swnj 			bcopy(ocp, nbp->b_un.b_addr+dp->i_size, 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 			}
2125972Swnj 			bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
21330Sbill 			brelse(bp);
2145972Swnj 			cp = nbp->b_un.b_addr;
2155972Swnj 			iput(dp);
2165972Swnj 			if (*cp == '/') {
2175990Swnj 				iput(pdp);
2185972Swnj 				while (*cp == '/')
2195972Swnj 					cp++;
2205972Swnj 				if ((dp = u.u_rdir) == NULL)
2215972Swnj 					dp = rootdir;
2225972Swnj 				ilock(dp);
2235972Swnj 				dp->i_count++;
2245972Swnj 			} else {
2255990Swnj 				dp = pdp;
2265990Swnj 				ilock(dp);
2275972Swnj 			}
2285972Swnj 			goto dirloop;
22930Sbill 		}
2305990Swnj 		iput(pdp);
2315972Swnj 		if (*cp == '/') {
2325972Swnj 			while (*cp == '/')
2335972Swnj 				cp++;
2345972Swnj 			goto dirloop;
2355972Swnj 		}
2365972Swnj 		goto out1;
23730Sbill 	}
23830Sbill 	/*
2395972Swnj 	 * Search failed.
24030Sbill 	 */
2414823Swnj 	if (bp != NULL)
24230Sbill 		brelse(bp);
2435972Swnj 	if (flag==1 && *cp=='\0' && dp->i_nlink) {
2444823Swnj 		if (access(dp, IWRITE))
24530Sbill 			goto out;
2465972Swnj 		if (eo>=0)
2475972Swnj 			u.u_offset = eo;
2485972Swnj 		dp->i_flag |= IUPD|ICHG;
2495972Swnj 		dp = NULL;
2505972Swnj 		goto out1;
25130Sbill 	}
2525972Swnj 	u.u_error = ENOENT;
25330Sbill out:
25430Sbill 	iput(dp);
2555972Swnj 	dp = NULL;
2565972Swnj out1:
2575972Swnj 	brelse(nbp);
2585972Swnj 	return (dp);
25930Sbill }
26030Sbill 
26130Sbill /*
26230Sbill  * Return the next character from the
26330Sbill  * kernel string pointed at by dirp.
26430Sbill  */
26530Sbill schar()
26630Sbill {
26730Sbill 
2685972Swnj 	return (*u.u_dirp++ & 0377);
26930Sbill }
27030Sbill 
27130Sbill /*
27230Sbill  * Return the next character from the
27330Sbill  * user string pointed at by dirp.
27430Sbill  */
27530Sbill uchar()
27630Sbill {
27730Sbill 	register c;
27830Sbill 
27930Sbill 	c = fubyte(u.u_dirp++);
2805972Swnj 	if (c == -1) {
28130Sbill 		u.u_error = EFAULT;
2825972Swnj 		c = 0;
2835972Swnj 	}
2845972Swnj 	return (c);
28530Sbill }
2865972Swnj 
2875972Swnj #ifndef vax
2885972Swnj strncmp(s1, s2, len)
2895972Swnj 	register char *s1, *s2;
2905972Swnj 	register len;
2915972Swnj {
2925972Swnj 
2935972Swnj 	do {
2945972Swnj 		if (*s1 != *s2++)
2955972Swnj 			return (1);
2965972Swnj 		if (*s1++ == '\0')
2975972Swnj 			return (0);
2985972Swnj 	} while (--len);
2995972Swnj 	return (0);
3005972Swnj }
3015972Swnj #endif
302