120 { NULL, NULL } 121}; 122static struct vnodeopv_desc ext2fs_vnodeop_opv_desc = 123 { &ext2_vnodeop_p, ext2_vnodeop_entries }; 124 125vop_t **ext2_specop_p; 126static struct vnodeopv_entry_desc ext2_specop_entries[] = { 127 { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, 128 { &vop_fsync_desc, (vop_t *) ext2_fsync }, 129 { &vop_inactive_desc, (vop_t *) ext2_inactive }, 130 { NULL, NULL } 131}; 132static struct vnodeopv_desc ext2fs_specop_opv_desc = 133 { &ext2_specop_p, ext2_specop_entries }; 134 135vop_t **ext2_fifoop_p; 136static struct vnodeopv_entry_desc ext2_fifoop_entries[] = { 137 { &vop_default_desc, (vop_t *) ufs_vnoperatefifo }, 138 { &vop_fsync_desc, (vop_t *) ext2_fsync }, 139 { &vop_inactive_desc, (vop_t *) ext2_inactive }, 140 { NULL, NULL } 141}; 142static struct vnodeopv_desc ext2fs_fifoop_opv_desc = 143 { &ext2_fifoop_p, ext2_fifoop_entries }; 144 145 VNODEOP_SET(ext2fs_vnodeop_opv_desc); 146 VNODEOP_SET(ext2fs_specop_opv_desc); 147 VNODEOP_SET(ext2fs_fifoop_opv_desc); 148 149#include <gnu/ext2fs/ext2_readwrite.c> 150 151/* 152 * A virgin directory (no blushing please). 153 * Note that the type and namlen fields are reversed relative to ufs. 154 * Also, we don't use `struct odirtemplate', since it would just cause 155 * endianness problems. 156 */ 157static struct dirtemplate mastertemplate = { 158 0, 12, 1, EXT2_FT_DIR, ".", 159 0, DIRBLKSIZ - 12, 2, EXT2_FT_DIR, ".." 160}; 161static struct dirtemplate omastertemplate = { 162 0, 12, 1, EXT2_FT_UNKNOWN, ".", 163 0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".." 164}; 165 166/* 167 * Create a regular file 168 */ 169static int 170ext2_create(ap) 171 struct vop_create_args /* { 172 struct vnode *a_dvp; 173 struct vnode **a_vpp; 174 struct componentname *a_cnp; 175 struct vattr *a_vap; 176 } */ *ap; 177{ 178 int error; 179 180 error = 181 ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), 182 ap->a_dvp, ap->a_vpp, ap->a_cnp); 183 if (error) 184 return (error); 185 return (0); 186} 187 188/* 189 * Synch an open file. 190 */ 191/* ARGSUSED */ 192static int 193ext2_fsync(ap) 194 struct vop_fsync_args /* { 195 struct vnode *a_vp; 196 struct ucred *a_cred; 197 int a_waitfor; 198 struct proc *a_p; 199 } */ *ap; 200{ 201 register struct vnode *vp = ap->a_vp; 202 register struct buf *bp; 203 struct buf *nbp; 204 int s; 205 206 /* 207 * XXX why is all this fs specific? 208 */ 209 210 /* 211 * Flush all dirty buffers associated with a vnode. 212 */ 213 ext2_discard_prealloc(VTOI(vp)); 214 215loop: 216 s = splbio(); 217 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 218 nbp = TAILQ_NEXT(bp, b_vnbufs); 219 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) 220 continue; 221 if ((bp->b_flags & B_DELWRI) == 0) 222 panic("ext2_fsync: not dirty"); 223 bremfree(bp); 224 splx(s); 225 /* 226 * Wait for I/O associated with indirect blocks to complete, 227 * since there is no way to quickly wait for them below. 228 */ 229 if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) 230 (void) bawrite(bp); 231 else 232 (void) bwrite(bp); 233 goto loop; 234 } 235 if (ap->a_waitfor == MNT_WAIT) { 236 while (vp->v_numoutput) { 237 vp->v_flag |= VBWAIT; 238 tsleep(&vp->v_numoutput, PRIBIO + 1, "e2fsyn", 0); 239 } 240#if DIAGNOSTIC 241 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) { 242 vprint("ext2_fsync: dirty", vp); 243 goto loop; 244 } 245#endif 246 } 247 splx(s); 248 return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT)); 249} 250 251/* 252 * Mknod vnode call 253 */ 254/* ARGSUSED */ 255static int 256ext2_mknod(ap) 257 struct vop_mknod_args /* { 258 struct vnode *a_dvp; 259 struct vnode **a_vpp; 260 struct componentname *a_cnp; 261 struct vattr *a_vap; 262 } */ *ap; 263{ 264 struct vattr *vap = ap->a_vap; 265 struct vnode **vpp = ap->a_vpp; 266 struct inode *ip; 267 ino_t ino; 268 int error; 269 270 error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), 271 ap->a_dvp, vpp, ap->a_cnp); 272 if (error) 273 return (error); 274 ip = VTOI(*vpp); 275 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 276 if (vap->va_rdev != VNOVAL) { 277 /* 278 * Want to be able to use this to make badblock 279 * inodes, so don't truncate the dev number. 280 */ 281 ip->i_rdev = vap->va_rdev; 282 } 283 /* 284 * Remove inode, then reload it through VFS_VGET so it is 285 * checked to see if it is an alias of an existing entry in 286 * the inode cache. 287 */ 288 vput(*vpp); 289 (*vpp)->v_type = VNON; 290 ino = ip->i_number; /* Save this before vgone() invalidates ip. */ 291 vgone(*vpp); 292 error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp); 293 if (error) { 294 *vpp = NULL; 295 return (error); 296 } 297 return (0); 298} 299 300static int 301ext2_remove(ap) 302 struct vop_remove_args /* { 303 struct vnode *a_dvp; 304 struct vnode *a_vp; 305 struct componentname *a_cnp; 306 } */ *ap; 307{ 308 struct inode *ip; 309 struct vnode *vp = ap->a_vp; 310 struct vnode *dvp = ap->a_dvp; 311 int error; 312 313 ip = VTOI(vp); 314 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 315 (VTOI(dvp)->i_flags & APPEND)) { 316 error = EPERM; 317 goto out; 318 } 319 error = ext2_dirremove(dvp, ap->a_cnp); 320 if (error == 0) { 321 ip->i_nlink--; 322 ip->i_flag |= IN_CHANGE; 323 } 324out: 325 return (error); 326} 327 328/* 329 * link vnode call 330 */ 331static int 332ext2_link(ap) 333 struct vop_link_args /* { 334 struct vnode *a_tdvp; 335 struct vnode *a_vp; 336 struct componentname *a_cnp; 337 } */ *ap; 338{ 339 struct vnode *vp = ap->a_vp; 340 struct vnode *tdvp = ap->a_tdvp; 341 struct componentname *cnp = ap->a_cnp; 342 struct proc *p = cnp->cn_proc; 343 struct inode *ip; 344 int error; 345 346#ifdef DIAGNOSTIC 347 if ((cnp->cn_flags & HASBUF) == 0) 348 panic("ufs_link: no name"); 349#endif 350 if (tdvp->v_mount != vp->v_mount) { 351 error = EXDEV; 352 goto out2; 353 } 354 if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) { 355 goto out2; 356 } 357 ip = VTOI(vp); 358 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 359 error = EMLINK; 360 goto out1; 361 } 362 if (ip->i_flags & (IMMUTABLE | APPEND)) { 363 error = EPERM; 364 goto out1; 365 } 366 ip->i_nlink++; 367 ip->i_flag |= IN_CHANGE; 368 error = UFS_UPDATE(vp, 1); 369 if (!error) 370 error = ext2_direnter(ip, tdvp, cnp); 371 if (error) { 372 ip->i_nlink--; 373 ip->i_flag |= IN_CHANGE; 374 } 375out1: 376 if (tdvp != vp) 377 VOP_UNLOCK(vp, 0, p); 378out2: 379 return (error); 380} 381 382/* 383 * Rename system call. 384 * See comments in sys/ufs/ufs/ufs_vnops.c 385 */ 386static int 387ext2_rename(ap) 388 struct vop_rename_args /* { 389 struct vnode *a_fdvp; 390 struct vnode *a_fvp; 391 struct componentname *a_fcnp; 392 struct vnode *a_tdvp; 393 struct vnode *a_tvp; 394 struct componentname *a_tcnp; 395 } */ *ap; 396{ 397 struct vnode *tvp = ap->a_tvp; 398 register struct vnode *tdvp = ap->a_tdvp; 399 struct vnode *fvp = ap->a_fvp; 400 struct vnode *fdvp = ap->a_fdvp; 401 struct componentname *tcnp = ap->a_tcnp; 402 struct componentname *fcnp = ap->a_fcnp; 403 struct proc *p = fcnp->cn_proc; 404 struct inode *ip, *xp, *dp; 405 struct dirtemplate dirbuf; 406 int doingdirectory = 0, oldparent = 0, newparent = 0; 407 int error = 0; 408 u_char namlen; 409 410#ifdef DIAGNOSTIC 411 if ((tcnp->cn_flags & HASBUF) == 0 || 412 (fcnp->cn_flags & HASBUF) == 0) 413 panic("ufs_rename: no name"); 414#endif 415 /* 416 * Check for cross-device rename. 417 */ 418 if ((fvp->v_mount != tdvp->v_mount) || 419 (tvp && (fvp->v_mount != tvp->v_mount))) { 420 error = EXDEV; 421abortit: 422 if (tdvp == tvp) 423 vrele(tdvp); 424 else 425 vput(tdvp); 426 if (tvp) 427 vput(tvp); 428 vrele(fdvp); 429 vrele(fvp); 430 return (error); 431 } 432 433 if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 434 (VTOI(tdvp)->i_flags & APPEND))) { 435 error = EPERM; 436 goto abortit; 437 } 438 439 /* 440 * Check if just deleting a link name or if we've lost a race. 441 * If another process completes the same rename after we've looked 442 * up the source and have blocked looking up the target, then the 443 * source and target inodes may be identical now although the 444 * names were never linked. 445 */ 446 if (fvp == tvp) { 447 if (fvp->v_type == VDIR) { 448 /* 449 * Linked directories are impossible, so we must 450 * have lost the race. Pretend that the rename 451 * completed before the lookup. 452 */ 453#ifdef UFS_RENAME_DEBUG 454 printf("ufs_rename: fvp == tvp for directories\n"); 455#endif 456 error = ENOENT; 457 goto abortit; 458 } 459 460 /* Release destination completely. */ 461 vput(tdvp); 462 vput(tvp); 463 464 /* 465 * Delete source. There is another race now that everything 466 * is unlocked, but this doesn't cause any new complications. 467 * Relookup() may find a file that is unrelated to the 468 * original one, or it may fail. Too bad. 469 */ 470 vrele(fdvp); 471 vrele(fvp); 472 fcnp->cn_flags &= ~MODMASK; 473 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 474 fcnp->cn_nameiop = DELETE; 475 VREF(fdvp); 476 error = relookup(fdvp, &fvp, fcnp); 477 if (error == 0) 478 vrele(fdvp); 479 if (fvp == NULL) { 480#ifdef UFS_RENAME_DEBUG 481 printf("ufs_rename: from name disappeared\n"); 482#endif 483 return (ENOENT); 484 } 485 error = VOP_REMOVE(fdvp, fvp, fcnp); 486 if (fdvp == fvp) 487 vrele(fdvp); 488 else 489 vput(fdvp); 490 if (fvp != NULLVP) 491 vput(fvp); 492 return (error); 493 } 494 if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0) 495 goto abortit; 496 dp = VTOI(fdvp); 497 ip = VTOI(fvp); 498 if (ip->i_nlink >= LINK_MAX) { 499 VOP_UNLOCK(fvp, 0, p); 500 error = EMLINK; 501 goto abortit; 502 } 503 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) 504 || (dp->i_flags & APPEND)) { 505 VOP_UNLOCK(fvp, 0, p); 506 error = EPERM; 507 goto abortit; 508 } 509 if ((ip->i_mode & IFMT) == IFDIR) { 510 /* 511 * Avoid ".", "..", and aliases of "." for obvious reasons. 512 */ 513 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 514 dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT || 515 (ip->i_flag & IN_RENAME)) { 516 VOP_UNLOCK(fvp, 0, p); 517 error = EINVAL; 518 goto abortit; 519 } 520 ip->i_flag |= IN_RENAME; 521 oldparent = dp->i_number; 522 doingdirectory++; 523 } 524 vrele(fdvp); 525 526 /* 527 * When the target exists, both the directory 528 * and target vnodes are returned locked. 529 */ 530 dp = VTOI(tdvp); 531 xp = NULL; 532 if (tvp) 533 xp = VTOI(tvp); 534 535 /* 536 * 1) Bump link count while we're moving stuff 537 * around. If we crash somewhere before 538 * completing our work, the link count 539 * may be wrong, but correctable. 540 */ 541 ip->i_nlink++; 542 ip->i_flag |= IN_CHANGE; 543 if ((error = UFS_UPDATE(fvp, 1)) != 0) { 544 VOP_UNLOCK(fvp, 0, p); 545 goto bad; 546 } 547 548 /* 549 * If ".." must be changed (ie the directory gets a new 550 * parent) then the source directory must not be in the 551 * directory heirarchy above the target, as this would 552 * orphan everything below the source directory. Also 553 * the user must have write permission in the source so 554 * as to be able to change "..". We must repeat the call 555 * to namei, as the parent directory is unlocked by the 556 * call to checkpath(). 557 */ 558 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 559 VOP_UNLOCK(fvp, 0, p); 560 if (oldparent != dp->i_number) 561 newparent = dp->i_number; 562 if (doingdirectory && newparent) { 563 if (error) /* write access check above */ 564 goto bad; 565 if (xp != NULL) 566 vput(tvp); 567 error = ext2_checkpath(ip, dp, tcnp->cn_cred); 568 if (error) 569 goto out; 570 VREF(tdvp); 571 error = relookup(tdvp, &tvp, tcnp); 572 if (error) 573 goto out; 574 vrele(tdvp); 575 dp = VTOI(tdvp); 576 xp = NULL; 577 if (tvp) 578 xp = VTOI(tvp); 579 } 580 /* 581 * 2) If target doesn't exist, link the target 582 * to the source and unlink the source. 583 * Otherwise, rewrite the target directory 584 * entry to reference the source inode and 585 * expunge the original entry's existence. 586 */ 587 if (xp == NULL) { 588 if (dp->i_dev != ip->i_dev) 589 panic("ufs_rename: EXDEV"); 590 /* 591 * Account for ".." in new directory. 592 * When source and destination have the same 593 * parent we don't fool with the link count. 594 */ 595 if (doingdirectory && newparent) { 596 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 597 error = EMLINK; 598 goto bad; 599 } 600 dp->i_nlink++; 601 dp->i_flag |= IN_CHANGE; 602 error = UFS_UPDATE(tdvp, 1); 603 if (error) 604 goto bad; 605 } 606 error = ext2_direnter(ip, tdvp, tcnp); 607 if (error) { 608 if (doingdirectory && newparent) { 609 dp->i_nlink--; 610 dp->i_flag |= IN_CHANGE; 611 (void)UFS_UPDATE(tdvp, 1); 612 } 613 goto bad; 614 } 615 vput(tdvp); 616 } else { 617 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 618 panic("ufs_rename: EXDEV"); 619 /* 620 * Short circuit rename(foo, foo). 621 */ 622 if (xp->i_number == ip->i_number) 623 panic("ufs_rename: same file"); 624 /* 625 * If the parent directory is "sticky", then the user must 626 * own the parent directory, or the destination of the rename, 627 * otherwise the destination may not be changed (except by 628 * root). This implements append-only directories. 629 */ 630 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && 631 tcnp->cn_cred->cr_uid != dp->i_uid && 632 xp->i_uid != tcnp->cn_cred->cr_uid) { 633 error = EPERM; 634 goto bad; 635 } 636 /* 637 * Target must be empty if a directory and have no links 638 * to it. Also, ensure source and target are compatible 639 * (both directories, or both not directories). 640 */ 641 if ((xp->i_mode&IFMT) == IFDIR) { 642 if (! ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) || 643 xp->i_nlink > 2) { 644 error = ENOTEMPTY; 645 goto bad; 646 } 647 if (!doingdirectory) { 648 error = ENOTDIR; 649 goto bad; 650 } 651 cache_purge(tdvp); 652 } else if (doingdirectory) { 653 error = EISDIR; 654 goto bad; 655 } 656 error = ext2_dirrewrite(dp, ip, tcnp); 657 if (error) 658 goto bad; 659 /* 660 * If the target directory is in the same 661 * directory as the source directory, 662 * decrement the link count on the parent 663 * of the target directory. 664 */ 665 if (doingdirectory && !newparent) { 666 dp->i_nlink--; 667 dp->i_flag |= IN_CHANGE; 668 } 669 vput(tdvp); 670 /* 671 * Adjust the link count of the target to 672 * reflect the dirrewrite above. If this is 673 * a directory it is empty and there are 674 * no links to it, so we can squash the inode and 675 * any space associated with it. We disallowed 676 * renaming over top of a directory with links to 677 * it above, as the remaining link would point to 678 * a directory without "." or ".." entries. 679 */ 680 xp->i_nlink--; 681 if (doingdirectory) { 682 if (--xp->i_nlink != 0) 683 panic("ufs_rename: linked directory"); 684 error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, 685 tcnp->cn_cred, tcnp->cn_proc); 686 } 687 xp->i_flag |= IN_CHANGE; 688 vput(tvp); 689 xp = NULL; 690 } 691 692 /* 693 * 3) Unlink the source. 694 */ 695 fcnp->cn_flags &= ~MODMASK; 696 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 697 VREF(fdvp); 698 error = relookup(fdvp, &fvp, fcnp); 699 if (error == 0) 700 vrele(fdvp); 701 if (fvp != NULL) { 702 xp = VTOI(fvp); 703 dp = VTOI(fdvp); 704 } else { 705 /* 706 * From name has disappeared. 707 */ 708 if (doingdirectory) 709 panic("ufs_rename: lost dir entry"); 710 vrele(ap->a_fvp); 711 return (0); 712 } 713 /* 714 * Ensure that the directory entry still exists and has not 715 * changed while the new name has been entered. If the source is 716 * a file then the entry may have been unlinked or renamed. In 717 * either case there is no further work to be done. If the source 718 * is a directory then it cannot have been rmdir'ed; its link 719 * count of three would cause a rmdir to fail with ENOTEMPTY. 720 * The IN_RENAME flag ensures that it cannot be moved by another 721 * rename. 722 */ 723 if (xp != ip) { 724 if (doingdirectory) 725 panic("ufs_rename: lost dir entry"); 726 } else { 727 /* 728 * If the source is a directory with a 729 * new parent, the link count of the old 730 * parent directory must be decremented 731 * and ".." set to point to the new parent. 732 */ 733 if (doingdirectory && newparent) { 734 dp->i_nlink--; 735 dp->i_flag |= IN_CHANGE; 736 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf, 737 sizeof (struct dirtemplate), (off_t)0, 738 UIO_SYSSPACE, IO_NODELOCKED, 739 tcnp->cn_cred, (int *)0, (struct proc *)0); 740 if (error == 0) { 741 /* Like ufs little-endian: */ 742 namlen = dirbuf.dotdot_type; 743 if (namlen != 2 || 744 dirbuf.dotdot_name[0] != '.' || 745 dirbuf.dotdot_name[1] != '.') { 746 ufs_dirbad(xp, (doff_t)12, 747 "rename: mangled dir"); 748 } else { 749 dirbuf.dotdot_ino = newparent; 750 (void) vn_rdwr(UIO_WRITE, fvp, 751 (caddr_t)&dirbuf, 752 sizeof (struct dirtemplate), 753 (off_t)0, UIO_SYSSPACE, 754 IO_NODELOCKED|IO_SYNC, 755 tcnp->cn_cred, (int *)0, 756 (struct proc *)0); 757 cache_purge(fdvp); 758 } 759 } 760 } 761 error = ext2_dirremove(fdvp, fcnp); 762 if (!error) { 763 xp->i_nlink--; 764 xp->i_flag |= IN_CHANGE; 765 } 766 xp->i_flag &= ~IN_RENAME; 767 } 768 if (dp) 769 vput(fdvp); 770 if (xp) 771 vput(fvp); 772 vrele(ap->a_fvp); 773 return (error); 774 775bad: 776 if (xp) 777 vput(ITOV(xp)); 778 vput(ITOV(dp)); 779out: 780 if (doingdirectory) 781 ip->i_flag &= ~IN_RENAME; 782 if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) { 783 ip->i_nlink--; 784 ip->i_flag |= IN_CHANGE; 785 ip->i_flag &= ~IN_RENAME; 786 vput(fvp); 787 } else 788 vrele(fvp); 789 return (error); 790} 791 792/* 793 * Mkdir system call 794 */ 795static int 796ext2_mkdir(ap) 797 struct vop_mkdir_args /* { 798 struct vnode *a_dvp; 799 struct vnode **a_vpp; 800 struct componentname *a_cnp; 801 struct vattr *a_vap; 802 } */ *ap; 803{ 804 register struct vnode *dvp = ap->a_dvp; 805 register struct vattr *vap = ap->a_vap; 806 register struct componentname *cnp = ap->a_cnp; 807 register struct inode *ip, *dp; 808 struct vnode *tvp; 809 struct dirtemplate dirtemplate, *dtp; 810 int error, dmode; 811 812#ifdef DIAGNOSTIC 813 if ((cnp->cn_flags & HASBUF) == 0) 814 panic("ufs_mkdir: no name"); 815#endif 816 dp = VTOI(dvp); 817 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 818 error = EMLINK; 819 goto out; 820 } 821 dmode = vap->va_mode & 0777; 822 dmode |= IFDIR; 823 /* 824 * Must simulate part of ext2_makeinode here to acquire the inode, 825 * but not have it entered in the parent directory. The entry is 826 * made later after writing "." and ".." entries. 827 */ 828 error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); 829 if (error) 830 goto out; 831 ip = VTOI(tvp); 832 ip->i_gid = dp->i_gid; 833#ifdef SUIDDIR 834 { 835#ifdef QUOTA 836 struct ucred ucred, *ucp; 837 ucp = cnp->cn_cred; 838#endif I 839 /* 840 * if we are hacking owners here, (only do this where told to) 841 * and we are not giving it TOO root, (would subvert quotas) 842 * then go ahead and give it to the other user. 843 * The new directory also inherits the SUID bit. 844 * If user's UID and dir UID are the same, 845 * 'give it away' so that the SUID is still forced on. 846 */ 847 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) && 848 (dp->i_mode & ISUID) && dp->i_uid) { 849 dmode |= ISUID; 850 ip->i_uid = dp->i_uid; 851#ifdef QUOTA 852 if (dp->i_uid != cnp->cn_cred->cr_uid) { 853 /* 854 * make sure the correct user gets charged 855 * for the space. 856 * Make a dummy credential for the victim. 857 * XXX This seems to never be accessed out of 858 * our context so a stack variable is ok. 859 */ 860 ucred.cr_ref = 1; 861 ucred.cr_uid = ip->i_uid; 862 ucred.cr_ngroups = 1; 863 ucred.cr_groups[0] = dp->i_gid; 864 ucp = &ucred; 865 } 866#endif I 867 } else { 868 ip->i_uid = cnp->cn_cred->cr_uid; 869 } 870#ifdef QUOTA 871 if ((error = getinoquota(ip)) || 872 (error = chkiq(ip, 1, ucp, 0))) { 873 UFS_VFREE(tvp, ip->i_number, dmode); 874 vput(tvp); 875 return (error); 876 } 877#endif 878 } 879#else 880 ip->i_uid = cnp->cn_cred->cr_uid; 881#ifdef QUOTA 882 if ((error = getinoquota(ip)) || 883 (error = chkiq(ip, 1, cnp->cn_cred, 0))) { 884 UFS_VFREE(tvp, ip->i_number, dmode); 885 vput(tvp); 886 return (error); 887 } 888#endif 889#endif 890 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 891 ip->i_mode = dmode; 892 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ 893 ip->i_nlink = 2; 894 if (cnp->cn_flags & ISWHITEOUT) 895 ip->i_flags |= UF_OPAQUE; 896 error = UFS_UPDATE(tvp, 1); 897 898 /* 899 * Bump link count in parent directory 900 * to reflect work done below. Should 901 * be done before reference is created 902 * so reparation is possible if we crash. 903 */ 904 dp->i_nlink++; 905 dp->i_flag |= IN_CHANGE; 906 error = UFS_UPDATE(dvp, 1); 907 if (error) 908 goto bad; 909 910 /* Initialize directory with "." and ".." from static template. */ 911 if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es, 912 EXT2_FEATURE_INCOMPAT_FILETYPE)) 913 dtp = &mastertemplate; 914 else 915 dtp = &omastertemplate; 916 dirtemplate = *dtp; 917 dirtemplate.dot_ino = ip->i_number; 918 dirtemplate.dotdot_ino = dp->i_number; 919 /* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 920 * so let's just redefine it - for this function only 921 */ 922#undef DIRBLKSIZ 923#define DIRBLKSIZ VTOI(dvp)->i_e2fs->s_blocksize 924 dirtemplate.dotdot_reclen = DIRBLKSIZ - 12; 925 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, 926 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 927 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0); 928 if (error) { 929 dp->i_nlink--; 930 dp->i_flag |= IN_CHANGE; 931 goto bad; 932 } 933 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 934 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */ 935 else { 936 ip->i_size = DIRBLKSIZ; 937 ip->i_flag |= IN_CHANGE; 938 } 939 940 /* Directory set up, now install its entry in the parent directory. */ 941 error = ext2_direnter(ip, dvp, cnp); 942 if (error) { 943 dp->i_nlink--; 944 dp->i_flag |= IN_CHANGE; 945 } 946bad: 947 /* 948 * No need to do an explicit VOP_TRUNCATE here, vrele will do this 949 * for us because we set the link count to 0. 950 */ 951 if (error) { 952 ip->i_nlink = 0; 953 ip->i_flag |= IN_CHANGE; 954 vput(tvp); 955 } else 956 *ap->a_vpp = tvp; 957out: 958 return (error); 959#undef DIRBLKSIZ 960#define DIRBLKSIZ DEV_BSIZE 961} 962 963/* 964 * Rmdir system call. 965 */ 966static int 967ext2_rmdir(ap) 968 struct vop_rmdir_args /* { 969 struct vnode *a_dvp; 970 struct vnode *a_vp; 971 struct componentname *a_cnp; 972 } */ *ap; 973{ 974 struct vnode *vp = ap->a_vp; 975 struct vnode *dvp = ap->a_dvp; 976 struct componentname *cnp = ap->a_cnp; 977 struct proc *p = cnp->cn_proc; 978 struct inode *ip, *dp; 979 int error; 980 981 ip = VTOI(vp); 982 dp = VTOI(dvp); 983 984 /* 985 * Verify the directory is empty (and valid). 986 * (Rmdir ".." won't be valid since 987 * ".." will contain a reference to 988 * the current directory and thus be 989 * non-empty.) 990 */ 991 error = 0; 992 if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) { 993 error = ENOTEMPTY; 994 goto out; 995 } 996 if ((dp->i_flags & APPEND) 997 || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) { 998 error = EPERM; 999 goto out; 1000 } 1001 /* 1002 * Delete reference to directory before purging 1003 * inode. If we crash in between, the directory 1004 * will be reattached to lost+found, 1005 */ 1006 error = ext2_dirremove(dvp, cnp); 1007 if (error) 1008 goto out; 1009 dp->i_nlink--; 1010 dp->i_flag |= IN_CHANGE; 1011 cache_purge(dvp); 1012 VOP_UNLOCK(dvp, 0, p); 1013 /* 1014 * Truncate inode. The only stuff left 1015 * in the directory is "." and "..". The 1016 * "." reference is inconsequential since 1017 * we're quashing it. The ".." reference 1018 * has already been adjusted above. We've 1019 * removed the "." reference and the reference 1020 * in the parent directory, but there may be 1021 * other hard links so decrement by 2 and 1022 * worry about them later. 1023 */ 1024 ip->i_nlink -= 2; 1025 error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, p); 1026 cache_purge(ITOV(ip)); 1027 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 1028out: 1029 return (error); 1030} 1031 1032/* 1033 * symlink -- make a symbolic link 1034 */ 1035static int 1036ext2_symlink(ap) 1037 struct vop_symlink_args /* { 1038 struct vnode *a_dvp; 1039 struct vnode **a_vpp; 1040 struct componentname *a_cnp; 1041 struct vattr *a_vap; 1042 char *a_target; 1043 } */ *ap; 1044{ 1045 register struct vnode *vp, **vpp = ap->a_vpp; 1046 register struct inode *ip; 1047 int len, error; 1048 1049 error = ext2_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, 1050 vpp, ap->a_cnp); 1051 if (error) 1052 return (error); 1053 vp = *vpp; 1054 len = strlen(ap->a_target); 1055 if (len < vp->v_mount->mnt_maxsymlinklen) { 1056 ip = VTOI(vp); 1057 bcopy(ap->a_target, (char *)ip->i_shortlink, len); 1058 ip->i_size = len; 1059 ip->i_flag |= IN_CHANGE | IN_UPDATE; 1060 } else 1061 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 1062 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0, 1063 (struct proc *)0); 1064 if (error) 1065 vput(vp); 1066 return (error); 1067} 1068 1069/* 1070 * Allocate a new inode. 1071 */ 1072static int 1073ext2_makeinode(mode, dvp, vpp, cnp) 1074 int mode; 1075 struct vnode *dvp; 1076 struct vnode **vpp; 1077 struct componentname *cnp; 1078{ 1079 register struct inode *ip, *pdir; 1080 struct vnode *tvp; 1081 int error; 1082 1083 pdir = VTOI(dvp); 1084#ifdef DIAGNOSTIC 1085 if ((cnp->cn_flags & HASBUF) == 0) 1086 panic("ext2_makeinode: no name"); 1087#endif 1088 *vpp = NULL; 1089 if ((mode & IFMT) == 0) 1090 mode |= IFREG; 1091 1092 error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp); 1093 if (error) { 1094 return (error); 1095 } 1096 ip = VTOI(tvp); 1097 ip->i_gid = pdir->i_gid; 1098#ifdef SUIDDIR 1099 { 1100#ifdef QUOTA 1101 struct ucred ucred, *ucp; 1102 ucp = cnp->cn_cred; 1103#endif I 1104 /* 1105 * if we are 1106 * not the owner of the directory, 1107 * and we are hacking owners here, (only do this where told to) 1108 * and we are not giving it TOO root, (would subvert quotas) 1109 * then go ahead and give it to the other user. 1110 * Note that this drops off the execute bits for security. 1111 */ 1112 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) && 1113 (pdir->i_mode & ISUID) && 1114 (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { 1115 ip->i_uid = pdir->i_uid; 1116 mode &= ~07111; 1117#ifdef QUOTA 1118 /* 1119 * make sure the correct user gets charged 1120 * for the space. 1121 * Quickly knock up a dummy credential for the victim. 1122 * XXX This seems to never be accessed out of our 1123 * context so a stack variable is ok. 1124 */ 1125 ucred.cr_ref = 1; 1126 ucred.cr_uid = ip->i_uid; 1127 ucred.cr_ngroups = 1; 1128 ucred.cr_groups[0] = pdir->i_gid; 1129 ucp = &ucred; 1130#endif I 1131 } else { 1132 ip->i_uid = cnp->cn_cred->cr_uid; 1133 } 1134 1135#ifdef QUOTA 1136 if ((error = getinoquota(ip)) || 1137 (error = chkiq(ip, 1, ucp, 0))) { 1138 UFS_VFREE(tvp, ip->i_number, mode); 1139 vput(tvp); 1140 return (error); 1141 } 1142#endif 1143 } 1144#else 1145 ip->i_uid = cnp->cn_cred->cr_uid; 1146#ifdef QUOTA 1147 if ((error = getinoquota(ip)) || 1148 (error = chkiq(ip, 1, cnp->cn_cred, 0))) { 1149 UFS_VFREE(tvp, ip->i_number, mode); 1150 vput(tvp); 1151 return (error); 1152 } 1153#endif 1154#endif 1155 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1156 ip->i_mode = mode; 1157 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ 1158 ip->i_nlink = 1; 1159 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && 1160 suser_xxx(cnp->cn_cred, 0, PRISON_ROOT)) 1161 ip->i_mode &= ~ISGID; 1162 1163 if (cnp->cn_flags & ISWHITEOUT) 1164 ip->i_flags |= UF_OPAQUE; 1165 1166 /* 1167 * Make sure inode goes to disk before directory entry. 1168 */ 1169 error = UFS_UPDATE(tvp, 1); 1170 if (error) 1171 goto bad; 1172 error = ext2_direnter(ip, dvp, cnp); 1173 if (error) 1174 goto bad; 1175 1176 *vpp = tvp; 1177 return (0); 1178 1179bad: 1180 /* 1181 * Write error occurred trying to update the inode 1182 * or the directory so must deallocate the inode. 1183 */ 1184 ip->i_nlink = 0; 1185 ip->i_flag |= IN_CHANGE; 1186 vput(tvp); 1187 return (error); 1188}
| 116 { NULL, NULL } 117}; 118static struct vnodeopv_desc ext2fs_vnodeop_opv_desc = 119 { &ext2_vnodeop_p, ext2_vnodeop_entries }; 120 121vop_t **ext2_specop_p; 122static struct vnodeopv_entry_desc ext2_specop_entries[] = { 123 { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, 124 { &vop_fsync_desc, (vop_t *) ext2_fsync }, 125 { &vop_inactive_desc, (vop_t *) ext2_inactive }, 126 { NULL, NULL } 127}; 128static struct vnodeopv_desc ext2fs_specop_opv_desc = 129 { &ext2_specop_p, ext2_specop_entries }; 130 131vop_t **ext2_fifoop_p; 132static struct vnodeopv_entry_desc ext2_fifoop_entries[] = { 133 { &vop_default_desc, (vop_t *) ufs_vnoperatefifo }, 134 { &vop_fsync_desc, (vop_t *) ext2_fsync }, 135 { &vop_inactive_desc, (vop_t *) ext2_inactive }, 136 { NULL, NULL } 137}; 138static struct vnodeopv_desc ext2fs_fifoop_opv_desc = 139 { &ext2_fifoop_p, ext2_fifoop_entries }; 140 141 VNODEOP_SET(ext2fs_vnodeop_opv_desc); 142 VNODEOP_SET(ext2fs_specop_opv_desc); 143 VNODEOP_SET(ext2fs_fifoop_opv_desc); 144 145#include <gnu/ext2fs/ext2_readwrite.c> 146 147/* 148 * A virgin directory (no blushing please). 149 * Note that the type and namlen fields are reversed relative to ufs. 150 * Also, we don't use `struct odirtemplate', since it would just cause 151 * endianness problems. 152 */ 153static struct dirtemplate mastertemplate = { 154 0, 12, 1, EXT2_FT_DIR, ".", 155 0, DIRBLKSIZ - 12, 2, EXT2_FT_DIR, ".." 156}; 157static struct dirtemplate omastertemplate = { 158 0, 12, 1, EXT2_FT_UNKNOWN, ".", 159 0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".." 160}; 161 162/* 163 * Create a regular file 164 */ 165static int 166ext2_create(ap) 167 struct vop_create_args /* { 168 struct vnode *a_dvp; 169 struct vnode **a_vpp; 170 struct componentname *a_cnp; 171 struct vattr *a_vap; 172 } */ *ap; 173{ 174 int error; 175 176 error = 177 ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), 178 ap->a_dvp, ap->a_vpp, ap->a_cnp); 179 if (error) 180 return (error); 181 return (0); 182} 183 184/* 185 * Synch an open file. 186 */ 187/* ARGSUSED */ 188static int 189ext2_fsync(ap) 190 struct vop_fsync_args /* { 191 struct vnode *a_vp; 192 struct ucred *a_cred; 193 int a_waitfor; 194 struct proc *a_p; 195 } */ *ap; 196{ 197 register struct vnode *vp = ap->a_vp; 198 register struct buf *bp; 199 struct buf *nbp; 200 int s; 201 202 /* 203 * XXX why is all this fs specific? 204 */ 205 206 /* 207 * Flush all dirty buffers associated with a vnode. 208 */ 209 ext2_discard_prealloc(VTOI(vp)); 210 211loop: 212 s = splbio(); 213 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 214 nbp = TAILQ_NEXT(bp, b_vnbufs); 215 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) 216 continue; 217 if ((bp->b_flags & B_DELWRI) == 0) 218 panic("ext2_fsync: not dirty"); 219 bremfree(bp); 220 splx(s); 221 /* 222 * Wait for I/O associated with indirect blocks to complete, 223 * since there is no way to quickly wait for them below. 224 */ 225 if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) 226 (void) bawrite(bp); 227 else 228 (void) bwrite(bp); 229 goto loop; 230 } 231 if (ap->a_waitfor == MNT_WAIT) { 232 while (vp->v_numoutput) { 233 vp->v_flag |= VBWAIT; 234 tsleep(&vp->v_numoutput, PRIBIO + 1, "e2fsyn", 0); 235 } 236#if DIAGNOSTIC 237 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) { 238 vprint("ext2_fsync: dirty", vp); 239 goto loop; 240 } 241#endif 242 } 243 splx(s); 244 return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT)); 245} 246 247/* 248 * Mknod vnode call 249 */ 250/* ARGSUSED */ 251static int 252ext2_mknod(ap) 253 struct vop_mknod_args /* { 254 struct vnode *a_dvp; 255 struct vnode **a_vpp; 256 struct componentname *a_cnp; 257 struct vattr *a_vap; 258 } */ *ap; 259{ 260 struct vattr *vap = ap->a_vap; 261 struct vnode **vpp = ap->a_vpp; 262 struct inode *ip; 263 ino_t ino; 264 int error; 265 266 error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), 267 ap->a_dvp, vpp, ap->a_cnp); 268 if (error) 269 return (error); 270 ip = VTOI(*vpp); 271 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 272 if (vap->va_rdev != VNOVAL) { 273 /* 274 * Want to be able to use this to make badblock 275 * inodes, so don't truncate the dev number. 276 */ 277 ip->i_rdev = vap->va_rdev; 278 } 279 /* 280 * Remove inode, then reload it through VFS_VGET so it is 281 * checked to see if it is an alias of an existing entry in 282 * the inode cache. 283 */ 284 vput(*vpp); 285 (*vpp)->v_type = VNON; 286 ino = ip->i_number; /* Save this before vgone() invalidates ip. */ 287 vgone(*vpp); 288 error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp); 289 if (error) { 290 *vpp = NULL; 291 return (error); 292 } 293 return (0); 294} 295 296static int 297ext2_remove(ap) 298 struct vop_remove_args /* { 299 struct vnode *a_dvp; 300 struct vnode *a_vp; 301 struct componentname *a_cnp; 302 } */ *ap; 303{ 304 struct inode *ip; 305 struct vnode *vp = ap->a_vp; 306 struct vnode *dvp = ap->a_dvp; 307 int error; 308 309 ip = VTOI(vp); 310 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 311 (VTOI(dvp)->i_flags & APPEND)) { 312 error = EPERM; 313 goto out; 314 } 315 error = ext2_dirremove(dvp, ap->a_cnp); 316 if (error == 0) { 317 ip->i_nlink--; 318 ip->i_flag |= IN_CHANGE; 319 } 320out: 321 return (error); 322} 323 324/* 325 * link vnode call 326 */ 327static int 328ext2_link(ap) 329 struct vop_link_args /* { 330 struct vnode *a_tdvp; 331 struct vnode *a_vp; 332 struct componentname *a_cnp; 333 } */ *ap; 334{ 335 struct vnode *vp = ap->a_vp; 336 struct vnode *tdvp = ap->a_tdvp; 337 struct componentname *cnp = ap->a_cnp; 338 struct proc *p = cnp->cn_proc; 339 struct inode *ip; 340 int error; 341 342#ifdef DIAGNOSTIC 343 if ((cnp->cn_flags & HASBUF) == 0) 344 panic("ufs_link: no name"); 345#endif 346 if (tdvp->v_mount != vp->v_mount) { 347 error = EXDEV; 348 goto out2; 349 } 350 if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) { 351 goto out2; 352 } 353 ip = VTOI(vp); 354 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 355 error = EMLINK; 356 goto out1; 357 } 358 if (ip->i_flags & (IMMUTABLE | APPEND)) { 359 error = EPERM; 360 goto out1; 361 } 362 ip->i_nlink++; 363 ip->i_flag |= IN_CHANGE; 364 error = UFS_UPDATE(vp, 1); 365 if (!error) 366 error = ext2_direnter(ip, tdvp, cnp); 367 if (error) { 368 ip->i_nlink--; 369 ip->i_flag |= IN_CHANGE; 370 } 371out1: 372 if (tdvp != vp) 373 VOP_UNLOCK(vp, 0, p); 374out2: 375 return (error); 376} 377 378/* 379 * Rename system call. 380 * See comments in sys/ufs/ufs/ufs_vnops.c 381 */ 382static int 383ext2_rename(ap) 384 struct vop_rename_args /* { 385 struct vnode *a_fdvp; 386 struct vnode *a_fvp; 387 struct componentname *a_fcnp; 388 struct vnode *a_tdvp; 389 struct vnode *a_tvp; 390 struct componentname *a_tcnp; 391 } */ *ap; 392{ 393 struct vnode *tvp = ap->a_tvp; 394 register struct vnode *tdvp = ap->a_tdvp; 395 struct vnode *fvp = ap->a_fvp; 396 struct vnode *fdvp = ap->a_fdvp; 397 struct componentname *tcnp = ap->a_tcnp; 398 struct componentname *fcnp = ap->a_fcnp; 399 struct proc *p = fcnp->cn_proc; 400 struct inode *ip, *xp, *dp; 401 struct dirtemplate dirbuf; 402 int doingdirectory = 0, oldparent = 0, newparent = 0; 403 int error = 0; 404 u_char namlen; 405 406#ifdef DIAGNOSTIC 407 if ((tcnp->cn_flags & HASBUF) == 0 || 408 (fcnp->cn_flags & HASBUF) == 0) 409 panic("ufs_rename: no name"); 410#endif 411 /* 412 * Check for cross-device rename. 413 */ 414 if ((fvp->v_mount != tdvp->v_mount) || 415 (tvp && (fvp->v_mount != tvp->v_mount))) { 416 error = EXDEV; 417abortit: 418 if (tdvp == tvp) 419 vrele(tdvp); 420 else 421 vput(tdvp); 422 if (tvp) 423 vput(tvp); 424 vrele(fdvp); 425 vrele(fvp); 426 return (error); 427 } 428 429 if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 430 (VTOI(tdvp)->i_flags & APPEND))) { 431 error = EPERM; 432 goto abortit; 433 } 434 435 /* 436 * Check if just deleting a link name or if we've lost a race. 437 * If another process completes the same rename after we've looked 438 * up the source and have blocked looking up the target, then the 439 * source and target inodes may be identical now although the 440 * names were never linked. 441 */ 442 if (fvp == tvp) { 443 if (fvp->v_type == VDIR) { 444 /* 445 * Linked directories are impossible, so we must 446 * have lost the race. Pretend that the rename 447 * completed before the lookup. 448 */ 449#ifdef UFS_RENAME_DEBUG 450 printf("ufs_rename: fvp == tvp for directories\n"); 451#endif 452 error = ENOENT; 453 goto abortit; 454 } 455 456 /* Release destination completely. */ 457 vput(tdvp); 458 vput(tvp); 459 460 /* 461 * Delete source. There is another race now that everything 462 * is unlocked, but this doesn't cause any new complications. 463 * Relookup() may find a file that is unrelated to the 464 * original one, or it may fail. Too bad. 465 */ 466 vrele(fdvp); 467 vrele(fvp); 468 fcnp->cn_flags &= ~MODMASK; 469 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 470 fcnp->cn_nameiop = DELETE; 471 VREF(fdvp); 472 error = relookup(fdvp, &fvp, fcnp); 473 if (error == 0) 474 vrele(fdvp); 475 if (fvp == NULL) { 476#ifdef UFS_RENAME_DEBUG 477 printf("ufs_rename: from name disappeared\n"); 478#endif 479 return (ENOENT); 480 } 481 error = VOP_REMOVE(fdvp, fvp, fcnp); 482 if (fdvp == fvp) 483 vrele(fdvp); 484 else 485 vput(fdvp); 486 if (fvp != NULLVP) 487 vput(fvp); 488 return (error); 489 } 490 if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0) 491 goto abortit; 492 dp = VTOI(fdvp); 493 ip = VTOI(fvp); 494 if (ip->i_nlink >= LINK_MAX) { 495 VOP_UNLOCK(fvp, 0, p); 496 error = EMLINK; 497 goto abortit; 498 } 499 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) 500 || (dp->i_flags & APPEND)) { 501 VOP_UNLOCK(fvp, 0, p); 502 error = EPERM; 503 goto abortit; 504 } 505 if ((ip->i_mode & IFMT) == IFDIR) { 506 /* 507 * Avoid ".", "..", and aliases of "." for obvious reasons. 508 */ 509 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 510 dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT || 511 (ip->i_flag & IN_RENAME)) { 512 VOP_UNLOCK(fvp, 0, p); 513 error = EINVAL; 514 goto abortit; 515 } 516 ip->i_flag |= IN_RENAME; 517 oldparent = dp->i_number; 518 doingdirectory++; 519 } 520 vrele(fdvp); 521 522 /* 523 * When the target exists, both the directory 524 * and target vnodes are returned locked. 525 */ 526 dp = VTOI(tdvp); 527 xp = NULL; 528 if (tvp) 529 xp = VTOI(tvp); 530 531 /* 532 * 1) Bump link count while we're moving stuff 533 * around. If we crash somewhere before 534 * completing our work, the link count 535 * may be wrong, but correctable. 536 */ 537 ip->i_nlink++; 538 ip->i_flag |= IN_CHANGE; 539 if ((error = UFS_UPDATE(fvp, 1)) != 0) { 540 VOP_UNLOCK(fvp, 0, p); 541 goto bad; 542 } 543 544 /* 545 * If ".." must be changed (ie the directory gets a new 546 * parent) then the source directory must not be in the 547 * directory heirarchy above the target, as this would 548 * orphan everything below the source directory. Also 549 * the user must have write permission in the source so 550 * as to be able to change "..". We must repeat the call 551 * to namei, as the parent directory is unlocked by the 552 * call to checkpath(). 553 */ 554 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 555 VOP_UNLOCK(fvp, 0, p); 556 if (oldparent != dp->i_number) 557 newparent = dp->i_number; 558 if (doingdirectory && newparent) { 559 if (error) /* write access check above */ 560 goto bad; 561 if (xp != NULL) 562 vput(tvp); 563 error = ext2_checkpath(ip, dp, tcnp->cn_cred); 564 if (error) 565 goto out; 566 VREF(tdvp); 567 error = relookup(tdvp, &tvp, tcnp); 568 if (error) 569 goto out; 570 vrele(tdvp); 571 dp = VTOI(tdvp); 572 xp = NULL; 573 if (tvp) 574 xp = VTOI(tvp); 575 } 576 /* 577 * 2) If target doesn't exist, link the target 578 * to the source and unlink the source. 579 * Otherwise, rewrite the target directory 580 * entry to reference the source inode and 581 * expunge the original entry's existence. 582 */ 583 if (xp == NULL) { 584 if (dp->i_dev != ip->i_dev) 585 panic("ufs_rename: EXDEV"); 586 /* 587 * Account for ".." in new directory. 588 * When source and destination have the same 589 * parent we don't fool with the link count. 590 */ 591 if (doingdirectory && newparent) { 592 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 593 error = EMLINK; 594 goto bad; 595 } 596 dp->i_nlink++; 597 dp->i_flag |= IN_CHANGE; 598 error = UFS_UPDATE(tdvp, 1); 599 if (error) 600 goto bad; 601 } 602 error = ext2_direnter(ip, tdvp, tcnp); 603 if (error) { 604 if (doingdirectory && newparent) { 605 dp->i_nlink--; 606 dp->i_flag |= IN_CHANGE; 607 (void)UFS_UPDATE(tdvp, 1); 608 } 609 goto bad; 610 } 611 vput(tdvp); 612 } else { 613 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 614 panic("ufs_rename: EXDEV"); 615 /* 616 * Short circuit rename(foo, foo). 617 */ 618 if (xp->i_number == ip->i_number) 619 panic("ufs_rename: same file"); 620 /* 621 * If the parent directory is "sticky", then the user must 622 * own the parent directory, or the destination of the rename, 623 * otherwise the destination may not be changed (except by 624 * root). This implements append-only directories. 625 */ 626 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && 627 tcnp->cn_cred->cr_uid != dp->i_uid && 628 xp->i_uid != tcnp->cn_cred->cr_uid) { 629 error = EPERM; 630 goto bad; 631 } 632 /* 633 * Target must be empty if a directory and have no links 634 * to it. Also, ensure source and target are compatible 635 * (both directories, or both not directories). 636 */ 637 if ((xp->i_mode&IFMT) == IFDIR) { 638 if (! ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) || 639 xp->i_nlink > 2) { 640 error = ENOTEMPTY; 641 goto bad; 642 } 643 if (!doingdirectory) { 644 error = ENOTDIR; 645 goto bad; 646 } 647 cache_purge(tdvp); 648 } else if (doingdirectory) { 649 error = EISDIR; 650 goto bad; 651 } 652 error = ext2_dirrewrite(dp, ip, tcnp); 653 if (error) 654 goto bad; 655 /* 656 * If the target directory is in the same 657 * directory as the source directory, 658 * decrement the link count on the parent 659 * of the target directory. 660 */ 661 if (doingdirectory && !newparent) { 662 dp->i_nlink--; 663 dp->i_flag |= IN_CHANGE; 664 } 665 vput(tdvp); 666 /* 667 * Adjust the link count of the target to 668 * reflect the dirrewrite above. If this is 669 * a directory it is empty and there are 670 * no links to it, so we can squash the inode and 671 * any space associated with it. We disallowed 672 * renaming over top of a directory with links to 673 * it above, as the remaining link would point to 674 * a directory without "." or ".." entries. 675 */ 676 xp->i_nlink--; 677 if (doingdirectory) { 678 if (--xp->i_nlink != 0) 679 panic("ufs_rename: linked directory"); 680 error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, 681 tcnp->cn_cred, tcnp->cn_proc); 682 } 683 xp->i_flag |= IN_CHANGE; 684 vput(tvp); 685 xp = NULL; 686 } 687 688 /* 689 * 3) Unlink the source. 690 */ 691 fcnp->cn_flags &= ~MODMASK; 692 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 693 VREF(fdvp); 694 error = relookup(fdvp, &fvp, fcnp); 695 if (error == 0) 696 vrele(fdvp); 697 if (fvp != NULL) { 698 xp = VTOI(fvp); 699 dp = VTOI(fdvp); 700 } else { 701 /* 702 * From name has disappeared. 703 */ 704 if (doingdirectory) 705 panic("ufs_rename: lost dir entry"); 706 vrele(ap->a_fvp); 707 return (0); 708 } 709 /* 710 * Ensure that the directory entry still exists and has not 711 * changed while the new name has been entered. If the source is 712 * a file then the entry may have been unlinked or renamed. In 713 * either case there is no further work to be done. If the source 714 * is a directory then it cannot have been rmdir'ed; its link 715 * count of three would cause a rmdir to fail with ENOTEMPTY. 716 * The IN_RENAME flag ensures that it cannot be moved by another 717 * rename. 718 */ 719 if (xp != ip) { 720 if (doingdirectory) 721 panic("ufs_rename: lost dir entry"); 722 } else { 723 /* 724 * If the source is a directory with a 725 * new parent, the link count of the old 726 * parent directory must be decremented 727 * and ".." set to point to the new parent. 728 */ 729 if (doingdirectory && newparent) { 730 dp->i_nlink--; 731 dp->i_flag |= IN_CHANGE; 732 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf, 733 sizeof (struct dirtemplate), (off_t)0, 734 UIO_SYSSPACE, IO_NODELOCKED, 735 tcnp->cn_cred, (int *)0, (struct proc *)0); 736 if (error == 0) { 737 /* Like ufs little-endian: */ 738 namlen = dirbuf.dotdot_type; 739 if (namlen != 2 || 740 dirbuf.dotdot_name[0] != '.' || 741 dirbuf.dotdot_name[1] != '.') { 742 ufs_dirbad(xp, (doff_t)12, 743 "rename: mangled dir"); 744 } else { 745 dirbuf.dotdot_ino = newparent; 746 (void) vn_rdwr(UIO_WRITE, fvp, 747 (caddr_t)&dirbuf, 748 sizeof (struct dirtemplate), 749 (off_t)0, UIO_SYSSPACE, 750 IO_NODELOCKED|IO_SYNC, 751 tcnp->cn_cred, (int *)0, 752 (struct proc *)0); 753 cache_purge(fdvp); 754 } 755 } 756 } 757 error = ext2_dirremove(fdvp, fcnp); 758 if (!error) { 759 xp->i_nlink--; 760 xp->i_flag |= IN_CHANGE; 761 } 762 xp->i_flag &= ~IN_RENAME; 763 } 764 if (dp) 765 vput(fdvp); 766 if (xp) 767 vput(fvp); 768 vrele(ap->a_fvp); 769 return (error); 770 771bad: 772 if (xp) 773 vput(ITOV(xp)); 774 vput(ITOV(dp)); 775out: 776 if (doingdirectory) 777 ip->i_flag &= ~IN_RENAME; 778 if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) { 779 ip->i_nlink--; 780 ip->i_flag |= IN_CHANGE; 781 ip->i_flag &= ~IN_RENAME; 782 vput(fvp); 783 } else 784 vrele(fvp); 785 return (error); 786} 787 788/* 789 * Mkdir system call 790 */ 791static int 792ext2_mkdir(ap) 793 struct vop_mkdir_args /* { 794 struct vnode *a_dvp; 795 struct vnode **a_vpp; 796 struct componentname *a_cnp; 797 struct vattr *a_vap; 798 } */ *ap; 799{ 800 register struct vnode *dvp = ap->a_dvp; 801 register struct vattr *vap = ap->a_vap; 802 register struct componentname *cnp = ap->a_cnp; 803 register struct inode *ip, *dp; 804 struct vnode *tvp; 805 struct dirtemplate dirtemplate, *dtp; 806 int error, dmode; 807 808#ifdef DIAGNOSTIC 809 if ((cnp->cn_flags & HASBUF) == 0) 810 panic("ufs_mkdir: no name"); 811#endif 812 dp = VTOI(dvp); 813 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 814 error = EMLINK; 815 goto out; 816 } 817 dmode = vap->va_mode & 0777; 818 dmode |= IFDIR; 819 /* 820 * Must simulate part of ext2_makeinode here to acquire the inode, 821 * but not have it entered in the parent directory. The entry is 822 * made later after writing "." and ".." entries. 823 */ 824 error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); 825 if (error) 826 goto out; 827 ip = VTOI(tvp); 828 ip->i_gid = dp->i_gid; 829#ifdef SUIDDIR 830 { 831#ifdef QUOTA 832 struct ucred ucred, *ucp; 833 ucp = cnp->cn_cred; 834#endif I 835 /* 836 * if we are hacking owners here, (only do this where told to) 837 * and we are not giving it TOO root, (would subvert quotas) 838 * then go ahead and give it to the other user. 839 * The new directory also inherits the SUID bit. 840 * If user's UID and dir UID are the same, 841 * 'give it away' so that the SUID is still forced on. 842 */ 843 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) && 844 (dp->i_mode & ISUID) && dp->i_uid) { 845 dmode |= ISUID; 846 ip->i_uid = dp->i_uid; 847#ifdef QUOTA 848 if (dp->i_uid != cnp->cn_cred->cr_uid) { 849 /* 850 * make sure the correct user gets charged 851 * for the space. 852 * Make a dummy credential for the victim. 853 * XXX This seems to never be accessed out of 854 * our context so a stack variable is ok. 855 */ 856 ucred.cr_ref = 1; 857 ucred.cr_uid = ip->i_uid; 858 ucred.cr_ngroups = 1; 859 ucred.cr_groups[0] = dp->i_gid; 860 ucp = &ucred; 861 } 862#endif I 863 } else { 864 ip->i_uid = cnp->cn_cred->cr_uid; 865 } 866#ifdef QUOTA 867 if ((error = getinoquota(ip)) || 868 (error = chkiq(ip, 1, ucp, 0))) { 869 UFS_VFREE(tvp, ip->i_number, dmode); 870 vput(tvp); 871 return (error); 872 } 873#endif 874 } 875#else 876 ip->i_uid = cnp->cn_cred->cr_uid; 877#ifdef QUOTA 878 if ((error = getinoquota(ip)) || 879 (error = chkiq(ip, 1, cnp->cn_cred, 0))) { 880 UFS_VFREE(tvp, ip->i_number, dmode); 881 vput(tvp); 882 return (error); 883 } 884#endif 885#endif 886 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 887 ip->i_mode = dmode; 888 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ 889 ip->i_nlink = 2; 890 if (cnp->cn_flags & ISWHITEOUT) 891 ip->i_flags |= UF_OPAQUE; 892 error = UFS_UPDATE(tvp, 1); 893 894 /* 895 * Bump link count in parent directory 896 * to reflect work done below. Should 897 * be done before reference is created 898 * so reparation is possible if we crash. 899 */ 900 dp->i_nlink++; 901 dp->i_flag |= IN_CHANGE; 902 error = UFS_UPDATE(dvp, 1); 903 if (error) 904 goto bad; 905 906 /* Initialize directory with "." and ".." from static template. */ 907 if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es, 908 EXT2_FEATURE_INCOMPAT_FILETYPE)) 909 dtp = &mastertemplate; 910 else 911 dtp = &omastertemplate; 912 dirtemplate = *dtp; 913 dirtemplate.dot_ino = ip->i_number; 914 dirtemplate.dotdot_ino = dp->i_number; 915 /* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 916 * so let's just redefine it - for this function only 917 */ 918#undef DIRBLKSIZ 919#define DIRBLKSIZ VTOI(dvp)->i_e2fs->s_blocksize 920 dirtemplate.dotdot_reclen = DIRBLKSIZ - 12; 921 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, 922 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 923 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0); 924 if (error) { 925 dp->i_nlink--; 926 dp->i_flag |= IN_CHANGE; 927 goto bad; 928 } 929 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 930 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */ 931 else { 932 ip->i_size = DIRBLKSIZ; 933 ip->i_flag |= IN_CHANGE; 934 } 935 936 /* Directory set up, now install its entry in the parent directory. */ 937 error = ext2_direnter(ip, dvp, cnp); 938 if (error) { 939 dp->i_nlink--; 940 dp->i_flag |= IN_CHANGE; 941 } 942bad: 943 /* 944 * No need to do an explicit VOP_TRUNCATE here, vrele will do this 945 * for us because we set the link count to 0. 946 */ 947 if (error) { 948 ip->i_nlink = 0; 949 ip->i_flag |= IN_CHANGE; 950 vput(tvp); 951 } else 952 *ap->a_vpp = tvp; 953out: 954 return (error); 955#undef DIRBLKSIZ 956#define DIRBLKSIZ DEV_BSIZE 957} 958 959/* 960 * Rmdir system call. 961 */ 962static int 963ext2_rmdir(ap) 964 struct vop_rmdir_args /* { 965 struct vnode *a_dvp; 966 struct vnode *a_vp; 967 struct componentname *a_cnp; 968 } */ *ap; 969{ 970 struct vnode *vp = ap->a_vp; 971 struct vnode *dvp = ap->a_dvp; 972 struct componentname *cnp = ap->a_cnp; 973 struct proc *p = cnp->cn_proc; 974 struct inode *ip, *dp; 975 int error; 976 977 ip = VTOI(vp); 978 dp = VTOI(dvp); 979 980 /* 981 * Verify the directory is empty (and valid). 982 * (Rmdir ".." won't be valid since 983 * ".." will contain a reference to 984 * the current directory and thus be 985 * non-empty.) 986 */ 987 error = 0; 988 if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) { 989 error = ENOTEMPTY; 990 goto out; 991 } 992 if ((dp->i_flags & APPEND) 993 || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) { 994 error = EPERM; 995 goto out; 996 } 997 /* 998 * Delete reference to directory before purging 999 * inode. If we crash in between, the directory 1000 * will be reattached to lost+found, 1001 */ 1002 error = ext2_dirremove(dvp, cnp); 1003 if (error) 1004 goto out; 1005 dp->i_nlink--; 1006 dp->i_flag |= IN_CHANGE; 1007 cache_purge(dvp); 1008 VOP_UNLOCK(dvp, 0, p); 1009 /* 1010 * Truncate inode. The only stuff left 1011 * in the directory is "." and "..". The 1012 * "." reference is inconsequential since 1013 * we're quashing it. The ".." reference 1014 * has already been adjusted above. We've 1015 * removed the "." reference and the reference 1016 * in the parent directory, but there may be 1017 * other hard links so decrement by 2 and 1018 * worry about them later. 1019 */ 1020 ip->i_nlink -= 2; 1021 error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, p); 1022 cache_purge(ITOV(ip)); 1023 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 1024out: 1025 return (error); 1026} 1027 1028/* 1029 * symlink -- make a symbolic link 1030 */ 1031static int 1032ext2_symlink(ap) 1033 struct vop_symlink_args /* { 1034 struct vnode *a_dvp; 1035 struct vnode **a_vpp; 1036 struct componentname *a_cnp; 1037 struct vattr *a_vap; 1038 char *a_target; 1039 } */ *ap; 1040{ 1041 register struct vnode *vp, **vpp = ap->a_vpp; 1042 register struct inode *ip; 1043 int len, error; 1044 1045 error = ext2_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, 1046 vpp, ap->a_cnp); 1047 if (error) 1048 return (error); 1049 vp = *vpp; 1050 len = strlen(ap->a_target); 1051 if (len < vp->v_mount->mnt_maxsymlinklen) { 1052 ip = VTOI(vp); 1053 bcopy(ap->a_target, (char *)ip->i_shortlink, len); 1054 ip->i_size = len; 1055 ip->i_flag |= IN_CHANGE | IN_UPDATE; 1056 } else 1057 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 1058 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0, 1059 (struct proc *)0); 1060 if (error) 1061 vput(vp); 1062 return (error); 1063} 1064 1065/* 1066 * Allocate a new inode. 1067 */ 1068static int 1069ext2_makeinode(mode, dvp, vpp, cnp) 1070 int mode; 1071 struct vnode *dvp; 1072 struct vnode **vpp; 1073 struct componentname *cnp; 1074{ 1075 register struct inode *ip, *pdir; 1076 struct vnode *tvp; 1077 int error; 1078 1079 pdir = VTOI(dvp); 1080#ifdef DIAGNOSTIC 1081 if ((cnp->cn_flags & HASBUF) == 0) 1082 panic("ext2_makeinode: no name"); 1083#endif 1084 *vpp = NULL; 1085 if ((mode & IFMT) == 0) 1086 mode |= IFREG; 1087 1088 error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp); 1089 if (error) { 1090 return (error); 1091 } 1092 ip = VTOI(tvp); 1093 ip->i_gid = pdir->i_gid; 1094#ifdef SUIDDIR 1095 { 1096#ifdef QUOTA 1097 struct ucred ucred, *ucp; 1098 ucp = cnp->cn_cred; 1099#endif I 1100 /* 1101 * if we are 1102 * not the owner of the directory, 1103 * and we are hacking owners here, (only do this where told to) 1104 * and we are not giving it TOO root, (would subvert quotas) 1105 * then go ahead and give it to the other user. 1106 * Note that this drops off the execute bits for security. 1107 */ 1108 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) && 1109 (pdir->i_mode & ISUID) && 1110 (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { 1111 ip->i_uid = pdir->i_uid; 1112 mode &= ~07111; 1113#ifdef QUOTA 1114 /* 1115 * make sure the correct user gets charged 1116 * for the space. 1117 * Quickly knock up a dummy credential for the victim. 1118 * XXX This seems to never be accessed out of our 1119 * context so a stack variable is ok. 1120 */ 1121 ucred.cr_ref = 1; 1122 ucred.cr_uid = ip->i_uid; 1123 ucred.cr_ngroups = 1; 1124 ucred.cr_groups[0] = pdir->i_gid; 1125 ucp = &ucred; 1126#endif I 1127 } else { 1128 ip->i_uid = cnp->cn_cred->cr_uid; 1129 } 1130 1131#ifdef QUOTA 1132 if ((error = getinoquota(ip)) || 1133 (error = chkiq(ip, 1, ucp, 0))) { 1134 UFS_VFREE(tvp, ip->i_number, mode); 1135 vput(tvp); 1136 return (error); 1137 } 1138#endif 1139 } 1140#else 1141 ip->i_uid = cnp->cn_cred->cr_uid; 1142#ifdef QUOTA 1143 if ((error = getinoquota(ip)) || 1144 (error = chkiq(ip, 1, cnp->cn_cred, 0))) { 1145 UFS_VFREE(tvp, ip->i_number, mode); 1146 vput(tvp); 1147 return (error); 1148 } 1149#endif 1150#endif 1151 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1152 ip->i_mode = mode; 1153 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ 1154 ip->i_nlink = 1; 1155 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && 1156 suser_xxx(cnp->cn_cred, 0, PRISON_ROOT)) 1157 ip->i_mode &= ~ISGID; 1158 1159 if (cnp->cn_flags & ISWHITEOUT) 1160 ip->i_flags |= UF_OPAQUE; 1161 1162 /* 1163 * Make sure inode goes to disk before directory entry. 1164 */ 1165 error = UFS_UPDATE(tvp, 1); 1166 if (error) 1167 goto bad; 1168 error = ext2_direnter(ip, dvp, cnp); 1169 if (error) 1170 goto bad; 1171 1172 *vpp = tvp; 1173 return (0); 1174 1175bad: 1176 /* 1177 * Write error occurred trying to update the inode 1178 * or the directory so must deallocate the inode. 1179 */ 1180 ip->i_nlink = 0; 1181 ip->i_flag |= IN_CHANGE; 1182 vput(tvp); 1183 return (error); 1184}
|