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.42 (Berkeley) 03/15/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 * The borrowing of variables 130 * here is somewhat 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 slotfreespace = slotsize = slotneeded = 0; 177 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 178 (cnp->cn_flags & ISLASTCN)) { 179 slotstatus = NONE; 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 entryoffsetinblock = 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 prevoff = dp->i_offset; 209 endsearch = roundup(dp->i_size, DIRBLKSIZ); 210 enduseful = 0; 211 212 searchloop: 213 while (dp->i_offset < endsearch) { 214 /* 215 * If offset is on a block boundary, read the next directory 216 * block. Release previous if it exists. 217 */ 218 if ((dp->i_offset & bmask) == 0) { 219 if (bp != NULL) 220 brelse(bp); 221 if (error = VOP_BLKATOFF(dvp, dp->i_offset, NULL, &bp)) 222 return (error); 223 entryoffsetinblock = 0; 224 } 225 /* 226 * If still looking for a slot, and at a DIRBLKSIZE 227 * boundary, have to start looking for free space again. 228 */ 229 if (slotstatus == NONE && 230 (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { 231 slotoffset = -1; 232 slotfreespace = 0; 233 } 234 /* 235 * Get pointer to next entry. 236 * Full validation checks are slow, so we only check 237 * enough to insure forward progress through the 238 * directory. Complete checks can be run by patching 239 * "dirchk" to be true. 240 */ 241 ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 242 if (ep->d_reclen == 0 || 243 dirchk && ufs_dirbadentry(ep, entryoffsetinblock)) { 244 int i; 245 246 ufs_dirbad(dp, dp->i_offset, "mangled entry"); 247 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 248 dp->i_offset += i; 249 entryoffsetinblock += i; 250 continue; 251 } 252 253 /* 254 * If an appropriate sized slot has not yet been found, 255 * check to see if one is available. Also accumulate space 256 * in the current block so that we can determine if 257 * compaction is viable. 258 */ 259 if (slotstatus != FOUND) { 260 int size = ep->d_reclen; 261 262 if (ep->d_ino != 0) 263 size -= DIRSIZ(ep); 264 if (size > 0) { 265 if (size >= slotneeded) { 266 slotstatus = FOUND; 267 slotoffset = dp->i_offset; 268 slotsize = ep->d_reclen; 269 } else if (slotstatus == NONE) { 270 slotfreespace += size; 271 if (slotoffset == -1) 272 slotoffset = dp->i_offset; 273 if (slotfreespace >= slotneeded) { 274 slotstatus = COMPACT; 275 slotsize = dp->i_offset + 276 ep->d_reclen - slotoffset; 277 } 278 } 279 } 280 } 281 282 /* 283 * Check for a name match. 284 */ 285 if (ep->d_ino) { 286 if (ep->d_namlen == cnp->cn_namelen && 287 !bcmp(cnp->cn_nameptr, ep->d_name, 288 (unsigned)ep->d_namlen)) { 289 /* 290 * Save directory entry's inode number and 291 * reclen in ndp->ni_ufs area, and release 292 * directory buffer. 293 */ 294 dp->i_ino = ep->d_ino; 295 dp->i_reclen = ep->d_reclen; 296 brelse(bp); 297 goto found; 298 } 299 } 300 prevoff = dp->i_offset; 301 dp->i_offset += ep->d_reclen; 302 entryoffsetinblock += ep->d_reclen; 303 if (ep->d_ino) 304 enduseful = dp->i_offset; 305 } 306 /* notfound: */ 307 /* 308 * If we started in the middle of the directory and failed 309 * to find our target, we must check the beginning as well. 310 */ 311 if (numdirpasses == 2) { 312 numdirpasses--; 313 dp->i_offset = 0; 314 endsearch = dp->i_diroff; 315 goto searchloop; 316 } 317 if (bp != NULL) 318 brelse(bp); 319 /* 320 * If creating, and at end of pathname and current 321 * directory has not been removed, then can consider 322 * allowing file to be created. 323 */ 324 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 325 (cnp->cn_flags & ISLASTCN) && dp->i_nlink != 0) { 326 /* 327 * Access for write is interpreted as allowing 328 * creation of files in the directory. 329 */ 330 if (error = ufs_access(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc)) 331 return (error); 332 /* 333 * Return an indication of where the new directory 334 * entry should be put. If we didn't find a slot, 335 * then set dp->i_count to 0 indicating 336 * that the new slot belongs at the end of the 337 * directory. If we found a slot, then the new entry 338 * can be put in the range from dp->i_offset to 339 * dp->i_offset + dp->i_count. 340 */ 341 if (slotstatus == NONE) { 342 dp->i_offset = roundup(dp->i_size, DIRBLKSIZ); 343 dp->i_count = 0; 344 enduseful = dp->i_offset; 345 } else { 346 dp->i_offset = slotoffset; 347 dp->i_count = slotsize; 348 if (enduseful < slotoffset + slotsize) 349 enduseful = slotoffset + slotsize; 350 } 351 dp->i_endoff = roundup(enduseful, DIRBLKSIZ); 352 dp->i_flag |= IUPD|ICHG; 353 /* 354 * We return with the directory locked, so that 355 * the parameters we set up above will still be 356 * valid if we actually decide to do a direnter(). 357 * We return ni_vp == NULL to indicate that the entry 358 * does not currently exist; we leave a pointer to 359 * the (locked) directory inode in ndp->ni_dvp. 360 * The pathname buffer is saved so that the name 361 * can be obtained later. 362 * 363 * NB - if the directory is unlocked, then this 364 * information cannot be used. 365 */ 366 cnp->cn_flags |= SAVENAME; 367 if (!lockparent) 368 IUNLOCK(dp); 369 return (EJUSTRETURN); 370 } 371 /* 372 * Insert name into cache (as non-existent) if appropriate. 373 */ 374 if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) 375 cache_enter(dvp, *vpp, cnp); 376 return (ENOENT); 377 378 found: 379 if (numdirpasses == 2) 380 nchstats.ncs_pass2++; 381 /* 382 * Check that directory length properly reflects presence 383 * of this entry. 384 */ 385 if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 386 ufs_dirbad(dp, dp->i_offset, "i_size too small"); 387 dp->i_size = entryoffsetinblock + DIRSIZ(ep); 388 dp->i_flag |= IUPD|ICHG; 389 } 390 391 /* 392 * Found component in pathname. 393 * If the final component of path name, save information 394 * in the cache as to where the entry was found. 395 */ 396 if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == LOOKUP) 397 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); 398 399 /* 400 * If deleting, and at end of pathname, return 401 * parameters which can be used to remove file. 402 * If the wantparent flag isn't set, we return only 403 * the directory (in ndp->ni_dvp), otherwise we go 404 * on and lock the inode, being careful with ".". 405 */ 406 if (cnp->cn_nameiop == DELETE && (cnp->cn_flags & ISLASTCN)) { 407 /* 408 * Write access to directory required to delete files. 409 */ 410 if (error = ufs_access(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc)) 411 return (error); 412 /* 413 * Return pointer to current entry in dp->i_offset, 414 * and distance past previous entry (if there 415 * is a previous entry in this block) in dp->i_count. 416 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 417 */ 418 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 419 dp->i_count = 0; 420 else 421 dp->i_count = dp->i_offset - prevoff; 422 if (dp->i_number == dp->i_ino) { 423 VREF(vdp); 424 *vpp = vdp; 425 return (0); 426 } 427 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) 428 return (error); 429 /* 430 * If directory is "sticky", then user must own 431 * the directory, or the file in it, else she 432 * may not delete it (unless she's root). This 433 * implements append-only directories. 434 */ 435 if ((dp->i_mode & ISVTX) && 436 cnp->cn_cred->cr_uid != 0 && 437 cnp->cn_cred->cr_uid != dp->i_uid && 438 VTOI(tdp)->i_uid != cnp->cn_cred->cr_uid) { 439 vput(tdp); 440 return (EPERM); 441 } 442 *vpp = tdp; 443 if (!lockparent) 444 IUNLOCK(dp); 445 return (0); 446 } 447 448 /* 449 * If rewriting (RENAME), return the inode and the 450 * information required to rewrite the present directory 451 * Must get inode of directory entry to verify it's a 452 * regular file, or empty directory. 453 */ 454 if (cnp->cn_nameiop == RENAME && wantparent && 455 (cnp->cn_flags & ISLASTCN)) { 456 if (error = ufs_access(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc)) 457 return (error); 458 /* 459 * Careful about locking second inode. 460 * This can only occur if the target is ".". 461 */ 462 if (dp->i_number == dp->i_ino) 463 return (EISDIR); 464 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) 465 return (error); 466 *vpp = tdp; 467 cnp->cn_flags |= SAVENAME; 468 if (!lockparent) 469 IUNLOCK(dp); 470 return (0); 471 } 472 473 /* 474 * Step through the translation in the name. We do not `iput' the 475 * directory because we may need it again if a symbolic link 476 * is relative to the current directory. Instead we save it 477 * unlocked as "pdp". We must get the target inode before unlocking 478 * the directory to insure that the inode will not be removed 479 * before we get it. We prevent deadlock by always fetching 480 * inodes from the root, moving down the directory tree. Thus 481 * when following backward pointers ".." we must unlock the 482 * parent directory before getting the requested directory. 483 * There is a potential race condition here if both the current 484 * and parent directories are removed before the `iget' for the 485 * inode associated with ".." returns. We hope that this occurs 486 * infrequently since we cannot avoid this race condition without 487 * implementing a sophisticated deadlock detection algorithm. 488 * Note also that this simple deadlock detection scheme will not 489 * work if the file system has any hard links other than ".." 490 * that point backwards in the directory structure. 491 */ 492 pdp = dp; 493 if (cnp->cn_flags & ISDOTDOT) { 494 IUNLOCK(pdp); /* race to get the inode */ 495 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) { 496 ILOCK(pdp); 497 return (error); 498 } 499 if (lockparent && (cnp->cn_flags & ISLASTCN)) 500 ILOCK(pdp); 501 *vpp = tdp; 502 } else if (dp->i_number == dp->i_ino) { 503 VREF(dvp); /* we want ourself, ie "." */ 504 *vpp = dvp; 505 } else { 506 if (error = VOP_VGET(dvp, dp->i_ino, &tdp)) 507 return (error); 508 if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 509 IUNLOCK(pdp); 510 *vpp = tdp; 511 } 512 513 /* 514 * Insert name into cache if appropriate. 515 */ 516 if (cnp->cn_flags & MAKEENTRY) 517 cache_enter(dvp, *vpp, cnp); 518 return (0); 519 } 520 521 void 522 ufs_dirbad(ip, offset, how) 523 struct inode *ip; 524 off_t offset; 525 char *how; 526 { 527 struct mount *mp; 528 529 mp = ITOV(ip)->v_mount; 530 (void)printf("%s: bad dir ino %d at offset %d: %s\n", 531 mp->mnt_stat.f_mntonname, ip->i_number, offset, how); 532 if ((mp->mnt_stat.f_flags & MNT_RDONLY) == 0) 533 panic("bad dir"); 534 } 535 536 /* 537 * Do consistency checking on a directory entry: 538 * record length must be multiple of 4 539 * entry must fit in rest of its DIRBLKSIZ block 540 * record must be large enough to contain entry 541 * name is not longer than MAXNAMLEN 542 * name must be as long as advertised, and null terminated 543 */ 544 int 545 ufs_dirbadentry(ep, entryoffsetinblock) 546 register struct direct *ep; 547 int entryoffsetinblock; 548 { 549 register int i; 550 551 if ((ep->d_reclen & 0x3) != 0 || 552 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 553 ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) { 554 /*return (1); */ 555 printf("First bad\n"); 556 goto bad; 557 } 558 for (i = 0; i < ep->d_namlen; i++) 559 if (ep->d_name[i] == '\0') { 560 /*return (1); */ 561 printf("Second bad\n"); 562 goto bad; 563 } 564 if (ep->d_name[i]) 565 goto bad; 566 return (ep->d_name[i]); 567 bad: 568 printf("ufs_dirbadentry: jumping out: reclen: %d namlen %d ino %d name %s\n", 569 ep->d_reclen, ep->d_namlen, ep->d_ino, ep->d_name ); 570 return(1); 571 } 572 573 /* 574 * Write a directory entry after a call to namei, using the parameters 575 * that it left in nameidata. The argument ip is the inode which the new 576 * directory entry will refer to. Dvp is a pointer to the directory to 577 * be written, which was left locked by namei. Remaining parameters 578 * (dp->i_offset, dp->i_count) indicate how the space for the new 579 * entry is to be obtained. 580 */ 581 int 582 ufs_direnter(ip, dvp, cnp) 583 struct inode *ip; 584 struct vnode *dvp; 585 register struct componentname *cnp; 586 { 587 register struct direct *ep, *nep; 588 register struct inode *dp; 589 struct buf *bp; 590 struct direct newdir; 591 struct iovec aiov; 592 struct uio auio; 593 u_int dsize; 594 int error, loc, newentrysize, spacefree; 595 char *dirbuf; 596 597 #ifdef DIAGNOSTIC 598 if ((cnp->cn_flags & SAVENAME) == 0) 599 panic("direnter: missing name"); 600 #endif 601 dp = VTOI(dvp); 602 newdir.d_ino = ip->i_number; 603 newdir.d_namlen = cnp->cn_namelen; 604 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); 605 newentrysize = DIRSIZ(&newdir); 606 if (dp->i_count == 0) { 607 /* 608 * If dp->i_count is 0, then namei could find no 609 * space in the directory. Here, dp->i_offset will 610 * be on a directory block boundary and we will write the 611 * new entry into a fresh block. 612 */ 613 if (dp->i_offset & (DIRBLKSIZ - 1)) 614 panic("wdir: newblk"); 615 auio.uio_offset = dp->i_offset; 616 newdir.d_reclen = DIRBLKSIZ; 617 auio.uio_resid = newentrysize; 618 aiov.iov_len = newentrysize; 619 aiov.iov_base = (caddr_t)&newdir; 620 auio.uio_iov = &aiov; 621 auio.uio_iovcnt = 1; 622 auio.uio_rw = UIO_WRITE; 623 auio.uio_segflg = UIO_SYSSPACE; 624 auio.uio_procp = (struct proc *)0; 625 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); 626 if (DIRBLKSIZ > 627 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 628 /* XXX should grow with balloc() */ 629 panic("ufs_direnter: frag size"); 630 else if (!error) { 631 dp->i_size = roundup(dp->i_size, DIRBLKSIZ); 632 dp->i_flag |= ICHG; 633 } 634 return (error); 635 } 636 637 /* 638 * If dp->i_count is non-zero, then namei found space 639 * for the new entry in the range dp->i_offset to 640 * dp->i_offset + dp->i_count in the directory. 641 * To use this space, we may have to compact the entries located 642 * there, by copying them together towards the beginning of the 643 * block, leaving the free space in one usable chunk at the end. 644 */ 645 646 /* 647 * Increase size of directory if entry eats into new space. 648 * This should never push the size past a new multiple of 649 * DIRBLKSIZE. 650 * 651 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 652 */ 653 if (dp->i_offset + dp->i_count > dp->i_size) 654 dp->i_size = dp->i_offset + dp->i_count; 655 /* 656 * Get the block containing the space for the new directory entry. 657 */ 658 if (error = VOP_BLKATOFF(dvp, dp->i_offset, &dirbuf, &bp)) 659 return (error); 660 /* 661 * Find space for the new entry. In the simple case, the entry at 662 * offset base will have the space. If it does not, then namei 663 * arranged that compacting the region dp->i_offset to 664 * dp->i_offset + dp->i_count would yield the 665 * space. 666 */ 667 ep = (struct direct *)dirbuf; 668 dsize = DIRSIZ(ep); 669 spacefree = ep->d_reclen - dsize; 670 for (loc = ep->d_reclen; loc < dp->i_count; ) { 671 nep = (struct direct *)(dirbuf + loc); 672 if (ep->d_ino) { 673 /* trim the existing slot */ 674 ep->d_reclen = dsize; 675 ep = (struct direct *)((char *)ep + dsize); 676 } else { 677 /* overwrite; nothing there; header is ours */ 678 spacefree += dsize; 679 } 680 dsize = DIRSIZ(nep); 681 spacefree += nep->d_reclen - dsize; 682 loc += nep->d_reclen; 683 bcopy((caddr_t)nep, (caddr_t)ep, dsize); 684 } 685 /* 686 * Update the pointer fields in the previous entry (if any), 687 * copy in the new entry, and write out the block. 688 */ 689 if (ep->d_ino == 0) { 690 if (spacefree + dsize < newentrysize) 691 panic("wdir: compact1"); 692 newdir.d_reclen = spacefree + dsize; 693 } else { 694 if (spacefree < newentrysize) 695 panic("wdir: compact2"); 696 newdir.d_reclen = spacefree; 697 ep->d_reclen = dsize; 698 ep = (struct direct *)((char *)ep + dsize); 699 } 700 bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize); 701 error = VOP_BWRITE(bp); 702 dp->i_flag |= IUPD|ICHG; 703 if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) 704 error = VOP_TRUNCATE(dvp, (u_long)dp->i_endoff, IO_SYNC); 705 return (error); 706 } 707 708 /* 709 * Remove a directory entry after a call to namei, using 710 * the parameters which it left in nameidata. The entry 711 * dp->i_offset contains the offset into the directory of the 712 * entry to be eliminated. The dp->i_count field contains the 713 * size of the previous record in the directory. If this 714 * is 0, the first entry is being deleted, so we need only 715 * zero the inode number to mark the entry as free. If the 716 * entry is not the first in the directory, we must reclaim 717 * the space of the now empty record by adding the record size 718 * to the size of the previous entry. 719 */ 720 int 721 ufs_dirremove(dvp, cnp) 722 struct vnode *dvp; 723 struct componentname *cnp; 724 { 725 register struct inode *dp; 726 struct direct *ep; 727 struct buf *bp; 728 int error; 729 730 dp = VTOI(dvp); 731 if (dp->i_count == 0) { 732 /* 733 * First entry in block: set d_ino to zero. 734 */ 735 if (error = VOP_BLKATOFF(dvp, dp->i_offset, (char **)&ep, &bp)) 736 return (error); 737 ep->d_ino = 0; 738 error = VOP_BWRITE(bp); 739 dp->i_flag |= IUPD|ICHG; 740 return (error); 741 } 742 /* 743 * Collapse new free space into previous entry. 744 */ 745 if (error = VOP_BLKATOFF(dvp, 746 dp->i_offset - dp->i_count, (char **)&ep, &bp)) 747 return (error); 748 ep->d_reclen += dp->i_reclen; 749 error = VOP_BWRITE(bp); 750 dp->i_flag |= IUPD|ICHG; 751 return (error); 752 } 753 754 /* 755 * Rewrite an existing directory entry to point at the inode 756 * supplied. The parameters describing the directory entry are 757 * set up by a call to namei. 758 */ 759 int 760 ufs_dirrewrite(dp, ip, cnp) 761 struct inode *dp, *ip; 762 struct componentname *cnp; 763 { 764 struct buf *bp; 765 struct direct *ep; 766 int error; 767 768 if (error = VOP_BLKATOFF(ITOV(dp), dp->i_offset, (char **)&ep, &bp)) 769 return (error); 770 ep->d_ino = ip->i_number; 771 error = VOP_BWRITE(bp); 772 dp->i_flag |= IUPD|ICHG; 773 return (error); 774 } 775 776 /* 777 * Check if a directory is empty or not. 778 * Inode supplied must be locked. 779 * 780 * Using a struct dirtemplate here is not precisely 781 * what we want, but better than using a struct direct. 782 * 783 * NB: does not handle corrupted directories. 784 */ 785 int 786 ufs_dirempty(ip, parentino, cred) 787 register struct inode *ip; 788 ino_t parentino; 789 struct ucred *cred; 790 { 791 register off_t off; 792 struct dirtemplate dbuf; 793 register struct direct *dp = (struct direct *)&dbuf; 794 int error, count; 795 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 796 797 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 798 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, 799 UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); 800 /* 801 * Since we read MINDIRSIZ, residual must 802 * be 0 unless we're at end of file. 803 */ 804 if (error || count != 0) 805 return (0); 806 /* avoid infinite loops */ 807 if (dp->d_reclen == 0) 808 return (0); 809 /* skip empty entries */ 810 if (dp->d_ino == 0) 811 continue; 812 /* accept only "." and ".." */ 813 if (dp->d_namlen > 2) 814 return (0); 815 if (dp->d_name[0] != '.') 816 return (0); 817 /* 818 * At this point d_namlen must be 1 or 2. 819 * 1 implies ".", 2 implies ".." if second 820 * char is also "." 821 */ 822 if (dp->d_namlen == 1) 823 continue; 824 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 825 continue; 826 return (0); 827 } 828 return (1); 829 } 830 831 /* 832 * Check if source directory is in the path of the target directory. 833 * Target is supplied locked, source is unlocked. 834 * The target is always iput before returning. 835 */ 836 int 837 ufs_checkpath(source, target, cred) 838 struct inode *source, *target; 839 struct ucred *cred; 840 { 841 struct dirtemplate dirbuf; 842 register struct inode *ip; 843 struct vnode *vp; 844 int error, rootino; 845 846 ip = target; 847 if (ip->i_number == source->i_number) { 848 error = EEXIST; 849 goto out; 850 } 851 rootino = ROOTINO; 852 error = 0; 853 if (ip->i_number == rootino) 854 goto out; 855 856 for (;;) { 857 if ((ip->i_mode & IFMT) != IFDIR) { 858 error = ENOTDIR; 859 break; 860 } 861 vp = ITOV(ip); 862 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 863 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 864 IO_NODELOCKED, cred, (int *)0, (struct proc *)0); 865 if (error != 0) 866 break; 867 if (dirbuf.dotdot_namlen != 2 || 868 dirbuf.dotdot_name[0] != '.' || 869 dirbuf.dotdot_name[1] != '.') { 870 error = ENOTDIR; 871 break; 872 } 873 if (dirbuf.dotdot_ino == source->i_number) { 874 error = EINVAL; 875 break; 876 } 877 if (dirbuf.dotdot_ino == rootino) 878 break; 879 ufs_iput(ip); 880 if (error = VOP_VGET(vp, dirbuf.dotdot_ino, &vp)) 881 break; 882 ip = VTOI(vp); 883 } 884 885 out: 886 if (error == ENOTDIR) 887 printf("checkpath: .. not a directory\n"); 888 if (ip != NULL) 889 ufs_iput(ip); 890 return (error); 891 } 892