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