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