1 /* $NetBSD: ext2fs_vnops.c,v 1.3 1997/07/01 07:34:03 bouyer 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 = 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)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 != 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 = 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 = 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 * A virgin directory (no blushing please). 946 */ 947 static struct ext2fs_dirtemplate mastertemplate = { 948 0, 12, 1, ".", 949 0, - 12, 2, ".." /* XXX -12 should be e2fs_bsize-12 */ 950 }; 951 952 /* 953 * Mkdir system call 954 */ 955 int 956 ext2fs_mkdir(v) 957 void *v; 958 { 959 struct vop_mkdir_args /* { 960 struct vnode *a_dvp; 961 struct vnode **a_vpp; 962 struct componentname *a_cnp; 963 struct vattr *a_vap; 964 } */ *ap = v; 965 register struct vnode *dvp = ap->a_dvp; 966 register struct vattr *vap = ap->a_vap; 967 register struct componentname *cnp = ap->a_cnp; 968 register struct inode *ip, *dp; 969 struct vnode *tvp; 970 struct ext2fs_dirtemplate dirtemplate, *dtp; 971 struct timespec ts; 972 int error, dmode; 973 974 #ifdef DIAGNOSTIC 975 if ((cnp->cn_flags & HASBUF) == 0) 976 panic("ext2fs_mkdir: no name"); 977 #endif 978 dp = VTOI(dvp); 979 if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) { 980 error = EMLINK; 981 goto out; 982 } 983 dmode = vap->va_mode & ACCESSPERMS; 984 dmode |= IFDIR; 985 /* 986 * Must simulate part of ext2fs_makeinode here to acquire the inode, 987 * but not have it entered in the parent directory. The entry is 988 * made later after writing "." and ".." entries. 989 */ 990 if ((error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) != 0) 991 goto out; 992 ip = VTOI(tvp); 993 ip->i_e2fs_uid = cnp->cn_cred->cr_uid; 994 ip->i_e2fs_gid = dp->i_e2fs_gid; 995 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 996 ip->i_e2fs_mode = dmode; 997 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ 998 ip->i_e2fs_nlink = 2; 999 TIMEVAL_TO_TIMESPEC(&time, &ts); 1000 error = VOP_UPDATE(tvp, &ts, &ts, 1); 1001 1002 /* 1003 * Bump link count in parent directory 1004 * to reflect work done below. Should 1005 * be done before reference is created 1006 * so reparation is possible if we crash. 1007 */ 1008 dp->i_e2fs_nlink++; 1009 dp->i_flag |= IN_CHANGE; 1010 if ((error = VOP_UPDATE(dvp, &ts, &ts, 1)) != 0) 1011 goto bad; 1012 1013 /* Initialize directory with "." and ".." from static template. */ 1014 dtp = &mastertemplate; 1015 dirtemplate = *dtp; 1016 dirtemplate.dot_ino = ip->i_number; 1017 dirtemplate.dotdot_ino = dp->i_number; 1018 /* Correct reclen of second entry */ 1019 dirtemplate.dotdot_reclen = VTOI(dvp)->i_e2fs->e2fs_bsize - 12; 1020 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, 1021 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 1022 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0); 1023 if (error) { 1024 dp->i_e2fs_nlink--; 1025 dp->i_flag |= IN_CHANGE; 1026 goto bad; 1027 } 1028 if (VTOI(dvp)->i_e2fs->e2fs_bsize > 1029 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 1030 panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */ 1031 else { 1032 ip->i_e2fs_size = VTOI(dvp)->i_e2fs->e2fs_bsize; 1033 ip->i_flag |= IN_CHANGE; 1034 } 1035 1036 /* Directory set up, now install it's entry in the parent directory. */ 1037 error = ext2fs_direnter(ip, dvp, cnp); 1038 if (error != 0) { 1039 dp->i_e2fs_nlink--; 1040 dp->i_flag |= IN_CHANGE; 1041 } 1042 bad: 1043 /* 1044 * No need to do an explicit VOP_TRUNCATE here, vrele will do this 1045 * for us because we set the link count to 0. 1046 */ 1047 if (error) { 1048 ip->i_e2fs_nlink = 0; 1049 ip->i_flag |= IN_CHANGE; 1050 vput(tvp); 1051 } else 1052 *ap->a_vpp = tvp; 1053 out: 1054 FREE(cnp->cn_pnbuf, M_NAMEI); 1055 vput(dvp); 1056 return (error); 1057 } 1058 1059 /* 1060 * Rmdir system call. 1061 */ 1062 int 1063 ext2fs_rmdir(v) 1064 void *v; 1065 { 1066 struct vop_rmdir_args /* { 1067 struct vnode *a_dvp; 1068 struct vnode *a_vp; 1069 struct componentname *a_cnp; 1070 } */ *ap = v; 1071 register struct vnode *vp = ap->a_vp; 1072 register struct vnode *dvp = ap->a_dvp; 1073 register struct componentname *cnp = ap->a_cnp; 1074 register struct inode *ip, *dp; 1075 int error; 1076 1077 ip = VTOI(vp); 1078 dp = VTOI(dvp); 1079 /* 1080 * No rmdir "." please. 1081 */ 1082 if (dp == ip) { 1083 vrele(dvp); 1084 vput(vp); 1085 return (EINVAL); 1086 } 1087 /* 1088 * Verify the directory is empty (and valid). 1089 * (Rmdir ".." won't be valid since 1090 * ".." will contain a reference to 1091 * the current directory and thus be 1092 * non-empty.) 1093 */ 1094 error = 0; 1095 if (ip->i_e2fs_nlink != 2 || 1096 !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 1097 error = ENOTEMPTY; 1098 goto out; 1099 } 1100 if ((dp->i_e2fs_flags & EXT2_APPEND) || 1101 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) { 1102 error = EPERM; 1103 goto out; 1104 } 1105 /* 1106 * Delete reference to directory before purging 1107 * inode. If we crash in between, the directory 1108 * will be reattached to lost+found, 1109 */ 1110 error = ext2fs_dirremove(dvp, cnp); 1111 if (error != 0) 1112 goto out; 1113 dp->i_e2fs_nlink--; 1114 dp->i_flag |= IN_CHANGE; 1115 cache_purge(dvp); 1116 vput(dvp); 1117 dvp = NULL; 1118 /* 1119 * Truncate inode. The only stuff left 1120 * in the directory is "." and "..". The 1121 * "." reference is inconsequential since 1122 * we're quashing it. The ".." reference 1123 * has already been adjusted above. We've 1124 * removed the "." reference and the reference 1125 * in the parent directory, but there may be 1126 * other hard links so decrement by 2 and 1127 * worry about them later. 1128 */ 1129 ip->i_e2fs_nlink -= 2; 1130 error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, 1131 cnp->cn_proc); 1132 cache_purge(ITOV(ip)); 1133 out: 1134 if (dvp) 1135 vput(dvp); 1136 vput(vp); 1137 return (error); 1138 } 1139 1140 /* 1141 * symlink -- make a symbolic link 1142 */ 1143 int 1144 ext2fs_symlink(v) 1145 void *v; 1146 { 1147 struct vop_symlink_args /* { 1148 struct vnode *a_dvp; 1149 struct vnode **a_vpp; 1150 struct componentname *a_cnp; 1151 struct vattr *a_vap; 1152 char *a_target; 1153 } */ *ap = v; 1154 register struct vnode *vp, **vpp = ap->a_vpp; 1155 register struct inode *ip; 1156 int len, error; 1157 1158 error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, 1159 vpp, ap->a_cnp); 1160 if (error) 1161 return (error); 1162 vp = *vpp; 1163 len = strlen(ap->a_target); 1164 if (len < vp->v_mount->mnt_maxsymlinklen) { 1165 ip = VTOI(vp); 1166 bcopy(ap->a_target, (char *)ip->i_din.e2fs_din.e2di_shortlink, len); 1167 ip->i_e2fs_size = len; 1168 ip->i_flag |= IN_CHANGE | IN_UPDATE; 1169 } else 1170 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 1171 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0, 1172 (struct proc *)0); 1173 vput(vp); 1174 return (error); 1175 } 1176 1177 /* 1178 * Return target name of a symbolic link 1179 */ 1180 int 1181 ext2fs_readlink(v) 1182 void *v; 1183 { 1184 struct vop_readlink_args /* { 1185 struct vnode *a_vp; 1186 struct uio *a_uio; 1187 struct ucred *a_cred; 1188 } */ *ap = v; 1189 register struct vnode *vp = ap->a_vp; 1190 register struct inode *ip = VTOI(vp); 1191 int isize; 1192 1193 isize = ip->i_e2fs_size; 1194 if (isize < vp->v_mount->mnt_maxsymlinklen || 1195 (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) { 1196 uiomove((char *)ip->i_din.e2fs_din.e2di_shortlink, isize, ap->a_uio); 1197 return (0); 1198 } 1199 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); 1200 } 1201 1202 /* 1203 * Advisory record locking support 1204 */ 1205 int 1206 ext2fs_advlock(v) 1207 void *v; 1208 { 1209 struct vop_advlock_args /* { 1210 struct vnode *a_vp; 1211 caddr_t a_id; 1212 int a_op; 1213 struct flock *a_fl; 1214 int a_flags; 1215 } */ *ap = v; 1216 register struct inode *ip = VTOI(ap->a_vp); 1217 1218 return (lf_advlock(&ip->i_lockf, ip->i_e2fs_size, ap->a_id, ap->a_op, 1219 ap->a_fl, ap->a_flags)); 1220 } 1221 1222 /* 1223 * Initialize the vnode associated with a new inode, handle aliased 1224 * vnodes. 1225 */ 1226 int 1227 ext2fs_vinit(mntp, specops, fifoops, vpp) 1228 struct mount *mntp; 1229 int (**specops) __P((void *)); 1230 int (**fifoops) __P((void *)); 1231 struct vnode **vpp; 1232 { 1233 struct inode *ip; 1234 struct vnode *vp, *nvp; 1235 1236 vp = *vpp; 1237 ip = VTOI(vp); 1238 switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) { 1239 case VCHR: 1240 case VBLK: 1241 vp->v_op = specops; 1242 if ((nvp = checkalias(vp, ip->i_din.e2fs_din.e2di_rdev, mntp)) 1243 != NULL) { 1244 /* 1245 * Discard unneeded vnode, but save its inode. 1246 */ 1247 ufs_ihashrem(ip); 1248 VOP_UNLOCK(vp); 1249 nvp->v_data = vp->v_data; 1250 vp->v_data = NULL; 1251 vp->v_op = spec_vnodeop_p; 1252 vrele(vp); 1253 vgone(vp); 1254 /* 1255 * Reinitialize aliased inode. 1256 */ 1257 vp = nvp; 1258 ip->i_vnode = vp; 1259 ufs_ihashins(ip); 1260 } 1261 break; 1262 case VFIFO: 1263 #ifdef FIFO 1264 vp->v_op = fifoops; 1265 break; 1266 #else 1267 return (EOPNOTSUPP); 1268 #endif 1269 case VNON: 1270 case VBAD: 1271 case VSOCK: 1272 case VLNK: 1273 case VDIR: 1274 case VREG: 1275 break; 1276 } 1277 if (ip->i_number == ROOTINO) 1278 vp->v_flag |= VROOT; 1279 /* 1280 * Initialize modrev times 1281 */ 1282 SETHIGH(ip->i_modrev, mono_time.tv_sec); 1283 SETLOW(ip->i_modrev, mono_time.tv_usec * 4294); 1284 *vpp = vp; 1285 return (0); 1286 } 1287 1288 /* 1289 * Allocate a new inode. 1290 */ 1291 int 1292 ext2fs_makeinode(mode, dvp, vpp, cnp) 1293 int mode; 1294 struct vnode *dvp; 1295 struct vnode **vpp; 1296 struct componentname *cnp; 1297 { 1298 register struct inode *ip, *pdir; 1299 struct timespec ts; 1300 struct vnode *tvp; 1301 int error; 1302 1303 pdir = VTOI(dvp); 1304 #ifdef DIAGNOSTIC 1305 if ((cnp->cn_flags & HASBUF) == 0) 1306 panic("ext2fs_makeinode: no name"); 1307 #endif 1308 *vpp = NULL; 1309 if ((mode & IFMT) == 0) 1310 mode |= IFREG; 1311 1312 if ((error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) != 0) { 1313 free(cnp->cn_pnbuf, M_NAMEI); 1314 vput(dvp); 1315 return (error); 1316 } 1317 ip = VTOI(tvp); 1318 ip->i_e2fs_gid = pdir->i_e2fs_gid; 1319 ip->i_e2fs_uid = cnp->cn_cred->cr_uid; 1320 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1321 ip->i_e2fs_mode = mode; 1322 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ 1323 ip->i_e2fs_nlink = 1; 1324 if ((ip->i_e2fs_mode & ISGID) && 1325 !groupmember(ip->i_e2fs_gid, cnp->cn_cred) && 1326 suser(cnp->cn_cred, NULL)) 1327 ip->i_e2fs_mode &= ~ISGID; 1328 1329 /* 1330 * Make sure inode goes to disk before directory entry. 1331 */ 1332 TIMEVAL_TO_TIMESPEC(&time, &ts); 1333 if ((error = VOP_UPDATE(tvp, &ts, &ts, 1)) != 0) 1334 goto bad; 1335 error = ext2fs_direnter(ip, dvp, cnp); 1336 if (error != 0) 1337 goto bad; 1338 if ((cnp->cn_flags & SAVESTART) == 0) 1339 FREE(cnp->cn_pnbuf, M_NAMEI); 1340 vput(dvp); 1341 *vpp = tvp; 1342 return (0); 1343 1344 bad: 1345 /* 1346 * Write error occurred trying to update the inode 1347 * or the directory so must deallocate the inode. 1348 */ 1349 free(cnp->cn_pnbuf, M_NAMEI); 1350 vput(dvp); 1351 ip->i_e2fs_nlink = 0; 1352 ip->i_flag |= IN_CHANGE; 1353 vput(tvp); 1354 return (error); 1355 } 1356 1357 /* 1358 * Reclaim an inode so that it can be used for other purposes. 1359 */ 1360 int 1361 ext2fs_reclaim(v) 1362 void *v; 1363 { 1364 struct vop_reclaim_args /* { 1365 struct vnode *a_vp; 1366 } */ *ap = v; 1367 register struct vnode *vp = ap->a_vp; 1368 struct inode *ip; 1369 extern int prtactive; 1370 1371 if (prtactive && vp->v_usecount != 0) 1372 vprint("ext2fs_reclaim: pushing active", vp); 1373 /* 1374 * Remove the inode from its hash chain. 1375 */ 1376 ip = VTOI(vp); 1377 ufs_ihashrem(ip); 1378 /* 1379 * Purge old data structures associated with the inode. 1380 */ 1381 cache_purge(vp); 1382 if (ip->i_devvp) { 1383 vrele(ip->i_devvp); 1384 ip->i_devvp = 0; 1385 } 1386 1387 FREE(vp->v_data, M_EXT2FSNODE); 1388 vp->v_data = NULL; 1389 return (0); 1390 } 1391 1392 /* Global vfs data structures for ext2fs. */ 1393 int (**ext2fs_vnodeop_p) __P((void *)); 1394 struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = { 1395 { &vop_default_desc, vn_default_error }, 1396 { &vop_lookup_desc, ext2fs_lookup }, /* lookup */ 1397 { &vop_create_desc, ext2fs_create }, /* create */ 1398 { &vop_mknod_desc, ext2fs_mknod }, /* mknod */ 1399 { &vop_open_desc, ext2fs_open }, /* open */ 1400 { &vop_close_desc, ufs_close }, /* close */ 1401 { &vop_access_desc, ext2fs_access }, /* access */ 1402 { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 1403 { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 1404 { &vop_read_desc, ext2fs_read }, /* read */ 1405 { &vop_write_desc, ext2fs_write }, /* write */ 1406 { &vop_lease_desc, ufs_lease_check }, /* lease */ 1407 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 1408 { &vop_poll_desc, ufs_poll }, /* poll */ 1409 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 1410 { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 1411 { &vop_seek_desc, ufs_seek }, /* seek */ 1412 { &vop_remove_desc, ext2fs_remove }, /* remove */ 1413 { &vop_link_desc, ext2fs_link }, /* link */ 1414 { &vop_rename_desc, ext2fs_rename }, /* rename */ 1415 { &vop_mkdir_desc, ext2fs_mkdir }, /* mkdir */ 1416 { &vop_rmdir_desc, ext2fs_rmdir }, /* rmdir */ 1417 { &vop_symlink_desc, ext2fs_symlink }, /* symlink */ 1418 { &vop_readdir_desc, ext2fs_readdir }, /* readdir */ 1419 { &vop_readlink_desc, ext2fs_readlink },/* readlink */ 1420 { &vop_abortop_desc, ufs_abortop }, /* abortop */ 1421 { &vop_inactive_desc, ext2fs_inactive },/* inactive */ 1422 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1423 { &vop_lock_desc, ufs_lock }, /* lock */ 1424 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1425 { &vop_bmap_desc, ext2fs_bmap }, /* bmap */ 1426 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 1427 { &vop_print_desc, ufs_print }, /* print */ 1428 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1429 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 1430 { &vop_advlock_desc, ext2fs_advlock }, /* advlock */ 1431 { &vop_blkatoff_desc, ext2fs_blkatoff },/* blkatoff */ 1432 { &vop_valloc_desc, ext2fs_valloc }, /* valloc */ 1433 { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 1434 { &vop_truncate_desc, ext2fs_truncate },/* truncate */ 1435 { &vop_update_desc, ext2fs_update }, /* update */ 1436 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1437 { (struct vnodeop_desc*)NULL, (int(*) __P((void*)))NULL } 1438 }; 1439 struct vnodeopv_desc ext2fs_vnodeop_opv_desc = 1440 { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries }; 1441 1442 int (**ext2fs_specop_p) __P((void *)); 1443 struct vnodeopv_entry_desc ext2fs_specop_entries[] = { 1444 { &vop_default_desc, vn_default_error }, 1445 { &vop_lookup_desc, spec_lookup }, /* lookup */ 1446 { &vop_create_desc, spec_create }, /* create */ 1447 { &vop_mknod_desc, spec_mknod }, /* mknod */ 1448 { &vop_open_desc, spec_open }, /* open */ 1449 { &vop_close_desc, ufsspec_close }, /* close */ 1450 { &vop_access_desc, ext2fs_access }, /* access */ 1451 { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 1452 { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 1453 { &vop_read_desc, ufsspec_read }, /* read */ 1454 { &vop_write_desc, ufsspec_write }, /* write */ 1455 { &vop_lease_desc, spec_lease_check }, /* lease */ 1456 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 1457 { &vop_poll_desc, spec_poll }, /* poll */ 1458 { &vop_mmap_desc, spec_mmap }, /* mmap */ 1459 { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 1460 { &vop_seek_desc, spec_seek }, /* seek */ 1461 { &vop_remove_desc, spec_remove }, /* remove */ 1462 { &vop_link_desc, spec_link }, /* link */ 1463 { &vop_rename_desc, spec_rename }, /* rename */ 1464 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 1465 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 1466 { &vop_symlink_desc, spec_symlink }, /* symlink */ 1467 { &vop_readdir_desc, spec_readdir }, /* readdir */ 1468 { &vop_readlink_desc, spec_readlink }, /* readlink */ 1469 { &vop_abortop_desc, spec_abortop }, /* abortop */ 1470 { &vop_inactive_desc, ext2fs_inactive },/* inactive */ 1471 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1472 { &vop_lock_desc, ufs_lock }, /* lock */ 1473 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1474 { &vop_bmap_desc, spec_bmap }, /* bmap */ 1475 { &vop_strategy_desc, spec_strategy }, /* strategy */ 1476 { &vop_print_desc, ufs_print }, /* print */ 1477 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1478 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 1479 { &vop_advlock_desc, spec_advlock }, /* advlock */ 1480 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 1481 { &vop_valloc_desc, spec_valloc }, /* valloc */ 1482 { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 1483 { &vop_truncate_desc, spec_truncate }, /* truncate */ 1484 { &vop_update_desc, ext2fs_update }, /* update */ 1485 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1486 { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } 1487 }; 1488 struct vnodeopv_desc ext2fs_specop_opv_desc = 1489 { &ext2fs_specop_p, ext2fs_specop_entries }; 1490 1491 #ifdef FIFO 1492 int (**ext2fs_fifoop_p) __P((void *)); 1493 struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = { 1494 { &vop_default_desc, vn_default_error }, 1495 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 1496 { &vop_create_desc, fifo_create }, /* create */ 1497 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 1498 { &vop_open_desc, fifo_open }, /* open */ 1499 { &vop_close_desc, ufsfifo_close }, /* close */ 1500 { &vop_access_desc, ext2fs_access }, /* access */ 1501 { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 1502 { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 1503 { &vop_read_desc, ufsfifo_read }, /* read */ 1504 { &vop_write_desc, ufsfifo_write }, /* write */ 1505 { &vop_lease_desc, fifo_lease_check }, /* lease */ 1506 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 1507 { &vop_poll_desc, fifo_poll }, /* poll */ 1508 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 1509 { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 1510 { &vop_seek_desc, fifo_seek }, /* seek */ 1511 { &vop_remove_desc, fifo_remove }, /* remove */ 1512 { &vop_link_desc, fifo_link }, /* link */ 1513 { &vop_rename_desc, fifo_rename }, /* rename */ 1514 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 1515 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 1516 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 1517 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 1518 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 1519 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 1520 { &vop_inactive_desc, ext2fs_inactive },/* inactive */ 1521 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1522 { &vop_lock_desc, ufs_lock }, /* lock */ 1523 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1524 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 1525 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 1526 { &vop_print_desc, ufs_print }, /* print */ 1527 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1528 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 1529 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 1530 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 1531 { &vop_valloc_desc, fifo_valloc }, /* valloc */ 1532 { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 1533 { &vop_truncate_desc, fifo_truncate }, /* truncate */ 1534 { &vop_update_desc, ext2fs_update }, /* update */ 1535 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1536 { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } 1537 }; 1538 struct vnodeopv_desc ext2fs_fifoop_opv_desc = 1539 { &ext2fs_fifoop_p, ext2fs_fifoop_entries }; 1540 #endif /* FIFO */ 1541