1 /* $NetBSD: ext2fs_vnops.c,v 1.40 2001/11/08 02:39:08 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94 42 * Modified for ext2fs by Manuel Bouyer. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.40 2001/11/08 02:39:08 lukem Exp $"); 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/resourcevar.h> 51 #include <sys/kernel.h> 52 #include <sys/file.h> 53 #include <sys/stat.h> 54 #include <sys/buf.h> 55 #include <sys/proc.h> 56 #include <sys/conf.h> 57 #include <sys/mount.h> 58 #include <sys/namei.h> 59 #include <sys/vnode.h> 60 #include <sys/lockf.h> 61 #include <sys/malloc.h> 62 #include <sys/pool.h> 63 #include <sys/signalvar.h> 64 65 #include <miscfs/fifofs/fifo.h> 66 #include <miscfs/genfs/genfs.h> 67 #include <miscfs/specfs/specdev.h> 68 69 #include <ufs/ufs/inode.h> 70 #include <ufs/ufs/ufs_extern.h> 71 #include <ufs/ufs/ufsmount.h> 72 73 #include <ufs/ext2fs/ext2fs.h> 74 #include <ufs/ext2fs/ext2fs_extern.h> 75 #include <ufs/ext2fs/ext2fs_dir.h> 76 77 extern int prtactive; 78 79 static int ext2fs_chmod 80 __P((struct vnode *, int, struct ucred *, struct proc *)); 81 static int ext2fs_chown 82 __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *)); 83 84 union _qcvt { 85 int64_t qcvt; 86 int32_t val[2]; 87 }; 88 #define SETHIGH(q, h) { \ 89 union _qcvt tmp; \ 90 tmp.qcvt = (q); \ 91 tmp.val[_QUAD_HIGHWORD] = (h); \ 92 (q) = tmp.qcvt; \ 93 } 94 #define SETLOW(q, l) { \ 95 union _qcvt tmp; \ 96 tmp.qcvt = (q); \ 97 tmp.val[_QUAD_LOWWORD] = (l); \ 98 (q) = tmp.qcvt; \ 99 } 100 101 /* 102 * Create a regular file 103 */ 104 int 105 ext2fs_create(v) 106 void *v; 107 { 108 struct vop_create_args /* { 109 struct vnode *a_dvp; 110 struct vnode **a_vpp; 111 struct componentname *a_cnp; 112 struct vattr *a_vap; 113 } */ *ap = v; 114 return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, 115 ap->a_vap->va_mode), 116 ap->a_dvp, ap->a_vpp, ap->a_cnp); 117 } 118 119 /* 120 * Mknod vnode call 121 */ 122 /* ARGSUSED */ 123 int 124 ext2fs_mknod(v) 125 void *v; 126 { 127 struct vop_mknod_args /* { 128 struct vnode *a_dvp; 129 struct vnode **a_vpp; 130 struct componentname *a_cnp; 131 struct vattr *a_vap; 132 } */ *ap = v; 133 struct vattr *vap = ap->a_vap; 134 struct vnode **vpp = ap->a_vpp; 135 struct inode *ip; 136 int error; 137 struct mount *mp; 138 ino_t ino; 139 140 if ((error = ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), 141 ap->a_dvp, vpp, ap->a_cnp)) != 0) 142 return (error); 143 ip = VTOI(*vpp); 144 mp = (*vpp)->v_mount; 145 ino = ip->i_number; 146 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 147 if (vap->va_rdev != VNOVAL) { 148 /* 149 * Want to be able to use this to make badblock 150 * inodes, so don't truncate the dev number. 151 */ 152 ip->i_din.e2fs_din.e2di_rdev = h2fs32(vap->va_rdev); 153 } 154 /* 155 * Remove inode so that it will be reloaded by VFS_VGET and 156 * checked to see if it is an alias of an existing entry in 157 * the inode cache. 158 */ 159 vput(*vpp); 160 (*vpp)->v_type = VNON; 161 vgone(*vpp); 162 error = VFS_VGET(mp, ino, vpp); 163 if (error != 0) { 164 *vpp = NULL; 165 return (error); 166 } 167 return (0); 168 } 169 170 /* 171 * Open called. 172 * 173 * Just check the APPEND flag. 174 */ 175 /* ARGSUSED */ 176 int 177 ext2fs_open(v) 178 void *v; 179 { 180 struct vop_open_args /* { 181 struct vnode *a_vp; 182 int a_mode; 183 struct ucred *a_cred; 184 struct proc *a_p; 185 } */ *ap = v; 186 187 /* 188 * Files marked append-only must be opened for appending. 189 */ 190 if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) && 191 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 192 return (EPERM); 193 return (0); 194 } 195 196 int 197 ext2fs_access(v) 198 void *v; 199 { 200 struct vop_access_args /* { 201 struct vnode *a_vp; 202 int a_mode; 203 struct ucred *a_cred; 204 struct proc *a_p; 205 } */ *ap = v; 206 struct vnode *vp = ap->a_vp; 207 struct inode *ip = VTOI(vp); 208 mode_t mode = ap->a_mode; 209 210 /* 211 * Disallow write attempts on read-only file systems; 212 * unless the file is a socket, fifo, or a block or 213 * character device resident on the file system. 214 */ 215 if (mode & VWRITE) { 216 switch (vp->v_type) { 217 case VDIR: 218 case VLNK: 219 case VREG: 220 if (vp->v_mount->mnt_flag & MNT_RDONLY) 221 return (EROFS); 222 break; 223 default: 224 break; 225 } 226 } 227 228 /* If immutable bit set, nobody gets to write it. */ 229 if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE)) 230 return (EPERM); 231 232 return (vaccess(vp->v_type, ip->i_e2fs_mode & ALLPERMS, 233 ip->i_e2fs_uid, ip->i_e2fs_gid, mode, ap->a_cred)); 234 } 235 236 /* ARGSUSED */ 237 int 238 ext2fs_getattr(v) 239 void *v; 240 { 241 struct vop_getattr_args /* { 242 struct vnode *a_vp; 243 struct vattr *a_vap; 244 struct ucred *a_cred; 245 struct proc *a_p; 246 } */ *ap = v; 247 struct vnode *vp = ap->a_vp; 248 struct inode *ip = VTOI(vp); 249 struct vattr *vap = ap->a_vap; 250 struct timespec ts; 251 252 TIMEVAL_TO_TIMESPEC(&time, &ts); 253 EXT2FS_ITIMES(ip, &ts, &ts, &ts); 254 /* 255 * Copy from inode table 256 */ 257 vap->va_fsid = ip->i_dev; 258 vap->va_fileid = ip->i_number; 259 vap->va_mode = ip->i_e2fs_mode & ALLPERMS; 260 vap->va_nlink = ip->i_e2fs_nlink; 261 vap->va_uid = ip->i_e2fs_uid; 262 vap->va_gid = ip->i_e2fs_gid; 263 vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din.e2di_rdev); 264 vap->va_size = vp->v_size; 265 vap->va_atime.tv_sec = ip->i_e2fs_atime; 266 vap->va_atime.tv_nsec = 0; 267 vap->va_mtime.tv_sec = ip->i_e2fs_mtime; 268 vap->va_mtime.tv_nsec = 0; 269 vap->va_ctime.tv_sec = ip->i_e2fs_ctime; 270 vap->va_ctime.tv_nsec = 0; 271 #ifdef EXT2FS_SYSTEM_FLAGS 272 vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0; 273 vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0; 274 #else 275 vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0; 276 vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0; 277 #endif 278 vap->va_gen = ip->i_e2fs_gen; 279 /* this doesn't belong here */ 280 if (vp->v_type == VBLK) 281 vap->va_blocksize = BLKDEV_IOSIZE; 282 else if (vp->v_type == VCHR) 283 vap->va_blocksize = MAXBSIZE; 284 else 285 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 286 vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock); 287 vap->va_type = vp->v_type; 288 vap->va_filerev = ip->i_modrev; 289 return (0); 290 } 291 292 /* 293 * Set attribute vnode op. called from several syscalls 294 */ 295 int 296 ext2fs_setattr(v) 297 void *v; 298 { 299 struct vop_setattr_args /* { 300 struct vnode *a_vp; 301 struct vattr *a_vap; 302 struct ucred *a_cred; 303 struct proc *a_p; 304 } */ *ap = v; 305 struct vattr *vap = ap->a_vap; 306 struct vnode *vp = ap->a_vp; 307 struct inode *ip = VTOI(vp); 308 struct ucred *cred = ap->a_cred; 309 struct proc *p = ap->a_p; 310 int error; 311 312 /* 313 * Check for unsettable attributes. 314 */ 315 if ((vap->va_type != VNON) || (vap->va_nlink != (nlink_t)VNOVAL) || 316 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 317 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 318 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 319 return (EINVAL); 320 } 321 if (vap->va_flags != VNOVAL) { 322 if (vp->v_mount->mnt_flag & MNT_RDONLY) 323 return (EROFS); 324 if (cred->cr_uid != ip->i_e2fs_uid && 325 (error = suser(cred, &p->p_acflag))) 326 return (error); 327 #ifdef EXT2FS_SYSTEM_FLAGS 328 if (cred->cr_uid == 0) { 329 if ((ip->i_e2fs_flags & 330 (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0) 331 return (EPERM); 332 ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE); 333 ip->i_e2fs_flags |= 334 (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 | 335 (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0; 336 } else 337 return (EPERM); 338 #else 339 ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE); 340 ip->i_e2fs_flags |= 341 (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 | 342 (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE : 0; 343 #endif 344 ip->i_flag |= IN_CHANGE; 345 if (vap->va_flags & (IMMUTABLE | APPEND)) 346 return (0); 347 } 348 if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) 349 return (EPERM); 350 /* 351 * Go through the fields and update iff not VNOVAL. 352 */ 353 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 354 if (vp->v_mount->mnt_flag & MNT_RDONLY) 355 return (EROFS); 356 error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p); 357 if (error) 358 return (error); 359 } 360 if (vap->va_size != VNOVAL) { 361 /* 362 * Disallow write attempts on read-only file systems; 363 * unless the file is a socket, fifo, or a block or 364 * character device resident on the file system. 365 */ 366 switch (vp->v_type) { 367 case VDIR: 368 return (EISDIR); 369 case VLNK: 370 case VREG: 371 if (vp->v_mount->mnt_flag & MNT_RDONLY) 372 return (EROFS); 373 default: 374 break; 375 } 376 error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p); 377 if (error) 378 return (error); 379 } 380 ip = VTOI(vp); 381 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 382 if (vp->v_mount->mnt_flag & MNT_RDONLY) 383 return (EROFS); 384 if (cred->cr_uid != ip->i_e2fs_uid && 385 (error = suser(cred, &p->p_acflag)) && 386 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 387 (error = VOP_ACCESS(vp, VWRITE, cred, p)))) 388 return (error); 389 if (vap->va_atime.tv_sec != VNOVAL) 390 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 391 ip->i_flag |= IN_ACCESS; 392 if (vap->va_mtime.tv_sec != VNOVAL) 393 ip->i_flag |= IN_CHANGE | IN_UPDATE; 394 error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 395 UPDATE_WAIT); 396 if (error) 397 return (error); 398 } 399 error = 0; 400 if (vap->va_mode != (mode_t)VNOVAL) { 401 if (vp->v_mount->mnt_flag & MNT_RDONLY) 402 return (EROFS); 403 error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p); 404 } 405 return (error); 406 } 407 408 /* 409 * Change the mode on a file. 410 * Inode must be locked before calling. 411 */ 412 static int 413 ext2fs_chmod(vp, mode, cred, p) 414 struct vnode *vp; 415 int mode; 416 struct ucred *cred; 417 struct proc *p; 418 { 419 struct inode *ip = VTOI(vp); 420 int error; 421 422 if (cred->cr_uid != ip->i_e2fs_uid && 423 (error = suser(cred, &p->p_acflag))) 424 return (error); 425 if (cred->cr_uid) { 426 if (vp->v_type != VDIR && (mode & S_ISTXT)) 427 return (EFTYPE); 428 if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID)) 429 return (EPERM); 430 } 431 ip->i_e2fs_mode &= ~ALLPERMS; 432 ip->i_e2fs_mode |= (mode & ALLPERMS); 433 ip->i_flag |= IN_CHANGE; 434 return (0); 435 } 436 437 /* 438 * Perform chown operation on inode ip; 439 * inode must be locked prior to call. 440 */ 441 static int 442 ext2fs_chown(vp, uid, gid, cred, p) 443 struct vnode *vp; 444 uid_t uid; 445 gid_t gid; 446 struct ucred *cred; 447 struct proc *p; 448 { 449 struct inode *ip = VTOI(vp); 450 uid_t ouid; 451 gid_t ogid; 452 int error = 0; 453 454 if (uid == (uid_t)VNOVAL) 455 uid = ip->i_e2fs_uid; 456 if (gid == (gid_t)VNOVAL) 457 gid = ip->i_e2fs_gid; 458 /* 459 * If we don't own the file, are trying to change the owner 460 * of the file, or are not a member of the target group, 461 * the caller must be superuser or the call fails. 462 */ 463 if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid || 464 (gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) && 465 (error = suser(cred, &p->p_acflag))) 466 return (error); 467 ogid = ip->i_e2fs_gid; 468 ouid = ip->i_e2fs_uid; 469 470 ip->i_e2fs_gid = gid; 471 ip->i_e2fs_uid = uid; 472 if (ouid != uid || ogid != gid) 473 ip->i_flag |= IN_CHANGE; 474 if (ouid != uid && cred->cr_uid != 0) 475 ip->i_e2fs_mode &= ~ISUID; 476 if (ogid != gid && cred->cr_uid != 0) 477 ip->i_e2fs_mode &= ~ISGID; 478 return (0); 479 } 480 481 int 482 ext2fs_remove(v) 483 void *v; 484 { 485 struct vop_remove_args /* { 486 struct vnode *a_dvp; 487 struct vnode *a_vp; 488 struct componentname *a_cnp; 489 } */ *ap = v; 490 struct inode *ip; 491 struct vnode *vp = ap->a_vp; 492 struct vnode *dvp = ap->a_dvp; 493 int error; 494 495 ip = VTOI(vp); 496 if (vp->v_type == VDIR || 497 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) || 498 (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) { 499 error = EPERM; 500 goto out; 501 } 502 error = ext2fs_dirremove(dvp, ap->a_cnp); 503 if (error == 0) { 504 ip->i_e2fs_nlink--; 505 ip->i_flag |= IN_CHANGE; 506 } 507 out: 508 if (dvp == vp) 509 vrele(vp); 510 else 511 vput(vp); 512 vput(dvp); 513 return (error); 514 } 515 516 /* 517 * link vnode call 518 */ 519 int 520 ext2fs_link(v) 521 void *v; 522 { 523 struct vop_link_args /* { 524 struct vnode *a_dvp; 525 struct vnode *a_vp; 526 struct componentname *a_cnp; 527 } */ *ap = v; 528 struct vnode *dvp = ap->a_dvp; 529 struct vnode *vp = ap->a_vp; 530 struct componentname *cnp = ap->a_cnp; 531 struct inode *ip; 532 int error; 533 534 #ifdef DIAGNOSTIC 535 if ((cnp->cn_flags & HASBUF) == 0) 536 panic("ext2fs_link: no name"); 537 #endif 538 if (vp->v_type == VDIR) { 539 VOP_ABORTOP(dvp, cnp); 540 error = EISDIR; 541 goto out2; 542 } 543 if (dvp->v_mount != vp->v_mount) { 544 VOP_ABORTOP(dvp, cnp); 545 error = EXDEV; 546 goto out2; 547 } 548 if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) { 549 VOP_ABORTOP(dvp, cnp); 550 goto out2; 551 } 552 ip = VTOI(vp); 553 if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) { 554 VOP_ABORTOP(dvp, cnp); 555 error = EMLINK; 556 goto out1; 557 } 558 if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) { 559 VOP_ABORTOP(dvp, cnp); 560 error = EPERM; 561 goto out1; 562 } 563 ip->i_e2fs_nlink++; 564 ip->i_flag |= IN_CHANGE; 565 error = VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT); 566 if (!error) 567 error = ext2fs_direnter(ip, dvp, cnp); 568 if (error) { 569 ip->i_e2fs_nlink--; 570 ip->i_flag |= IN_CHANGE; 571 } 572 PNBUF_PUT(cnp->cn_pnbuf); 573 out1: 574 if (dvp != vp) 575 VOP_UNLOCK(vp, 0); 576 out2: 577 vput(dvp); 578 return (error); 579 } 580 581 /* 582 * Rename system call. 583 * rename("foo", "bar"); 584 * is essentially 585 * unlink("bar"); 586 * link("foo", "bar"); 587 * unlink("foo"); 588 * but ``atomically''. Can't do full commit without saving state in the 589 * inode on disk which isn't feasible at this time. Best we can do is 590 * always guarantee the target exists. 591 * 592 * Basic algorithm is: 593 * 594 * 1) Bump link count on source while we're linking it to the 595 * target. This also ensure the inode won't be deleted out 596 * from underneath us while we work (it may be truncated by 597 * a concurrent `trunc' or `open' for creation). 598 * 2) Link source to destination. If destination already exists, 599 * delete it first. 600 * 3) Unlink source reference to inode if still around. If a 601 * directory was moved and the parent of the destination 602 * is different from the source, patch the ".." entry in the 603 * directory. 604 */ 605 int 606 ext2fs_rename(v) 607 void *v; 608 { 609 struct vop_rename_args /* { 610 struct vnode *a_fdvp; 611 struct vnode *a_fvp; 612 struct componentname *a_fcnp; 613 struct vnode *a_tdvp; 614 struct vnode *a_tvp; 615 struct componentname *a_tcnp; 616 } */ *ap = v; 617 struct vnode *tvp = ap->a_tvp; 618 struct vnode *tdvp = ap->a_tdvp; 619 struct vnode *fvp = ap->a_fvp; 620 struct vnode *fdvp = ap->a_fdvp; 621 struct componentname *tcnp = ap->a_tcnp; 622 struct componentname *fcnp = ap->a_fcnp; 623 struct inode *ip, *xp, *dp; 624 struct ext2fs_dirtemplate dirbuf; 625 int doingdirectory = 0, oldparent = 0, newparent = 0; 626 int error = 0; 627 u_char namlen; 628 629 #ifdef DIAGNOSTIC 630 if ((tcnp->cn_flags & HASBUF) == 0 || 631 (fcnp->cn_flags & HASBUF) == 0) 632 panic("ext2fs_rename: no name"); 633 #endif 634 /* 635 * Check for cross-device rename. 636 */ 637 if ((fvp->v_mount != tdvp->v_mount) || 638 (tvp && (fvp->v_mount != tvp->v_mount))) { 639 error = EXDEV; 640 abortit: 641 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */ 642 if (tdvp == tvp) 643 vrele(tdvp); 644 else 645 vput(tdvp); 646 if (tvp) 647 vput(tvp); 648 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ 649 vrele(fdvp); 650 vrele(fvp); 651 return (error); 652 } 653 654 /* 655 * Check if just deleting a link name. 656 */ 657 if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) || 658 (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) { 659 error = EPERM; 660 goto abortit; 661 } 662 if (fvp == tvp) { 663 if (fvp->v_type == VDIR) { 664 error = EINVAL; 665 goto abortit; 666 } 667 668 /* Release destination completely. */ 669 VOP_ABORTOP(tdvp, tcnp); 670 vput(tdvp); 671 vput(tvp); 672 673 /* Delete source. */ 674 vrele(fdvp); 675 vrele(fvp); 676 fcnp->cn_flags &= ~MODMASK; 677 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 678 if ((fcnp->cn_flags & SAVESTART) == 0) 679 panic("ext2fs_rename: lost from startdir"); 680 fcnp->cn_nameiop = DELETE; 681 (void) relookup(fdvp, &fvp, fcnp); 682 return (VOP_REMOVE(fdvp, fvp, fcnp)); 683 } 684 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 685 goto abortit; 686 dp = VTOI(fdvp); 687 ip = VTOI(fvp); 688 if ((nlink_t) ip->i_e2fs_nlink >= LINK_MAX) { 689 VOP_UNLOCK(fvp, 0); 690 error = EMLINK; 691 goto abortit; 692 } 693 if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) || 694 (dp->i_e2fs_flags & EXT2_APPEND)) { 695 VOP_UNLOCK(fvp, 0); 696 error = EPERM; 697 goto abortit; 698 } 699 if ((ip->i_e2fs_mode & IFMT) == IFDIR) { 700 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 701 if (!error && tvp) 702 error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, 703 tcnp->cn_proc); 704 if (error) { 705 VOP_UNLOCK(fvp, 0); 706 error = EACCES; 707 goto abortit; 708 } 709 /* 710 * Avoid ".", "..", and aliases of "." for obvious reasons. 711 */ 712 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 713 dp == ip || 714 (fcnp->cn_flags&ISDOTDOT) || 715 (tcnp->cn_flags & ISDOTDOT) || 716 (ip->i_flag & IN_RENAME)) { 717 VOP_UNLOCK(fvp, 0); 718 error = EINVAL; 719 goto abortit; 720 } 721 ip->i_flag |= IN_RENAME; 722 oldparent = dp->i_number; 723 doingdirectory++; 724 } 725 vrele(fdvp); 726 727 /* 728 * When the target exists, both the directory 729 * and target vnodes are returned locked. 730 */ 731 dp = VTOI(tdvp); 732 xp = NULL; 733 if (tvp) 734 xp = VTOI(tvp); 735 736 /* 737 * 1) Bump link count while we're moving stuff 738 * around. If we crash somewhere before 739 * completing our work, the link count 740 * may be wrong, but correctable. 741 */ 742 ip->i_e2fs_nlink++; 743 ip->i_flag |= IN_CHANGE; 744 if ((error = VOP_UPDATE(fvp, NULL, NULL, UPDATE_WAIT)) != 0) { 745 VOP_UNLOCK(fvp, 0); 746 goto bad; 747 } 748 749 /* 750 * If ".." must be changed (ie the directory gets a new 751 * parent) then the source directory must not be in the 752 * directory hierarchy above the target, as this would 753 * orphan everything below the source directory. Also 754 * the user must have write permission in the source so 755 * as to be able to change "..". We must repeat the call 756 * to namei, as the parent directory is unlocked by the 757 * call to checkpath(). 758 */ 759 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 760 VOP_UNLOCK(fvp, 0); 761 if (oldparent != dp->i_number) 762 newparent = dp->i_number; 763 if (doingdirectory && newparent) { 764 if (error) /* write access check above */ 765 goto bad; 766 if (xp != NULL) 767 vput(tvp); 768 error = ext2fs_checkpath(ip, dp, tcnp->cn_cred); 769 if (error != 0) 770 goto out; 771 if ((tcnp->cn_flags & SAVESTART) == 0) 772 panic("ext2fs_rename: lost to startdir"); 773 if ((error = relookup(tdvp, &tvp, tcnp)) != 0) 774 goto out; 775 dp = VTOI(tdvp); 776 xp = NULL; 777 if (tvp) 778 xp = VTOI(tvp); 779 } 780 /* 781 * 2) If target doesn't exist, link the target 782 * to the source and unlink the source. 783 * Otherwise, rewrite the target directory 784 * entry to reference the source inode and 785 * expunge the original entry's existence. 786 */ 787 if (xp == NULL) { 788 if (dp->i_dev != ip->i_dev) 789 panic("rename: EXDEV"); 790 /* 791 * Account for ".." in new directory. 792 * When source and destination have the same 793 * parent we don't fool with the link count. 794 */ 795 if (doingdirectory && newparent) { 796 if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) { 797 error = EMLINK; 798 goto bad; 799 } 800 dp->i_e2fs_nlink++; 801 dp->i_flag |= IN_CHANGE; 802 if ((error = VOP_UPDATE(tdvp, NULL, NULL, UPDATE_WAIT)) 803 != 0) 804 goto bad; 805 } 806 error = ext2fs_direnter(ip, tdvp, tcnp); 807 if (error != 0) { 808 if (doingdirectory && newparent) { 809 dp->i_e2fs_nlink--; 810 dp->i_flag |= IN_CHANGE; 811 (void)VOP_UPDATE(tdvp, NULL, NULL, UPDATE_WAIT); 812 } 813 goto bad; 814 } 815 vput(tdvp); 816 } else { 817 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 818 panic("rename: EXDEV"); 819 /* 820 * Short circuit rename(foo, foo). 821 */ 822 if (xp->i_number == ip->i_number) 823 panic("rename: same file"); 824 /* 825 * If the parent directory is "sticky", then the user must 826 * own the parent directory, or the destination of the rename, 827 * otherwise the destination may not be changed (except by 828 * root). This implements append-only directories. 829 */ 830 if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && 831 tcnp->cn_cred->cr_uid != dp->i_e2fs_uid && 832 xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) { 833 error = EPERM; 834 goto bad; 835 } 836 /* 837 * Target must be empty if a directory and have no links 838 * to it. Also, ensure source and target are compatible 839 * (both directories, or both not directories). 840 */ 841 if ((xp->i_e2fs_mode & IFMT) == IFDIR) { 842 if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) || 843 xp->i_e2fs_nlink > 2) { 844 error = ENOTEMPTY; 845 goto bad; 846 } 847 if (!doingdirectory) { 848 error = ENOTDIR; 849 goto bad; 850 } 851 cache_purge(tdvp); 852 } else if (doingdirectory) { 853 error = EISDIR; 854 goto bad; 855 } 856 error = ext2fs_dirrewrite(dp, ip, tcnp); 857 if (error != 0) 858 goto bad; 859 /* 860 * If the target directory is in the same 861 * directory as the source directory, 862 * decrement the link count on the parent 863 * of the target directory. 864 */ 865 if (doingdirectory && !newparent) { 866 dp->i_e2fs_nlink--; 867 dp->i_flag |= IN_CHANGE; 868 } 869 vput(tdvp); 870 /* 871 * Adjust the link count of the target to 872 * reflect the dirrewrite above. If this is 873 * a directory it is empty and there are 874 * no links to it, so we can squash the inode and 875 * any space associated with it. We disallowed 876 * renaming over top of a directory with links to 877 * it above, as the remaining link would point to 878 * a directory without "." or ".." entries. 879 */ 880 xp->i_e2fs_nlink--; 881 if (doingdirectory) { 882 if (--xp->i_e2fs_nlink != 0) 883 panic("rename: linked directory"); 884 error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC, 885 tcnp->cn_cred, tcnp->cn_proc); 886 } 887 xp->i_flag |= IN_CHANGE; 888 vput(tvp); 889 xp = NULL; 890 } 891 892 /* 893 * 3) Unlink the source. 894 */ 895 fcnp->cn_flags &= ~MODMASK; 896 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 897 if ((fcnp->cn_flags & SAVESTART) == 0) 898 panic("ext2fs_rename: lost from startdir"); 899 (void) relookup(fdvp, &fvp, fcnp); 900 if (fvp != NULL) { 901 xp = VTOI(fvp); 902 dp = VTOI(fdvp); 903 } else { 904 /* 905 * From name has disappeared. 906 */ 907 if (doingdirectory) 908 panic("ext2fs_rename: lost dir entry"); 909 vrele(ap->a_fvp); 910 return (0); 911 } 912 /* 913 * Ensure that the directory entry still exists and has not 914 * changed while the new name has been entered. If the source is 915 * a file then the entry may have been unlinked or renamed. In 916 * either case there is no further work to be done. If the source 917 * is a directory then it cannot have been rmdir'ed; its link 918 * count of three would cause a rmdir to fail with ENOTEMPTY. 919 * The IRENAME flag ensures that it cannot be moved by another 920 * rename. 921 */ 922 if (xp != ip) { 923 if (doingdirectory) 924 panic("ext2fs_rename: lost dir entry"); 925 } else { 926 /* 927 * If the source is a directory with a 928 * new parent, the link count of the old 929 * parent directory must be decremented 930 * and ".." set to point to the new parent. 931 */ 932 if (doingdirectory && newparent) { 933 dp->i_e2fs_nlink--; 934 dp->i_flag |= IN_CHANGE; 935 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf, 936 sizeof (struct ext2fs_dirtemplate), (off_t)0, 937 UIO_SYSSPACE, IO_NODELOCKED, 938 tcnp->cn_cred, (size_t *)0, (struct proc *)0); 939 if (error == 0) { 940 namlen = dirbuf.dotdot_namlen; 941 if (namlen != 2 || 942 dirbuf.dotdot_name[0] != '.' || 943 dirbuf.dotdot_name[1] != '.') { 944 ufs_dirbad(xp, (doff_t)12, 945 "ext2fs_rename: mangled dir"); 946 } else { 947 dirbuf.dotdot_ino = h2fs32(newparent); 948 (void) vn_rdwr(UIO_WRITE, fvp, 949 (caddr_t)&dirbuf, 950 sizeof (struct dirtemplate), 951 (off_t)0, UIO_SYSSPACE, 952 IO_NODELOCKED|IO_SYNC, 953 tcnp->cn_cred, (size_t *)0, 954 (struct proc *)0); 955 cache_purge(fdvp); 956 } 957 } 958 } 959 error = ext2fs_dirremove(fdvp, fcnp); 960 if (!error) { 961 xp->i_e2fs_nlink--; 962 xp->i_flag |= IN_CHANGE; 963 } 964 xp->i_flag &= ~IN_RENAME; 965 } 966 if (dp) 967 vput(fdvp); 968 if (xp) 969 vput(fvp); 970 vrele(ap->a_fvp); 971 return (error); 972 973 bad: 974 if (xp) 975 vput(ITOV(xp)); 976 vput(ITOV(dp)); 977 out: 978 if (doingdirectory) 979 ip->i_flag &= ~IN_RENAME; 980 if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { 981 ip->i_e2fs_nlink--; 982 ip->i_flag |= IN_CHANGE; 983 vput(fvp); 984 } else 985 vrele(fvp); 986 return (error); 987 } 988 989 /* 990 * Mkdir system call 991 */ 992 int 993 ext2fs_mkdir(v) 994 void *v; 995 { 996 struct vop_mkdir_args /* { 997 struct vnode *a_dvp; 998 struct vnode **a_vpp; 999 struct componentname *a_cnp; 1000 struct vattr *a_vap; 1001 } */ *ap = v; 1002 struct vnode *dvp = ap->a_dvp; 1003 struct vattr *vap = ap->a_vap; 1004 struct componentname *cnp = ap->a_cnp; 1005 struct inode *ip, *dp; 1006 struct vnode *tvp; 1007 struct ext2fs_dirtemplate dirtemplate; 1008 int error, dmode; 1009 1010 #ifdef DIAGNOSTIC 1011 if ((cnp->cn_flags & HASBUF) == 0) 1012 panic("ext2fs_mkdir: no name"); 1013 #endif 1014 dp = VTOI(dvp); 1015 if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) { 1016 error = EMLINK; 1017 goto out; 1018 } 1019 dmode = vap->va_mode & ACCESSPERMS; 1020 dmode |= IFDIR; 1021 /* 1022 * Must simulate part of ext2fs_makeinode here to acquire the inode, 1023 * but not have it entered in the parent directory. The entry is 1024 * made later after writing "." and ".." entries. 1025 */ 1026 if ((error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) != 0) 1027 goto out; 1028 ip = VTOI(tvp); 1029 ip->i_e2fs_uid = cnp->cn_cred->cr_uid; 1030 ip->i_e2fs_gid = dp->i_e2fs_gid; 1031 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1032 ip->i_e2fs_mode = dmode; 1033 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ 1034 ip->i_e2fs_nlink = 2; 1035 error = VOP_UPDATE(tvp, NULL, NULL, UPDATE_WAIT); 1036 1037 /* 1038 * Bump link count in parent directory 1039 * to reflect work done below. Should 1040 * be done before reference is created 1041 * so reparation is possible if we crash. 1042 */ 1043 dp->i_e2fs_nlink++; 1044 dp->i_flag |= IN_CHANGE; 1045 if ((error = VOP_UPDATE(dvp, NULL, NULL, UPDATE_WAIT)) != 0) 1046 goto bad; 1047 1048 /* Initialize directory with "." and ".." from static template. */ 1049 memset(&dirtemplate, 0, sizeof(dirtemplate)); 1050 dirtemplate.dot_ino = h2fs32(ip->i_number); 1051 dirtemplate.dot_reclen = h2fs16(12); 1052 dirtemplate.dot_namlen = 1; 1053 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 && 1054 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) { 1055 dirtemplate.dot_type = EXT2_FT_DIR; 1056 } 1057 dirtemplate.dot_name[0] = '.'; 1058 dirtemplate.dotdot_ino = h2fs32(dp->i_number); 1059 dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12); 1060 dirtemplate.dotdot_namlen = 2; 1061 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 && 1062 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) { 1063 dirtemplate.dotdot_type = EXT2_FT_DIR; 1064 } 1065 dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.'; 1066 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, 1067 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 1068 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0); 1069 if (error) { 1070 dp->i_e2fs_nlink--; 1071 dp->i_flag |= IN_CHANGE; 1072 goto bad; 1073 } 1074 if (VTOI(dvp)->i_e2fs->e2fs_bsize > 1075 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 1076 panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */ 1077 else { 1078 ip->i_e2fs_size = VTOI(dvp)->i_e2fs->e2fs_bsize; 1079 ip->i_flag |= IN_CHANGE; 1080 } 1081 1082 /* Directory set up, now install it's entry in the parent directory. */ 1083 error = ext2fs_direnter(ip, dvp, cnp); 1084 if (error != 0) { 1085 dp->i_e2fs_nlink--; 1086 dp->i_flag |= IN_CHANGE; 1087 } 1088 bad: 1089 /* 1090 * No need to do an explicit VOP_TRUNCATE here, vrele will do this 1091 * for us because we set the link count to 0. 1092 */ 1093 if (error) { 1094 ip->i_e2fs_nlink = 0; 1095 ip->i_flag |= IN_CHANGE; 1096 vput(tvp); 1097 } else 1098 *ap->a_vpp = tvp; 1099 out: 1100 PNBUF_PUT(cnp->cn_pnbuf); 1101 vput(dvp); 1102 return (error); 1103 } 1104 1105 /* 1106 * Rmdir system call. 1107 */ 1108 int 1109 ext2fs_rmdir(v) 1110 void *v; 1111 { 1112 struct vop_rmdir_args /* { 1113 struct vnode *a_dvp; 1114 struct vnode *a_vp; 1115 struct componentname *a_cnp; 1116 } */ *ap = v; 1117 struct vnode *vp = ap->a_vp; 1118 struct vnode *dvp = ap->a_dvp; 1119 struct componentname *cnp = ap->a_cnp; 1120 struct inode *ip, *dp; 1121 int error; 1122 1123 ip = VTOI(vp); 1124 dp = VTOI(dvp); 1125 /* 1126 * No rmdir "." please. 1127 */ 1128 if (dp == ip) { 1129 vrele(dvp); 1130 vput(vp); 1131 return (EINVAL); 1132 } 1133 /* 1134 * Verify the directory is empty (and valid). 1135 * (Rmdir ".." won't be valid since 1136 * ".." will contain a reference to 1137 * the current directory and thus be 1138 * non-empty.) 1139 */ 1140 error = 0; 1141 if (ip->i_e2fs_nlink != 2 || 1142 !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 1143 error = ENOTEMPTY; 1144 goto out; 1145 } 1146 if ((dp->i_e2fs_flags & EXT2_APPEND) || 1147 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) { 1148 error = EPERM; 1149 goto out; 1150 } 1151 /* 1152 * Delete reference to directory before purging 1153 * inode. If we crash in between, the directory 1154 * will be reattached to lost+found, 1155 */ 1156 error = ext2fs_dirremove(dvp, cnp); 1157 if (error != 0) 1158 goto out; 1159 dp->i_e2fs_nlink--; 1160 dp->i_flag |= IN_CHANGE; 1161 cache_purge(dvp); 1162 vput(dvp); 1163 dvp = NULL; 1164 /* 1165 * Truncate inode. The only stuff left 1166 * in the directory is "." and "..". The 1167 * "." reference is inconsequential since 1168 * we're quashing it. The ".." reference 1169 * has already been adjusted above. We've 1170 * removed the "." reference and the reference 1171 * in the parent directory, but there may be 1172 * other hard links so decrement by 2 and 1173 * worry about them later. 1174 */ 1175 ip->i_e2fs_nlink -= 2; 1176 error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, 1177 cnp->cn_proc); 1178 cache_purge(ITOV(ip)); 1179 out: 1180 if (dvp) 1181 vput(dvp); 1182 vput(vp); 1183 return (error); 1184 } 1185 1186 /* 1187 * symlink -- make a symbolic link 1188 */ 1189 int 1190 ext2fs_symlink(v) 1191 void *v; 1192 { 1193 struct vop_symlink_args /* { 1194 struct vnode *a_dvp; 1195 struct vnode **a_vpp; 1196 struct componentname *a_cnp; 1197 struct vattr *a_vap; 1198 char *a_target; 1199 } */ *ap = v; 1200 struct vnode *vp, **vpp = ap->a_vpp; 1201 struct inode *ip; 1202 int len, error; 1203 1204 error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, 1205 vpp, ap->a_cnp); 1206 if (error) 1207 return (error); 1208 vp = *vpp; 1209 len = strlen(ap->a_target); 1210 if (len < vp->v_mount->mnt_maxsymlinklen) { 1211 ip = VTOI(vp); 1212 memcpy((char *)ip->i_din.e2fs_din.e2di_shortlink, ap->a_target, len); 1213 ip->i_e2fs_size = len; 1214 ip->i_flag |= IN_CHANGE | IN_UPDATE; 1215 } else 1216 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 1217 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, 1218 (size_t *)0, (struct proc *)0); 1219 if (error) 1220 vput(vp); 1221 return (error); 1222 } 1223 1224 /* 1225 * Return target name of a symbolic link 1226 */ 1227 int 1228 ext2fs_readlink(v) 1229 void *v; 1230 { 1231 struct vop_readlink_args /* { 1232 struct vnode *a_vp; 1233 struct uio *a_uio; 1234 struct ucred *a_cred; 1235 } */ *ap = v; 1236 struct vnode *vp = ap->a_vp; 1237 struct inode *ip = VTOI(vp); 1238 int isize; 1239 1240 isize = ip->i_e2fs_size; 1241 if (isize < vp->v_mount->mnt_maxsymlinklen || 1242 (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) { 1243 uiomove((char *)ip->i_din.e2fs_din.e2di_shortlink, isize, ap->a_uio); 1244 return (0); 1245 } 1246 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); 1247 } 1248 1249 /* 1250 * Advisory record locking support 1251 */ 1252 int 1253 ext2fs_advlock(v) 1254 void *v; 1255 { 1256 struct vop_advlock_args /* { 1257 struct vnode *a_vp; 1258 caddr_t a_id; 1259 int a_op; 1260 struct flock *a_fl; 1261 int a_flags; 1262 } */ *ap = v; 1263 struct inode *ip = VTOI(ap->a_vp); 1264 1265 return lf_advlock(ap, &ip->i_lockf, ip->i_e2fs_size); 1266 } 1267 1268 /* 1269 * Initialize the vnode associated with a new inode, handle aliased 1270 * vnodes. 1271 */ 1272 int 1273 ext2fs_vinit(mntp, specops, fifoops, vpp) 1274 struct mount *mntp; 1275 int (**specops) __P((void *)); 1276 int (**fifoops) __P((void *)); 1277 struct vnode **vpp; 1278 { 1279 struct inode *ip; 1280 struct vnode *vp, *nvp; 1281 1282 vp = *vpp; 1283 ip = VTOI(vp); 1284 switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) { 1285 case VCHR: 1286 case VBLK: 1287 vp->v_op = specops; 1288 if ((nvp = checkalias(vp, 1289 fs2h32(ip->i_din.e2fs_din.e2di_rdev), mntp)) != NULL) { 1290 /* 1291 * Discard unneeded vnode, but save its inode. 1292 */ 1293 nvp->v_data = vp->v_data; 1294 vp->v_data = NULL; 1295 VOP_UNLOCK(vp, 0); 1296 vp->v_op = spec_vnodeop_p; 1297 vrele(vp); 1298 vgone(vp); 1299 lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock); 1300 /* 1301 * Reinitialize aliased inode. 1302 */ 1303 vp = nvp; 1304 ip->i_vnode = vp; 1305 } 1306 break; 1307 case VFIFO: 1308 vp->v_op = fifoops; 1309 break; 1310 case VNON: 1311 case VBAD: 1312 case VSOCK: 1313 case VLNK: 1314 case VDIR: 1315 case VREG: 1316 break; 1317 } 1318 if (ip->i_number == ROOTINO) 1319 vp->v_flag |= VROOT; 1320 /* 1321 * Initialize modrev times 1322 */ 1323 SETHIGH(ip->i_modrev, mono_time.tv_sec); 1324 SETLOW(ip->i_modrev, mono_time.tv_usec * 4294); 1325 *vpp = vp; 1326 return (0); 1327 } 1328 1329 /* 1330 * Allocate a new inode. 1331 */ 1332 int 1333 ext2fs_makeinode(mode, dvp, vpp, cnp) 1334 int mode; 1335 struct vnode *dvp; 1336 struct vnode **vpp; 1337 struct componentname *cnp; 1338 { 1339 struct inode *ip, *pdir; 1340 struct vnode *tvp; 1341 int error; 1342 1343 pdir = VTOI(dvp); 1344 #ifdef DIAGNOSTIC 1345 if ((cnp->cn_flags & HASBUF) == 0) 1346 panic("ext2fs_makeinode: no name"); 1347 #endif 1348 *vpp = NULL; 1349 if ((mode & IFMT) == 0) 1350 mode |= IFREG; 1351 1352 if ((error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) != 0) { 1353 PNBUF_PUT(cnp->cn_pnbuf); 1354 vput(dvp); 1355 return (error); 1356 } 1357 ip = VTOI(tvp); 1358 ip->i_e2fs_gid = pdir->i_e2fs_gid; 1359 ip->i_e2fs_uid = cnp->cn_cred->cr_uid; 1360 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1361 ip->i_e2fs_mode = mode; 1362 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ 1363 ip->i_e2fs_nlink = 1; 1364 if ((ip->i_e2fs_mode & ISGID) && 1365 !groupmember(ip->i_e2fs_gid, cnp->cn_cred) && 1366 suser(cnp->cn_cred, NULL)) 1367 ip->i_e2fs_mode &= ~ISGID; 1368 1369 /* 1370 * Make sure inode goes to disk before directory entry. 1371 */ 1372 if ((error = VOP_UPDATE(tvp, NULL, NULL, UPDATE_WAIT)) != 0) 1373 goto bad; 1374 error = ext2fs_direnter(ip, dvp, cnp); 1375 if (error != 0) 1376 goto bad; 1377 if ((cnp->cn_flags & SAVESTART) == 0) 1378 PNBUF_PUT(cnp->cn_pnbuf); 1379 vput(dvp); 1380 *vpp = tvp; 1381 return (0); 1382 1383 bad: 1384 /* 1385 * Write error occurred trying to update the inode 1386 * or the directory so must deallocate the inode. 1387 */ 1388 PNBUF_PUT(cnp->cn_pnbuf); 1389 vput(dvp); 1390 ip->i_e2fs_nlink = 0; 1391 ip->i_flag |= IN_CHANGE; 1392 vput(tvp); 1393 return (error); 1394 } 1395 1396 /* 1397 * Reclaim an inode so that it can be used for other purposes. 1398 */ 1399 int 1400 ext2fs_reclaim(v) 1401 void *v; 1402 { 1403 struct vop_reclaim_args /* { 1404 struct vnode *a_vp; 1405 } */ *ap = v; 1406 struct vnode *vp = ap->a_vp; 1407 struct inode *ip; 1408 1409 if (prtactive && vp->v_usecount != 0) 1410 vprint("ext2fs_reclaim: pushing active", vp); 1411 /* 1412 * Remove the inode from its hash chain. 1413 */ 1414 ip = VTOI(vp); 1415 ufs_ihashrem(ip); 1416 /* 1417 * Purge old data structures associated with the inode. 1418 */ 1419 cache_purge(vp); 1420 if (ip->i_devvp) { 1421 vrele(ip->i_devvp); 1422 ip->i_devvp = 0; 1423 } 1424 1425 pool_put(&ext2fs_inode_pool, vp->v_data); 1426 vp->v_data = NULL; 1427 return (0); 1428 } 1429 1430 /* Global vfs data structures for ext2fs. */ 1431 int (**ext2fs_vnodeop_p) __P((void *)); 1432 const struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = { 1433 { &vop_default_desc, vn_default_error }, 1434 { &vop_lookup_desc, ext2fs_lookup }, /* lookup */ 1435 { &vop_create_desc, ext2fs_create }, /* create */ 1436 { &vop_mknod_desc, ext2fs_mknod }, /* mknod */ 1437 { &vop_open_desc, ext2fs_open }, /* open */ 1438 { &vop_close_desc, ufs_close }, /* close */ 1439 { &vop_access_desc, ext2fs_access }, /* access */ 1440 { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 1441 { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 1442 { &vop_read_desc, ext2fs_read }, /* read */ 1443 { &vop_write_desc, ext2fs_write }, /* write */ 1444 { &vop_lease_desc, ufs_lease_check }, /* lease */ 1445 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 1446 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 1447 { &vop_poll_desc, ufs_poll }, /* poll */ 1448 { &vop_revoke_desc, ufs_revoke }, /* revoke */ 1449 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 1450 { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 1451 { &vop_seek_desc, ufs_seek }, /* seek */ 1452 { &vop_remove_desc, ext2fs_remove }, /* remove */ 1453 { &vop_link_desc, ext2fs_link }, /* link */ 1454 { &vop_rename_desc, ext2fs_rename }, /* rename */ 1455 { &vop_mkdir_desc, ext2fs_mkdir }, /* mkdir */ 1456 { &vop_rmdir_desc, ext2fs_rmdir }, /* rmdir */ 1457 { &vop_symlink_desc, ext2fs_symlink }, /* symlink */ 1458 { &vop_readdir_desc, ext2fs_readdir }, /* readdir */ 1459 { &vop_readlink_desc, ext2fs_readlink }, /* readlink */ 1460 { &vop_abortop_desc, ufs_abortop }, /* abortop */ 1461 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */ 1462 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1463 { &vop_lock_desc, ufs_lock }, /* lock */ 1464 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1465 { &vop_bmap_desc, ext2fs_bmap }, /* bmap */ 1466 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 1467 { &vop_print_desc, ufs_print }, /* print */ 1468 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1469 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 1470 { &vop_advlock_desc, ext2fs_advlock }, /* advlock */ 1471 { &vop_blkatoff_desc, ext2fs_blkatoff }, /* blkatoff */ 1472 { &vop_valloc_desc, ext2fs_valloc }, /* valloc */ 1473 { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 1474 { &vop_truncate_desc, ext2fs_truncate }, /* truncate */ 1475 { &vop_update_desc, ext2fs_update }, /* update */ 1476 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1477 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 1478 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 1479 { NULL, NULL } 1480 }; 1481 const struct vnodeopv_desc ext2fs_vnodeop_opv_desc = 1482 { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries }; 1483 1484 int (**ext2fs_specop_p) __P((void *)); 1485 const struct vnodeopv_entry_desc ext2fs_specop_entries[] = { 1486 { &vop_default_desc, vn_default_error }, 1487 { &vop_lookup_desc, spec_lookup }, /* lookup */ 1488 { &vop_create_desc, spec_create }, /* create */ 1489 { &vop_mknod_desc, spec_mknod }, /* mknod */ 1490 { &vop_open_desc, spec_open }, /* open */ 1491 { &vop_close_desc, ufsspec_close }, /* close */ 1492 { &vop_access_desc, ext2fs_access }, /* access */ 1493 { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 1494 { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 1495 { &vop_read_desc, ufsspec_read }, /* read */ 1496 { &vop_write_desc, ufsspec_write }, /* write */ 1497 { &vop_lease_desc, spec_lease_check }, /* lease */ 1498 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 1499 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 1500 { &vop_poll_desc, spec_poll }, /* poll */ 1501 { &vop_revoke_desc, spec_revoke }, /* revoke */ 1502 { &vop_mmap_desc, spec_mmap }, /* mmap */ 1503 { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 1504 { &vop_seek_desc, spec_seek }, /* seek */ 1505 { &vop_remove_desc, spec_remove }, /* remove */ 1506 { &vop_link_desc, spec_link }, /* link */ 1507 { &vop_rename_desc, spec_rename }, /* rename */ 1508 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 1509 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 1510 { &vop_symlink_desc, spec_symlink }, /* symlink */ 1511 { &vop_readdir_desc, spec_readdir }, /* readdir */ 1512 { &vop_readlink_desc, spec_readlink }, /* readlink */ 1513 { &vop_abortop_desc, spec_abortop }, /* abortop */ 1514 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */ 1515 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1516 { &vop_lock_desc, ufs_lock }, /* lock */ 1517 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1518 { &vop_bmap_desc, spec_bmap }, /* bmap */ 1519 { &vop_strategy_desc, spec_strategy }, /* strategy */ 1520 { &vop_print_desc, ufs_print }, /* print */ 1521 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1522 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 1523 { &vop_advlock_desc, spec_advlock }, /* advlock */ 1524 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 1525 { &vop_valloc_desc, spec_valloc }, /* valloc */ 1526 { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 1527 { &vop_truncate_desc, spec_truncate }, /* truncate */ 1528 { &vop_update_desc, ext2fs_update }, /* update */ 1529 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1530 { &vop_getpages_desc, spec_getpages }, /* getpages */ 1531 { &vop_putpages_desc, spec_putpages }, /* putpages */ 1532 { NULL, NULL } 1533 }; 1534 const struct vnodeopv_desc ext2fs_specop_opv_desc = 1535 { &ext2fs_specop_p, ext2fs_specop_entries }; 1536 1537 int (**ext2fs_fifoop_p) __P((void *)); 1538 const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = { 1539 { &vop_default_desc, vn_default_error }, 1540 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 1541 { &vop_create_desc, fifo_create }, /* create */ 1542 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 1543 { &vop_open_desc, fifo_open }, /* open */ 1544 { &vop_close_desc, ufsfifo_close }, /* close */ 1545 { &vop_access_desc, ext2fs_access }, /* access */ 1546 { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 1547 { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 1548 { &vop_read_desc, ufsfifo_read }, /* read */ 1549 { &vop_write_desc, ufsfifo_write }, /* write */ 1550 { &vop_lease_desc, fifo_lease_check }, /* lease */ 1551 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 1552 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 1553 { &vop_poll_desc, fifo_poll }, /* poll */ 1554 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 1555 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 1556 { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 1557 { &vop_seek_desc, fifo_seek }, /* seek */ 1558 { &vop_remove_desc, fifo_remove }, /* remove */ 1559 { &vop_link_desc, fifo_link }, /* link */ 1560 { &vop_rename_desc, fifo_rename }, /* rename */ 1561 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 1562 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 1563 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 1564 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 1565 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 1566 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 1567 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */ 1568 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1569 { &vop_lock_desc, ufs_lock }, /* lock */ 1570 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1571 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 1572 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 1573 { &vop_print_desc, ufs_print }, /* print */ 1574 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1575 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 1576 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 1577 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 1578 { &vop_valloc_desc, fifo_valloc }, /* valloc */ 1579 { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 1580 { &vop_truncate_desc, fifo_truncate }, /* truncate */ 1581 { &vop_update_desc, ext2fs_update }, /* update */ 1582 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1583 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 1584 { NULL, NULL } 1585 }; 1586 const struct vnodeopv_desc ext2fs_fifoop_opv_desc = 1587 { &ext2fs_fifoop_p, ext2fs_fifoop_entries }; 1588