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