1 /* ufs_lookup.c 4.15 82/04/19 */ 2 3 /* merged into kernel: @(#)nami.c 2.3 4/8/82 */ 4 5 #include "../h/param.h" 6 #include "../h/systm.h" 7 #include "../h/inode.h" 8 #include "../h/fs.h" 9 #include "../h/mount.h" 10 #include "../h/dir.h" 11 #include "../h/user.h" 12 #include "../h/buf.h" 13 #include "../h/conf.h" 14 15 /* 16 * Convert a pathname into a pointer to 17 * a locked inode. 18 * 19 * func = function called to get next char of name 20 * &uchar if name is in user space 21 * &schar if name is in system space 22 * flag = 0 if name is sought 23 * 1 if name is to be created 24 * 2 if name is to be deleted 25 * follow = 1 if links are to be followed at the end of the name 26 */ 27 struct inode * 28 namei(func, flag, follow) 29 int (*func)(), flag, follow; 30 { 31 register struct inode *dp; 32 register char *cp; 33 register struct buf *bp, *nbp; 34 register struct direct *ep; 35 register struct fs *fs; 36 struct inode *pdp; 37 enum {NONE, COMPACT, FOUND} slot; 38 int entryfree, entrysize; 39 int spccnt, size, newsize; 40 int loc, prevoff, curoff; 41 int i, nlink, bsize; 42 unsigned pathlen; 43 daddr_t lbn, bn; 44 dev_t d; 45 46 /* 47 * allocate name buffer; copy name 48 */ 49 nbp = geteblk(MAXPATHLEN); 50 nlink = 0; 51 for (i = 0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) { 52 if ((*cp & 0377) == ('/'|0200)) { 53 u.u_error = EPERM; 54 break; 55 } 56 #ifdef notdef 57 if (*cp++ & 0200 && flag == 1 || 58 cp >= nbp->b_un.b_addr + MAXPATHLEN) { 59 #else 60 cp++; 61 if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { 62 #endif 63 u.u_error = ENOENT; 64 break; 65 } 66 } 67 if (u.u_error) { 68 brelse(nbp); 69 return (NULL); 70 } 71 cp = nbp->b_un.b_addr; 72 /* 73 * If name starts with '/' start from 74 * root; otherwise start from current dir. 75 */ 76 dp = u.u_cdir; 77 if (*cp == '/') { 78 while (*cp == '/') 79 cp++; 80 if ((dp = u.u_rdir) == NULL) 81 dp = rootdir; 82 } 83 ilock(dp); 84 dp->i_count++; 85 fs = dp->i_fs; 86 newsize = 0; 87 dirloop: 88 /* 89 * dp must be a directory and 90 * must have X permission. 91 * cp is a path name relative to that directory. 92 */ 93 if ((dp->i_mode&IFMT) != IFDIR) 94 u.u_error = ENOTDIR; 95 (void) access(dp, IEXEC); 96 dirloop2: 97 for (i = 0; *cp != '\0' && *cp != '/'; cp++) { 98 #ifdef notdef 99 if (i >= MAXNAMLEN) { 100 u.u_error = ENOENT; 101 break; 102 } 103 u.u_dent.d_name[i] = *cp; 104 #else 105 if (i < MAXNAMLEN) { 106 u.u_dent.d_name[i] = *cp; 107 i++; 108 } 109 #endif 110 } 111 if (u.u_error) { 112 iput(dp); 113 brelse(nbp); 114 return (NULL); 115 } 116 u.u_dent.d_namlen = i; 117 u.u_dent.d_name[i] = '\0'; 118 newsize = DIRSIZ(&u.u_dent); 119 u.u_pdir = dp; 120 if (u.u_dent.d_name[0] == '\0') { /* null name, e.g. "/" or "" */ 121 if (flag != 0) { 122 u.u_error = ENOENT; 123 iput(dp); 124 dp = NULL; 125 } 126 u.u_offset = 0; 127 u.u_count = newsize; 128 brelse(nbp); 129 return (dp); 130 } 131 /* 132 * set up to search a directory 133 */ 134 if (flag == 1) 135 slot = NONE; 136 else 137 slot = FOUND; 138 u.u_offset = 0; 139 u.u_segflg = 1; 140 bp = NULL; 141 spccnt = 0; 142 loc = 0; 143 while (u.u_offset < dp->i_size) { 144 /* 145 * check to see if enough space has been accumulated to make 146 * an entry by compaction. Reset the free space counter each 147 * time a directory block is crossed. 148 */ 149 if (slot == NONE) { 150 if (spccnt >= newsize) { 151 slot = COMPACT; 152 entrysize = u.u_offset - entryfree; 153 } else if (loc % DIRBLKSIZ == 0) { 154 entryfree = NULL; 155 spccnt = 0; 156 } 157 } 158 /* 159 * If offset is on a block boundary, 160 * read the next directory block. 161 * Release previous if it exists. 162 */ 163 if (blkoff(fs, u.u_offset) == 0) { 164 if (bp != NULL) 165 brelse(bp); 166 lbn = (daddr_t)lblkno(fs, u.u_offset); 167 bsize = blksize(fs, dp, lbn); 168 if ((bn = bmap(dp, lbn, B_READ)) < 0) { 169 printf("hole in dir: %s i = %d\n", 170 fs->fs_fsmnt, dp->i_number); 171 if (fs->fs_ronly != 0 || 172 (bn = bmap(dp, lbn, B_WRITE, bsize)) < 0) { 173 u.u_offset += bsize; 174 bp = NULL; 175 continue; 176 } 177 } 178 bp = bread(dp->i_dev, fsbtodb(fs, bn), bsize); 179 if (bp->b_flags & B_ERROR) { 180 brelse(bp); 181 iput(dp); 182 brelse(nbp); 183 return (NULL); 184 } 185 loc = 0; 186 } else { 187 loc += ep->d_reclen; 188 } 189 /* 190 * calculate the next directory entry and run 191 * some rudimentary bounds checks to make sure 192 * that it is reasonable. If the check fails 193 * resync at the beginning of the next directory 194 * block. 195 */ 196 ep = (struct direct *)(bp->b_un.b_addr + loc); 197 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 198 if (ep->d_reclen <= 0 || ep->d_reclen > i) { 199 loc += i; 200 u.u_offset += i; 201 continue; 202 } 203 /* 204 * If an appropriate sized hole has not yet been found, 205 * check to see if one is available. Also accumulate space 206 * in the current block so that we can determine if 207 * compaction is viable. 208 */ 209 if (slot != FOUND) { 210 size = ep->d_reclen; 211 if (ep->d_ino != 0) 212 size -= DIRSIZ(ep); 213 if (size > 0) { 214 if (size >= newsize) { 215 slot = FOUND; 216 entryfree = u.u_offset; 217 entrysize = DIRSIZ(ep) + newsize; 218 } 219 if (entryfree == NULL) 220 entryfree = u.u_offset; 221 spccnt += size; 222 } 223 } 224 /* 225 * String compare the directory entry 226 * and the current component. 227 * If they do not match, continue to the next entry. 228 */ 229 prevoff = curoff; 230 curoff = u.u_offset; 231 u.u_offset += ep->d_reclen; 232 if (ep->d_ino == 0) 233 continue; 234 if (ep->d_namlen != u.u_dent.d_namlen) 235 continue; 236 if (bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen)) 237 continue; 238 /* 239 * Here a component matched in a directory. 240 * If there is more pathname, go back to 241 * dirloop, otherwise return. 242 */ 243 bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep)); 244 brelse(bp); 245 if (flag == 2 && *cp == '\0') { 246 brelse(nbp); 247 if (access(dp, IWRITE)) { 248 iput(dp); 249 return (NULL); 250 } 251 if (curoff % DIRBLKSIZ == 0) { 252 u.u_offset = curoff; 253 u.u_count = 0; 254 return (dp); 255 } 256 u.u_offset = prevoff; 257 u.u_count = DIRSIZ((struct direct *) 258 (bp->b_un.b_addr + blkoff(fs, prevoff))); 259 return (dp); 260 } 261 /* 262 * Special handling for ".." 263 */ 264 if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && 265 u.u_dent.d_name[2] == '\0') { 266 if (dp == u.u_rdir) 267 u.u_dent.d_ino = dp->i_number; 268 else if (u.u_dent.d_ino == ROOTINO && 269 dp->i_number == ROOTINO) { 270 for (i = 1; i < NMOUNT; i++) 271 if (mount[i].m_bufp != NULL && 272 mount[i].m_dev == dp->i_dev) { 273 iput(dp); 274 dp = mount[i].m_inodp; 275 ilock(dp); 276 dp->i_count++; 277 fs = dp->i_fs; 278 cp -= 2; /* back over .. */ 279 goto dirloop2; 280 } 281 } 282 } 283 d = dp->i_dev; 284 irele(dp); 285 pdp = dp; 286 dp = iget(d, fs, u.u_dent.d_ino); 287 if (dp == NULL) { 288 iput(pdp); 289 brelse(nbp); 290 return (NULL); 291 } 292 fs = dp->i_fs; 293 /* 294 * Check for symbolic link 295 */ 296 if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) { 297 pathlen = strlen(cp) + 1; 298 if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 299 ++nlink > MAXSYMLINKS) { 300 u.u_error = ELOOP; 301 iput(pdp); 302 iput(dp); 303 brelse(nbp); 304 return (NULL); 305 } 306 bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 307 bn = bmap(dp, (daddr_t)0, B_READ); 308 if (bn < 0) { 309 printf("hole in symlink: %s i = %d\n", 310 fs->fs_fsmnt, dp->i_number); 311 iput(pdp); 312 iput(dp); 313 brelse(nbp); 314 return (NULL); 315 } 316 bp = bread(dp->i_dev, fsbtodb(fs, bn), 317 (int)blksize(fs, dp, (daddr_t)0)); 318 if (bp->b_flags & B_ERROR) { 319 brelse(bp); 320 iput(pdp); 321 iput(dp); 322 brelse(nbp); 323 return (NULL); 324 } 325 bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, 326 (unsigned)dp->i_size); 327 brelse(bp); 328 cp = nbp->b_un.b_addr; 329 iput(dp); 330 if (*cp == '/') { 331 iput(pdp); 332 while (*cp == '/') 333 cp++; 334 if ((dp = u.u_rdir) == NULL) 335 dp = rootdir; 336 ilock(dp); 337 dp->i_count++; 338 } else { 339 dp = pdp; 340 ilock(dp); 341 } 342 fs = dp->i_fs; 343 goto dirloop; 344 } 345 iput(pdp); 346 if (*cp == '/') { 347 while (*cp == '/') 348 cp++; 349 goto dirloop; 350 } 351 /* 352 * End of path, so return name matched. 353 */ 354 u.u_offset -= ep->d_reclen; 355 u.u_count = newsize; 356 brelse(nbp); 357 return (dp); 358 } 359 /* 360 * Search failed. 361 * Report what is appropriate as per flag. 362 */ 363 if (bp != NULL) 364 brelse(bp); 365 if (flag == 1 && *cp == '\0' && dp->i_nlink != 0) { 366 brelse(nbp); 367 if (access(dp, IWRITE)) { 368 iput(dp); 369 return (NULL); 370 } 371 if (slot == NONE) { 372 u.u_count = 0; 373 } else { 374 u.u_offset = entryfree; 375 u.u_count = entrysize; 376 } 377 dp->i_flag |= IUPD|ICHG; 378 return (NULL); 379 } 380 u.u_error = ENOENT; 381 iput(dp); 382 brelse(nbp); 383 return (NULL); 384 } 385 386 /* 387 * Return the next character from the 388 * kernel string pointed at by dirp. 389 */ 390 schar() 391 { 392 393 return (*u.u_dirp++ & 0377); 394 } 395 396 /* 397 * Return the next character from the 398 * user string pointed at by dirp. 399 */ 400 uchar() 401 { 402 register c; 403 404 c = fubyte(u.u_dirp++); 405 if (c == -1) { 406 u.u_error = EFAULT; 407 c = 0; 408 } 409 return (c); 410 } 411 412 #ifndef vax 413 bcmp(s1, s2, len) 414 register char *s1, *s2; 415 register int len; 416 { 417 418 while (--len) 419 if (*s1++ != *s2++) 420 return (1); 421 return (0); 422 } 423 424 strlen(s1) 425 register char *s1; 426 { 427 register int len; 428 429 for (len = 0; *s1++ != '\0'; len++) 430 /* void */; 431 return (len); 432 } 433 #endif 434