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