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