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