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