ufs_lookup.c revision 303376
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 303376 2016-07-27 08:53:11Z 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 u_int64_t old_isize; 885 int error, ret, blkoff, loc, spacefree, flags, namlen; 886 char *dirbuf; 887 888 td = curthread; /* XXX */ 889 cr = td->td_ucred; 890 891 dp = VTOI(dvp); 892 newentrysize = DIRSIZ(OFSFMT(dvp), dirp); 893 894 if (dp->i_count == 0) { 895 /* 896 * If dp->i_count is 0, then namei could find no 897 * space in the directory. Here, dp->i_offset will 898 * be on a directory block boundary and we will write the 899 * new entry into a fresh block. 900 */ 901 if (dp->i_offset & (DIRBLKSIZ - 1)) 902 panic("ufs_direnter: newblk"); 903 flags = BA_CLRBUF; 904 if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) 905 flags |= IO_SYNC; 906#ifdef QUOTA 907 if ((error = getinoquota(dp)) != 0) { 908 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 909 bdwrite(newdirbp); 910 return (error); 911 } 912#endif 913 old_isize = dp->i_size; 914 vnode_pager_setsize(dvp, (u_long)dp->i_offset + DIRBLKSIZ); 915 if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ, 916 cr, flags, &bp)) != 0) { 917 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 918 bdwrite(newdirbp); 919 vnode_pager_setsize(dvp, (u_long)old_isize); 920 return (error); 921 } 922 dp->i_size = dp->i_offset + DIRBLKSIZ; 923 DIP_SET(dp, i_size, dp->i_size); 924 dp->i_flag |= IN_CHANGE | IN_UPDATE; 925 dirp->d_reclen = DIRBLKSIZ; 926 blkoff = dp->i_offset & 927 (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); 928 bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); 929#ifdef UFS_DIRHASH 930 if (dp->i_dirhash != NULL) { 931 ufsdirhash_newblk(dp, dp->i_offset); 932 ufsdirhash_add(dp, dirp, dp->i_offset); 933 ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, 934 dp->i_offset); 935 } 936#endif 937 if (DOINGSOFTDEP(dvp)) { 938 /* 939 * Ensure that the entire newly allocated block is a 940 * valid directory so that future growth within the 941 * block does not have to ensure that the block is 942 * written before the inode. 943 */ 944 blkoff += DIRBLKSIZ; 945 while (blkoff < bp->b_bcount) { 946 ((struct direct *) 947 (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; 948 blkoff += DIRBLKSIZ; 949 } 950 if (softdep_setup_directory_add(bp, dp, dp->i_offset, 951 dirp->d_ino, newdirbp, 1)) 952 dp->i_flag |= IN_NEEDSYNC; 953 if (newdirbp) 954 bdwrite(newdirbp); 955 bdwrite(bp); 956 if ((dp->i_flag & IN_NEEDSYNC) == 0) 957 return (UFS_UPDATE(dvp, 0)); 958 /* 959 * We have just allocated a directory block in an 960 * indirect block. We must prevent holes in the 961 * directory created if directory entries are 962 * written out of order. To accomplish this we 963 * fsync when we extend a directory into indirects. 964 * During rename it's not safe to drop the tvp lock 965 * so sync must be delayed until it is. 966 * 967 * This synchronous step could be removed if fsck and 968 * the kernel were taught to fill in sparse 969 * directories rather than panic. 970 */ 971 if (isrename) 972 return (0); 973 if (tvp != NULL) 974 VOP_UNLOCK(tvp, 0); 975 (void) VOP_FSYNC(dvp, MNT_WAIT, td); 976 if (tvp != NULL) 977 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 978 return (error); 979 } 980 if (DOINGASYNC(dvp)) { 981 bdwrite(bp); 982 return (UFS_UPDATE(dvp, 0)); 983 } 984 error = bwrite(bp); 985 ret = UFS_UPDATE(dvp, 1); 986 if (error == 0) 987 return (ret); 988 return (error); 989 } 990 991 /* 992 * If dp->i_count is non-zero, then namei found space for the new 993 * entry in the range dp->i_offset to dp->i_offset + dp->i_count 994 * in the directory. To use this space, we may have to compact 995 * the entries located there, by copying them together towards the 996 * beginning of the block, leaving the free space in one usable 997 * chunk at the end. 998 */ 999 1000 /* 1001 * Increase size of directory if entry eats into new space. 1002 * This should never push the size past a new multiple of 1003 * DIRBLKSIZE. 1004 * 1005 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 1006 */ 1007 if (dp->i_offset + dp->i_count > dp->i_size) { 1008 dp->i_size = dp->i_offset + dp->i_count; 1009 DIP_SET(dp, i_size, dp->i_size); 1010 } 1011 /* 1012 * Get the block containing the space for the new directory entry. 1013 */ 1014 error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp); 1015 if (error) { 1016 if (DOINGSOFTDEP(dvp) && newdirbp != NULL) 1017 bdwrite(newdirbp); 1018 return (error); 1019 } 1020 /* 1021 * Find space for the new entry. In the simple case, the entry at 1022 * offset base will have the space. If it does not, then namei 1023 * arranged that compacting the region dp->i_offset to 1024 * dp->i_offset + dp->i_count would yield the space. 1025 */ 1026 ep = (struct direct *)dirbuf; 1027 dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; 1028 spacefree = ep->d_reclen - dsize; 1029 for (loc = ep->d_reclen; loc < dp->i_count; ) { 1030 nep = (struct direct *)(dirbuf + loc); 1031 1032 /* Trim the existing slot (NB: dsize may be zero). */ 1033 ep->d_reclen = dsize; 1034 ep = (struct direct *)((char *)ep + dsize); 1035 1036 /* Read nep->d_reclen now as the bcopy() may clobber it. */ 1037 loc += nep->d_reclen; 1038 if (nep->d_ino == 0) { 1039 /* 1040 * A mid-block unused entry. Such entries are 1041 * never created by the kernel, but fsck_ffs 1042 * can create them (and it doesn't fix them). 1043 * 1044 * Add up the free space, and initialise the 1045 * relocated entry since we don't bcopy it. 1046 */ 1047 spacefree += nep->d_reclen; 1048 ep->d_ino = 0; 1049 dsize = 0; 1050 continue; 1051 } 1052 dsize = DIRSIZ(OFSFMT(dvp), nep); 1053 spacefree += nep->d_reclen - dsize; 1054#ifdef UFS_DIRHASH 1055 if (dp->i_dirhash != NULL) 1056 ufsdirhash_move(dp, nep, 1057 dp->i_offset + ((char *)nep - dirbuf), 1058 dp->i_offset + ((char *)ep - dirbuf)); 1059#endif 1060 if (DOINGSOFTDEP(dvp)) 1061 softdep_change_directoryentry_offset(bp, dp, dirbuf, 1062 (caddr_t)nep, (caddr_t)ep, dsize); 1063 else 1064 bcopy((caddr_t)nep, (caddr_t)ep, dsize); 1065 } 1066 /* 1067 * Here, `ep' points to a directory entry containing `dsize' in-use 1068 * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, 1069 * then the entry is completely unused (dsize == 0). The value 1070 * of ep->d_reclen is always indeterminate. 1071 * 1072 * Update the pointer fields in the previous entry (if any), 1073 * copy in the new entry, and write out the block. 1074 */ 1075# if (BYTE_ORDER == LITTLE_ENDIAN) 1076 if (OFSFMT(dvp)) 1077 namlen = ep->d_type; 1078 else 1079 namlen = ep->d_namlen; 1080# else 1081 namlen = ep->d_namlen; 1082# endif 1083 if (ep->d_ino == 0 || 1084 (ep->d_ino == WINO && namlen == dirp->d_namlen && 1085 bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { 1086 if (spacefree + dsize < newentrysize) 1087 panic("ufs_direnter: compact1"); 1088 dirp->d_reclen = spacefree + dsize; 1089 } else { 1090 if (spacefree < newentrysize) 1091 panic("ufs_direnter: compact2"); 1092 dirp->d_reclen = spacefree; 1093 ep->d_reclen = dsize; 1094 ep = (struct direct *)((char *)ep + dsize); 1095 } 1096#ifdef UFS_DIRHASH 1097 if (dp->i_dirhash != NULL && (ep->d_ino == 0 || 1098 dirp->d_reclen == spacefree)) 1099 ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf)); 1100#endif 1101 bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); 1102#ifdef UFS_DIRHASH 1103 if (dp->i_dirhash != NULL) 1104 ufsdirhash_checkblock(dp, dirbuf - 1105 (dp->i_offset & (DIRBLKSIZ - 1)), 1106 dp->i_offset & ~(DIRBLKSIZ - 1)); 1107#endif 1108 1109 if (DOINGSOFTDEP(dvp)) { 1110 (void) softdep_setup_directory_add(bp, dp, 1111 dp->i_offset + (caddr_t)ep - dirbuf, 1112 dirp->d_ino, newdirbp, 0); 1113 if (newdirbp != NULL) 1114 bdwrite(newdirbp); 1115 bdwrite(bp); 1116 } else { 1117 if (DOINGASYNC(dvp)) { 1118 bdwrite(bp); 1119 error = 0; 1120 } else { 1121 error = bwrite(bp); 1122 } 1123 } 1124 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1125 /* 1126 * If all went well, and the directory can be shortened, proceed 1127 * with the truncation. Note that we have to unlock the inode for 1128 * the entry that we just entered, as the truncation may need to 1129 * lock other inodes which can lead to deadlock if we also hold a 1130 * lock on the newly entered node. 1131 */ 1132 if (isrename == 0 && error == 0 && 1133 dp->i_endoff && dp->i_endoff < dp->i_size) { 1134 if (tvp != NULL) 1135 VOP_UNLOCK(tvp, 0); 1136 error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, 1137 IO_NORMAL | (DOINGASYNC(dvp) ? 0 : IO_SYNC), cr); 1138 if (error != 0) 1139 vprint("ufs_direnter: failed to truncate", dvp); 1140#ifdef UFS_DIRHASH 1141 if (error == 0 && dp->i_dirhash != NULL) 1142 ufsdirhash_dirtrunc(dp, dp->i_endoff); 1143#endif 1144 error = 0; 1145 if (tvp != NULL) 1146 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1147 } 1148 return (error); 1149} 1150 1151/* 1152 * Remove a directory entry after a call to namei, using 1153 * the parameters which it left in nameidata. The entry 1154 * dp->i_offset contains the offset into the directory of the 1155 * entry to be eliminated. The dp->i_count field contains the 1156 * size of the previous record in the directory. If this 1157 * is 0, the first entry is being deleted, so we need only 1158 * zero the inode number to mark the entry as free. If the 1159 * entry is not the first in the directory, we must reclaim 1160 * the space of the now empty record by adding the record size 1161 * to the size of the previous entry. 1162 */ 1163int 1164ufs_dirremove(dvp, ip, flags, isrmdir) 1165 struct vnode *dvp; 1166 struct inode *ip; 1167 int flags; 1168 int isrmdir; 1169{ 1170 struct inode *dp; 1171 struct direct *ep, *rep; 1172 struct buf *bp; 1173 int error; 1174 1175 dp = VTOI(dvp); 1176 1177 /* 1178 * Adjust the link count early so softdep can block if necessary. 1179 */ 1180 if (ip) { 1181 ip->i_effnlink--; 1182 if (DOINGSOFTDEP(dvp)) { 1183 softdep_setup_unlink(dp, ip); 1184 } else { 1185 ip->i_nlink--; 1186 DIP_SET(ip, i_nlink, ip->i_nlink); 1187 ip->i_flag |= IN_CHANGE; 1188 } 1189 } 1190 if (flags & DOWHITEOUT) { 1191 /* 1192 * Whiteout entry: set d_ino to WINO. 1193 */ 1194 if ((error = 1195 UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) 1196 return (error); 1197 ep->d_ino = WINO; 1198 ep->d_type = DT_WHT; 1199 goto out; 1200 } 1201 1202 if ((error = UFS_BLKATOFF(dvp, 1203 (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) 1204 return (error); 1205 1206 /* Set 'rep' to the entry being removed. */ 1207 if (dp->i_count == 0) 1208 rep = ep; 1209 else 1210 rep = (struct direct *)((char *)ep + ep->d_reclen); 1211#ifdef UFS_DIRHASH 1212 /* 1213 * Remove the dirhash entry. This is complicated by the fact 1214 * that `ep' is the previous entry when dp->i_count != 0. 1215 */ 1216 if (dp->i_dirhash != NULL) 1217 ufsdirhash_remove(dp, rep, dp->i_offset); 1218#endif 1219 if (ip && rep->d_ino != ip->i_number) 1220 panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", 1221 (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); 1222 if (dp->i_count == 0) { 1223 /* 1224 * First entry in block: set d_ino to zero. 1225 */ 1226 ep->d_ino = 0; 1227 } else { 1228 /* 1229 * Collapse new free space into previous entry. 1230 */ 1231 ep->d_reclen += rep->d_reclen; 1232 } 1233#ifdef UFS_DIRHASH 1234 if (dp->i_dirhash != NULL) 1235 ufsdirhash_checkblock(dp, (char *)ep - 1236 ((dp->i_offset - dp->i_count) & (DIRBLKSIZ - 1)), 1237 dp->i_offset & ~(DIRBLKSIZ - 1)); 1238#endif 1239out: 1240 error = 0; 1241 if (DOINGSOFTDEP(dvp)) { 1242 if (ip) 1243 softdep_setup_remove(bp, dp, ip, isrmdir); 1244 if (softdep_slowdown(dvp)) 1245 error = bwrite(bp); 1246 else 1247 bdwrite(bp); 1248 } else { 1249 if (flags & DOWHITEOUT) 1250 error = bwrite(bp); 1251 else if (DOINGASYNC(dvp) && dp->i_count != 0) 1252 bdwrite(bp); 1253 else 1254 error = bwrite(bp); 1255 } 1256 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1257 /* 1258 * If the last named reference to a snapshot goes away, 1259 * drop its snapshot reference so that it will be reclaimed 1260 * when last open reference goes away. 1261 */ 1262 if (ip != NULL && (ip->i_flags & SF_SNAPSHOT) != 0 && 1263 ip->i_effnlink == 0) 1264 UFS_SNAPGONE(ip); 1265 return (error); 1266} 1267 1268/* 1269 * Rewrite an existing directory entry to point at the inode 1270 * supplied. The parameters describing the directory entry are 1271 * set up by a call to namei. 1272 */ 1273int 1274ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) 1275 struct inode *dp, *oip; 1276 ino_t newinum; 1277 int newtype; 1278 int isrmdir; 1279{ 1280 struct buf *bp; 1281 struct direct *ep; 1282 struct vnode *vdp = ITOV(dp); 1283 int error; 1284 1285 /* 1286 * Drop the link before we lock the buf so softdep can block if 1287 * necessary. 1288 */ 1289 oip->i_effnlink--; 1290 if (DOINGSOFTDEP(vdp)) { 1291 softdep_setup_unlink(dp, oip); 1292 } else { 1293 oip->i_nlink--; 1294 DIP_SET(oip, i_nlink, oip->i_nlink); 1295 oip->i_flag |= IN_CHANGE; 1296 } 1297 1298 error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); 1299 if (error) 1300 return (error); 1301 if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' && 1302 ep->d_ino != oip->i_number) { 1303 brelse(bp); 1304 return (EIDRM); 1305 } 1306 ep->d_ino = newinum; 1307 if (!OFSFMT(vdp)) 1308 ep->d_type = newtype; 1309 if (DOINGSOFTDEP(vdp)) { 1310 softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); 1311 bdwrite(bp); 1312 } else { 1313 if (DOINGASYNC(vdp)) { 1314 bdwrite(bp); 1315 error = 0; 1316 } else { 1317 error = bwrite(bp); 1318 } 1319 } 1320 dp->i_flag |= IN_CHANGE | IN_UPDATE; 1321 /* 1322 * If the last named reference to a snapshot goes away, 1323 * drop its snapshot reference so that it will be reclaimed 1324 * when last open reference goes away. 1325 */ 1326 if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0) 1327 UFS_SNAPGONE(oip); 1328 return (error); 1329} 1330 1331/* 1332 * Check if a directory is empty or not. 1333 * Inode supplied must be locked. 1334 * 1335 * Using a struct dirtemplate here is not precisely 1336 * what we want, but better than using a struct direct. 1337 * 1338 * NB: does not handle corrupted directories. 1339 */ 1340int 1341ufs_dirempty(ip, parentino, cred) 1342 struct inode *ip; 1343 ino_t parentino; 1344 struct ucred *cred; 1345{ 1346 doff_t off; 1347 struct dirtemplate dbuf; 1348 struct direct *dp = (struct direct *)&dbuf; 1349 int error, namlen; 1350 ssize_t count; 1351#define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 1352 1353 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 1354 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, 1355 off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, 1356 NOCRED, &count, (struct thread *)0); 1357 /* 1358 * Since we read MINDIRSIZ, residual must 1359 * be 0 unless we're at end of file. 1360 */ 1361 if (error || count != 0) 1362 return (0); 1363 /* avoid infinite loops */ 1364 if (dp->d_reclen == 0) 1365 return (0); 1366 /* skip empty entries */ 1367 if (dp->d_ino == 0 || dp->d_ino == WINO) 1368 continue; 1369 /* accept only "." and ".." */ 1370# if (BYTE_ORDER == LITTLE_ENDIAN) 1371 if (OFSFMT(ITOV(ip))) 1372 namlen = dp->d_type; 1373 else 1374 namlen = dp->d_namlen; 1375# else 1376 namlen = dp->d_namlen; 1377# endif 1378 if (namlen > 2) 1379 return (0); 1380 if (dp->d_name[0] != '.') 1381 return (0); 1382 /* 1383 * At this point namlen must be 1 or 2. 1384 * 1 implies ".", 2 implies ".." if second 1385 * char is also "." 1386 */ 1387 if (namlen == 1 && dp->d_ino == ip->i_number) 1388 continue; 1389 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 1390 continue; 1391 return (0); 1392 } 1393 return (1); 1394} 1395 1396static int 1397ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino, 1398 struct vnode **dd_vp) 1399{ 1400 struct dirtemplate dirbuf; 1401 struct vnode *ddvp; 1402 int error, namlen; 1403 1404 ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino"); 1405 if (vp->v_type != VDIR) 1406 return (ENOTDIR); 1407 /* 1408 * First check to see if we have it in the name cache. 1409 */ 1410 if ((ddvp = vn_dir_dd_ino(vp)) != NULL) { 1411 KASSERT(ddvp->v_mount == vp->v_mount, 1412 ("ufs_dir_dd_ino: Unexpected mount point crossing")); 1413 *dd_ino = VTOI(ddvp)->i_number; 1414 *dd_vp = ddvp; 1415 return (0); 1416 } 1417 /* 1418 * Have to read the directory. 1419 */ 1420 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 1421 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 1422 IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); 1423 if (error != 0) 1424 return (error); 1425#if (BYTE_ORDER == LITTLE_ENDIAN) 1426 if (OFSFMT(vp)) 1427 namlen = dirbuf.dotdot_type; 1428 else 1429 namlen = dirbuf.dotdot_namlen; 1430#else 1431 namlen = dirbuf.dotdot_namlen; 1432#endif 1433 if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || 1434 dirbuf.dotdot_name[1] != '.') 1435 return (ENOTDIR); 1436 *dd_ino = dirbuf.dotdot_ino; 1437 *dd_vp = NULL; 1438 return (0); 1439} 1440 1441/* 1442 * Check if source directory is in the path of the target directory. 1443 */ 1444int 1445ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino) 1446{ 1447 struct mount *mp; 1448 struct vnode *tvp, *vp, *vp1; 1449 int error; 1450 ino_t dd_ino; 1451 1452 vp = tvp = ITOV(target); 1453 mp = vp->v_mount; 1454 *wait_ino = 0; 1455 if (target->i_number == source_ino) 1456 return (EEXIST); 1457 if (target->i_number == parent_ino) 1458 return (0); 1459 if (target->i_number == ROOTINO) 1460 return (0); 1461 for (;;) { 1462 error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1); 1463 if (error != 0) 1464 break; 1465 if (dd_ino == source_ino) { 1466 error = EINVAL; 1467 break; 1468 } 1469 if (dd_ino == ROOTINO) 1470 break; 1471 if (dd_ino == parent_ino) 1472 break; 1473 if (vp1 == NULL) { 1474 error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, 1475 &vp1); 1476 if (error != 0) { 1477 *wait_ino = dd_ino; 1478 break; 1479 } 1480 } 1481 KASSERT(dd_ino == VTOI(vp1)->i_number, 1482 ("directory %d reparented\n", VTOI(vp1)->i_number)); 1483 if (vp != tvp) 1484 vput(vp); 1485 vp = vp1; 1486 } 1487 1488 if (error == ENOTDIR) 1489 panic("checkpath: .. not a directory\n"); 1490 if (vp1 != NULL) 1491 vput(vp1); 1492 if (vp != tvp) 1493 vput(vp); 1494 return (error); 1495} 1496