1 /*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include "opt_ffs_broken_fixme.h" 41 #include "opt_ufs.h" 42 #include "opt_quota.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/namei.h> 48 #include <sys/bio.h> 49 #include <sys/buf.h> 50 #include <sys/proc.h> 51 #include <sys/stat.h> 52 #include <sys/mount.h> 53 #include <sys/vnode.h> 54 #include <sys/sysctl.h> 55 56 #include <vm/vm.h> 57 #include <vm/vm_extern.h> 58 59 #include <ufs/ufs/extattr.h> 60 #include <ufs/ufs/quota.h> 61 #include <ufs/ufs/inode.h> 62 #include <ufs/ufs/dir.h> 63 #ifdef UFS_DIRHASH 64 #include <ufs/ufs/dirhash.h> 65 #endif 66 #include <ufs/ufs/ufsmount.h> 67 #include <ufs/ufs/ufs_extern.h> 68 69 #ifdef DIAGNOSTIC 70 static int dirchk = 1; 71 #else 72 static int dirchk = 0; 73 #endif 74 75 SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); 76 77 /* true if old FS format...*/ 78 #define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) 79 80 static int 81 ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, 82 struct thread *td) 83 { 84 int error; 85 86 #ifdef UFS_ACL 87 /* 88 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 89 * 90 * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD 91 */ 92 93 /* 94 * XXX: Is this check required? 95 */ 96 error = VOP_ACCESS(vdp, VEXEC, cred, td); 97 if (error) 98 return (error); 99 100 error = VOP_ACCESSX(tdp, VDELETE, cred, td); 101 if (error == 0) 102 return (0); 103 104 error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred, td); 105 if (error == 0) 106 return (0); 107 108 error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); 109 if (error) 110 return (error); 111 112 #endif /* !UFS_ACL */ 113 114 /* 115 * Standard Unix access control - delete access requires VWRITE. 116 */ 117 error = VOP_ACCESS(vdp, VWRITE, cred, td); 118 if (error) 119 return (error); 120 121 /* 122 * If directory is "sticky", then user must own 123 * the directory, or the file in it, else she 124 * may not delete it (unless she's root). This 125 * implements append-only directories. 126 */ 127 if ((VTOI(vdp)->i_mode & ISVTX) && 128 VOP_ACCESS(vdp, VADMIN, cred, td) && 129 VOP_ACCESS(tdp, VADMIN, cred, td)) 130 return (EPERM); 131 132 return (0); 133 } 134 135 /* 136 * Convert a component of a pathname into a pointer to a locked inode. 137 * This is a very central and rather complicated routine. 138 * If the filesystem is not maintained in a strict tree hierarchy, 139 * this can result in a deadlock situation (see comments in code below). 140 * 141 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending 142 * on whether the name is to be looked up, created, renamed, or deleted. 143 * When CREATE, RENAME, or DELETE is specified, information usable in 144 * creating, renaming, or deleting a directory entry may be calculated. 145 * If flag has LOCKPARENT or'ed into it and the target of the pathname 146 * exists, lookup returns both the target and its parent directory locked. 147 * When creating or renaming and LOCKPARENT is specified, the target may 148 * not be ".". When deleting and LOCKPARENT is specified, the target may 149 * be "."., but the caller must check to ensure it does an vrele and vput 150 * instead of two vputs. 151 * 152 * This routine is actually used as VOP_CACHEDLOOKUP method, and the 153 * filesystem employs the generic vfs_cache_lookup() as VOP_LOOKUP 154 * method. 155 * 156 * vfs_cache_lookup() performs the following for us: 157 * check that it is a directory 158 * check accessibility of directory 159 * check for modification attempts on read-only mounts 160 * if name found in cache 161 * if at end of path and deleting or creating 162 * drop it 163 * else 164 * return name. 165 * return VOP_CACHEDLOOKUP() 166 * 167 * Overall outline of ufs_lookup: 168 * 169 * search for name in directory, to found or notfound 170 * notfound: 171 * if creating, return locked directory, leaving info on available slots 172 * else return error 173 * found: 174 * if at end of path and deleting, return information to allow delete 175 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 176 * inode and return info to allow rewrite 177 * if not at end, add name to cache; if at end and neither creating 178 * nor deleting, add name to cache 179 */ 180 int 181 ufs_lookup(ap) 182 struct vop_cachedlookup_args /* { 183 struct vnode *a_dvp; 184 struct vnode **a_vpp; 185 struct componentname *a_cnp; 186 } */ *ap; 187 { 188 189 return (ufs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); 190 } 191 192 int 193 ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, 194 ino_t *dd_ino) 195 { 196 struct inode *dp; /* inode for directory being searched */ 197 struct buf *bp; /* a buffer of directory entries */ 198 struct direct *ep; /* the current directory entry */ 199 int entryoffsetinblock; /* offset of ep in bp's buffer */ 200 enum {NONE, COMPACT, FOUND} slotstatus; 201 doff_t slotoffset; /* offset of area with free space */ 202 doff_t i_diroff; /* cached i_diroff value. */ 203 doff_t i_offset; /* cached i_offset value. */ 204 int slotsize; /* size of area at slotoffset */ 205 int slotfreespace; /* amount of space free in slot */ 206 int slotneeded; /* size of the entry we're seeking */ 207 int numdirpasses; /* strategy for directory search */ 208 doff_t endsearch; /* offset to end directory search */ 209 doff_t prevoff; /* prev entry dp->i_offset */ 210 struct vnode *pdp; /* saved dp during symlink work */ 211 struct vnode *tdp; /* returned by VFS_VGET */ 212 doff_t enduseful; /* pointer past last used dir slot */ 213 u_long bmask; /* block offset mask */ 214 int namlen, error; 215 struct ucred *cred = cnp->cn_cred; 216 int flags = cnp->cn_flags; 217 int nameiop = cnp->cn_nameiop; 218 ino_t ino, ino1; 219 int ltype; 220 221 if (vpp != NULL) 222 *vpp = NULL; 223 224 dp = VTOI(vdp); 225 226 /* 227 * Create a vm object if vmiodirenable is enabled. 228 * Alternatively we could call vnode_create_vobject 229 * in VFS_VGET but we could end up creating objects 230 * that are never used. 231 */ 232 vnode_create_vobject(vdp, DIP(dp, i_size), cnp->cn_thread); 233 234 bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; 235 236 restart: 237 bp = NULL; 238 slotoffset = -1; 239 240 /* 241 * We now have a segment name to search for, and a directory to search. 242 * 243 * Suppress search for slots unless creating 244 * file and at end of pathname, in which case 245 * we watch for a place to put the new file in 246 * case it doesn't already exist. 247 */ 248 ino = 0; 249 i_diroff = dp->i_diroff; 250 slotstatus = FOUND; 251 slotfreespace = slotsize = slotneeded = 0; 252 if ((nameiop == CREATE || nameiop == RENAME) && 253 (flags & ISLASTCN)) { 254 slotstatus = NONE; 255 slotneeded = DIRECTSIZ(cnp->cn_namelen); 256 } 257 258 #ifdef UFS_DIRHASH 259 /* 260 * Use dirhash for fast operations on large directories. The logic 261 * to determine whether to hash the directory is contained within 262 * ufsdirhash_build(); a zero return means that it decided to hash 263 * this directory and it successfully built up the hash table. 264 */ 265 if (ufsdirhash_build(dp) == 0) { 266 /* Look for a free slot if needed. */ 267 enduseful = dp->i_size; 268 if (slotstatus != FOUND) { 269 slotoffset = ufsdirhash_findfree(dp, slotneeded, 270 &slotsize); 271 if (slotoffset >= 0) { 272 slotstatus = COMPACT; 273 enduseful = ufsdirhash_enduseful(dp); 274 if (enduseful < 0) 275 enduseful = dp->i_size; 276 } 277 } 278 /* Look up the component. */ 279 numdirpasses = 1; 280 entryoffsetinblock = 0; /* silence compiler warning */ 281 switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, 282 &i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { 283 case 0: 284 ep = (struct direct *)((char *)bp->b_data + 285 (i_offset & bmask)); 286 goto foundentry; 287 case ENOENT: 288 i_offset = roundup2(dp->i_size, DIRBLKSIZ); 289 goto notfound; 290 default: 291 /* Something failed; just do a linear search. */ 292 break; 293 } 294 } 295 #endif /* UFS_DIRHASH */ 296 /* 297 * If there is cached information on a previous search of 298 * this directory, pick up where we last left off. 299 * We cache only lookups as these are the most common 300 * and have the greatest payoff. Caching CREATE has little 301 * benefit as it usually must search the entire directory 302 * to determine that the entry does not exist. Caching the 303 * location of the last DELETE or RENAME has not reduced 304 * profiling time and hence has been removed in the interest 305 * of simplicity. 306 */ 307 if (nameiop != LOOKUP || i_diroff == 0 || i_diroff >= dp->i_size) { 308 entryoffsetinblock = 0; 309 i_offset = 0; 310 numdirpasses = 1; 311 } else { 312 i_offset = i_diroff; 313 if ((entryoffsetinblock = i_offset & bmask) && 314 (error = UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp))) 315 return (error); 316 numdirpasses = 2; 317 nchstats.ncs_2passes++; 318 } 319 prevoff = i_offset; 320 endsearch = roundup2(dp->i_size, DIRBLKSIZ); 321 enduseful = 0; 322 323 searchloop: 324 while (i_offset < endsearch) { 325 /* 326 * If necessary, get the next directory block. 327 */ 328 if ((i_offset & bmask) == 0) { 329 if (bp != NULL) 330 brelse(bp); 331 error = 332 UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp); 333 if (error) 334 return (error); 335 entryoffsetinblock = 0; 336 } 337 /* 338 * If still looking for a slot, and at a DIRBLKSIZE 339 * boundary, have to start looking for free space again. 340 */ 341 if (slotstatus == NONE && 342 (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { 343 slotoffset = -1; 344 slotfreespace = 0; 345 } 346 /* 347 * Get pointer to next entry. 348 * Full validation checks are slow, so we only check 349 * enough to insure forward progress through the 350 * directory. Complete checks can be run by patching 351 * "dirchk" to be true. 352 */ 353 ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); 354 if (ep->d_reclen == 0 || ep->d_reclen > 355 DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 356 (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) { 357 int i; 358 359 ufs_dirbad(dp, i_offset, "mangled entry"); 360 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 361 i_offset += i; 362 entryoffsetinblock += i; 363 continue; 364 } 365 366 /* 367 * If an appropriate sized slot has not yet been found, 368 * check to see if one is available. Also accumulate space 369 * in the current block so that we can determine if 370 * compaction is viable. 371 */ 372 if (slotstatus != FOUND) { 373 int size = ep->d_reclen; 374 375 if (ep->d_ino != 0) 376 size -= DIRSIZ(OFSFMT(vdp), ep); 377 if (size > 0) { 378 if (size >= slotneeded) { 379 slotstatus = FOUND; 380 slotoffset = i_offset; 381 slotsize = ep->d_reclen; 382 } else if (slotstatus == NONE) { 383 slotfreespace += size; 384 if (slotoffset == -1) 385 slotoffset = i_offset; 386 if (slotfreespace >= slotneeded) { 387 slotstatus = COMPACT; 388 slotsize = i_offset + 389 ep->d_reclen - slotoffset; 390 } 391 } 392 } 393 } 394 395 /* 396 * Check for a name match. 397 */ 398 if (ep->d_ino) { 399 # if (BYTE_ORDER == LITTLE_ENDIAN) 400 if (OFSFMT(vdp)) 401 namlen = ep->d_type; 402 else 403 namlen = ep->d_namlen; 404 # else 405 namlen = ep->d_namlen; 406 # endif 407 if (namlen == cnp->cn_namelen && 408 (cnp->cn_nameptr[0] == ep->d_name[0]) && 409 !bcmp(cnp->cn_nameptr, ep->d_name, 410 (unsigned)namlen)) { 411 #ifdef UFS_DIRHASH 412 foundentry: 413 #endif 414 /* 415 * Save directory entry's inode number and 416 * reclen in ndp->ni_ufs area, and release 417 * directory buffer. 418 */ 419 if (vdp->v_mount->mnt_maxsymlinklen > 0 && 420 ep->d_type == DT_WHT) { 421 slotstatus = FOUND; 422 slotoffset = i_offset; 423 slotsize = ep->d_reclen; 424 enduseful = dp->i_size; 425 cnp->cn_flags |= ISWHITEOUT; 426 numdirpasses--; 427 goto notfound; 428 } 429 ino = ep->d_ino; 430 goto found; 431 } 432 } 433 prevoff = i_offset; 434 i_offset += ep->d_reclen; 435 entryoffsetinblock += ep->d_reclen; 436 if (ep->d_ino) 437 enduseful = i_offset; 438 } 439 notfound: 440 /* 441 * If we started in the middle of the directory and failed 442 * to find our target, we must check the beginning as well. 443 */ 444 if (numdirpasses == 2) { 445 numdirpasses--; 446 i_offset = 0; 447 endsearch = i_diroff; 448 goto searchloop; 449 } 450 if (bp != NULL) 451 brelse(bp); 452 /* 453 * If creating, and at end of pathname and current 454 * directory has not been removed, then can consider 455 * allowing file to be created. 456 */ 457 if ((nameiop == CREATE || nameiop == RENAME || 458 (nameiop == DELETE && 459 (cnp->cn_flags & DOWHITEOUT) && 460 (cnp->cn_flags & ISWHITEOUT))) && 461 (flags & ISLASTCN) && dp->i_effnlink != 0) { 462 /* 463 * Access for write is interpreted as allowing 464 * creation of files in the directory. 465 * 466 * XXX: Fix the comment above. 467 */ 468 if (flags & WILLBEDIR) 469 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); 470 else 471 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); 472 if (error) 473 return (error); 474 /* 475 * Return an indication of where the new directory 476 * entry should be put. If we didn't find a slot, 477 * then set dp->i_count to 0 indicating 478 * that the new slot belongs at the end of the 479 * directory. If we found a slot, then the new entry 480 * can be put in the range from dp->i_offset to 481 * dp->i_offset + dp->i_count. 482 */ 483 if (slotstatus == NONE) { 484 dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ); 485 dp->i_count = 0; 486 enduseful = dp->i_offset; 487 } else if (nameiop == DELETE) { 488 dp->i_offset = slotoffset; 489 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 490 dp->i_count = 0; 491 else 492 dp->i_count = dp->i_offset - prevoff; 493 } else { 494 dp->i_offset = slotoffset; 495 dp->i_count = slotsize; 496 if (enduseful < slotoffset + slotsize) 497 enduseful = slotoffset + slotsize; 498 } 499 dp->i_endoff = roundup2(enduseful, DIRBLKSIZ); 500 /* 501 * We return with the directory locked, so that 502 * the parameters we set up above will still be 503 * valid if we actually decide to do a direnter(). 504 * We return ni_vp == NULL to indicate that the entry 505 * does not currently exist; we leave a pointer to 506 * the (locked) directory inode in ndp->ni_dvp. 507 * The pathname buffer is saved so that the name 508 * can be obtained later. 509 * 510 * NB - if the directory is unlocked, then this 511 * information cannot be used. 512 */ 513 cnp->cn_flags |= SAVENAME; 514 return (EJUSTRETURN); 515 } 516 /* 517 * Insert name into cache (as non-existent) if appropriate. 518 */ 519 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 520 cache_enter(vdp, NULL, cnp); 521 return (ENOENT); 522 523 found: 524 if (dd_ino != NULL) 525 *dd_ino = ino; 526 if (numdirpasses == 2) 527 nchstats.ncs_pass2++; 528 /* 529 * Check that directory length properly reflects presence 530 * of this entry. 531 */ 532 if (i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) { 533 ufs_dirbad(dp, i_offset, "i_size too small"); 534 dp->i_size = i_offset + DIRSIZ(OFSFMT(vdp), ep); 535 DIP_SET(dp, i_size, dp->i_size); 536 dp->i_flag |= IN_CHANGE | IN_UPDATE; 537 } 538 brelse(bp); 539 540 /* 541 * Found component in pathname. 542 * If the final component of path name, save information 543 * in the cache as to where the entry was found. 544 */ 545 if ((flags & ISLASTCN) && nameiop == LOOKUP) 546 dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1); 547 548 /* 549 * If deleting, and at end of pathname, return 550 * parameters which can be used to remove file. 551 */ 552 if (nameiop == DELETE && (flags & ISLASTCN)) { 553 if (flags & LOCKPARENT) 554 ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); 555 /* 556 * Return pointer to current entry in dp->i_offset, 557 * and distance past previous entry (if there 558 * is a previous entry in this block) in dp->i_count. 559 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 560 * 561 * Technically we shouldn't be setting these in the 562 * WANTPARENT case (first lookup in rename()), but any 563 * lookups that will result in directory changes will 564 * overwrite these. 565 */ 566 dp->i_offset = i_offset; 567 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 568 dp->i_count = 0; 569 else 570 dp->i_count = dp->i_offset - prevoff; 571 if (dd_ino != NULL) 572 return (0); 573 if ((error = VFS_VGET(vdp->v_mount, ino, 574 LK_EXCLUSIVE, &tdp)) != 0) 575 return (error); 576 error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); 577 if (error) { 578 vput(tdp); 579 return (error); 580 } 581 if (dp->i_number == ino) { 582 VREF(vdp); 583 *vpp = vdp; 584 vput(tdp); 585 return (0); 586 } 587 588 *vpp = tdp; 589 return (0); 590 } 591 592 /* 593 * If rewriting (RENAME), return the inode and the 594 * information required to rewrite the present directory 595 * Must get inode of directory entry to verify it's a 596 * regular file, or empty directory. 597 */ 598 if (nameiop == RENAME && (flags & ISLASTCN)) { 599 if (flags & WILLBEDIR) 600 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); 601 else 602 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); 603 if (error) 604 return (error); 605 /* 606 * Careful about locking second inode. 607 * This can only occur if the target is ".". 608 */ 609 dp->i_offset = i_offset; 610 if (dp->i_number == ino) 611 return (EISDIR); 612 if (dd_ino != NULL) 613 return (0); 614 if ((error = VFS_VGET(vdp->v_mount, ino, 615 LK_EXCLUSIVE, &tdp)) != 0) 616 return (error); 617 618 error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); 619 if (error) { 620 vput(tdp); 621 return (error); 622 } 623 624 #ifdef SunOS_doesnt_do_that 625 /* 626 * The only purpose of this check is to return the correct 627 * error. Assume that we want to rename directory "a" 628 * to a file "b", and that we have no ACL_WRITE_DATA on 629 * a containing directory, but we _do_ have ACL_APPEND_DATA. 630 * In that case, the VOP_ACCESS check above will return 0, 631 * and the operation will fail with ENOTDIR instead 632 * of EACCESS. 633 */ 634 if (tdp->v_type == VDIR) 635 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); 636 else 637 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); 638 if (error) { 639 vput(tdp); 640 return (error); 641 } 642 #endif 643 644 *vpp = tdp; 645 cnp->cn_flags |= SAVENAME; 646 return (0); 647 } 648 if (dd_ino != NULL) 649 return (0); 650 651 /* 652 * Step through the translation in the name. We do not `vput' the 653 * directory because we may need it again if a symbolic link 654 * is relative to the current directory. Instead we save it 655 * unlocked as "pdp". We must get the target inode before unlocking 656 * the directory to insure that the inode will not be removed 657 * before we get it. We prevent deadlock by always fetching 658 * inodes from the root, moving down the directory tree. Thus 659 * when following backward pointers ".." we must unlock the 660 * parent directory before getting the requested directory. 661 * There is a potential race condition here if both the current 662 * and parent directories are removed before the VFS_VGET for the 663 * inode associated with ".." returns. We hope that this occurs 664 * infrequently since we cannot avoid this race condition without 665 * implementing a sophisticated deadlock detection algorithm. 666 * Note also that this simple deadlock detection scheme will not 667 * work if the filesystem has any hard links other than ".." 668 * that point backwards in the directory structure. 669 */ 670 pdp = vdp; 671 if (flags & ISDOTDOT) { 672 error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); 673 if (error) 674 return (error); 675 676 /* 677 * Recheck that ".." entry in the vdp directory points 678 * to the inode we looked up before vdp lock was 679 * dropped. 680 */ 681 error = ufs_lookup_ino(pdp, NULL, cnp, &ino1); 682 if (error) { 683 vput(tdp); 684 return (error); 685 } 686 if (ino1 != ino) { 687 vput(tdp); 688 goto restart; 689 } 690 691 *vpp = tdp; 692 } else if (dp->i_number == ino) { 693 VREF(vdp); /* we want ourself, ie "." */ 694 /* 695 * When we lookup "." we still can be asked to lock it 696 * differently. 697 */ 698 ltype = cnp->cn_lkflags & LK_TYPE_MASK; 699 if (ltype != VOP_ISLOCKED(vdp)) { 700 if (ltype == LK_EXCLUSIVE) 701 vn_lock(vdp, LK_UPGRADE | LK_RETRY); 702 else /* if (ltype == LK_SHARED) */ 703 vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); 704 /* 705 * Relock for the "." case may left us with 706 * reclaimed vnode. 707 */ 708 if (vdp->v_iflag & VI_DOOMED) { 709 vrele(vdp); 710 return (ENOENT); 711 } 712 } 713 *vpp = vdp; 714 } else { 715 error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp); 716 if (error) 717 return (error); 718 *vpp = tdp; 719 } 720 721 /* 722 * Insert name into cache if appropriate. 723 */ 724 if (cnp->cn_flags & MAKEENTRY) 725 cache_enter(vdp, *vpp, cnp); 726 return (0); 727 } 728 729 void 730 ufs_dirbad(ip, offset, how) 731 struct inode *ip; 732 doff_t offset; 733 char *how; 734 { 735 struct mount *mp; 736 737 mp = ITOV(ip)->v_mount; 738 if ((mp->mnt_flag & MNT_RDONLY) == 0) 739 panic("ufs_dirbad: %s: bad dir ino %lu at offset %ld: %s", 740 mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how); 741 else 742 (void)printf("%s: bad dir ino %lu at offset %ld: %s\n", 743 mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how); 744 } 745 746 /* 747 * Do consistency checking on a directory entry: 748 * record length must be multiple of 4 749 * entry must fit in rest of its DIRBLKSIZ block 750 * record must be large enough to contain entry 751 * name is not longer than MAXNAMLEN 752 * name must be as long as advertised, and null terminated 753 */ 754 int 755 ufs_dirbadentry(dp, ep, entryoffsetinblock) 756 struct vnode *dp; 757 struct direct *ep; 758 int entryoffsetinblock; 759 { 760 int i, namlen; 761 762 # if (BYTE_ORDER == LITTLE_ENDIAN) 763 if (OFSFMT(dp)) 764 namlen = ep->d_type; 765 else 766 namlen = ep->d_namlen; 767 # else 768 namlen = ep->d_namlen; 769 # endif 770 if ((ep->d_reclen & 0x3) != 0 || 771 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 772 ep->d_reclen < DIRSIZ(OFSFMT(dp), ep) || namlen > MAXNAMLEN) { 773 /*return (1); */ 774 printf("First bad\n"); 775 goto bad; 776 } 777 if (ep->d_ino == 0) 778 return (0); 779 for (i = 0; i < namlen; i++) 780 if (ep->d_name[i] == '\0') { 781 /*return (1); */ 782 printf("Second bad\n"); 783 goto bad; 784 } 785 if (ep->d_name[i]) 786 goto bad; 787 return (0); 788 bad: 789 return (1); 790 } 791 792 /* 793 * Construct a new directory entry after a call to namei, using the 794 * parameters that it left in the componentname argument cnp. The 795 * argument ip is the inode to which the new directory entry will refer. 796 */ 797 void 798 ufs_makedirentry(ip, cnp, newdirp) 799 struct inode *ip; 800 struct componentname *cnp; 801 struct direct *newdirp; 802 { 803 804 #ifdef INVARIANTS 805 if ((cnp->cn_flags & SAVENAME) == 0) 806 panic("ufs_makedirentry: missing name"); 807 #endif 808 newdirp->d_ino = ip->i_number; 809 newdirp->d_namlen = cnp->cn_namelen; 810 bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1); 811 if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) 812 newdirp->d_type = IFTODT(ip->i_mode); 813 else { 814 newdirp->d_type = 0; 815 # if (BYTE_ORDER == LITTLE_ENDIAN) 816 { u_char tmp = newdirp->d_namlen; 817 newdirp->d_namlen = newdirp->d_type; 818 newdirp->d_type = tmp; } 819 # endif 820 } 821 } 822 823 /* 824 * Write a directory entry after a call to namei, using the parameters 825 * that it left in nameidata. The argument dirp is the new directory 826 * entry contents. Dvp is a pointer to the directory to be written, 827 * which was left locked by namei. Remaining parameters (dp->i_offset, 828 * dp->i_count) indicate how the space for the new entry is to be obtained. 829 * Non-null bp indicates that a directory is being created (for the 830 * soft dependency code). 831 */ 832 int 833 ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename) 834 struct vnode *dvp; 835 struct vnode *tvp; 836 struct direct *dirp; 837 struct componentname *cnp; 838 struct buf *newdirbp; 839 int isrename; 840 { 841 struct ucred *cr; 842 struct thread *td; 843 int newentrysize; 844 struct inode *dp; 845 struct buf *bp; 846 u_int dsize; 847 struct direct *ep, *nep; 848 int error, ret, blkoff, loc, spacefree, flags, namlen; 849 char *dirbuf; 850 851 td = curthread; /* XXX */ 852 cr = td->td_ucred; 853 854 dp = VTOI(dvp); 855 newentrysize = DIRSIZ(OFSFMT(dvp), dirp); 856 857 if (dp->i_count == 0) { 858 /* 859 * If dp->i_count is 0, then namei could find no 860 * space in the directory. Here, dp->i_offset will 861 * be on a directory block boundary and we will write the 862 * new entry into a fresh block. 863 */ 864 if (dp->i_offset & (DIRBLKSIZ - 1)) 865 panic("ufs_direnter: newblk"); 866 flags = BA_CLRBUF; 867 if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) 868 flags |= IO_SYNC; 869 #ifdef QUOTA 870 if ((error = getinoquota(dp)) != 0) { 871 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 872 bdwrite(newdirbp); 873 return (error); 874 } 875 #endif 876 if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ, 877 cr, flags, &bp)) != 0) { 878 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 879 bdwrite(newdirbp); 880 return (error); 881 } 882 dp->i_size = dp->i_offset + DIRBLKSIZ; 883 DIP_SET(dp, i_size, dp->i_size); 884 dp->i_flag |= IN_CHANGE | IN_UPDATE; 885 vnode_pager_setsize(dvp, (u_long)dp->i_size); 886 dirp->d_reclen = DIRBLKSIZ; 887 blkoff = dp->i_offset & 888 (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); 889 bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); 890 #ifdef UFS_DIRHASH 891 if (dp->i_dirhash != NULL) { 892 ufsdirhash_newblk(dp, dp->i_offset); 893 ufsdirhash_add(dp, dirp, dp->i_offset); 894 ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, 895 dp->i_offset); 896 } 897 #endif 898 if (DOINGSOFTDEP(dvp)) { 899 /* 900 * Ensure that the entire newly allocated block is a 901 * valid directory so that future growth within the 902 * block does not have to ensure that the block is 903 * written before the inode. 904 */ 905 blkoff += DIRBLKSIZ; 906 while (blkoff < bp->b_bcount) { 907 ((struct direct *) 908 (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; 909 blkoff += DIRBLKSIZ; 910 } 911 if (softdep_setup_directory_add(bp, dp, dp->i_offset, 912 dirp->d_ino, newdirbp, 1)) 913 dp->i_flag |= IN_NEEDSYNC; 914 if (newdirbp) 915 bdwrite(newdirbp); 916 bdwrite(bp); 917 if ((dp->i_flag & IN_NEEDSYNC) == 0) 918 return (UFS_UPDATE(dvp, 0)); 919 /* 920 * We have just allocated a directory block in an 921 * indirect block. We must prevent holes in the 922 * directory created if directory entries are 923 * written out of order. To accomplish this we 924 * fsync when we extend a directory into indirects. 925 * During rename it's not safe to drop the tvp lock 926 * so sync must be delayed until it is. 927 * 928 * This synchronous step could be removed if fsck and 929 * the kernel were taught to fill in sparse 930 * directories rather than panic. 931 */ 932 if (isrename) 933 return (0); 934 if (tvp != NULL) 935 VOP_UNLOCK(tvp, 0); 936 error = VOP_FSYNC(dvp, MNT_WAIT, td); 937 if (tvp != NULL) 938 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 939 return (error); 940 } 941 if (DOINGASYNC(dvp)) { 942 bdwrite(bp); 943 return (UFS_UPDATE(dvp, 0)); 944 } 945 error = bwrite(bp); 946 ret = UFS_UPDATE(dvp, 1); 947 if (error == 0) 948 return (ret); 949 return (error); 950 } 951 952 /* 953 * If dp->i_count is non-zero, then namei found space for the new 954 * entry in the range dp->i_offset to dp->i_offset + dp->i_count 955 * in the directory. To use this space, we may have to compact 956 * the entries located there, by copying them together towards the 957 * beginning of the block, leaving the free space in one usable 958 * chunk at the end. 959 */ 960 961 /* 962 * Increase size of directory if entry eats into new space. 963 * This should never push the size past a new multiple of 964 * DIRBLKSIZE. 965 * 966 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 967 */ 968 if (dp->i_offset + dp->i_count > dp->i_size) { 969 dp->i_size = dp->i_offset + dp->i_count; 970 DIP_SET(dp, i_size, dp->i_size); 971 } 972 /* 973 * Get the block containing the space for the new directory entry. 974 */ 975 error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp); 976 if (error) { 977 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 978 bdwrite(newdirbp); 979 return (error); 980 } 981 /* 982 * Find space for the new entry. In the simple case, the entry at 983 * offset base will have the space. If it does not, then namei 984 * arranged that compacting the region dp->i_offset to 985 * dp->i_offset + dp->i_count would yield the space. 986 */ 987 ep = (struct direct *)dirbuf; 988 dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; 989 spacefree = ep->d_reclen - dsize; 990 for (loc = ep->d_reclen; loc < dp->i_count; ) { 991 nep = (struct direct *)(dirbuf + loc); 992 993 /* Trim the existing slot (NB: dsize may be zero). */ 994 ep->d_reclen = dsize; 995 ep = (struct direct *)((char *)ep + dsize); 996 997 /* Read nep->d_reclen now as the bcopy() may clobber it. */ 998 loc += nep->d_reclen; 999 if (nep->d_ino == 0) { 1000 /* 1001 * A mid-block unused entry. Such entries are 1002 * never created by the kernel, but fsck_ffs 1003 * can create them (and it doesn't fix them). 1004 * 1005 * Add up the free space, and initialise the 1006 * relocated entry since we don't bcopy it. 1007 */ 1008 spacefree += nep->d_reclen; 1009 ep->d_ino = 0; 1010 dsize = 0; 1011 continue; 1012 } 1013 dsize = DIRSIZ(OFSFMT(dvp), nep); 1014 spacefree += nep->d_reclen - dsize; 1015 #ifdef UFS_DIRHASH 1016 if (dp->i_dirhash != NULL) 1017 ufsdirhash_move(dp, nep, 1018 dp->i_offset + ((char *)nep - dirbuf), 1019 dp->i_offset + ((char *)ep - dirbuf)); 1020 #endif 1021 if (DOINGSOFTDEP(dvp)) 1022 softdep_change_directoryentry_offset(bp, dp, dirbuf, 1023 (caddr_t)nep, (caddr_t)ep, dsize); 1024 else 1025 bcopy((caddr_t)nep, (caddr_t)ep, dsize); 1026 } 1027 /* 1028 * Here, `ep' points to a directory entry containing `dsize' in-use 1029 * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, 1030 * then the entry is completely unused (dsize == 0). The value 1031 * of ep->d_reclen is always indeterminate. 1032 * 1033 * Update the pointer fields in the previous entry (if any), 1034 * copy in the new entry, and write out the block. 1035 */ 1036 # if (BYTE_ORDER == LITTLE_ENDIAN) 1037 if (OFSFMT(dvp)) 1038 namlen = ep->d_type; 1039 else 1040 namlen = ep->d_namlen; 1041 # else 1042 namlen = ep->d_namlen; 1043 # endif 1044 if (ep->d_ino == 0 || 1045 (ep->d_ino == WINO && namlen == dirp->d_namlen && 1046 bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { 1047 if (spacefree + dsize < newentrysize) 1048 panic("ufs_direnter: compact1"); 1049 dirp->d_reclen = spacefree + dsize; 1050 } else { 1051 if (spacefree < newentrysize) 1052 panic("ufs_direnter: compact2"); 1053 dirp->d_reclen = spacefree; 1054 ep->d_reclen = dsize; 1055 ep = (struct direct *)((char *)ep + dsize); 1056 } 1057 #ifdef UFS_DIRHASH 1058 if (dp->i_dirhash != NULL && (ep->d_ino == 0 || 1059 dirp->d_reclen == spacefree)) 1060 ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf)); 1061 #endif 1062 bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); 1063 #ifdef UFS_DIRHASH 1064 if (dp->i_dirhash != NULL) 1065 ufsdirhash_checkblock(dp, dirbuf - 1066 (dp->i_offset & (DIRBLKSIZ - 1)), 1067 dp->i_offset & ~(DIRBLKSIZ - 1)); 1068 #endif 1069 1070 if (DOINGSOFTDEP(dvp)) { 1071 (void) softdep_setup_directory_add(bp, dp, 1072 dp->i_offset + (caddr_t)ep - dirbuf, 1073 dirp->d_ino, newdirbp, 0); 1074 if (newdirbp != NULL) 1075 bdwrite(newdirbp); 1076 bdwrite(bp); 1077 } else { 1078 if (DOINGASYNC(dvp)) { 1079 bdwrite(bp); 1080 error = 0; 1081 } else { 1082 error = bwrite(bp); 1083 } 1084 } 1085 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1086 /* 1087 * If all went well, and the directory can be shortened, proceed 1088 * with the truncation. Note that we have to unlock the inode for 1089 * the entry that we just entered, as the truncation may need to 1090 * lock other inodes which can lead to deadlock if we also hold a 1091 * lock on the newly entered node. 1092 */ 1093 if (isrename == 0 && error == 0 && 1094 dp->i_endoff && dp->i_endoff < dp->i_size) { 1095 if (tvp != NULL) 1096 VOP_UNLOCK(tvp, 0); 1097 #ifdef UFS_DIRHASH 1098 if (dp->i_dirhash != NULL) 1099 ufsdirhash_dirtrunc(dp, dp->i_endoff); 1100 #endif 1101 (void) UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, 1102 IO_NORMAL | IO_SYNC, cr, td); 1103 if (tvp != NULL) 1104 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1105 } 1106 return (error); 1107 } 1108 1109 /* 1110 * Remove a directory entry after a call to namei, using 1111 * the parameters which it left in nameidata. The entry 1112 * dp->i_offset contains the offset into the directory of the 1113 * entry to be eliminated. The dp->i_count field contains the 1114 * size of the previous record in the directory. If this 1115 * is 0, the first entry is being deleted, so we need only 1116 * zero the inode number to mark the entry as free. If the 1117 * entry is not the first in the directory, we must reclaim 1118 * the space of the now empty record by adding the record size 1119 * to the size of the previous entry. 1120 */ 1121 int 1122 ufs_dirremove(dvp, ip, flags, isrmdir) 1123 struct vnode *dvp; 1124 struct inode *ip; 1125 int flags; 1126 int isrmdir; 1127 { 1128 struct inode *dp; 1129 struct direct *ep, *rep; 1130 struct buf *bp; 1131 int error; 1132 1133 dp = VTOI(dvp); 1134 1135 /* 1136 * Adjust the link count early so softdep can block if necessary. 1137 */ 1138 if (ip) { 1139 ip->i_effnlink--; 1140 if (DOINGSOFTDEP(dvp)) { 1141 softdep_setup_unlink(dp, ip); 1142 } else { 1143 ip->i_nlink--; 1144 DIP_SET(ip, i_nlink, ip->i_nlink); 1145 ip->i_flag |= IN_CHANGE; 1146 } 1147 } 1148 if (flags & DOWHITEOUT) { 1149 /* 1150 * Whiteout entry: set d_ino to WINO. 1151 */ 1152 if ((error = 1153 UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) 1154 return (error); 1155 ep->d_ino = WINO; 1156 ep->d_type = DT_WHT; 1157 goto out; 1158 } 1159 1160 if ((error = UFS_BLKATOFF(dvp, 1161 (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) 1162 return (error); 1163 1164 /* Set 'rep' to the entry being removed. */ 1165 if (dp->i_count == 0) 1166 rep = ep; 1167 else 1168 rep = (struct direct *)((char *)ep + ep->d_reclen); 1169 #ifdef UFS_DIRHASH 1170 /* 1171 * Remove the dirhash entry. This is complicated by the fact 1172 * that `ep' is the previous entry when dp->i_count != 0. 1173 */ 1174 if (dp->i_dirhash != NULL) 1175 ufsdirhash_remove(dp, rep, dp->i_offset); 1176 #endif 1177 if (ip && rep->d_ino != ip->i_number) 1178 panic("ufs_dirremove: ip %d does not match dirent ino %d\n", 1179 ip->i_number, rep->d_ino); 1180 if (dp->i_count == 0) { 1181 /* 1182 * First entry in block: set d_ino to zero. 1183 */ 1184 ep->d_ino = 0; 1185 } else { 1186 /* 1187 * Collapse new free space into previous entry. 1188 */ 1189 ep->d_reclen += rep->d_reclen; 1190 } 1191 #ifdef UFS_DIRHASH 1192 if (dp->i_dirhash != NULL) 1193 ufsdirhash_checkblock(dp, (char *)ep - 1194 ((dp->i_offset - dp->i_count) & (DIRBLKSIZ - 1)), 1195 dp->i_offset & ~(DIRBLKSIZ - 1)); 1196 #endif 1197 out: 1198 error = 0; 1199 if (DOINGSOFTDEP(dvp)) { 1200 if (ip) 1201 softdep_setup_remove(bp, dp, ip, isrmdir); 1202 if (softdep_slowdown(dvp)) 1203 error = bwrite(bp); 1204 else 1205 bdwrite(bp); 1206 } else { 1207 if (flags & DOWHITEOUT) 1208 error = bwrite(bp); 1209 else if (DOINGASYNC(dvp) && dp->i_count != 0) 1210 bdwrite(bp); 1211 else 1212 error = bwrite(bp); 1213 } 1214 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1215 /* 1216 * If the last named reference to a snapshot goes away, 1217 * drop its snapshot reference so that it will be reclaimed 1218 * when last open reference goes away. 1219 */ 1220 #if defined(FFS) || defined(IFS) 1221 if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 && ip->i_effnlink == 0) 1222 ffs_snapgone(ip); 1223 #endif 1224 return (error); 1225 } 1226 1227 /* 1228 * Rewrite an existing directory entry to point at the inode 1229 * supplied. The parameters describing the directory entry are 1230 * set up by a call to namei. 1231 */ 1232 int 1233 ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) 1234 struct inode *dp, *oip; 1235 ino_t newinum; 1236 int newtype; 1237 int isrmdir; 1238 { 1239 struct buf *bp; 1240 struct direct *ep; 1241 struct vnode *vdp = ITOV(dp); 1242 int error; 1243 1244 /* 1245 * Drop the link before we lock the buf so softdep can block if 1246 * necessary. 1247 */ 1248 oip->i_effnlink--; 1249 if (DOINGSOFTDEP(vdp)) { 1250 softdep_setup_unlink(dp, oip); 1251 } else { 1252 oip->i_nlink--; 1253 DIP_SET(oip, i_nlink, oip->i_nlink); 1254 oip->i_flag |= IN_CHANGE; 1255 } 1256 1257 error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); 1258 if (error) 1259 return (error); 1260 if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' && 1261 ep->d_ino != oip->i_number) { 1262 brelse(bp); 1263 return (EIDRM); 1264 } 1265 ep->d_ino = newinum; 1266 if (!OFSFMT(vdp)) 1267 ep->d_type = newtype; 1268 if (DOINGSOFTDEP(vdp)) { 1269 softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); 1270 bdwrite(bp); 1271 } else { 1272 if (DOINGASYNC(vdp)) { 1273 bdwrite(bp); 1274 error = 0; 1275 } else { 1276 error = bwrite(bp); 1277 } 1278 } 1279 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1280 /* 1281 * If the last named reference to a snapshot goes away, 1282 * drop its snapshot reference so that it will be reclaimed 1283 * when last open reference goes away. 1284 */ 1285 #if defined(FFS) || defined(IFS) 1286 if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0) 1287 ffs_snapgone(oip); 1288 #endif 1289 return (error); 1290 } 1291 1292 /* 1293 * Check if a directory is empty or not. 1294 * Inode supplied must be locked. 1295 * 1296 * Using a struct dirtemplate here is not precisely 1297 * what we want, but better than using a struct direct. 1298 * 1299 * NB: does not handle corrupted directories. 1300 */ 1301 int 1302 ufs_dirempty(ip, parentino, cred) 1303 struct inode *ip; 1304 ino_t parentino; 1305 struct ucred *cred; 1306 { 1307 doff_t off; 1308 struct dirtemplate dbuf; 1309 struct direct *dp = (struct direct *)&dbuf; 1310 int error, count, namlen; 1311 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 1312 1313 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 1314 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, 1315 off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, 1316 NOCRED, &count, (struct thread *)0); 1317 /* 1318 * Since we read MINDIRSIZ, residual must 1319 * be 0 unless we're at end of file. 1320 */ 1321 if (error || count != 0) 1322 return (0); 1323 /* avoid infinite loops */ 1324 if (dp->d_reclen == 0) 1325 return (0); 1326 /* skip empty entries */ 1327 if (dp->d_ino == 0 || dp->d_ino == WINO) 1328 continue; 1329 /* accept only "." and ".." */ 1330 # if (BYTE_ORDER == LITTLE_ENDIAN) 1331 if (OFSFMT(ITOV(ip))) 1332 namlen = dp->d_type; 1333 else 1334 namlen = dp->d_namlen; 1335 # else 1336 namlen = dp->d_namlen; 1337 # endif 1338 if (namlen > 2) 1339 return (0); 1340 if (dp->d_name[0] != '.') 1341 return (0); 1342 /* 1343 * At this point namlen must be 1 or 2. 1344 * 1 implies ".", 2 implies ".." if second 1345 * char is also "." 1346 */ 1347 if (namlen == 1 && dp->d_ino == ip->i_number) 1348 continue; 1349 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 1350 continue; 1351 return (0); 1352 } 1353 return (1); 1354 } 1355 1356 static int 1357 ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino) 1358 { 1359 struct dirtemplate dirbuf; 1360 int error, namlen; 1361 1362 if (vp->v_type != VDIR) 1363 return (ENOTDIR); 1364 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 1365 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 1366 IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); 1367 if (error != 0) 1368 return (error); 1369 #if (BYTE_ORDER == LITTLE_ENDIAN) 1370 if (OFSFMT(vp)) 1371 namlen = dirbuf.dotdot_type; 1372 else 1373 namlen = dirbuf.dotdot_namlen; 1374 #else 1375 namlen = dirbuf.dotdot_namlen; 1376 #endif 1377 if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || 1378 dirbuf.dotdot_name[1] != '.') 1379 return (ENOTDIR); 1380 *dd_ino = dirbuf.dotdot_ino; 1381 return (0); 1382 } 1383 1384 /* 1385 * Check if source directory is in the path of the target directory. 1386 */ 1387 int 1388 ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino) 1389 { 1390 struct mount *mp; 1391 struct vnode *tvp, *vp, *vp1; 1392 int error; 1393 ino_t dd_ino; 1394 1395 vp = tvp = ITOV(target); 1396 mp = vp->v_mount; 1397 *wait_ino = 0; 1398 if (target->i_number == source_ino) 1399 return (EEXIST); 1400 if (target->i_number == parent_ino) 1401 return (0); 1402 if (target->i_number == ROOTINO) 1403 return (0); 1404 error = 0; 1405 for (;;) { 1406 error = ufs_dir_dd_ino(vp, cred, &dd_ino); 1407 if (error != 0) 1408 break; 1409 if (dd_ino == source_ino) { 1410 error = EINVAL; 1411 break; 1412 } 1413 if (dd_ino == ROOTINO) 1414 break; 1415 if (dd_ino == parent_ino) 1416 break; 1417 error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, &vp1); 1418 if (error != 0) { 1419 *wait_ino = dd_ino; 1420 break; 1421 } 1422 /* Recheck that ".." still points to vp1 after relock of vp */ 1423 error = ufs_dir_dd_ino(vp, cred, &dd_ino); 1424 if (error != 0) { 1425 vput(vp1); 1426 break; 1427 } 1428 /* Redo the check of ".." if directory was reparented */ 1429 if (dd_ino != VTOI(vp1)->i_number) { 1430 vput(vp1); 1431 continue; 1432 } 1433 if (vp != tvp) 1434 vput(vp); 1435 vp = vp1; 1436 } 1437 1438 if (error == ENOTDIR) 1439 panic("checkpath: .. not a directory\n"); 1440 if (vp != tvp) 1441 vput(vp); 1442 return (error); 1443 } 1444