1*6571Smckusic /* vfs_lookup.c 4.15 82/04/19 */ 230Sbill 3*6571Smckusic /* merged into kernel: @(#)nami.c 2.3 4/8/82 */ 4*6571Smckusic 530Sbill #include "../h/param.h" 630Sbill #include "../h/systm.h" 730Sbill #include "../h/inode.h" 8*6571Smckusic #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 1530Sbill /* 1630Sbill * Convert a pathname into a pointer to 175972Swnj * a locked inode. 1830Sbill * 1930Sbill * func = function called to get next char of name 2030Sbill * &uchar if name is in user space 2130Sbill * &schar if name is in system space 2230Sbill * flag = 0 if name is sought 2330Sbill * 1 if name is to be created 2430Sbill * 2 if name is to be deleted 255972Swnj * follow = 1 if links are to be followed at the end of the name 2630Sbill */ 2730Sbill struct inode * 285972Swnj namei(func, flag, follow) 295972Swnj int (*func)(), flag, follow; 3030Sbill { 3130Sbill register struct inode *dp; 3230Sbill register char *cp; 335972Swnj register struct buf *bp, *nbp; 34194Sbill register struct direct *ep; 35*6571Smckusic register struct fs *fs; 365990Swnj struct inode *pdp; 37*6571Smckusic enum {NONE, COMPACT, FOUND} slot; 38*6571Smckusic int entryfree, entrysize; 39*6571Smckusic int spccnt, size, newsize; 40*6571Smckusic int loc, prevoff, curoff; 41*6571Smckusic int i, nlink, bsize; 42*6571Smckusic unsigned pathlen; 43*6571Smckusic daddr_t lbn, bn; 4430Sbill dev_t d; 4530Sbill 4630Sbill /* 475972Swnj * allocate name buffer; copy name 485972Swnj */ 49*6571Smckusic nbp = geteblk(MAXPATHLEN); 505972Swnj nlink = 0; 51*6571Smckusic for (i = 0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) { 52*6571Smckusic if ((*cp & 0377) == ('/'|0200)) { 536066Sroot u.u_error = EPERM; 546066Sroot break; 556066Sroot } 566066Sroot #ifdef notdef 57*6571Smckusic if (*cp++ & 0200 && flag == 1 || 58*6571Smckusic cp >= nbp->b_un.b_addr + MAXPATHLEN) { 596066Sroot #else 606066Sroot cp++; 61*6571Smckusic if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { 626066Sroot #endif 635972Swnj u.u_error = ENOENT; 645972Swnj break; 655972Swnj } 665972Swnj } 675972Swnj if (u.u_error) { 68*6571Smckusic brelse(nbp); 69*6571Smckusic return (NULL); 705972Swnj } 715972Swnj cp = nbp->b_un.b_addr; 725972Swnj /* 7330Sbill * If name starts with '/' start from 7430Sbill * root; otherwise start from current dir. 7530Sbill */ 7630Sbill dp = u.u_cdir; 775972Swnj if (*cp == '/') { 785972Swnj while (*cp == '/') 795972Swnj cp++; 8030Sbill if ((dp = u.u_rdir) == NULL) 8130Sbill dp = rootdir; 8230Sbill } 835972Swnj ilock(dp); 845972Swnj dp->i_count++; 85*6571Smckusic fs = dp->i_fs; 86*6571Smckusic newsize = 0; 87*6571Smckusic dirloop: 8830Sbill /* 8930Sbill * dp must be a directory and 9030Sbill * must have X permission. 915972Swnj * cp is a path name relative to that directory. 9230Sbill */ 934823Swnj if ((dp->i_mode&IFMT) != IFDIR) 9430Sbill u.u_error = ENOTDIR; 95194Sbill (void) access(dp, IEXEC); 966384Swnj dirloop2: 97*6571Smckusic for (i = 0; *cp != '\0' && *cp != '/'; cp++) { 986066Sroot #ifdef notdef 99*6571Smckusic if (i >= MAXNAMLEN) { 1005972Swnj u.u_error = ENOENT; 1015972Swnj break; 1025972Swnj } 103*6571Smckusic u.u_dent.d_name[i] = *cp; 1046066Sroot #else 105*6571Smckusic if (i < MAXNAMLEN) { 106*6571Smckusic u.u_dent.d_name[i] = *cp; 107*6571Smckusic i++; 108*6571Smckusic } 1096066Sroot #endif 1105972Swnj } 111*6571Smckusic if (u.u_error) { 112*6571Smckusic iput(dp); 113*6571Smckusic brelse(nbp); 114*6571Smckusic return (NULL); 115*6571Smckusic } 116*6571Smckusic u.u_dent.d_namlen = i; 117*6571Smckusic u.u_dent.d_name[i] = '\0'; 118*6571Smckusic newsize = DIRSIZ(&u.u_dent); 1195990Swnj u.u_pdir = dp; 120*6571Smckusic if (u.u_dent.d_name[0] == '\0') { /* null name, e.g. "/" or "" */ 121*6571Smckusic if (flag != 0) { 1225972Swnj u.u_error = ENOENT; 123*6571Smckusic iput(dp); 124*6571Smckusic dp = NULL; 1255972Swnj } 126*6571Smckusic u.u_offset = 0; 127*6571Smckusic u.u_count = newsize; 128*6571Smckusic brelse(nbp); 129*6571Smckusic return (dp); 1305972Swnj } 131*6571Smckusic /* 132*6571Smckusic * set up to search a directory 133*6571Smckusic */ 134*6571Smckusic if (flag == 1) 135*6571Smckusic slot = NONE; 136*6571Smckusic else 137*6571Smckusic slot = FOUND; 138*6571Smckusic u.u_offset = 0; 13930Sbill u.u_segflg = 1; 14030Sbill bp = NULL; 141*6571Smckusic spccnt = 0; 142*6571Smckusic loc = 0; 143*6571Smckusic while (u.u_offset < dp->i_size) { 1445972Swnj /* 145*6571Smckusic * check to see if enough space has been accumulated to make 146*6571Smckusic * an entry by compaction. Reset the free space counter each 147*6571Smckusic * time a directory block is crossed. 148*6571Smckusic */ 149*6571Smckusic if (slot == NONE) { 150*6571Smckusic if (spccnt >= newsize) { 151*6571Smckusic slot = COMPACT; 152*6571Smckusic entrysize = u.u_offset - entryfree; 153*6571Smckusic } else if (loc % DIRBLKSIZ == 0) { 154*6571Smckusic entryfree = NULL; 155*6571Smckusic spccnt = 0; 156*6571Smckusic } 157*6571Smckusic } 158*6571Smckusic /* 1595972Swnj * If offset is on a block boundary, 1605972Swnj * read the next directory block. 1615972Swnj * Release previous if it exists. 1625972Swnj */ 163*6571Smckusic if (blkoff(fs, u.u_offset) == 0) { 1645972Swnj if (bp != NULL) 1655972Swnj brelse(bp); 166*6571Smckusic lbn = (daddr_t)lblkno(fs, u.u_offset); 167*6571Smckusic bsize = blksize(fs, dp, lbn); 168*6571Smckusic if ((bn = bmap(dp, lbn, B_READ)) < 0) { 169*6571Smckusic printf("hole in dir: %s i = %d\n", 170*6571Smckusic fs->fs_fsmnt, dp->i_number); 171*6571Smckusic if (fs->fs_ronly != 0 || 172*6571Smckusic (bn = bmap(dp, lbn, B_WRITE, bsize)) < 0) { 173*6571Smckusic u.u_offset += bsize; 174*6571Smckusic bp = NULL; 175*6571Smckusic continue; 176*6571Smckusic } 177*6571Smckusic } 178*6571Smckusic bp = bread(dp->i_dev, fsbtodb(fs, bn), bsize); 1795972Swnj if (bp->b_flags & B_ERROR) { 1805972Swnj brelse(bp); 181*6571Smckusic iput(dp); 182*6571Smckusic brelse(nbp); 183*6571Smckusic return (NULL); 1845972Swnj } 185*6571Smckusic loc = 0; 186*6571Smckusic } else { 187*6571Smckusic loc += ep->d_reclen; 1885972Swnj } 1895972Swnj /* 190*6571Smckusic * calculate the next directory entry and run 191*6571Smckusic * some rudimentary bounds checks to make sure 192*6571Smckusic * that it is reasonable. If the check fails 193*6571Smckusic * resync at the beginning of the next directory 194*6571Smckusic * block. 195*6571Smckusic */ 196*6571Smckusic ep = (struct direct *)(bp->b_un.b_addr + loc); 197*6571Smckusic i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 198*6571Smckusic if (ep->d_reclen <= 0 || ep->d_reclen > i) { 199*6571Smckusic loc += i; 200*6571Smckusic u.u_offset += i; 201*6571Smckusic continue; 202*6571Smckusic } 203*6571Smckusic /* 204*6571Smckusic * If an appropriate sized hole has not yet been found, 205*6571Smckusic * check to see if one is available. Also accumulate space 206*6571Smckusic * in the current block so that we can determine if 207*6571Smckusic * compaction is viable. 208*6571Smckusic */ 209*6571Smckusic if (slot != FOUND) { 210*6571Smckusic size = ep->d_reclen; 211*6571Smckusic if (ep->d_ino != 0) 212*6571Smckusic size -= DIRSIZ(ep); 213*6571Smckusic if (size > 0) { 214*6571Smckusic if (size >= newsize) { 215*6571Smckusic slot = FOUND; 216*6571Smckusic entryfree = u.u_offset; 217*6571Smckusic entrysize = DIRSIZ(ep) + newsize; 218*6571Smckusic } 219*6571Smckusic if (entryfree == NULL) 220*6571Smckusic entryfree = u.u_offset; 221*6571Smckusic spccnt += size; 222*6571Smckusic } 223*6571Smckusic } 224*6571Smckusic /* 2255972Swnj * String compare the directory entry 2265972Swnj * and the current component. 227*6571Smckusic * If they do not match, continue to the next entry. 2285972Swnj */ 229*6571Smckusic prevoff = curoff; 230*6571Smckusic curoff = u.u_offset; 231*6571Smckusic u.u_offset += ep->d_reclen; 232*6571Smckusic if (ep->d_ino == 0) 2335972Swnj continue; 234*6571Smckusic if (ep->d_namlen != u.u_dent.d_namlen) 2355972Swnj continue; 236*6571Smckusic if (bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen)) 237*6571Smckusic continue; 2385972Swnj /* 2395972Swnj * Here a component matched in a directory. 2405972Swnj * If there is more pathname, go back to 2415972Swnj * dirloop, otherwise return. 2425972Swnj */ 243*6571Smckusic bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep)); 2445972Swnj brelse(bp); 245*6571Smckusic if (flag == 2 && *cp == '\0') { 246*6571Smckusic brelse(nbp); 247*6571Smckusic if (access(dp, IWRITE)) { 248*6571Smckusic iput(dp); 249*6571Smckusic return (NULL); 250*6571Smckusic } 251*6571Smckusic if (curoff % DIRBLKSIZ == 0) { 252*6571Smckusic u.u_offset = curoff; 253*6571Smckusic u.u_count = 0; 254*6571Smckusic return (dp); 255*6571Smckusic } 256*6571Smckusic u.u_offset = prevoff; 257*6571Smckusic u.u_count = DIRSIZ((struct direct *) 258*6571Smckusic (bp->b_un.b_addr + blkoff(fs, prevoff))); 259*6571Smckusic return (dp); 26030Sbill } 2615972Swnj /* 2625972Swnj * Special handling for ".." 2635972Swnj */ 264*6571Smckusic if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && 265*6571Smckusic u.u_dent.d_name[2] == '\0') { 2665972Swnj if (dp == u.u_rdir) 2675972Swnj u.u_dent.d_ino = dp->i_number; 268*6571Smckusic else if (u.u_dent.d_ino == ROOTINO && 2695972Swnj dp->i_number == ROOTINO) { 270*6571Smckusic for (i = 1; i < NMOUNT; i++) 2715972Swnj if (mount[i].m_bufp != NULL && 2725972Swnj mount[i].m_dev == dp->i_dev) { 2735972Swnj iput(dp); 2745972Swnj dp = mount[i].m_inodp; 2755972Swnj ilock(dp); 2765972Swnj dp->i_count++; 277*6571Smckusic fs = dp->i_fs; 2785972Swnj cp -= 2; /* back over .. */ 2796384Swnj goto dirloop2; 2805972Swnj } 2815972Swnj } 2825972Swnj } 2835972Swnj d = dp->i_dev; 2845990Swnj irele(dp); 2855990Swnj pdp = dp; 286*6571Smckusic dp = iget(d, fs, u.u_dent.d_ino); 2875990Swnj if (dp == NULL) { 2885990Swnj iput(pdp); 289*6571Smckusic brelse(nbp); 290*6571Smckusic return (NULL); 2915990Swnj } 292*6571Smckusic fs = dp->i_fs; 2935972Swnj /* 2945972Swnj * Check for symbolic link 2955972Swnj */ 296*6571Smckusic if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) { 297*6571Smckusic pathlen = strlen(cp) + 1; 298*6571Smckusic if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 299*6571Smckusic ++nlink > MAXSYMLINKS) { 3005972Swnj u.u_error = ELOOP; 3015990Swnj iput(pdp); 302*6571Smckusic iput(dp); 303*6571Smckusic brelse(nbp); 304*6571Smckusic return (NULL); 3055972Swnj } 306*6571Smckusic bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 307*6571Smckusic bn = bmap(dp, (daddr_t)0, B_READ); 308*6571Smckusic if (bn < 0) { 309*6571Smckusic printf("hole in symlink: %s i = %d\n", 310*6571Smckusic fs->fs_fsmnt, dp->i_number); 311*6571Smckusic iput(pdp); 312*6571Smckusic iput(dp); 313*6571Smckusic brelse(nbp); 314*6571Smckusic return (NULL); 315*6571Smckusic } 316*6571Smckusic bp = bread(dp->i_dev, fsbtodb(fs, bn), 317*6571Smckusic (int)blksize(fs, dp, (daddr_t)0)); 3185972Swnj if (bp->b_flags & B_ERROR) { 3195972Swnj brelse(bp); 3205990Swnj iput(pdp); 321*6571Smckusic iput(dp); 322*6571Smckusic brelse(nbp); 323*6571Smckusic return (NULL); 3245972Swnj } 3256164Ssam bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, 3266164Ssam (unsigned)dp->i_size); 32730Sbill brelse(bp); 3285972Swnj cp = nbp->b_un.b_addr; 3295972Swnj iput(dp); 3305972Swnj if (*cp == '/') { 3315990Swnj iput(pdp); 3325972Swnj while (*cp == '/') 3335972Swnj cp++; 3345972Swnj if ((dp = u.u_rdir) == NULL) 3355972Swnj dp = rootdir; 3365972Swnj ilock(dp); 3375972Swnj dp->i_count++; 3385972Swnj } else { 3395990Swnj dp = pdp; 3405990Swnj ilock(dp); 3415972Swnj } 342*6571Smckusic fs = dp->i_fs; 3435972Swnj goto dirloop; 34430Sbill } 3455990Swnj iput(pdp); 3465972Swnj if (*cp == '/') { 3475972Swnj while (*cp == '/') 3485972Swnj cp++; 3495972Swnj goto dirloop; 3505972Swnj } 351*6571Smckusic /* 352*6571Smckusic * End of path, so return name matched. 353*6571Smckusic */ 354*6571Smckusic u.u_offset -= ep->d_reclen; 355*6571Smckusic u.u_count = newsize; 356*6571Smckusic brelse(nbp); 357*6571Smckusic return (dp); 35830Sbill } 35930Sbill /* 3605972Swnj * Search failed. 361*6571Smckusic * Report what is appropriate as per flag. 36230Sbill */ 3634823Swnj if (bp != NULL) 36430Sbill brelse(bp); 365*6571Smckusic if (flag == 1 && *cp == '\0' && dp->i_nlink != 0) { 366*6571Smckusic brelse(nbp); 367*6571Smckusic if (access(dp, IWRITE)) { 368*6571Smckusic iput(dp); 369*6571Smckusic return (NULL); 370*6571Smckusic } 371*6571Smckusic if (slot == NONE) { 372*6571Smckusic u.u_count = 0; 373*6571Smckusic } else { 374*6571Smckusic u.u_offset = entryfree; 375*6571Smckusic u.u_count = entrysize; 376*6571Smckusic } 3775972Swnj dp->i_flag |= IUPD|ICHG; 378*6571Smckusic return (NULL); 37930Sbill } 3805972Swnj u.u_error = ENOENT; 38130Sbill iput(dp); 3825972Swnj brelse(nbp); 383*6571Smckusic return (NULL); 38430Sbill } 38530Sbill 38630Sbill /* 38730Sbill * Return the next character from the 38830Sbill * kernel string pointed at by dirp. 38930Sbill */ 39030Sbill schar() 39130Sbill { 39230Sbill 3935972Swnj return (*u.u_dirp++ & 0377); 39430Sbill } 39530Sbill 39630Sbill /* 39730Sbill * Return the next character from the 39830Sbill * user string pointed at by dirp. 39930Sbill */ 40030Sbill uchar() 40130Sbill { 40230Sbill register c; 40330Sbill 40430Sbill c = fubyte(u.u_dirp++); 4055972Swnj if (c == -1) { 40630Sbill u.u_error = EFAULT; 4075972Swnj c = 0; 4085972Swnj } 4095972Swnj return (c); 41030Sbill } 4115972Swnj 4125972Swnj #ifndef vax 413*6571Smckusic bcmp(s1, s2, len) 4145972Swnj register char *s1, *s2; 415*6571Smckusic register int len; 4165972Swnj { 4175972Swnj 418*6571Smckusic while (--len) 419*6571Smckusic if (*s1++ != *s2++) 4205972Swnj return (1); 4215972Swnj return (0); 4225972Swnj } 423*6571Smckusic 424*6571Smckusic strlen(s1) 425*6571Smckusic register char *s1; 426*6571Smckusic { 427*6571Smckusic register int len; 428*6571Smckusic 429*6571Smckusic for (len = 0; *s1++ != '\0'; len++) 430*6571Smckusic /* void */; 431*6571Smckusic return (len); 432*6571Smckusic } 4335972Swnj #endif 434