1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ufs_lookup.c 7.39 (Berkeley) 02/04/92 8 */ 9 10 #include <sys/param.h> 11 #include <sys/namei.h> 12 #include <sys/buf.h> 13 #include <sys/file.h> 14 #include <sys/mount.h> 15 #include <sys/vnode.h> 16 17 #include <ufs/ufs/quota.h> 18 #include <ufs/ufs/inode.h> 19 #include <ufs/ufs/dir.h> 20 #include <ufs/ufs/ufsmount.h> 21 #include <ufs/ufs/ufs_extern.h> 22 23 struct nchstats nchstats; 24 #ifdef DIAGNOSTIC 25 int dirchk = 1; 26 #else 27 int dirchk = 0; 28 #endif 29 30 /* 31 * Convert a component of a pathname into a pointer to a locked inode. 32 * This is a very central and rather complicated routine. 33 * If the file system is not maintained in a strict tree hierarchy, 34 * this can result in a deadlock situation (see comments in code below). 35 * 36 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending on 37 * whether the name is to be looked up, created, renamed, or deleted. 38 * When CREATE, RENAME, or DELETE is specified, information usable in 39 * creating, renaming, or deleting a directory entry may be calculated. 40 * If flag has LOCKPARENT or'ed into it and the target of the pathname 41 * exists, lookup returns both the target and its parent directory locked. 42 * When creating or renaming and LOCKPARENT is specified, the target may 43 * not be ".". When deleting and LOCKPARENT is specified, the target may 44 * be "."., but the caller must check to ensure it does an vrele and iput 45 * instead of two iputs. 46 * 47 * Overall outline of ufs_lookup: 48 * 49 * check accessibility of directory 50 * look for name in cache, if found, then if at end of path 51 * and deleting or creating, drop it, else return name 52 * search for name in directory, to found or notfound 53 * notfound: 54 * if creating, return locked directory, leaving info on available slots 55 * else return error 56 * found: 57 * if at end of path and deleting, return information to allow delete 58 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 59 * inode and return info to allow rewrite 60 * if not at end, add name to cache; if at end and neither creating 61 * nor deleting, add name to cache 62 * 63 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. 64 */ 65 int 66 ufs_lookup(dvp, vpp, cnp) 67 struct vnode *dvp; 68 struct vnode **vpp; 69 struct componentname *cnp; 70 { 71 register struct inode *dp; /* the directory we are searching */ 72 struct buf *bp; /* a buffer of directory entries */ 73 register struct direct *ep; /* the current directory entry */ 74 int entryoffsetinblock; /* offset of ep in bp's buffer */ 75 enum {NONE, COMPACT, FOUND} slotstatus; 76 int slotoffset; /* offset of area with free space */ 77 int slotsize; /* size of area at slotoffset */ 78 int slotfreespace; /* amount of space free in slot */ 79 int slotneeded; /* size of the entry we're seeking */ 80 int numdirpasses; /* strategy for directory search */ 81 int endsearch; /* offset to end directory search */ 82 int prevoff; /* prev entry dp->i_offset */ 83 struct inode *pdp; /* saved dp during symlink work */ 84 struct vnode *tdp; /* returned by VOP_VGET */ 85 off_t enduseful; /* pointer past last used dir slot */ 86 u_long bmask; /* block offset mask */ 87 int lockparent; /* 1 => lockparent flag is set */ 88 int wantparent; /* 1 => wantparent or lockparent flag */ 89 int error; 90 struct vnode *vdp = dvp; /* saved for one special case */ 91 92 bp = NULL; 93 slotoffset = -1; 94 *vpp = NULL; 95 dp = VTOI(dvp); 96 lockparent = cnp->cn_flags & LOCKPARENT; 97 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 98 99 /* 100 * Check accessiblity of directory. 101 */ 102 if ((dp->i_mode & IFMT) != IFDIR) 103 return (ENOTDIR); 104 if (error = ufs_access(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc)) 105 return (error); 106 107 /* 108 * We now have a segment name to search for, and a directory to search. 109 * 110 * Before tediously performing a linear scan of the directory, 111 * check the name cache to see if the directory/name pair 112 * we are looking for is known already. 113 */ 114 if (error = cache_lookup(dvp, vpp, cnp)) { 115 int vpid; /* capability number of vnode */ 116 117 if (error == ENOENT) 118 return (error); 119 #ifdef PARANOID 120 if (dvp == ndp->ni_rdir && (cnp->cn_flags & ISDOTDOT)) 121 panic("ufs_lookup: .. through root"); 122 #endif 123 /* 124 * Get the next vnode in the path. 125 * See comment below starting `Step through' for 126 * an explaination of the locking protocol. 127 */ 128 /* 129 * NEEDSWORK: The borrowing of variables 130 * here is quite confusing. Usually, dvp/dp 131 * is the directory being searched. 132 * Here it's the target returned from the cache. 133 */ 134 pdp = dp; 135 dp = VTOI(*vpp); 136 dvp = *vpp; 137 vpid = dvp->v_id; 138 if (pdp == dp) { /* lookup on "." */ 139 VREF(dvp); 140 error = 0; 141 } else if (cnp->cn_flags & ISDOTDOT) { 142 IUNLOCK(pdp); 143 error = vget(dvp); 144 if (!error && lockparent && (cnp->cn_flags & ISLASTCN)) 145 ILOCK(pdp); 146 } else { 147 error = vget(dvp); 148 if (!lockparent || error || !(cnp->cn_flags & ISLASTCN)) 149 IUNLOCK(pdp); 150 } 151 /* 152 * Check that the capability number did not change 153 * while we were waiting for the lock. 154 */ 155 if (!error) { 156 if (vpid == dvp->v_id) 157 return (0); 158 ufs_iput(dp); 159 if (lockparent && pdp != dp && 160 (cnp->cn_flags & ISLASTCN)) 161 IUNLOCK(pdp); 162 } 163 ILOCK(pdp); 164 dp = pdp; 165 dvp = ITOV(dp); 166 *vpp = NULL; 167 } 168 169 /* 170 * Suppress search for slots unless creating 171 * file and at end of pathname, in which case 172 * we watch for a place to put the new file in 173 * case it doesn't already exist. 174 */ 175 slotstatus = FOUND; 176 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 177 (cnp->cn_flags & ISLASTCN)) { 178 slotstatus = NONE; 179 slotfreespace = 0; 180 slotneeded = ((sizeof (struct direct) - (MAXNAMLEN + 1)) + 181 ((cnp->cn_namelen + 1 + 3) &~ 3)); 182 } 183 184 /* 185 * If there is cached information on a previous search of 186 * this directory, pick up where we last left off. 187 * We cache only lookups as these are the most common 188 * and have the greatest payoff. Caching CREATE has little 189 * benefit as it usually must search the entire directory 190 * to determine that the entry does not exist. Caching the 191 * location of the last DELETE or RENAME has not reduced 192 * profiling time and hence has been removed in the interest 193 * of simplicity. 194 */ 195 bmask = VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; 196 if (cnp->cn_nameiop != LOOKUP || dp->i_diroff == 0 || 197 dp->i_diroff > dp->i_size) { 198 dp->i_offset = 0; 199 numdirpasses = 1; 200 } else { 201 dp->i_offset = dp->i_diroff; 202 if ((entryoffsetinblock = dp->i_offset & bmask) && 203 (error = VOP_BLKATOFF(dvp, dp->i_offset, NULL, &bp))) 204 return (error); 205 numdirpasses = 2; 206 nchstats.ncs_2passes++; 207 } 208 endsearch = roundup(dp->i_size, DIRBLKSIZ); 209 enduseful = 0; 210 211 searchloop: 212 while (dp->i_offset < endsearch) { 213 /* 214 * If offset is on a block boundary, read the next directory 215 * block. Release previous if it exists. 216 */ 217 if ((dp->i_offset & bmask) == 0) { 218 if (bp != NULL) 219 brelse(bp); 220 if (error = VOP_BLKATOFF(dvp, dp->i_offset, NULL, &bp)) 221 return (error); 222 entryoffsetinblock = 0; 223 } 224 /* 225 * If still looking for a slot, and at a DIRBLKSIZE 226 * boundary, have to start looking for free space again. 227 */ 228 if (slotstatus == NONE && 229 (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { 230 slotoffset = -1; 231 slotfreespace = 0; 232 } 233 /* 234 * Get pointer to next entry. 235 * Full validation checks are slow, so we only check 236 * enough to insure forward progress through the 237 * directory. Complete checks can be run by patching 238 * "dirchk" to be true. 239 */ 240 ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 241 if (ep->d_reclen == 0 || 242 dirchk && ufs_dirbadentry(ep, entryoffsetinblock)) { 243 int i; 244 245 ufs_dirbad(dp, dp->i_offset, "mangled entry"); 246 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 247 dp->i_offset += i; 248 entryoffsetinblock += i; 249 continue; 250 } 251 252 /* 253 * If an appropriate sized slot has not yet been found, 254 * check to see if one is available. Also accumulate space 255 * in the current block so that we can determine if 256 * compaction is viable. 257 */ 258 if (slotstatus != FOUND) { 259 int size = ep->d_reclen; 260 261 if (ep->d_ino != 0) 262 size -= DIRSIZ(ep); 263 if (size > 0) { 264 if (size >= slotneeded) { 265 slotstatus = FOUND; 266 slotoffset = dp->i_offset; 267 slotsize = ep->d_reclen; 268 } else if (slotstatus == NONE) { 269 slotfreespace += size; 270 if (slotoffset == -1) 271 slotoffset = dp->i_offset; 272 if (slotfreespace >= slotneeded) { 273 slotstatus = COMPACT; 274 slotsize = dp->i_offset + 275 ep->d_reclen - slotoffset; 276 } 277 } 278 } 279 } 280 281 /* 282 * Check for a name match. 283 */ 284 if (ep->d_ino) { 285 if (ep->d_namlen == cnp->cn_namelen && 286 !bcmp(cnp->cn_nameptr, ep->d_name, 287 (unsigned)ep->d_namlen)) { 288 /* 289 * Save directory entry's inode number and 290 * reclen in ndp->ni_ufs area, and release 291 * directory buffer. 292 */ 293 dp->i_ino = ep->d_ino; 294 dp->i_reclen = ep->d_reclen; 295 brelse(bp); 296 goto found; 297 } 298 } 299 prevoff = dp->i_offset; 300 dp->i_offset += ep->d_reclen; 301 entryoffsetinblock += ep->d_reclen; 302 if (ep->d_ino) 303 enduseful = dp->i_offset; 304 } 305 /* notfound: */ 306 /* 307 * If we started in the middle of the directory and failed 308 * to find our target, we must check the beginning as well. 309 */ 310 if (numdirpasses == 2) { 311 numdirpasses--; 312 dp->i_offset = 0; 313 endsearch = dp->i_diroff; 314 goto searchloop; 315 } 316 if (bp != NULL) 317 brelse(bp); 318 /* 319 * If creating, and at end of pathname and current 320 * directory has not been removed, then can consider 321 * allowing file to be created. 322 */ 323 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 324 (cnp->cn_flags & ISLASTCN) && dp->i_nlink != 0) { 325 /* 326 * Access for write is interpreted as allowing 327 * creation of files in the directory. 328 */ 329 if (error = ufs_access(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc)) 330 return (error); 331 /* 332 * Return an indication of where the new directory 333 * entry should be put. If we didn't find a slot, 334 * then set dp->i_count to 0 indicating 335 * that the new slot belongs at the end of the 336 * directory. If we found a slot, then the new entry 337 * can be put in the range from dp->i_offset to 338 * dp->i_offset + dp->i_count. 339 */ 340 if (slotstatus == NONE) { 341 dp->i_offset = roundup(dp->i_size, DIRBLKSIZ); 342 dp->i_count = 0; 343 enduseful = dp->i_offset; 344 } else { 345 dp->i_offset = slotoffset; 346 dp->i_count = slotsize; 347 if (enduseful < slotoffset + slotsize) 348 enduseful = slotoffset + slotsize; 349 } 350 dp->i_endoff = roundup(enduseful, DIRBLKSIZ); 351 dp->i_flag |= IUPD|ICHG; 352 /* 353 * We return with the directory locked, so that 354 * the parameters we set up above will still be 355 * valid if we actually decide to do a direnter(). 356 * We return ni_vp == NULL to indicate that the entry 357 * does not currently exist; we leave a pointer to 358 * the (locked) directory inode in ndp->ni_dvp. 359 * The pathname buffer is saved so that the name 360 * can be obtained later. 361 * 362 * NB - if the directory is unlocked, then this 363 * information cannot be used. 364 */ 365 cnp->cn_flags |= SAVENAME; 366 if (!lockparent) 367 IUNLOCK(dp); 368 } 369 /* 370 * Insert name into cache (as non-existent) if appropriate. 371 */ 372 if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) 373 cache_enter(dvp, *vpp, cnp); 374 return (ENOENT); 375 376 found: 377 if (numdirpasses == 2) 378 nchstats.ncs_pass2++; 379 /* 380 * Check that directory length properly reflects presence 381 * of this entry. 382 */ 383 if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 384 ufs_dirbad(dp, dp->i_offset, "i_size too small"); 385 dp->i_size = entryoffsetinblock + DIRSIZ(ep); 386 dp->i_flag |= IUPD|ICHG; 387 } 388 389 /* 390 * Found component in pathname. 391 * If the final component of path name, save information 392 * in the cache as to where the entry was found. 393 */ 394 if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == LOOKUP) 395 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); 396 397 /* 398 * If deleting, and at end of pathname, return 399 * parameters which can be used to remove file. 400 * If the wantparent flag isn't set, we return only 401 * the directory (in ndp->ni_dvp), otherwise we go 402 * on and lock the inode, being careful with ".". 403 */ 404 if (cnp->cn_nameiop == DELETE && (cnp->cn_flags & ISLASTCN)) { 405 /* 406 * Write access to directory required to delete files. 407 */ 408 if (error = ufs_access(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc)) 409 return (error); 410 /* 411 * Return pointer to current entry in dp->i_offset, 412 * and distance past previous entry (if there 413 * is a previous entry in this block) in dp->i_count. 414 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 415 */ 416 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 417 dp->i_count = 0; 418 else 419 dp->i_count = dp->i_offset - prevoff; 420 if (dp->i_number == dp->i_ino) { 421 VREF(vdp); 422 *vpp = vdp; 423 return (0); 424 } 425 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) 426 return (error); 427 /* 428 * If directory is "sticky", then user must own 429 * the directory, or the file in it, else she 430 * may not delete it (unless she's root). This 431 * implements append-only directories. 432 */ 433 if ((dp->i_mode & ISVTX) && 434 cnp->cn_cred->cr_uid != 0 && 435 cnp->cn_cred->cr_uid != dp->i_uid && 436 VTOI(tdp)->i_uid != cnp->cn_cred->cr_uid) { 437 vput(tdp); 438 return (EPERM); 439 } 440 *vpp = tdp; 441 if (!lockparent) 442 IUNLOCK(dp); 443 return (0); 444 } 445 446 /* 447 * If rewriting (RENAME), return the inode and the 448 * information required to rewrite the present directory 449 * Must get inode of directory entry to verify it's a 450 * regular file, or empty directory. 451 */ 452 if (cnp->cn_nameiop == RENAME && wantparent && 453 (cnp->cn_flags & ISLASTCN)) { 454 if (error = ufs_access(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc)) 455 return (error); 456 /* 457 * Careful about locking second inode. 458 * This can only occur if the target is ".". 459 */ 460 if (dp->i_number == dp->i_ino) 461 return (EISDIR); 462 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) 463 return (error); 464 *vpp = tdp; 465 cnp->cn_flags |= SAVENAME; 466 if (!lockparent) 467 IUNLOCK(dp); 468 return (0); 469 } 470 471 /* 472 * Step through the translation in the name. We do not `iput' the 473 * directory because we may need it again if a symbolic link 474 * is relative to the current directory. Instead we save it 475 * unlocked as "pdp". We must get the target inode before unlocking 476 * the directory to insure that the inode will not be removed 477 * before we get it. We prevent deadlock by always fetching 478 * inodes from the root, moving down the directory tree. Thus 479 * when following backward pointers ".." we must unlock the 480 * parent directory before getting the requested directory. 481 * There is a potential race condition here if both the current 482 * and parent directories are removed before the `iget' for the 483 * inode associated with ".." returns. We hope that this occurs 484 * infrequently since we cannot avoid this race condition without 485 * implementing a sophisticated deadlock detection algorithm. 486 * Note also that this simple deadlock detection scheme will not 487 * work if the file system has any hard links other than ".." 488 * that point backwards in the directory structure. 489 */ 490 pdp = dp; 491 if (cnp->cn_flags & ISDOTDOT) { 492 IUNLOCK(pdp); /* race to get the inode */ 493 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) { 494 ILOCK(pdp); 495 return (error); 496 } 497 if (lockparent && (cnp->cn_flags & ISLASTCN)) 498 ILOCK(pdp); 499 *vpp = tdp; 500 } else if (dp->i_number == dp->i_ino) { 501 VREF(dvp); /* we want ourself, ie "." */ 502 *vpp = dvp; 503 } else { 504 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) 505 return (error); 506 if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 507 IUNLOCK(pdp); 508 *vpp = tdp; 509 } 510 511 /* 512 * Insert name into cache if appropriate. 513 */ 514 if (cnp->cn_flags & MAKEENTRY) 515 cache_enter(dvp, *vpp, cnp); 516 return (0); 517 } 518 519 void 520 ufs_dirbad(ip, offset, how) 521 struct inode *ip; 522 off_t offset; 523 char *how; 524 { 525 struct mount *mp; 526 527 mp = ITOV(ip)->v_mount; 528 (void)printf("%s: bad dir ino %d at offset %d: %s\n", 529 mp->mnt_stat.f_mntonname, ip->i_number, offset, how); 530 if ((mp->mnt_stat.f_flags & MNT_RDONLY) == 0) 531 panic("bad dir"); 532 } 533 534 /* 535 * Do consistency checking on a directory entry: 536 * record length must be multiple of 4 537 * entry must fit in rest of its DIRBLKSIZ block 538 * record must be large enough to contain entry 539 * name is not longer than MAXNAMLEN 540 * name must be as long as advertised, and null terminated 541 */ 542 int 543 ufs_dirbadentry(ep, entryoffsetinblock) 544 register struct direct *ep; 545 int entryoffsetinblock; 546 { 547 register int i; 548 549 if ((ep->d_reclen & 0x3) != 0 || 550 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 551 ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) { 552 /*return (1); */ 553 printf("First bad\n"); 554 goto bad; 555 } 556 for (i = 0; i < ep->d_namlen; i++) 557 if (ep->d_name[i] == '\0') { 558 /*return (1); */ 559 printf("Second bad\n"); 560 goto bad; 561 } 562 if (ep->d_name[i]) 563 goto bad; 564 return (ep->d_name[i]); 565 bad: 566 printf("ufs_dirbadentry: jumping out: reclen: %d namlen %d ino %d name %s\n", 567 ep->d_reclen, ep->d_namlen, ep->d_ino, ep->d_name ); 568 return(1); 569 } 570 571 /* 572 * Write a directory entry after a call to namei, using the parameters 573 * that it left in nameidata. The argument ip is the inode which the new 574 * directory entry will refer to. Dvp is a pointer to the directory to 575 * be written, which was left locked by namei. Remaining parameters 576 * (dp->i_offset, dp->i_count) indicate how the space for the new 577 * entry is to be obtained. 578 */ 579 int 580 ufs_direnter(ip, dvp, cnp) 581 struct inode *ip; 582 struct vnode *dvp; 583 register struct componentname *cnp; 584 { 585 register struct direct *ep, *nep; 586 register struct inode *dp; 587 struct buf *bp; 588 struct direct newdir; 589 struct iovec aiov; 590 struct uio auio; 591 u_int dsize; 592 int error, loc, newentrysize, spacefree; 593 char *dirbuf; 594 595 #ifdef DIAGNOSTIC 596 if ((cnp->cn_flags & SAVENAME) == 0) 597 panic("direnter: missing name"); 598 #endif 599 dp = VTOI(dvp); 600 newdir.d_ino = ip->i_number; 601 newdir.d_namlen = cnp->cn_namelen; 602 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); 603 newentrysize = DIRSIZ(&newdir); 604 if (dp->i_count == 0) { 605 /* 606 * If dp->i_count is 0, then namei could find no 607 * space in the directory. Here, dp->i_offset will 608 * be on a directory block boundary and we will write the 609 * new entry into a fresh block. 610 */ 611 if (dp->i_offset & (DIRBLKSIZ - 1)) 612 panic("wdir: newblk"); 613 auio.uio_offset = dp->i_offset; 614 newdir.d_reclen = DIRBLKSIZ; 615 auio.uio_resid = newentrysize; 616 aiov.iov_len = newentrysize; 617 aiov.iov_base = (caddr_t)&newdir; 618 auio.uio_iov = &aiov; 619 auio.uio_iovcnt = 1; 620 auio.uio_rw = UIO_WRITE; 621 auio.uio_segflg = UIO_SYSSPACE; 622 auio.uio_procp = (struct proc *)0; 623 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); 624 if (DIRBLKSIZ > 625 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 626 /* XXX should grow with balloc() */ 627 panic("ufs_direnter: frag size"); 628 else if (!error) { 629 dp->i_size = roundup(dp->i_size, DIRBLKSIZ); 630 dp->i_flag |= ICHG; 631 } 632 return (error); 633 } 634 635 /* 636 * If dp->i_count is non-zero, then namei found space 637 * for the new entry in the range dp->i_offset to 638 * dp->i_offset + dp->i_count in the directory. 639 * To use this space, we may have to compact the entries located 640 * there, by copying them together towards the beginning of the 641 * block, leaving the free space in one usable chunk at the end. 642 */ 643 644 /* 645 * Increase size of directory if entry eats into new space. 646 * This should never push the size past a new multiple of 647 * DIRBLKSIZE. 648 * 649 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 650 */ 651 if (dp->i_offset + dp->i_count > dp->i_size) 652 dp->i_size = dp->i_offset + dp->i_count; 653 /* 654 * Get the block containing the space for the new directory entry. 655 */ 656 if (error = VOP_BLKATOFF(dvp, dp->i_offset, &dirbuf, &bp)) 657 return (error); 658 /* 659 * Find space for the new entry. In the simple case, the entry at 660 * offset base will have the space. If it does not, then namei 661 * arranged that compacting the region dp->i_offset to 662 * dp->i_offset + dp->i_count would yield the 663 * space. 664 */ 665 ep = (struct direct *)dirbuf; 666 dsize = DIRSIZ(ep); 667 spacefree = ep->d_reclen - dsize; 668 for (loc = ep->d_reclen; loc < dp->i_count; ) { 669 nep = (struct direct *)(dirbuf + loc); 670 if (ep->d_ino) { 671 /* trim the existing slot */ 672 ep->d_reclen = dsize; 673 ep = (struct direct *)((char *)ep + dsize); 674 } else { 675 /* overwrite; nothing there; header is ours */ 676 spacefree += dsize; 677 } 678 dsize = DIRSIZ(nep); 679 spacefree += nep->d_reclen - dsize; 680 loc += nep->d_reclen; 681 bcopy((caddr_t)nep, (caddr_t)ep, dsize); 682 } 683 /* 684 * Update the pointer fields in the previous entry (if any), 685 * copy in the new entry, and write out the block. 686 */ 687 if (ep->d_ino == 0) { 688 if (spacefree + dsize < newentrysize) 689 panic("wdir: compact1"); 690 newdir.d_reclen = spacefree + dsize; 691 } else { 692 if (spacefree < newentrysize) 693 panic("wdir: compact2"); 694 newdir.d_reclen = spacefree; 695 ep->d_reclen = dsize; 696 ep = (struct direct *)((char *)ep + dsize); 697 } 698 bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize); 699 error = VOP_BWRITE(bp); 700 dp->i_flag |= IUPD|ICHG; 701 if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) 702 error = VOP_TRUNCATE(dvp, (u_long)dp->i_endoff, IO_SYNC); 703 return (error); 704 } 705 706 /* 707 * Remove a directory entry after a call to namei, using 708 * the parameters which it left in nameidata. The entry 709 * dp->i_offset contains the offset into the directory of the 710 * entry to be eliminated. The dp->i_count field contains the 711 * size of the previous record in the directory. If this 712 * is 0, the first entry is being deleted, so we need only 713 * zero the inode number to mark the entry as free. If the 714 * entry is not the first in the directory, we must reclaim 715 * the space of the now empty record by adding the record size 716 * to the size of the previous entry. 717 */ 718 int 719 ufs_dirremove(dvp, cnp) 720 struct vnode *dvp; 721 struct componentname *cnp; 722 { 723 register struct inode *dp; 724 struct direct *ep; 725 struct buf *bp; 726 int error; 727 728 dp = VTOI(dvp); 729 if (dp->i_count == 0) { 730 /* 731 * First entry in block: set d_ino to zero. 732 */ 733 if (error = VOP_BLKATOFF(dvp, dp->i_offset, (char **)&ep, &bp)) 734 return (error); 735 ep->d_ino = 0; 736 error = VOP_BWRITE(bp); 737 dp->i_flag |= IUPD|ICHG; 738 return (error); 739 } 740 /* 741 * Collapse new free space into previous entry. 742 */ 743 if (error = VOP_BLKATOFF(dvp, 744 dp->i_offset - dp->i_count, (char **)&ep, &bp)) 745 return (error); 746 ep->d_reclen += dp->i_reclen; 747 error = VOP_BWRITE(bp); 748 dp->i_flag |= IUPD|ICHG; 749 return (error); 750 } 751 752 /* 753 * Rewrite an existing directory entry to point at the inode 754 * supplied. The parameters describing the directory entry are 755 * set up by a call to namei. 756 */ 757 int 758 ufs_dirrewrite(dp, ip, cnp) 759 struct inode *dp, *ip; 760 struct componentname *cnp; 761 { 762 struct buf *bp; 763 struct direct *ep; 764 int error; 765 766 if (error = VOP_BLKATOFF(ITOV(dp), dp->i_offset, (char **)&ep, &bp)) 767 return (error); 768 ep->d_ino = ip->i_number; 769 error = VOP_BWRITE(bp); 770 dp->i_flag |= IUPD|ICHG; 771 return (error); 772 } 773 774 /* 775 * Check if a directory is empty or not. 776 * Inode supplied must be locked. 777 * 778 * Using a struct dirtemplate here is not precisely 779 * what we want, but better than using a struct direct. 780 * 781 * NB: does not handle corrupted directories. 782 */ 783 int 784 ufs_dirempty(ip, parentino, cred) 785 register struct inode *ip; 786 ino_t parentino; 787 struct ucred *cred; 788 { 789 register off_t off; 790 struct dirtemplate dbuf; 791 register struct direct *dp = (struct direct *)&dbuf; 792 int error, count; 793 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 794 795 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 796 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, 797 UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); 798 /* 799 * Since we read MINDIRSIZ, residual must 800 * be 0 unless we're at end of file. 801 */ 802 if (error || count != 0) 803 return (0); 804 /* avoid infinite loops */ 805 if (dp->d_reclen == 0) 806 return (0); 807 /* skip empty entries */ 808 if (dp->d_ino == 0) 809 continue; 810 /* accept only "." and ".." */ 811 if (dp->d_namlen > 2) 812 return (0); 813 if (dp->d_name[0] != '.') 814 return (0); 815 /* 816 * At this point d_namlen must be 1 or 2. 817 * 1 implies ".", 2 implies ".." if second 818 * char is also "." 819 */ 820 if (dp->d_namlen == 1) 821 continue; 822 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 823 continue; 824 return (0); 825 } 826 return (1); 827 } 828 829 /* 830 * Check if source directory is in the path of the target directory. 831 * Target is supplied locked, source is unlocked. 832 * The target is always iput before returning. 833 */ 834 int 835 ufs_checkpath(source, target, cred) 836 struct inode *source, *target; 837 struct ucred *cred; 838 { 839 struct dirtemplate dirbuf; 840 register struct inode *ip; 841 struct vnode *vp; 842 int error, rootino; 843 844 ip = target; 845 if (ip->i_number == source->i_number) { 846 error = EEXIST; 847 goto out; 848 } 849 rootino = ROOTINO; 850 error = 0; 851 if (ip->i_number == rootino) 852 goto out; 853 854 for (;;) { 855 if ((ip->i_mode & IFMT) != IFDIR) { 856 error = ENOTDIR; 857 break; 858 } 859 vp = ITOV(ip); 860 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 861 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 862 IO_NODELOCKED, cred, (int *)0, (struct proc *)0); 863 if (error != 0) 864 break; 865 if (dirbuf.dotdot_namlen != 2 || 866 dirbuf.dotdot_name[0] != '.' || 867 dirbuf.dotdot_name[1] != '.') { 868 error = ENOTDIR; 869 break; 870 } 871 if (dirbuf.dotdot_ino == source->i_number) { 872 error = EINVAL; 873 break; 874 } 875 if (dirbuf.dotdot_ino == rootino) 876 break; 877 ufs_iput(ip); 878 if (error = VOP_VGET(vp, dirbuf.dotdot_ino, &vp)) 879 break; 880 ip = VTOI(vp); 881 } 882 883 out: 884 if (error == ENOTDIR) 885 printf("checkpath: .. not a directory\n"); 886 if (ip != NULL) 887 ufs_iput(ip); 888 return (error); 889 } 890