1*7441Sroot /* vfs_lookup.c 4.17 82/07/15 */ 230Sbill 36571Smckusic /* merged into kernel: @(#)nami.c 2.3 4/8/82 */ 46571Smckusic 530Sbill #include "../h/param.h" 630Sbill #include "../h/systm.h" 730Sbill #include "../h/inode.h" 86571Smckusic #include "../h/fs.h" 930Sbill #include "../h/mount.h" 1030Sbill #include "../h/dir.h" 1130Sbill #include "../h/user.h" 1230Sbill #include "../h/buf.h" 132275Swnj #include "../h/conf.h" 1430Sbill 15*7441Sroot #ifdef EFS 16*7441Sroot extern int efs_major; 17*7441Sroot #endif 18*7441Sroot 1930Sbill /* 2030Sbill * Convert a pathname into a pointer to 215972Swnj * a locked inode. 2230Sbill * 2330Sbill * func = function called to get next char of name 2430Sbill * &uchar if name is in user space 2530Sbill * &schar if name is in system space 2630Sbill * flag = 0 if name is sought 2730Sbill * 1 if name is to be created 2830Sbill * 2 if name is to be deleted 295972Swnj * follow = 1 if links are to be followed at the end of the name 3030Sbill */ 3130Sbill struct inode * 325972Swnj namei(func, flag, follow) 335972Swnj int (*func)(), flag, follow; 3430Sbill { 3530Sbill register struct inode *dp; 3630Sbill register char *cp; 375972Swnj register struct buf *bp, *nbp; 38194Sbill register struct direct *ep; 396571Smckusic register struct fs *fs; 405990Swnj struct inode *pdp; 416571Smckusic enum {NONE, COMPACT, FOUND} slot; 426571Smckusic int entryfree, entrysize; 436571Smckusic int spccnt, size, newsize; 446571Smckusic int loc, prevoff, curoff; 456571Smckusic int i, nlink, bsize; 466571Smckusic unsigned pathlen; 476571Smckusic daddr_t lbn, bn; 4830Sbill dev_t d; 4930Sbill 5030Sbill /* 515972Swnj * allocate name buffer; copy name 525972Swnj */ 536571Smckusic nbp = geteblk(MAXPATHLEN); 545972Swnj nlink = 0; 556571Smckusic for (i = 0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) { 566571Smckusic if ((*cp & 0377) == ('/'|0200)) { 576066Sroot u.u_error = EPERM; 586066Sroot break; 596066Sroot } 606066Sroot #ifdef notdef 616571Smckusic if (*cp++ & 0200 && flag == 1 || 626571Smckusic cp >= nbp->b_un.b_addr + MAXPATHLEN) { 636066Sroot #else 646066Sroot cp++; 656571Smckusic if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { 666066Sroot #endif 675972Swnj u.u_error = ENOENT; 685972Swnj break; 695972Swnj } 705972Swnj } 715972Swnj if (u.u_error) { 726571Smckusic brelse(nbp); 736571Smckusic return (NULL); 745972Swnj } 755972Swnj cp = nbp->b_un.b_addr; 765972Swnj /* 7730Sbill * If name starts with '/' start from 7830Sbill * root; otherwise start from current dir. 7930Sbill */ 8030Sbill dp = u.u_cdir; 815972Swnj if (*cp == '/') { 825972Swnj while (*cp == '/') 835972Swnj cp++; 8430Sbill if ((dp = u.u_rdir) == NULL) 8530Sbill dp = rootdir; 8630Sbill } 875972Swnj ilock(dp); 885972Swnj dp->i_count++; 896571Smckusic fs = dp->i_fs; 906571Smckusic newsize = 0; 916571Smckusic dirloop: 9230Sbill /* 9330Sbill * dp must be a directory and 9430Sbill * must have X permission. 955972Swnj * cp is a path name relative to that directory. 9630Sbill */ 97*7441Sroot #ifdef EFS 98*7441Sroot /* 99*7441Sroot * But first, if the last component was a character special file 100*7441Sroot * and the major device is the extended file system device 101*7441Sroot * then return even if more pathname exists. 102*7441Sroot */ 103*7441Sroot if ((dp->i_mode & IFMT) == IFCHR && major(dp->i_rdev) == efs_major) { 104*7441Sroot brelse(nbp); 105*7441Sroot return(dp); 106*7441Sroot } 107*7441Sroot #endif 1084823Swnj if ((dp->i_mode&IFMT) != IFDIR) 10930Sbill u.u_error = ENOTDIR; 110194Sbill (void) access(dp, IEXEC); 1116384Swnj dirloop2: 1126571Smckusic for (i = 0; *cp != '\0' && *cp != '/'; cp++) { 1136066Sroot #ifdef notdef 1146571Smckusic if (i >= MAXNAMLEN) { 1155972Swnj u.u_error = ENOENT; 1165972Swnj break; 1175972Swnj } 1186571Smckusic u.u_dent.d_name[i] = *cp; 1196066Sroot #else 1206571Smckusic if (i < MAXNAMLEN) { 1216571Smckusic u.u_dent.d_name[i] = *cp; 1226571Smckusic i++; 1236571Smckusic } 1246066Sroot #endif 1255972Swnj } 1266571Smckusic if (u.u_error) { 1276571Smckusic iput(dp); 1286571Smckusic brelse(nbp); 1296571Smckusic return (NULL); 1306571Smckusic } 1316571Smckusic u.u_dent.d_namlen = i; 1326571Smckusic u.u_dent.d_name[i] = '\0'; 1336571Smckusic newsize = DIRSIZ(&u.u_dent); 1345990Swnj u.u_pdir = dp; 1356571Smckusic if (u.u_dent.d_name[0] == '\0') { /* null name, e.g. "/" or "" */ 1366571Smckusic if (flag != 0) { 1375972Swnj u.u_error = ENOENT; 1386571Smckusic iput(dp); 1396571Smckusic dp = NULL; 1405972Swnj } 1416571Smckusic u.u_offset = 0; 1426571Smckusic u.u_count = newsize; 1436571Smckusic brelse(nbp); 1446571Smckusic return (dp); 1455972Swnj } 1466571Smckusic /* 1476571Smckusic * set up to search a directory 1486571Smckusic */ 1496571Smckusic if (flag == 1) 1506571Smckusic slot = NONE; 1516571Smckusic else 1526571Smckusic slot = FOUND; 1536571Smckusic u.u_offset = 0; 15430Sbill u.u_segflg = 1; 15530Sbill bp = NULL; 1566571Smckusic spccnt = 0; 1576571Smckusic loc = 0; 1586571Smckusic while (u.u_offset < dp->i_size) { 1595972Swnj /* 1606571Smckusic * check to see if enough space has been accumulated to make 1616571Smckusic * an entry by compaction. Reset the free space counter each 1626571Smckusic * time a directory block is crossed. 1636571Smckusic */ 1646571Smckusic if (slot == NONE) { 1656571Smckusic if (spccnt >= newsize) { 1666571Smckusic slot = COMPACT; 1676571Smckusic entrysize = u.u_offset - entryfree; 1686571Smckusic } else if (loc % DIRBLKSIZ == 0) { 1696571Smckusic entryfree = NULL; 1706571Smckusic spccnt = 0; 1716571Smckusic } 1726571Smckusic } 1736571Smckusic /* 1745972Swnj * If offset is on a block boundary, 1755972Swnj * read the next directory block. 1765972Swnj * Release previous if it exists. 1775972Swnj */ 1786571Smckusic if (blkoff(fs, u.u_offset) == 0) { 1795972Swnj if (bp != NULL) 1805972Swnj brelse(bp); 1816571Smckusic lbn = (daddr_t)lblkno(fs, u.u_offset); 1826571Smckusic bsize = blksize(fs, dp, lbn); 1836571Smckusic if ((bn = bmap(dp, lbn, B_READ)) < 0) { 1846571Smckusic printf("hole in dir: %s i = %d\n", 1856571Smckusic fs->fs_fsmnt, dp->i_number); 1866571Smckusic if (fs->fs_ronly != 0 || 1876571Smckusic (bn = bmap(dp, lbn, B_WRITE, bsize)) < 0) { 1886571Smckusic u.u_offset += bsize; 1896571Smckusic bp = NULL; 1906571Smckusic continue; 1916571Smckusic } 1926571Smckusic } 1936571Smckusic bp = bread(dp->i_dev, fsbtodb(fs, bn), bsize); 1945972Swnj if (bp->b_flags & B_ERROR) { 1955972Swnj brelse(bp); 1966571Smckusic iput(dp); 1976571Smckusic brelse(nbp); 1986571Smckusic return (NULL); 1995972Swnj } 2006571Smckusic loc = 0; 2016571Smckusic } else { 2026571Smckusic loc += ep->d_reclen; 2035972Swnj } 2045972Swnj /* 2056571Smckusic * calculate the next directory entry and run 2066571Smckusic * some rudimentary bounds checks to make sure 2076571Smckusic * that it is reasonable. If the check fails 2086571Smckusic * resync at the beginning of the next directory 2096571Smckusic * block. 2106571Smckusic */ 2116571Smckusic ep = (struct direct *)(bp->b_un.b_addr + loc); 2126571Smckusic i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 2136571Smckusic if (ep->d_reclen <= 0 || ep->d_reclen > i) { 2146571Smckusic loc += i; 2156571Smckusic u.u_offset += i; 2166571Smckusic continue; 2176571Smckusic } 2186571Smckusic /* 2196571Smckusic * If an appropriate sized hole has not yet been found, 2206571Smckusic * check to see if one is available. Also accumulate space 2216571Smckusic * in the current block so that we can determine if 2226571Smckusic * compaction is viable. 2236571Smckusic */ 2246571Smckusic if (slot != FOUND) { 2256571Smckusic size = ep->d_reclen; 2266571Smckusic if (ep->d_ino != 0) 2276571Smckusic size -= DIRSIZ(ep); 2286571Smckusic if (size > 0) { 2296571Smckusic if (size >= newsize) { 2306571Smckusic slot = FOUND; 2316571Smckusic entryfree = u.u_offset; 2326571Smckusic entrysize = DIRSIZ(ep) + newsize; 2336571Smckusic } 2346571Smckusic if (entryfree == NULL) 2356571Smckusic entryfree = u.u_offset; 2366571Smckusic spccnt += size; 2376571Smckusic } 2386571Smckusic } 2396571Smckusic /* 2405972Swnj * String compare the directory entry 2415972Swnj * and the current component. 2426571Smckusic * If they do not match, continue to the next entry. 2435972Swnj */ 2446571Smckusic prevoff = curoff; 2456571Smckusic curoff = u.u_offset; 2466571Smckusic u.u_offset += ep->d_reclen; 2476571Smckusic if (ep->d_ino == 0) 2485972Swnj continue; 2496571Smckusic if (ep->d_namlen != u.u_dent.d_namlen) 2505972Swnj continue; 2516571Smckusic if (bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen)) 2526571Smckusic continue; 2535972Swnj /* 2545972Swnj * Here a component matched in a directory. 2555972Swnj * If there is more pathname, go back to 2565972Swnj * dirloop, otherwise return. 2575972Swnj */ 2586571Smckusic bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep)); 2595972Swnj brelse(bp); 2606571Smckusic if (flag == 2 && *cp == '\0') { 2616571Smckusic brelse(nbp); 2626571Smckusic if (access(dp, IWRITE)) { 2636571Smckusic iput(dp); 2646571Smckusic return (NULL); 2656571Smckusic } 2666571Smckusic if (curoff % DIRBLKSIZ == 0) { 2676571Smckusic u.u_offset = curoff; 2686571Smckusic u.u_count = 0; 2696571Smckusic return (dp); 2706571Smckusic } 2716571Smckusic u.u_offset = prevoff; 2726571Smckusic u.u_count = DIRSIZ((struct direct *) 2736571Smckusic (bp->b_un.b_addr + blkoff(fs, prevoff))); 2746571Smckusic return (dp); 27530Sbill } 2765972Swnj /* 2775972Swnj * Special handling for ".." 2785972Swnj */ 2796571Smckusic if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && 2806571Smckusic u.u_dent.d_name[2] == '\0') { 2815972Swnj if (dp == u.u_rdir) 2825972Swnj u.u_dent.d_ino = dp->i_number; 2836571Smckusic else if (u.u_dent.d_ino == ROOTINO && 2845972Swnj dp->i_number == ROOTINO) { 2856571Smckusic for (i = 1; i < NMOUNT; i++) 2865972Swnj if (mount[i].m_bufp != NULL && 2875972Swnj mount[i].m_dev == dp->i_dev) { 2885972Swnj iput(dp); 2895972Swnj dp = mount[i].m_inodp; 2905972Swnj ilock(dp); 2915972Swnj dp->i_count++; 2926571Smckusic fs = dp->i_fs; 2935972Swnj cp -= 2; /* back over .. */ 2946384Swnj goto dirloop2; 2955972Swnj } 2965972Swnj } 2975972Swnj } 2985972Swnj d = dp->i_dev; 2995990Swnj pdp = dp; 3007119Smckusick iunlock(pdp); 3016571Smckusic dp = iget(d, fs, u.u_dent.d_ino); 3025990Swnj if (dp == NULL) { 3037119Smckusick irele(pdp); 3046571Smckusic brelse(nbp); 3056571Smckusic return (NULL); 3065990Swnj } 3076571Smckusic fs = dp->i_fs; 3085972Swnj /* 3095972Swnj * Check for symbolic link 3105972Swnj */ 3116571Smckusic if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) { 3126571Smckusic pathlen = strlen(cp) + 1; 3136571Smckusic if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 3146571Smckusic ++nlink > MAXSYMLINKS) { 3155972Swnj u.u_error = ELOOP; 3167119Smckusick irele(pdp); 3176571Smckusic iput(dp); 3186571Smckusic brelse(nbp); 3196571Smckusic return (NULL); 3205972Swnj } 3216571Smckusic bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 3226571Smckusic bn = bmap(dp, (daddr_t)0, B_READ); 3236571Smckusic if (bn < 0) { 3246571Smckusic printf("hole in symlink: %s i = %d\n", 3256571Smckusic fs->fs_fsmnt, dp->i_number); 3267119Smckusick irele(pdp); 3276571Smckusic iput(dp); 3286571Smckusic brelse(nbp); 3296571Smckusic return (NULL); 3306571Smckusic } 3316571Smckusic bp = bread(dp->i_dev, fsbtodb(fs, bn), 3326571Smckusic (int)blksize(fs, dp, (daddr_t)0)); 3335972Swnj if (bp->b_flags & B_ERROR) { 3345972Swnj brelse(bp); 3357119Smckusick irele(pdp); 3366571Smckusic iput(dp); 3376571Smckusic brelse(nbp); 3386571Smckusic return (NULL); 3395972Swnj } 3406164Ssam bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, 3416164Ssam (unsigned)dp->i_size); 34230Sbill brelse(bp); 3435972Swnj cp = nbp->b_un.b_addr; 3445972Swnj iput(dp); 3455972Swnj if (*cp == '/') { 3467119Smckusick irele(pdp); 3475972Swnj while (*cp == '/') 3485972Swnj cp++; 3495972Swnj if ((dp = u.u_rdir) == NULL) 3505972Swnj dp = rootdir; 3515972Swnj ilock(dp); 3525972Swnj dp->i_count++; 3535972Swnj } else { 3545990Swnj dp = pdp; 3555990Swnj ilock(dp); 3565972Swnj } 3576571Smckusic fs = dp->i_fs; 3585972Swnj goto dirloop; 35930Sbill } 3607119Smckusick irele(pdp); 3615972Swnj if (*cp == '/') { 3625972Swnj while (*cp == '/') 3635972Swnj cp++; 3645972Swnj goto dirloop; 3655972Swnj } 3666571Smckusic /* 3676571Smckusic * End of path, so return name matched. 3686571Smckusic */ 3696571Smckusic u.u_offset -= ep->d_reclen; 3706571Smckusic u.u_count = newsize; 3716571Smckusic brelse(nbp); 3726571Smckusic return (dp); 37330Sbill } 37430Sbill /* 3755972Swnj * Search failed. 3766571Smckusic * Report what is appropriate as per flag. 37730Sbill */ 3784823Swnj if (bp != NULL) 37930Sbill brelse(bp); 3806571Smckusic if (flag == 1 && *cp == '\0' && dp->i_nlink != 0) { 3816571Smckusic brelse(nbp); 3826571Smckusic if (access(dp, IWRITE)) { 3836571Smckusic iput(dp); 3846571Smckusic return (NULL); 3856571Smckusic } 3866571Smckusic if (slot == NONE) { 3876571Smckusic u.u_count = 0; 3886571Smckusic } else { 3896571Smckusic u.u_offset = entryfree; 3906571Smckusic u.u_count = entrysize; 3916571Smckusic } 3925972Swnj dp->i_flag |= IUPD|ICHG; 3936571Smckusic return (NULL); 39430Sbill } 3955972Swnj u.u_error = ENOENT; 39630Sbill iput(dp); 3975972Swnj brelse(nbp); 3986571Smckusic return (NULL); 39930Sbill } 40030Sbill 40130Sbill /* 40230Sbill * Return the next character from the 40330Sbill * kernel string pointed at by dirp. 40430Sbill */ 40530Sbill schar() 40630Sbill { 40730Sbill 4085972Swnj return (*u.u_dirp++ & 0377); 40930Sbill } 41030Sbill 41130Sbill /* 41230Sbill * Return the next character from the 41330Sbill * user string pointed at by dirp. 41430Sbill */ 41530Sbill uchar() 41630Sbill { 41730Sbill register c; 41830Sbill 41930Sbill c = fubyte(u.u_dirp++); 4205972Swnj if (c == -1) { 42130Sbill u.u_error = EFAULT; 4225972Swnj c = 0; 4235972Swnj } 4245972Swnj return (c); 42530Sbill } 4265972Swnj 4275972Swnj #ifndef vax 4286571Smckusic bcmp(s1, s2, len) 4295972Swnj register char *s1, *s2; 4306571Smckusic register int len; 4315972Swnj { 4325972Swnj 4336571Smckusic while (--len) 4346571Smckusic if (*s1++ != *s2++) 4355972Swnj return (1); 4365972Swnj return (0); 4375972Swnj } 4386571Smckusic 4396571Smckusic strlen(s1) 4406571Smckusic register char *s1; 4416571Smckusic { 4426571Smckusic register int len; 4436571Smckusic 4446571Smckusic for (len = 0; *s1++ != '\0'; len++) 4456571Smckusic /* void */; 4466571Smckusic return (len); 4476571Smckusic } 4485972Swnj #endif 449