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