ufs_lookup.c revision 300597
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: stable/10/sys/ufs/ufs/ufs_lookup.c 300597 2016-05-24 10:34:24Z kib $"); 39 40#include "opt_ufs.h" 41#include "opt_quota.h" 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/kernel.h> 46#include <sys/namei.h> 47#include <sys/bio.h> 48#include <sys/buf.h> 49#include <sys/proc.h> 50#include <sys/stat.h> 51#include <sys/mount.h> 52#include <sys/vnode.h> 53#include <sys/sysctl.h> 54 55#include <vm/vm.h> 56#include <vm/vm_extern.h> 57 58#include <ufs/ufs/extattr.h> 59#include <ufs/ufs/quota.h> 60#include <ufs/ufs/inode.h> 61#include <ufs/ufs/dir.h> 62#ifdef UFS_DIRHASH 63#include <ufs/ufs/dirhash.h> 64#endif 65#include <ufs/ufs/ufsmount.h> 66#include <ufs/ufs/ufs_extern.h> 67 68#ifdef DIAGNOSTIC 69static int dirchk = 1; 70#else 71static int dirchk = 0; 72#endif 73 74SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); 75 76/* true if old FS format...*/ 77#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) 78 79#ifdef QUOTA 80static int 81ufs_lookup_upgrade_lock(struct vnode *vp) 82{ 83 int error; 84 85 ASSERT_VOP_LOCKED(vp, __FUNCTION__); 86 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) 87 return (0); 88 89 error = 0; 90 91 /* 92 * Upgrade vnode lock, since getinoquota() 93 * requires exclusive lock to modify inode. 94 */ 95 vhold(vp); 96 vn_lock(vp, LK_UPGRADE | LK_RETRY); 97 VI_LOCK(vp); 98 if (vp->v_iflag & VI_DOOMED) 99 error = ENOENT; 100 vdropl(vp); 101 return (error); 102} 103#endif 104 105static int 106ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, 107 struct thread *td) 108{ 109 int error; 110 111#ifdef UFS_ACL 112 /* 113 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 114 * 115 * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD 116 */ 117 118 /* 119 * XXX: Is this check required? 120 */ 121 error = VOP_ACCESS(vdp, VEXEC, cred, td); 122 if (error) 123 return (error); 124 125 error = VOP_ACCESSX(tdp, VDELETE, cred, td); 126 if (error == 0) 127 return (0); 128 129 error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred, td); 130 if (error == 0) 131 return (0); 132 133 error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); 134 if (error) 135 return (error); 136 137#endif /* !UFS_ACL */ 138 139 /* 140 * Standard Unix access control - delete access requires VWRITE. 141 */ 142 error = VOP_ACCESS(vdp, VWRITE, cred, td); 143 if (error) 144 return (error); 145 146 /* 147 * If directory is "sticky", then user must own 148 * the directory, or the file in it, else she 149 * may not delete it (unless she's root). This 150 * implements append-only directories. 151 */ 152 if ((VTOI(vdp)->i_mode & ISVTX) && 153 VOP_ACCESS(vdp, VADMIN, cred, td) && 154 VOP_ACCESS(tdp, VADMIN, cred, td)) 155 return (EPERM); 156 157 return (0); 158} 159 160/* 161 * Convert a component of a pathname into a pointer to a locked inode. 162 * This is a very central and rather complicated routine. 163 * If the filesystem is not maintained in a strict tree hierarchy, 164 * this can result in a deadlock situation (see comments in code below). 165 * 166 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending 167 * on whether the name is to be looked up, created, renamed, or deleted. 168 * When CREATE, RENAME, or DELETE is specified, information usable in 169 * creating, renaming, or deleting a directory entry may be calculated. 170 * If flag has LOCKPARENT or'ed into it and the target of the pathname 171 * exists, lookup returns both the target and its parent directory locked. 172 * When creating or renaming and LOCKPARENT is specified, the target may 173 * not be ".". When deleting and LOCKPARENT is specified, the target may 174 * be "."., but the caller must check to ensure it does an vrele and vput 175 * instead of two vputs. 176 * 177 * This routine is actually used as VOP_CACHEDLOOKUP method, and the 178 * filesystem employs the generic vfs_cache_lookup() as VOP_LOOKUP 179 * method. 180 * 181 * vfs_cache_lookup() performs the following for us: 182 * check that it is a directory 183 * check accessibility of directory 184 * check for modification attempts on read-only mounts 185 * if name found in cache 186 * if at end of path and deleting or creating 187 * drop it 188 * else 189 * return name. 190 * return VOP_CACHEDLOOKUP() 191 * 192 * Overall outline of ufs_lookup: 193 * 194 * search for name in directory, to found or notfound 195 * notfound: 196 * if creating, return locked directory, leaving info on available slots 197 * else return error 198 * found: 199 * if at end of path and deleting, return information to allow delete 200 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 201 * inode and return info to allow rewrite 202 * if not at end, add name to cache; if at end and neither creating 203 * nor deleting, add name to cache 204 */ 205int 206ufs_lookup(ap) 207 struct vop_cachedlookup_args /* { 208 struct vnode *a_dvp; 209 struct vnode **a_vpp; 210 struct componentname *a_cnp; 211 } */ *ap; 212{ 213 214 return (ufs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); 215} 216 217int 218ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, 219 ino_t *dd_ino) 220{ 221 struct inode *dp; /* inode for directory being searched */ 222 struct buf *bp; /* a buffer of directory entries */ 223 struct direct *ep; /* the current directory entry */ 224 int entryoffsetinblock; /* offset of ep in bp's buffer */ 225 enum {NONE, COMPACT, FOUND} slotstatus; 226 doff_t slotoffset; /* offset of area with free space */ 227 doff_t i_diroff; /* cached i_diroff value. */ 228 doff_t i_offset; /* cached i_offset value. */ 229 int slotsize; /* size of area at slotoffset */ 230 int slotfreespace; /* amount of space free in slot */ 231 int slotneeded; /* size of the entry we're seeking */ 232 int numdirpasses; /* strategy for directory search */ 233 doff_t endsearch; /* offset to end directory search */ 234 doff_t prevoff; /* prev entry dp->i_offset */ 235 struct vnode *pdp; /* saved dp during symlink work */ 236 struct vnode *tdp; /* returned by VFS_VGET */ 237 doff_t enduseful; /* pointer past last used dir slot */ 238 u_long bmask; /* block offset mask */ 239 int namlen, error; 240 struct ucred *cred = cnp->cn_cred; 241 int flags = cnp->cn_flags; 242 int nameiop = cnp->cn_nameiop; 243 ino_t ino, ino1; 244 int ltype; 245 246 if (vpp != NULL) 247 *vpp = NULL; 248 249 dp = VTOI(vdp); 250 if (dp->i_effnlink == 0) 251 return (ENOENT); 252 253 /* 254 * Create a vm object if vmiodirenable is enabled. 255 * Alternatively we could call vnode_create_vobject 256 * in VFS_VGET but we could end up creating objects 257 * that are never used. 258 */ 259 vnode_create_vobject(vdp, DIP(dp, i_size), cnp->cn_thread); 260 261 bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; 262#ifdef QUOTA 263 if ((nameiop == DELETE || nameiop == RENAME) && (flags & ISLASTCN)) { 264 error = ufs_lookup_upgrade_lock(vdp); 265 if (error != 0) 266 return (error); 267 } 268#endif 269 270restart: 271 bp = NULL; 272 slotoffset = -1; 273 274 /* 275 * We now have a segment name to search for, and a directory to search. 276 * 277 * Suppress search for slots unless creating 278 * file and at end of pathname, in which case 279 * we watch for a place to put the new file in 280 * case it doesn't already exist. 281 */ 282 ino = 0; 283 i_diroff = dp->i_diroff; 284 slotstatus = FOUND; 285 slotfreespace = slotsize = slotneeded = 0; 286 if ((nameiop == CREATE || nameiop == RENAME) && 287 (flags & ISLASTCN)) { 288 slotstatus = NONE; 289 slotneeded = DIRECTSIZ(cnp->cn_namelen); 290 } 291 292#ifdef UFS_DIRHASH 293 /* 294 * Use dirhash for fast operations on large directories. The logic 295 * to determine whether to hash the directory is contained within 296 * ufsdirhash_build(); a zero return means that it decided to hash 297 * this directory and it successfully built up the hash table. 298 */ 299 if (ufsdirhash_build(dp) == 0) { 300 /* Look for a free slot if needed. */ 301 enduseful = dp->i_size; 302 if (slotstatus != FOUND) { 303 slotoffset = ufsdirhash_findfree(dp, slotneeded, 304 &slotsize); 305 if (slotoffset >= 0) { 306 slotstatus = COMPACT; 307 enduseful = ufsdirhash_enduseful(dp); 308 if (enduseful < 0) 309 enduseful = dp->i_size; 310 } 311 } 312 /* Look up the component. */ 313 numdirpasses = 1; 314 entryoffsetinblock = 0; /* silence compiler warning */ 315 switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, 316 &i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { 317 case 0: 318 ep = (struct direct *)((char *)bp->b_data + 319 (i_offset & bmask)); 320 goto foundentry; 321 case ENOENT: 322 i_offset = roundup2(dp->i_size, DIRBLKSIZ); 323 goto notfound; 324 default: 325 /* Something failed; just do a linear search. */ 326 break; 327 } 328 } 329#endif /* UFS_DIRHASH */ 330 /* 331 * If there is cached information on a previous search of 332 * this directory, pick up where we last left off. 333 * We cache only lookups as these are the most common 334 * and have the greatest payoff. Caching CREATE has little 335 * benefit as it usually must search the entire directory 336 * to determine that the entry does not exist. Caching the 337 * location of the last DELETE or RENAME has not reduced 338 * profiling time and hence has been removed in the interest 339 * of simplicity. 340 */ 341 if (nameiop != LOOKUP || i_diroff == 0 || i_diroff >= dp->i_size) { 342 entryoffsetinblock = 0; 343 i_offset = 0; 344 numdirpasses = 1; 345 } else { 346 i_offset = i_diroff; 347 if ((entryoffsetinblock = i_offset & bmask) && 348 (error = UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp))) 349 return (error); 350 numdirpasses = 2; 351 nchstats.ncs_2passes++; 352 } 353 prevoff = i_offset; 354 endsearch = roundup2(dp->i_size, DIRBLKSIZ); 355 enduseful = 0; 356 357searchloop: 358 while (i_offset < endsearch) { 359 /* 360 * If necessary, get the next directory block. 361 */ 362 if ((i_offset & bmask) == 0) { 363 if (bp != NULL) 364 brelse(bp); 365 error = 366 UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp); 367 if (error) 368 return (error); 369 entryoffsetinblock = 0; 370 } 371 /* 372 * If still looking for a slot, and at a DIRBLKSIZE 373 * boundary, have to start looking for free space again. 374 */ 375 if (slotstatus == NONE && 376 (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { 377 slotoffset = -1; 378 slotfreespace = 0; 379 } 380 /* 381 * Get pointer to next entry. 382 * Full validation checks are slow, so we only check 383 * enough to insure forward progress through the 384 * directory. Complete checks can be run by patching 385 * "dirchk" to be true. 386 */ 387 ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); 388 if (ep->d_reclen == 0 || ep->d_reclen > 389 DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 390 (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) { 391 int i; 392 393 ufs_dirbad(dp, i_offset, "mangled entry"); 394 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 395 i_offset += i; 396 entryoffsetinblock += i; 397 continue; 398 } 399 400 /* 401 * If an appropriate sized slot has not yet been found, 402 * check to see if one is available. Also accumulate space 403 * in the current block so that we can determine if 404 * compaction is viable. 405 */ 406 if (slotstatus != FOUND) { 407 int size = ep->d_reclen; 408 409 if (ep->d_ino != 0) 410 size -= DIRSIZ(OFSFMT(vdp), ep); 411 if (size > 0) { 412 if (size >= slotneeded) { 413 slotstatus = FOUND; 414 slotoffset = i_offset; 415 slotsize = ep->d_reclen; 416 } else if (slotstatus == NONE) { 417 slotfreespace += size; 418 if (slotoffset == -1) 419 slotoffset = i_offset; 420 if (slotfreespace >= slotneeded) { 421 slotstatus = COMPACT; 422 slotsize = i_offset + 423 ep->d_reclen - slotoffset; 424 } 425 } 426 } 427 } 428 429 /* 430 * Check for a name match. 431 */ 432 if (ep->d_ino) { 433# if (BYTE_ORDER == LITTLE_ENDIAN) 434 if (OFSFMT(vdp)) 435 namlen = ep->d_type; 436 else 437 namlen = ep->d_namlen; 438# else 439 namlen = ep->d_namlen; 440# endif 441 if (namlen == cnp->cn_namelen && 442 (cnp->cn_nameptr[0] == ep->d_name[0]) && 443 !bcmp(cnp->cn_nameptr, ep->d_name, 444 (unsigned)namlen)) { 445#ifdef UFS_DIRHASH 446foundentry: 447#endif 448 /* 449 * Save directory entry's inode number and 450 * reclen in ndp->ni_ufs area, and release 451 * directory buffer. 452 */ 453 if (vdp->v_mount->mnt_maxsymlinklen > 0 && 454 ep->d_type == DT_WHT) { 455 slotstatus = FOUND; 456 slotoffset = i_offset; 457 slotsize = ep->d_reclen; 458 enduseful = dp->i_size; 459 cnp->cn_flags |= ISWHITEOUT; 460 numdirpasses--; 461 goto notfound; 462 } 463 ino = ep->d_ino; 464 goto found; 465 } 466 } 467 prevoff = i_offset; 468 i_offset += ep->d_reclen; 469 entryoffsetinblock += ep->d_reclen; 470 if (ep->d_ino) 471 enduseful = i_offset; 472 } 473notfound: 474 /* 475 * If we started in the middle of the directory and failed 476 * to find our target, we must check the beginning as well. 477 */ 478 if (numdirpasses == 2) { 479 numdirpasses--; 480 i_offset = 0; 481 endsearch = i_diroff; 482 goto searchloop; 483 } 484 if (bp != NULL) 485 brelse(bp); 486 /* 487 * If creating, and at end of pathname and current 488 * directory has not been removed, then can consider 489 * allowing file to be created. 490 */ 491 if ((nameiop == CREATE || nameiop == RENAME || 492 (nameiop == DELETE && 493 (cnp->cn_flags & DOWHITEOUT) && 494 (cnp->cn_flags & ISWHITEOUT))) && 495 (flags & ISLASTCN) && dp->i_effnlink != 0) { 496 /* 497 * Access for write is interpreted as allowing 498 * creation of files in the directory. 499 * 500 * XXX: Fix the comment above. 501 */ 502 if (flags & WILLBEDIR) 503 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); 504 else 505 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); 506 if (error) 507 return (error); 508 /* 509 * Return an indication of where the new directory 510 * entry should be put. If we didn't find a slot, 511 * then set dp->i_count to 0 indicating 512 * that the new slot belongs at the end of the 513 * directory. If we found a slot, then the new entry 514 * can be put in the range from dp->i_offset to 515 * dp->i_offset + dp->i_count. 516 */ 517 if (slotstatus == NONE) { 518 dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ); 519 dp->i_count = 0; 520 enduseful = dp->i_offset; 521 } else if (nameiop == DELETE) { 522 dp->i_offset = slotoffset; 523 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 524 dp->i_count = 0; 525 else 526 dp->i_count = dp->i_offset - prevoff; 527 } else { 528 dp->i_offset = slotoffset; 529 dp->i_count = slotsize; 530 if (enduseful < slotoffset + slotsize) 531 enduseful = slotoffset + slotsize; 532 } 533 dp->i_endoff = roundup2(enduseful, DIRBLKSIZ); 534 /* 535 * We return with the directory locked, so that 536 * the parameters we set up above will still be 537 * valid if we actually decide to do a direnter(). 538 * We return ni_vp == NULL to indicate that the entry 539 * does not currently exist; we leave a pointer to 540 * the (locked) directory inode in ndp->ni_dvp. 541 * The pathname buffer is saved so that the name 542 * can be obtained later. 543 * 544 * NB - if the directory is unlocked, then this 545 * information cannot be used. 546 */ 547 cnp->cn_flags |= SAVENAME; 548 return (EJUSTRETURN); 549 } 550 /* 551 * Insert name into cache (as non-existent) if appropriate. 552 */ 553 if ((cnp->cn_flags & MAKEENTRY) != 0) 554 cache_enter(vdp, NULL, cnp); 555 return (ENOENT); 556 557found: 558 if (dd_ino != NULL) 559 *dd_ino = ino; 560 if (numdirpasses == 2) 561 nchstats.ncs_pass2++; 562 /* 563 * Check that directory length properly reflects presence 564 * of this entry. 565 */ 566 if (i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) { 567 ufs_dirbad(dp, i_offset, "i_size too small"); 568 dp->i_size = i_offset + DIRSIZ(OFSFMT(vdp), ep); 569 DIP_SET(dp, i_size, dp->i_size); 570 dp->i_flag |= IN_CHANGE | IN_UPDATE; 571 } 572 brelse(bp); 573 574 /* 575 * Found component in pathname. 576 * If the final component of path name, save information 577 * in the cache as to where the entry was found. 578 */ 579 if ((flags & ISLASTCN) && nameiop == LOOKUP) 580 dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1); 581 582 /* 583 * If deleting, and at end of pathname, return 584 * parameters which can be used to remove file. 585 */ 586 if (nameiop == DELETE && (flags & ISLASTCN)) { 587 if (flags & LOCKPARENT) 588 ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); 589 /* 590 * Return pointer to current entry in dp->i_offset, 591 * and distance past previous entry (if there 592 * is a previous entry in this block) in dp->i_count. 593 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 594 * 595 * Technically we shouldn't be setting these in the 596 * WANTPARENT case (first lookup in rename()), but any 597 * lookups that will result in directory changes will 598 * overwrite these. 599 */ 600 dp->i_offset = i_offset; 601 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 602 dp->i_count = 0; 603 else 604 dp->i_count = dp->i_offset - prevoff; 605 if (dd_ino != NULL) 606 return (0); 607 if ((error = VFS_VGET(vdp->v_mount, ino, 608 LK_EXCLUSIVE, &tdp)) != 0) 609 return (error); 610 error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); 611 if (error) { 612 vput(tdp); 613 return (error); 614 } 615 if (dp->i_number == ino) { 616 VREF(vdp); 617 *vpp = vdp; 618 vput(tdp); 619 return (0); 620 } 621 622 *vpp = tdp; 623 return (0); 624 } 625 626 /* 627 * If rewriting (RENAME), return the inode and the 628 * information required to rewrite the present directory 629 * Must get inode of directory entry to verify it's a 630 * regular file, or empty directory. 631 */ 632 if (nameiop == RENAME && (flags & ISLASTCN)) { 633 if (flags & WILLBEDIR) 634 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); 635 else 636 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); 637 if (error) 638 return (error); 639 /* 640 * Careful about locking second inode. 641 * This can only occur if the target is ".". 642 */ 643 dp->i_offset = i_offset; 644 if (dp->i_number == ino) 645 return (EISDIR); 646 if (dd_ino != NULL) 647 return (0); 648 if ((error = VFS_VGET(vdp->v_mount, ino, 649 LK_EXCLUSIVE, &tdp)) != 0) 650 return (error); 651 652 error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); 653 if (error) { 654 vput(tdp); 655 return (error); 656 } 657 658#ifdef SunOS_doesnt_do_that 659 /* 660 * The only purpose of this check is to return the correct 661 * error. Assume that we want to rename directory "a" 662 * to a file "b", and that we have no ACL_WRITE_DATA on 663 * a containing directory, but we _do_ have ACL_APPEND_DATA. 664 * In that case, the VOP_ACCESS check above will return 0, 665 * and the operation will fail with ENOTDIR instead 666 * of EACCESS. 667 */ 668 if (tdp->v_type == VDIR) 669 error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); 670 else 671 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); 672 if (error) { 673 vput(tdp); 674 return (error); 675 } 676#endif 677 678 *vpp = tdp; 679 cnp->cn_flags |= SAVENAME; 680 return (0); 681 } 682 if (dd_ino != NULL) 683 return (0); 684 685 /* 686 * Step through the translation in the name. We do not `vput' the 687 * directory because we may need it again if a symbolic link 688 * is relative to the current directory. Instead we save it 689 * unlocked as "pdp". We must get the target inode before unlocking 690 * the directory to insure that the inode will not be removed 691 * before we get it. We prevent deadlock by always fetching 692 * inodes from the root, moving down the directory tree. Thus 693 * when following backward pointers ".." we must unlock the 694 * parent directory before getting the requested directory. 695 * There is a potential race condition here if both the current 696 * and parent directories are removed before the VFS_VGET for the 697 * inode associated with ".." returns. We hope that this occurs 698 * infrequently since we cannot avoid this race condition without 699 * implementing a sophisticated deadlock detection algorithm. 700 * Note also that this simple deadlock detection scheme will not 701 * work if the filesystem has any hard links other than ".." 702 * that point backwards in the directory structure. 703 */ 704 pdp = vdp; 705 if (flags & ISDOTDOT) { 706 error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); 707 if (error) 708 return (error); 709 710 /* 711 * Recheck that ".." entry in the vdp directory points 712 * to the inode we looked up before vdp lock was 713 * dropped. 714 */ 715 error = ufs_lookup_ino(pdp, NULL, cnp, &ino1); 716 if (error) { 717 vput(tdp); 718 return (error); 719 } 720 if (ino1 != ino) { 721 vput(tdp); 722 goto restart; 723 } 724 725 *vpp = tdp; 726 } else if (dp->i_number == ino) { 727 VREF(vdp); /* we want ourself, ie "." */ 728 /* 729 * When we lookup "." we still can be asked to lock it 730 * differently. 731 */ 732 ltype = cnp->cn_lkflags & LK_TYPE_MASK; 733 if (ltype != VOP_ISLOCKED(vdp)) { 734 if (ltype == LK_EXCLUSIVE) 735 vn_lock(vdp, LK_UPGRADE | LK_RETRY); 736 else /* if (ltype == LK_SHARED) */ 737 vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); 738 /* 739 * Relock for the "." case may left us with 740 * reclaimed vnode. 741 */ 742 if (vdp->v_iflag & VI_DOOMED) { 743 vrele(vdp); 744 return (ENOENT); 745 } 746 } 747 *vpp = vdp; 748 } else { 749 error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp); 750 if (error) 751 return (error); 752 *vpp = tdp; 753 } 754 755 /* 756 * Insert name into cache if appropriate. 757 */ 758 if (cnp->cn_flags & MAKEENTRY) 759 cache_enter(vdp, *vpp, cnp); 760 return (0); 761} 762 763void 764ufs_dirbad(ip, offset, how) 765 struct inode *ip; 766 doff_t offset; 767 char *how; 768{ 769 struct mount *mp; 770 771 mp = ITOV(ip)->v_mount; 772 if ((mp->mnt_flag & MNT_RDONLY) == 0) 773 panic("ufs_dirbad: %s: bad dir ino %ju at offset %ld: %s", 774 mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, 775 (long)offset, how); 776 else 777 (void)printf("%s: bad dir ino %ju at offset %ld: %s\n", 778 mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, 779 (long)offset, how); 780} 781 782/* 783 * Do consistency checking on a directory entry: 784 * record length must be multiple of 4 785 * entry must fit in rest of its DIRBLKSIZ block 786 * record must be large enough to contain entry 787 * name is not longer than MAXNAMLEN 788 * name must be as long as advertised, and null terminated 789 */ 790int 791ufs_dirbadentry(dp, ep, entryoffsetinblock) 792 struct vnode *dp; 793 struct direct *ep; 794 int entryoffsetinblock; 795{ 796 int i, namlen; 797 798# if (BYTE_ORDER == LITTLE_ENDIAN) 799 if (OFSFMT(dp)) 800 namlen = ep->d_type; 801 else 802 namlen = ep->d_namlen; 803# else 804 namlen = ep->d_namlen; 805# endif 806 if ((ep->d_reclen & 0x3) != 0 || 807 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 808 ep->d_reclen < DIRSIZ(OFSFMT(dp), ep) || namlen > MAXNAMLEN) { 809 /*return (1); */ 810 printf("First bad\n"); 811 goto bad; 812 } 813 if (ep->d_ino == 0) 814 return (0); 815 for (i = 0; i < namlen; i++) 816 if (ep->d_name[i] == '\0') { 817 /*return (1); */ 818 printf("Second bad\n"); 819 goto bad; 820 } 821 if (ep->d_name[i]) 822 goto bad; 823 return (0); 824bad: 825 return (1); 826} 827 828/* 829 * Construct a new directory entry after a call to namei, using the 830 * parameters that it left in the componentname argument cnp. The 831 * argument ip is the inode to which the new directory entry will refer. 832 */ 833void 834ufs_makedirentry(ip, cnp, newdirp) 835 struct inode *ip; 836 struct componentname *cnp; 837 struct direct *newdirp; 838{ 839 840#ifdef INVARIANTS 841 if ((cnp->cn_flags & SAVENAME) == 0) 842 panic("ufs_makedirentry: missing name"); 843#endif 844 newdirp->d_ino = ip->i_number; 845 newdirp->d_namlen = cnp->cn_namelen; 846 bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1); 847 if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) 848 newdirp->d_type = IFTODT(ip->i_mode); 849 else { 850 newdirp->d_type = 0; 851# if (BYTE_ORDER == LITTLE_ENDIAN) 852 { u_char tmp = newdirp->d_namlen; 853 newdirp->d_namlen = newdirp->d_type; 854 newdirp->d_type = tmp; } 855# endif 856 } 857} 858 859/* 860 * Write a directory entry after a call to namei, using the parameters 861 * that it left in nameidata. The argument dirp is the new directory 862 * entry contents. Dvp is a pointer to the directory to be written, 863 * which was left locked by namei. Remaining parameters (dp->i_offset, 864 * dp->i_count) indicate how the space for the new entry is to be obtained. 865 * Non-null bp indicates that a directory is being created (for the 866 * soft dependency code). 867 */ 868int 869ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename) 870 struct vnode *dvp; 871 struct vnode *tvp; 872 struct direct *dirp; 873 struct componentname *cnp; 874 struct buf *newdirbp; 875 int isrename; 876{ 877 struct ucred *cr; 878 struct thread *td; 879 int newentrysize; 880 struct inode *dp; 881 struct buf *bp; 882 u_int dsize; 883 struct direct *ep, *nep; 884 int error, ret, blkoff, loc, spacefree, flags, namlen; 885 char *dirbuf; 886 887 td = curthread; /* XXX */ 888 cr = td->td_ucred; 889 890 dp = VTOI(dvp); 891 newentrysize = DIRSIZ(OFSFMT(dvp), dirp); 892 893 if (dp->i_count == 0) { 894 /* 895 * If dp->i_count is 0, then namei could find no 896 * space in the directory. Here, dp->i_offset will 897 * be on a directory block boundary and we will write the 898 * new entry into a fresh block. 899 */ 900 if (dp->i_offset & (DIRBLKSIZ - 1)) 901 panic("ufs_direnter: newblk"); 902 flags = BA_CLRBUF; 903 if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) 904 flags |= IO_SYNC; 905#ifdef QUOTA 906 if ((error = getinoquota(dp)) != 0) { 907 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 908 bdwrite(newdirbp); 909 return (error); 910 } 911#endif 912 if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ, 913 cr, flags, &bp)) != 0) { 914 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 915 bdwrite(newdirbp); 916 return (error); 917 } 918 dp->i_size = dp->i_offset + DIRBLKSIZ; 919 DIP_SET(dp, i_size, dp->i_size); 920 dp->i_flag |= IN_CHANGE | IN_UPDATE; 921 vnode_pager_setsize(dvp, (u_long)dp->i_size); 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 == 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 dp->i_offset & ~(DIRBLKSIZ - 1)); 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 | IO_SYNC, cr); 1135 if (error != 0) 1136 vprint("ufs_direnter: failed to truncate", dvp); 1137#ifdef UFS_DIRHASH 1138 if (error == 0 && dp->i_dirhash != NULL) 1139 ufsdirhash_dirtrunc(dp, dp->i_endoff); 1140#endif 1141 error = 0; 1142 if (tvp != NULL) 1143 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1144 } 1145 return (error); 1146} 1147 1148/* 1149 * Remove a directory entry after a call to namei, using 1150 * the parameters which it left in nameidata. The entry 1151 * dp->i_offset contains the offset into the directory of the 1152 * entry to be eliminated. The dp->i_count field contains the 1153 * size of the previous record in the directory. If this 1154 * is 0, the first entry is being deleted, so we need only 1155 * zero the inode number to mark the entry as free. If the 1156 * entry is not the first in the directory, we must reclaim 1157 * the space of the now empty record by adding the record size 1158 * to the size of the previous entry. 1159 */ 1160int 1161ufs_dirremove(dvp, ip, flags, isrmdir) 1162 struct vnode *dvp; 1163 struct inode *ip; 1164 int flags; 1165 int isrmdir; 1166{ 1167 struct inode *dp; 1168 struct direct *ep, *rep; 1169 struct buf *bp; 1170 int error; 1171 1172 dp = VTOI(dvp); 1173 1174 /* 1175 * Adjust the link count early so softdep can block if necessary. 1176 */ 1177 if (ip) { 1178 ip->i_effnlink--; 1179 if (DOINGSOFTDEP(dvp)) { 1180 softdep_setup_unlink(dp, ip); 1181 } else { 1182 ip->i_nlink--; 1183 DIP_SET(ip, i_nlink, ip->i_nlink); 1184 ip->i_flag |= IN_CHANGE; 1185 } 1186 } 1187 if (flags & DOWHITEOUT) { 1188 /* 1189 * Whiteout entry: set d_ino to WINO. 1190 */ 1191 if ((error = 1192 UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) 1193 return (error); 1194 ep->d_ino = WINO; 1195 ep->d_type = DT_WHT; 1196 goto out; 1197 } 1198 1199 if ((error = UFS_BLKATOFF(dvp, 1200 (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) 1201 return (error); 1202 1203 /* Set 'rep' to the entry being removed. */ 1204 if (dp->i_count == 0) 1205 rep = ep; 1206 else 1207 rep = (struct direct *)((char *)ep + ep->d_reclen); 1208#ifdef UFS_DIRHASH 1209 /* 1210 * Remove the dirhash entry. This is complicated by the fact 1211 * that `ep' is the previous entry when dp->i_count != 0. 1212 */ 1213 if (dp->i_dirhash != NULL) 1214 ufsdirhash_remove(dp, rep, dp->i_offset); 1215#endif 1216 if (ip && rep->d_ino != ip->i_number) 1217 panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", 1218 (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); 1219 if (dp->i_count == 0) { 1220 /* 1221 * First entry in block: set d_ino to zero. 1222 */ 1223 ep->d_ino = 0; 1224 } else { 1225 /* 1226 * Collapse new free space into previous entry. 1227 */ 1228 ep->d_reclen += rep->d_reclen; 1229 } 1230#ifdef UFS_DIRHASH 1231 if (dp->i_dirhash != NULL) 1232 ufsdirhash_checkblock(dp, (char *)ep - 1233 ((dp->i_offset - dp->i_count) & (DIRBLKSIZ - 1)), 1234 dp->i_offset & ~(DIRBLKSIZ - 1)); 1235#endif 1236out: 1237 error = 0; 1238 if (DOINGSOFTDEP(dvp)) { 1239 if (ip) 1240 softdep_setup_remove(bp, dp, ip, isrmdir); 1241 if (softdep_slowdown(dvp)) 1242 error = bwrite(bp); 1243 else 1244 bdwrite(bp); 1245 } else { 1246 if (flags & DOWHITEOUT) 1247 error = bwrite(bp); 1248 else if (DOINGASYNC(dvp) && dp->i_count != 0) 1249 bdwrite(bp); 1250 else 1251 error = bwrite(bp); 1252 } 1253 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1254 /* 1255 * If the last named reference to a snapshot goes away, 1256 * drop its snapshot reference so that it will be reclaimed 1257 * when last open reference goes away. 1258 */ 1259 if (ip != NULL && (ip->i_flags & SF_SNAPSHOT) != 0 && 1260 ip->i_effnlink == 0) 1261 UFS_SNAPGONE(ip); 1262 return (error); 1263} 1264 1265/* 1266 * Rewrite an existing directory entry to point at the inode 1267 * supplied. The parameters describing the directory entry are 1268 * set up by a call to namei. 1269 */ 1270int 1271ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) 1272 struct inode *dp, *oip; 1273 ino_t newinum; 1274 int newtype; 1275 int isrmdir; 1276{ 1277 struct buf *bp; 1278 struct direct *ep; 1279 struct vnode *vdp = ITOV(dp); 1280 int error; 1281 1282 /* 1283 * Drop the link before we lock the buf so softdep can block if 1284 * necessary. 1285 */ 1286 oip->i_effnlink--; 1287 if (DOINGSOFTDEP(vdp)) { 1288 softdep_setup_unlink(dp, oip); 1289 } else { 1290 oip->i_nlink--; 1291 DIP_SET(oip, i_nlink, oip->i_nlink); 1292 oip->i_flag |= IN_CHANGE; 1293 } 1294 1295 error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); 1296 if (error) 1297 return (error); 1298 if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' && 1299 ep->d_ino != oip->i_number) { 1300 brelse(bp); 1301 return (EIDRM); 1302 } 1303 ep->d_ino = newinum; 1304 if (!OFSFMT(vdp)) 1305 ep->d_type = newtype; 1306 if (DOINGSOFTDEP(vdp)) { 1307 softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); 1308 bdwrite(bp); 1309 } else { 1310 if (DOINGASYNC(vdp)) { 1311 bdwrite(bp); 1312 error = 0; 1313 } else { 1314 error = bwrite(bp); 1315 } 1316 } 1317 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1318 /* 1319 * If the last named reference to a snapshot goes away, 1320 * drop its snapshot reference so that it will be reclaimed 1321 * when last open reference goes away. 1322 */ 1323 if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0) 1324 UFS_SNAPGONE(oip); 1325 return (error); 1326} 1327 1328/* 1329 * Check if a directory is empty or not. 1330 * Inode supplied must be locked. 1331 * 1332 * Using a struct dirtemplate here is not precisely 1333 * what we want, but better than using a struct direct. 1334 * 1335 * NB: does not handle corrupted directories. 1336 */ 1337int 1338ufs_dirempty(ip, parentino, cred) 1339 struct inode *ip; 1340 ino_t parentino; 1341 struct ucred *cred; 1342{ 1343 doff_t off; 1344 struct dirtemplate dbuf; 1345 struct direct *dp = (struct direct *)&dbuf; 1346 int error, namlen; 1347 ssize_t count; 1348#define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 1349 1350 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 1351 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, 1352 off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, 1353 NOCRED, &count, (struct thread *)0); 1354 /* 1355 * Since we read MINDIRSIZ, residual must 1356 * be 0 unless we're at end of file. 1357 */ 1358 if (error || count != 0) 1359 return (0); 1360 /* avoid infinite loops */ 1361 if (dp->d_reclen == 0) 1362 return (0); 1363 /* skip empty entries */ 1364 if (dp->d_ino == 0 || dp->d_ino == WINO) 1365 continue; 1366 /* accept only "." and ".." */ 1367# if (BYTE_ORDER == LITTLE_ENDIAN) 1368 if (OFSFMT(ITOV(ip))) 1369 namlen = dp->d_type; 1370 else 1371 namlen = dp->d_namlen; 1372# else 1373 namlen = dp->d_namlen; 1374# endif 1375 if (namlen > 2) 1376 return (0); 1377 if (dp->d_name[0] != '.') 1378 return (0); 1379 /* 1380 * At this point namlen must be 1 or 2. 1381 * 1 implies ".", 2 implies ".." if second 1382 * char is also "." 1383 */ 1384 if (namlen == 1 && dp->d_ino == ip->i_number) 1385 continue; 1386 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 1387 continue; 1388 return (0); 1389 } 1390 return (1); 1391} 1392 1393static int 1394ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino, 1395 struct vnode **dd_vp) 1396{ 1397 struct dirtemplate dirbuf; 1398 struct vnode *ddvp; 1399 int error, namlen; 1400 1401 ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino"); 1402 if (vp->v_type != VDIR) 1403 return (ENOTDIR); 1404 /* 1405 * First check to see if we have it in the name cache. 1406 */ 1407 if ((ddvp = vn_dir_dd_ino(vp)) != NULL) { 1408 KASSERT(ddvp->v_mount == vp->v_mount, 1409 ("ufs_dir_dd_ino: Unexpected mount point crossing")); 1410 *dd_ino = VTOI(ddvp)->i_number; 1411 *dd_vp = ddvp; 1412 return (0); 1413 } 1414 /* 1415 * Have to read the directory. 1416 */ 1417 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 1418 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 1419 IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); 1420 if (error != 0) 1421 return (error); 1422#if (BYTE_ORDER == LITTLE_ENDIAN) 1423 if (OFSFMT(vp)) 1424 namlen = dirbuf.dotdot_type; 1425 else 1426 namlen = dirbuf.dotdot_namlen; 1427#else 1428 namlen = dirbuf.dotdot_namlen; 1429#endif 1430 if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || 1431 dirbuf.dotdot_name[1] != '.') 1432 return (ENOTDIR); 1433 *dd_ino = dirbuf.dotdot_ino; 1434 *dd_vp = NULL; 1435 return (0); 1436} 1437 1438/* 1439 * Check if source directory is in the path of the target directory. 1440 */ 1441int 1442ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino) 1443{ 1444 struct mount *mp; 1445 struct vnode *tvp, *vp, *vp1; 1446 int error; 1447 ino_t dd_ino; 1448 1449 vp = tvp = ITOV(target); 1450 mp = vp->v_mount; 1451 *wait_ino = 0; 1452 if (target->i_number == source_ino) 1453 return (EEXIST); 1454 if (target->i_number == parent_ino) 1455 return (0); 1456 if (target->i_number == ROOTINO) 1457 return (0); 1458 for (;;) { 1459 error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1); 1460 if (error != 0) 1461 break; 1462 if (dd_ino == source_ino) { 1463 error = EINVAL; 1464 break; 1465 } 1466 if (dd_ino == ROOTINO) 1467 break; 1468 if (dd_ino == parent_ino) 1469 break; 1470 if (vp1 == NULL) { 1471 error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, 1472 &vp1); 1473 if (error != 0) { 1474 *wait_ino = dd_ino; 1475 break; 1476 } 1477 } 1478 KASSERT(dd_ino == VTOI(vp1)->i_number, 1479 ("directory %d reparented\n", VTOI(vp1)->i_number)); 1480 if (vp != tvp) 1481 vput(vp); 1482 vp = vp1; 1483 } 1484 1485 if (error == ENOTDIR) 1486 panic("checkpath: .. not a directory\n"); 1487 if (vp1 != NULL) 1488 vput(vp1); 1489 if (vp != tvp) 1490 vput(vp); 1491 return (error); 1492} 1493