|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)ufs_vnops.c 7.64 (Berkeley) 5/16/91 ! 34: */ ! 35: ! 36: #include "param.h" ! 37: #include "systm.h" ! 38: #include "namei.h" ! 39: #include "resourcevar.h" ! 40: #include "kernel.h" ! 41: #include "file.h" ! 42: #include "stat.h" ! 43: #include "buf.h" ! 44: #include "proc.h" ! 45: #include "conf.h" ! 46: #include "mount.h" ! 47: #include "vnode.h" ! 48: #include "specdev.h" ! 49: #include "fifo.h" ! 50: #include "malloc.h" ! 51: ! 52: #include "lockf.h" ! 53: #include "quota.h" ! 54: #include "inode.h" ! 55: #include "dir.h" ! 56: #include "fs.h" ! 57: ! 58: /* ! 59: * Create a regular file ! 60: */ ! 61: ufs_create(ndp, vap, p) ! 62: struct nameidata *ndp; ! 63: struct vattr *vap; ! 64: struct proc *p; ! 65: { ! 66: struct inode *ip; ! 67: int error; ! 68: ! 69: if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) ! 70: return (error); ! 71: ndp->ni_vp = ITOV(ip); ! 72: return (0); ! 73: } ! 74: ! 75: /* ! 76: * Mknod vnode call ! 77: */ ! 78: /* ARGSUSED */ ! 79: ufs_mknod(ndp, vap, cred, p) ! 80: struct nameidata *ndp; ! 81: struct ucred *cred; ! 82: struct vattr *vap; ! 83: struct proc *p; ! 84: { ! 85: register struct vnode *vp; ! 86: struct inode *ip; ! 87: int error; ! 88: ! 89: if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) ! 90: return (error); ! 91: ip->i_flag |= IACC|IUPD|ICHG; ! 92: if (vap->va_rdev != VNOVAL) { ! 93: /* ! 94: * Want to be able to use this to make badblock ! 95: * inodes, so don't truncate the dev number. ! 96: */ ! 97: ip->i_rdev = vap->va_rdev; ! 98: } ! 99: /* ! 100: * Remove inode so that it will be reloaded by iget and ! 101: * checked to see if it is an alias of an existing entry ! 102: * in the inode cache. ! 103: */ ! 104: vp = ITOV(ip); ! 105: vput(vp); ! 106: vp->v_type = VNON; ! 107: vgone(vp); ! 108: return (0); ! 109: } ! 110: ! 111: /* ! 112: * Open called. ! 113: * ! 114: * Nothing to do. ! 115: */ ! 116: /* ARGSUSED */ ! 117: ufs_open(vp, mode, cred, p) ! 118: struct vnode *vp; ! 119: int mode; ! 120: struct ucred *cred; ! 121: struct proc *p; ! 122: { ! 123: ! 124: return (0); ! 125: } ! 126: ! 127: /* ! 128: * Close called ! 129: * ! 130: * Update the times on the inode. ! 131: */ ! 132: /* ARGSUSED */ ! 133: ufs_close(vp, fflag, cred, p) ! 134: struct vnode *vp; ! 135: int fflag; ! 136: struct ucred *cred; ! 137: struct proc *p; ! 138: { ! 139: register struct inode *ip = VTOI(vp); ! 140: ! 141: if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) ! 142: ITIMES(ip, &time, &time); ! 143: return (0); ! 144: } ! 145: ! 146: /* ! 147: * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. ! 148: * The mode is shifted to select the owner/group/other fields. The ! 149: * super user is granted all permissions. ! 150: */ ! 151: ufs_access(vp, mode, cred, p) ! 152: struct vnode *vp; ! 153: register int mode; ! 154: struct ucred *cred; ! 155: struct proc *p; ! 156: { ! 157: register struct inode *ip = VTOI(vp); ! 158: register gid_t *gp; ! 159: int i, error; ! 160: ! 161: #ifdef DIAGNOSTIC ! 162: if (!VOP_ISLOCKED(vp)) { ! 163: vprint("ufs_access: not locked", vp); ! 164: panic("ufs_access: not locked"); ! 165: } ! 166: #endif ! 167: #ifdef QUOTA ! 168: if (mode & VWRITE) { ! 169: switch (vp->v_type) { ! 170: case VREG: case VDIR: case VLNK: ! 171: if (error = getinoquota(ip)) ! 172: return (error); ! 173: } ! 174: } ! 175: #endif /* QUOTA */ ! 176: /* ! 177: * If you're the super-user, you always get access. ! 178: */ ! 179: if (cred->cr_uid == 0) ! 180: return (0); ! 181: /* ! 182: * Access check is based on only one of owner, group, public. ! 183: * If not owner, then check group. If not a member of the ! 184: * group, then check public access. ! 185: */ ! 186: if (cred->cr_uid != ip->i_uid) { ! 187: mode >>= 3; ! 188: gp = cred->cr_groups; ! 189: for (i = 0; i < cred->cr_ngroups; i++, gp++) ! 190: if (ip->i_gid == *gp) ! 191: goto found; ! 192: mode >>= 3; ! 193: found: ! 194: ; ! 195: } ! 196: if ((ip->i_mode & mode) != 0) ! 197: return (0); ! 198: return (EACCES); ! 199: } ! 200: ! 201: /* ARGSUSED */ ! 202: ufs_getattr(vp, vap, cred, p) ! 203: struct vnode *vp; ! 204: register struct vattr *vap; ! 205: struct ucred *cred; ! 206: struct proc *p; ! 207: { ! 208: register struct inode *ip = VTOI(vp); ! 209: ! 210: ITIMES(ip, &time, &time); ! 211: /* ! 212: * Copy from inode table ! 213: */ ! 214: vap->va_fsid = ip->i_dev; ! 215: vap->va_fileid = ip->i_number; ! 216: vap->va_mode = ip->i_mode & ~IFMT; ! 217: vap->va_nlink = ip->i_nlink; ! 218: vap->va_uid = ip->i_uid; ! 219: vap->va_gid = ip->i_gid; ! 220: vap->va_rdev = (dev_t)ip->i_rdev; ! 221: #ifdef tahoe ! 222: vap->va_size = ip->i_size; ! 223: vap->va_size_rsv = 0; ! 224: #else ! 225: vap->va_qsize = ip->i_din.di_qsize; ! 226: #endif ! 227: vap->va_atime.tv_sec = ip->i_atime; ! 228: vap->va_atime.tv_usec = 0; ! 229: vap->va_mtime.tv_sec = ip->i_mtime; ! 230: vap->va_mtime.tv_usec = 0; ! 231: vap->va_ctime.tv_sec = ip->i_ctime; ! 232: vap->va_ctime.tv_usec = 0; ! 233: vap->va_flags = ip->i_flags; ! 234: vap->va_gen = ip->i_gen; ! 235: /* this doesn't belong here */ ! 236: if (vp->v_type == VBLK) ! 237: vap->va_blocksize = BLKDEV_IOSIZE; ! 238: else if (vp->v_type == VCHR) ! 239: vap->va_blocksize = MAXBSIZE; ! 240: else ! 241: vap->va_blocksize = ip->i_fs->fs_bsize; ! 242: vap->va_bytes = dbtob(ip->i_blocks); ! 243: vap->va_bytes_rsv = 0; ! 244: vap->va_type = vp->v_type; ! 245: return (0); ! 246: } ! 247: ! 248: /* ! 249: * Set attribute vnode op. called from several syscalls ! 250: */ ! 251: ufs_setattr(vp, vap, cred, p) ! 252: register struct vnode *vp; ! 253: register struct vattr *vap; ! 254: register struct ucred *cred; ! 255: struct proc *p; ! 256: { ! 257: register struct inode *ip = VTOI(vp); ! 258: int error = 0; ! 259: ! 260: /* ! 261: * Check for unsetable attributes. ! 262: */ ! 263: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || ! 264: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || ! 265: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ! 266: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { ! 267: return (EINVAL); ! 268: } ! 269: /* ! 270: * Go through the fields and update iff not VNOVAL. ! 271: */ ! 272: if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) ! 273: if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) ! 274: return (error); ! 275: if (vap->va_size != VNOVAL) { ! 276: if (vp->v_type == VDIR) ! 277: return (EISDIR); ! 278: if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ ! 279: return (error); ! 280: } ! 281: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { ! 282: if (cred->cr_uid != ip->i_uid && ! 283: (error = suser(cred, &p->p_acflag))) ! 284: return (error); ! 285: if (vap->va_atime.tv_sec != VNOVAL) ! 286: ip->i_flag |= IACC; ! 287: if (vap->va_mtime.tv_sec != VNOVAL) ! 288: ip->i_flag |= IUPD; ! 289: ip->i_flag |= ICHG; ! 290: if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) ! 291: return (error); ! 292: } ! 293: if (vap->va_mode != (u_short)VNOVAL) ! 294: error = chmod1(vp, (int)vap->va_mode, p); ! 295: if (vap->va_flags != VNOVAL) { ! 296: if (cred->cr_uid != ip->i_uid && ! 297: (error = suser(cred, &p->p_acflag))) ! 298: return (error); ! 299: if (cred->cr_uid == 0) { ! 300: ip->i_flags = vap->va_flags; ! 301: } else { ! 302: ip->i_flags &= 0xffff0000; ! 303: ip->i_flags |= (vap->va_flags & 0xffff); ! 304: } ! 305: ip->i_flag |= ICHG; ! 306: } ! 307: return (error); ! 308: } ! 309: ! 310: /* ! 311: * Change the mode on a file. ! 312: * Inode must be locked before calling. ! 313: */ ! 314: chmod1(vp, mode, p) ! 315: register struct vnode *vp; ! 316: register int mode; ! 317: struct proc *p; ! 318: { ! 319: register struct ucred *cred = p->p_ucred; ! 320: register struct inode *ip = VTOI(vp); ! 321: int error; ! 322: ! 323: if (cred->cr_uid != ip->i_uid && ! 324: (error = suser(cred, &p->p_acflag))) ! 325: return (error); ! 326: if (cred->cr_uid) { ! 327: if (vp->v_type != VDIR && (mode & ISVTX)) ! 328: return (EFTYPE); ! 329: if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) ! 330: return (EPERM); ! 331: } ! 332: ip->i_mode &= ~07777; ! 333: ip->i_mode |= mode & 07777; ! 334: ip->i_flag |= ICHG; ! 335: if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) ! 336: (void) vnode_pager_uncache(vp); ! 337: return (0); ! 338: } ! 339: ! 340: /* ! 341: * Perform chown operation on inode ip; ! 342: * inode must be locked prior to call. ! 343: */ ! 344: chown1(vp, uid, gid, p) ! 345: register struct vnode *vp; ! 346: uid_t uid; ! 347: gid_t gid; ! 348: struct proc *p; ! 349: { ! 350: register struct inode *ip = VTOI(vp); ! 351: register struct ucred *cred = p->p_ucred; ! 352: uid_t ouid; ! 353: gid_t ogid; ! 354: int error = 0; ! 355: #ifdef QUOTA ! 356: register int i; ! 357: long change; ! 358: #endif ! 359: ! 360: if (uid == (u_short)VNOVAL) ! 361: uid = ip->i_uid; ! 362: if (gid == (u_short)VNOVAL) ! 363: gid = ip->i_gid; ! 364: /* ! 365: * If we don't own the file, are trying to change the owner ! 366: * of the file, or are not a member of the target group, ! 367: * the caller must be superuser or the call fails. ! 368: */ ! 369: if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || ! 370: !groupmember((gid_t)gid, cred)) && ! 371: (error = suser(cred, &p->p_acflag))) ! 372: return (error); ! 373: ouid = ip->i_uid; ! 374: ogid = ip->i_gid; ! 375: #ifdef QUOTA ! 376: if (error = getinoquota(ip)) ! 377: return (error); ! 378: if (ouid == uid) { ! 379: dqrele(vp, ip->i_dquot[USRQUOTA]); ! 380: ip->i_dquot[USRQUOTA] = NODQUOT; ! 381: } ! 382: if (ogid == gid) { ! 383: dqrele(vp, ip->i_dquot[GRPQUOTA]); ! 384: ip->i_dquot[GRPQUOTA] = NODQUOT; ! 385: } ! 386: change = ip->i_blocks; ! 387: (void) chkdq(ip, -change, cred, CHOWN); ! 388: (void) chkiq(ip, -1, cred, CHOWN); ! 389: for (i = 0; i < MAXQUOTAS; i++) { ! 390: dqrele(vp, ip->i_dquot[i]); ! 391: ip->i_dquot[i] = NODQUOT; ! 392: } ! 393: #endif ! 394: ip->i_uid = uid; ! 395: ip->i_gid = gid; ! 396: #ifdef QUOTA ! 397: if ((error = getinoquota(ip)) == 0) { ! 398: if (ouid == uid) { ! 399: dqrele(vp, ip->i_dquot[USRQUOTA]); ! 400: ip->i_dquot[USRQUOTA] = NODQUOT; ! 401: } ! 402: if (ogid == gid) { ! 403: dqrele(vp, ip->i_dquot[GRPQUOTA]); ! 404: ip->i_dquot[GRPQUOTA] = NODQUOT; ! 405: } ! 406: if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { ! 407: if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) ! 408: goto good; ! 409: else ! 410: (void) chkdq(ip, -change, cred, CHOWN|FORCE); ! 411: } ! 412: for (i = 0; i < MAXQUOTAS; i++) { ! 413: dqrele(vp, ip->i_dquot[i]); ! 414: ip->i_dquot[i] = NODQUOT; ! 415: } ! 416: } ! 417: ip->i_uid = ouid; ! 418: ip->i_gid = ogid; ! 419: if (getinoquota(ip) == 0) { ! 420: if (ouid == uid) { ! 421: dqrele(vp, ip->i_dquot[USRQUOTA]); ! 422: ip->i_dquot[USRQUOTA] = NODQUOT; ! 423: } ! 424: if (ogid == gid) { ! 425: dqrele(vp, ip->i_dquot[GRPQUOTA]); ! 426: ip->i_dquot[GRPQUOTA] = NODQUOT; ! 427: } ! 428: (void) chkdq(ip, change, cred, FORCE|CHOWN); ! 429: (void) chkiq(ip, 1, cred, FORCE|CHOWN); ! 430: (void) getinoquota(ip); ! 431: } ! 432: return (error); ! 433: good: ! 434: if (getinoquota(ip)) ! 435: panic("chown: lost quota"); ! 436: #endif /* QUOTA */ ! 437: if (ouid != uid || ogid != gid) ! 438: ip->i_flag |= ICHG; ! 439: if (ouid != uid && cred->cr_uid != 0) ! 440: ip->i_mode &= ~ISUID; ! 441: if (ogid != gid && cred->cr_uid != 0) ! 442: ip->i_mode &= ~ISGID; ! 443: return (0); ! 444: } ! 445: ! 446: /* ! 447: * Vnode op for reading. ! 448: */ ! 449: /* ARGSUSED */ ! 450: ufs_read(vp, uio, ioflag, cred) ! 451: struct vnode *vp; ! 452: register struct uio *uio; ! 453: int ioflag; ! 454: struct ucred *cred; ! 455: { ! 456: register struct inode *ip = VTOI(vp); ! 457: register struct fs *fs; ! 458: struct buf *bp; ! 459: daddr_t lbn, bn, rablock; ! 460: int size, diff, error = 0; ! 461: long n, on, type; ! 462: ! 463: #ifdef DIAGNOSTIC ! 464: if (uio->uio_rw != UIO_READ) ! 465: panic("ufs_read mode"); ! 466: type = ip->i_mode & IFMT; ! 467: if (type != IFDIR && type != IFREG && type != IFLNK) ! 468: panic("ufs_read type"); ! 469: #endif ! 470: if (uio->uio_resid == 0) ! 471: return (0); ! 472: if (uio->uio_offset < 0) ! 473: return (EINVAL); ! 474: ip->i_flag |= IACC; ! 475: fs = ip->i_fs; ! 476: do { ! 477: lbn = lblkno(fs, uio->uio_offset); ! 478: on = blkoff(fs, uio->uio_offset); ! 479: n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); ! 480: diff = ip->i_size - uio->uio_offset; ! 481: if (diff <= 0) ! 482: return (0); ! 483: if (diff < n) ! 484: n = diff; ! 485: size = blksize(fs, ip, lbn); ! 486: rablock = lbn + 1; ! 487: if (vp->v_lastr + 1 == lbn && ! 488: lblktosize(fs, rablock) < ip->i_size) ! 489: error = breada(ITOV(ip), lbn, size, rablock, ! 490: blksize(fs, ip, rablock), NOCRED, &bp); ! 491: else ! 492: error = bread(ITOV(ip), lbn, size, NOCRED, &bp); ! 493: vp->v_lastr = lbn; ! 494: n = MIN(n, size - bp->b_resid); ! 495: if (error) { ! 496: brelse(bp); ! 497: return (error); ! 498: } ! 499: error = uiomove(bp->b_un.b_addr + on, (int)n, uio); ! 500: if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) ! 501: bp->b_flags |= B_AGE; ! 502: brelse(bp); ! 503: } while (error == 0 && uio->uio_resid > 0 && n != 0); ! 504: return (error); ! 505: } ! 506: ! 507: /* ! 508: * Vnode op for writing. ! 509: */ ! 510: ufs_write(vp, uio, ioflag, cred) ! 511: register struct vnode *vp; ! 512: struct uio *uio; ! 513: int ioflag; ! 514: struct ucred *cred; ! 515: { ! 516: struct proc *p = uio->uio_procp; ! 517: register struct inode *ip = VTOI(vp); ! 518: register struct fs *fs; ! 519: struct buf *bp; ! 520: daddr_t lbn, bn; ! 521: u_long osize; ! 522: int n, on, flags; ! 523: int size, resid, error = 0; ! 524: ! 525: #ifdef DIAGNOSTIC ! 526: if (uio->uio_rw != UIO_WRITE) ! 527: panic("ufs_write mode"); ! 528: #endif ! 529: switch (vp->v_type) { ! 530: case VREG: ! 531: if (ioflag & IO_APPEND) ! 532: uio->uio_offset = ip->i_size; ! 533: /* fall through */ ! 534: case VLNK: ! 535: break; ! 536: ! 537: case VDIR: ! 538: if ((ioflag & IO_SYNC) == 0) ! 539: panic("ufs_write nonsync dir write"); ! 540: break; ! 541: ! 542: default: ! 543: panic("ufs_write type"); ! 544: } ! 545: if (uio->uio_offset < 0) ! 546: return (EINVAL); ! 547: if (uio->uio_resid == 0) ! 548: return (0); ! 549: /* ! 550: * Maybe this should be above the vnode op call, but so long as ! 551: * file servers have no limits, i don't think it matters ! 552: */ ! 553: if (vp->v_type == VREG && p && ! 554: uio->uio_offset + uio->uio_resid > ! 555: p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { ! 556: psignal(p, SIGXFSZ); ! 557: return (EFBIG); ! 558: } ! 559: resid = uio->uio_resid; ! 560: osize = ip->i_size; ! 561: fs = ip->i_fs; ! 562: flags = 0; ! 563: if (ioflag & IO_SYNC) ! 564: flags = B_SYNC; ! 565: do { ! 566: lbn = lblkno(fs, uio->uio_offset); ! 567: on = blkoff(fs, uio->uio_offset); ! 568: n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); ! 569: if (n < fs->fs_bsize) ! 570: flags |= B_CLRBUF; ! 571: else ! 572: flags &= ~B_CLRBUF; ! 573: if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) ! 574: break; ! 575: bn = bp->b_blkno; ! 576: if (uio->uio_offset + n > ip->i_size) { ! 577: ip->i_size = uio->uio_offset + n; ! 578: vnode_pager_setsize(vp, ip->i_size); ! 579: } ! 580: size = blksize(fs, ip, lbn); ! 581: (void) vnode_pager_uncache(vp); ! 582: n = MIN(n, size - bp->b_resid); ! 583: error = uiomove(bp->b_un.b_addr + on, n, uio); ! 584: if (ioflag & IO_SYNC) ! 585: (void) bwrite(bp); ! 586: else if (n + on == fs->fs_bsize) { ! 587: bp->b_flags |= B_AGE; ! 588: bawrite(bp); ! 589: } else ! 590: bdwrite(bp); ! 591: ip->i_flag |= IUPD|ICHG; ! 592: if (cred->cr_uid != 0) ! 593: ip->i_mode &= ~(ISUID|ISGID); ! 594: } while (error == 0 && uio->uio_resid > 0 && n != 0); ! 595: if (error && (ioflag & IO_UNIT)) { ! 596: (void) itrunc(ip, osize, ioflag & IO_SYNC); ! 597: uio->uio_offset -= resid - uio->uio_resid; ! 598: uio->uio_resid = resid; ! 599: } ! 600: if (!error && (ioflag & IO_SYNC)) ! 601: error = iupdat(ip, &time, &time, 1); ! 602: return (error); ! 603: } ! 604: ! 605: /* ARGSUSED */ ! 606: ufs_ioctl(vp, com, data, fflag, cred, p) ! 607: struct vnode *vp; ! 608: int com; ! 609: caddr_t data; ! 610: int fflag; ! 611: struct ucred *cred; ! 612: struct proc *p; ! 613: { ! 614: ! 615: return (ENOTTY); ! 616: } ! 617: ! 618: /* ARGSUSED */ ! 619: ufs_select(vp, which, fflags, cred, p) ! 620: struct vnode *vp; ! 621: int which, fflags; ! 622: struct ucred *cred; ! 623: struct proc *p; ! 624: { ! 625: ! 626: /* ! 627: * We should really check to see if I/O is possible. ! 628: */ ! 629: return (1); ! 630: } ! 631: ! 632: /* ! 633: * Mmap a file ! 634: * ! 635: * NB Currently unsupported. ! 636: */ ! 637: /* ARGSUSED */ ! 638: ufs_mmap(vp, fflags, cred, p) ! 639: struct vnode *vp; ! 640: int fflags; ! 641: struct ucred *cred; ! 642: struct proc *p; ! 643: { ! 644: ! 645: return (EINVAL); ! 646: } ! 647: ! 648: /* ! 649: * Synch an open file. ! 650: */ ! 651: /* ARGSUSED */ ! 652: ufs_fsync(vp, fflags, cred, waitfor, p) ! 653: struct vnode *vp; ! 654: int fflags; ! 655: struct ucred *cred; ! 656: int waitfor; ! 657: struct proc *p; ! 658: { ! 659: struct inode *ip = VTOI(vp); ! 660: ! 661: if (fflags & FWRITE) ! 662: ip->i_flag |= ICHG; ! 663: vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); ! 664: return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); ! 665: } ! 666: ! 667: /* ! 668: * Seek on a file ! 669: * ! 670: * Nothing to do, so just return. ! 671: */ ! 672: /* ARGSUSED */ ! 673: ufs_seek(vp, oldoff, newoff, cred) ! 674: struct vnode *vp; ! 675: off_t oldoff, newoff; ! 676: struct ucred *cred; ! 677: { ! 678: ! 679: return (0); ! 680: } ! 681: ! 682: /* ! 683: * ufs remove ! 684: * Hard to avoid races here, especially ! 685: * in unlinking directories. ! 686: */ ! 687: ufs_remove(ndp, p) ! 688: struct nameidata *ndp; ! 689: struct proc *p; ! 690: { ! 691: register struct inode *ip, *dp; ! 692: int error; ! 693: ! 694: ip = VTOI(ndp->ni_vp); ! 695: dp = VTOI(ndp->ni_dvp); ! 696: error = dirremove(ndp); ! 697: if (!error) { ! 698: ip->i_nlink--; ! 699: ip->i_flag |= ICHG; ! 700: } ! 701: if (dp == ip) ! 702: vrele(ITOV(ip)); ! 703: else ! 704: iput(ip); ! 705: iput(dp); ! 706: return (error); ! 707: } ! 708: ! 709: /* ! 710: * link vnode call ! 711: */ ! 712: ufs_link(vp, ndp, p) ! 713: register struct vnode *vp; ! 714: register struct nameidata *ndp; ! 715: struct proc *p; ! 716: { ! 717: register struct inode *ip = VTOI(vp); ! 718: int error; ! 719: ! 720: #ifdef DIANOSTIC ! 721: if ((ndp->ni_nameiop & HASBUF) == 0) ! 722: panic("ufs_link: no name"); ! 723: #endif ! 724: if ((unsigned short)ip->i_nlink >= LINK_MAX) { ! 725: free(ndp->ni_pnbuf, M_NAMEI); ! 726: return (EMLINK); ! 727: } ! 728: if (ndp->ni_dvp != vp) ! 729: ILOCK(ip); ! 730: ip->i_nlink++; ! 731: ip->i_flag |= ICHG; ! 732: error = iupdat(ip, &time, &time, 1); ! 733: if (!error) ! 734: error = direnter(ip, ndp); ! 735: if (ndp->ni_dvp != vp) ! 736: IUNLOCK(ip); ! 737: FREE(ndp->ni_pnbuf, M_NAMEI); ! 738: vput(ndp->ni_dvp); ! 739: if (error) { ! 740: ip->i_nlink--; ! 741: ip->i_flag |= ICHG; ! 742: } ! 743: return (error); ! 744: } ! 745: ! 746: /* ! 747: * Rename system call. ! 748: * rename("foo", "bar"); ! 749: * is essentially ! 750: * unlink("bar"); ! 751: * link("foo", "bar"); ! 752: * unlink("foo"); ! 753: * but ``atomically''. Can't do full commit without saving state in the ! 754: * inode on disk which isn't feasible at this time. Best we can do is ! 755: * always guarantee the target exists. ! 756: * ! 757: * Basic algorithm is: ! 758: * ! 759: * 1) Bump link count on source while we're linking it to the ! 760: * target. This also ensure the inode won't be deleted out ! 761: * from underneath us while we work (it may be truncated by ! 762: * a concurrent `trunc' or `open' for creation). ! 763: * 2) Link source to destination. If destination already exists, ! 764: * delete it first. ! 765: * 3) Unlink source reference to inode if still around. If a ! 766: * directory was moved and the parent of the destination ! 767: * is different from the source, patch the ".." entry in the ! 768: * directory. ! 769: */ ! 770: ufs_rename(fndp, tndp, p) ! 771: register struct nameidata *fndp, *tndp; ! 772: struct proc *p; ! 773: { ! 774: register struct inode *ip, *xp, *dp; ! 775: struct dirtemplate dirbuf; ! 776: int doingdirectory = 0, oldparent = 0, newparent = 0; ! 777: int error = 0; ! 778: ! 779: #ifdef DIANOSTIC ! 780: if ((tndp->ni_nameiop & HASBUF) == 0 || ! 781: (fndp->ni_nameiop & HASBUF) == 0) ! 782: panic("ufs_rename: no name"); ! 783: #endif ! 784: dp = VTOI(fndp->ni_dvp); ! 785: ip = VTOI(fndp->ni_vp); ! 786: /* ! 787: * Check if just deleting a link name. ! 788: */ ! 789: if (fndp->ni_vp == tndp->ni_vp) { ! 790: VOP_ABORTOP(tndp); ! 791: vput(tndp->ni_dvp); ! 792: vput(tndp->ni_vp); ! 793: vrele(fndp->ni_dvp); ! 794: if ((ip->i_mode&IFMT) == IFDIR) { ! 795: VOP_ABORTOP(fndp); ! 796: vrele(fndp->ni_vp); ! 797: return (EINVAL); ! 798: } ! 799: doingdirectory = 0; ! 800: goto unlinkit; ! 801: } ! 802: ILOCK(ip); ! 803: if ((ip->i_mode&IFMT) == IFDIR) { ! 804: /* ! 805: * Avoid ".", "..", and aliases of "." for obvious reasons. ! 806: */ ! 807: if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') || ! 808: dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { ! 809: VOP_ABORTOP(tndp); ! 810: vput(tndp->ni_dvp); ! 811: if (tndp->ni_vp) ! 812: vput(tndp->ni_vp); ! 813: VOP_ABORTOP(fndp); ! 814: vrele(fndp->ni_dvp); ! 815: vput(fndp->ni_vp); ! 816: return (EINVAL); ! 817: } ! 818: ip->i_flag |= IRENAME; ! 819: oldparent = dp->i_number; ! 820: doingdirectory++; ! 821: } ! 822: vrele(fndp->ni_dvp); ! 823: ! 824: /* ! 825: * 1) Bump link count while we're moving stuff ! 826: * around. If we crash somewhere before ! 827: * completing our work, the link count ! 828: * may be wrong, but correctable. ! 829: */ ! 830: ip->i_nlink++; ! 831: ip->i_flag |= ICHG; ! 832: error = iupdat(ip, &time, &time, 1); ! 833: IUNLOCK(ip); ! 834: ! 835: /* ! 836: * When the target exists, both the directory ! 837: * and target vnodes are returned locked. ! 838: */ ! 839: dp = VTOI(tndp->ni_dvp); ! 840: xp = NULL; ! 841: if (tndp->ni_vp) ! 842: xp = VTOI(tndp->ni_vp); ! 843: /* ! 844: * If ".." must be changed (ie the directory gets a new ! 845: * parent) then the source directory must not be in the ! 846: * directory heirarchy above the target, as this would ! 847: * orphan everything below the source directory. Also ! 848: * the user must have write permission in the source so ! 849: * as to be able to change "..". We must repeat the call ! 850: * to namei, as the parent directory is unlocked by the ! 851: * call to checkpath(). ! 852: */ ! 853: if (oldparent != dp->i_number) ! 854: newparent = dp->i_number; ! 855: if (doingdirectory && newparent) { ! 856: VOP_LOCK(fndp->ni_vp); ! 857: error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); ! 858: VOP_UNLOCK(fndp->ni_vp); ! 859: if (error) ! 860: goto bad; ! 861: if (xp != NULL) ! 862: iput(xp); ! 863: if (error = checkpath(ip, dp, tndp->ni_cred)) ! 864: goto out; ! 865: if ((tndp->ni_nameiop & SAVESTART) == 0) ! 866: panic("ufs_rename: lost to startdir"); ! 867: if (error = lookup(tndp, p)) ! 868: goto out; ! 869: dp = VTOI(tndp->ni_dvp); ! 870: xp = NULL; ! 871: if (tndp->ni_vp) ! 872: xp = VTOI(tndp->ni_vp); ! 873: } ! 874: /* ! 875: * 2) If target doesn't exist, link the target ! 876: * to the source and unlink the source. ! 877: * Otherwise, rewrite the target directory ! 878: * entry to reference the source inode and ! 879: * expunge the original entry's existence. ! 880: */ ! 881: if (xp == NULL) { ! 882: if (dp->i_dev != ip->i_dev) ! 883: panic("rename: EXDEV"); ! 884: /* ! 885: * Account for ".." in new directory. ! 886: * When source and destination have the same ! 887: * parent we don't fool with the link count. ! 888: */ ! 889: if (doingdirectory && newparent) { ! 890: if ((unsigned short)dp->i_nlink >= LINK_MAX) { ! 891: error = EMLINK; ! 892: goto bad; ! 893: } ! 894: dp->i_nlink++; ! 895: dp->i_flag |= ICHG; ! 896: if (error = iupdat(dp, &time, &time, 1)) ! 897: goto bad; ! 898: } ! 899: if (error = direnter(ip, tndp)) { ! 900: if (doingdirectory && newparent) { ! 901: dp->i_nlink--; ! 902: dp->i_flag |= ICHG; ! 903: (void) iupdat(dp, &time, &time, 1); ! 904: } ! 905: goto bad; ! 906: } ! 907: iput(dp); ! 908: } else { ! 909: if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) ! 910: panic("rename: EXDEV"); ! 911: /* ! 912: * Short circuit rename(foo, foo). ! 913: */ ! 914: if (xp->i_number == ip->i_number) ! 915: panic("rename: same file"); ! 916: /* ! 917: * If the parent directory is "sticky", then the user must ! 918: * own the parent directory, or the destination of the rename, ! 919: * otherwise the destination may not be changed (except by ! 920: * root). This implements append-only directories. ! 921: */ ! 922: if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && ! 923: tndp->ni_cred->cr_uid != dp->i_uid && ! 924: xp->i_uid != tndp->ni_cred->cr_uid) { ! 925: error = EPERM; ! 926: goto bad; ! 927: } ! 928: /* ! 929: * Target must be empty if a directory and have no links ! 930: * to it. Also, ensure source and target are compatible ! 931: * (both directories, or both not directories). ! 932: */ ! 933: if ((xp->i_mode&IFMT) == IFDIR) { ! 934: if (!dirempty(xp, dp->i_number, tndp->ni_cred) || ! 935: xp->i_nlink > 2) { ! 936: error = ENOTEMPTY; ! 937: goto bad; ! 938: } ! 939: if (!doingdirectory) { ! 940: error = ENOTDIR; ! 941: goto bad; ! 942: } ! 943: cache_purge(ITOV(dp)); ! 944: } else if (doingdirectory) { ! 945: error = EISDIR; ! 946: goto bad; ! 947: } ! 948: if (error = dirrewrite(dp, ip, tndp)) ! 949: goto bad; ! 950: /* ! 951: * If the target directory is in the same ! 952: * directory as the source directory, ! 953: * decrement the link count on the parent ! 954: * of the target directory. ! 955: */ ! 956: if (doingdirectory && !newparent) { ! 957: dp->i_nlink--; ! 958: dp->i_flag |= ICHG; ! 959: } ! 960: vput(ITOV(dp)); ! 961: /* ! 962: * Adjust the link count of the target to ! 963: * reflect the dirrewrite above. If this is ! 964: * a directory it is empty and there are ! 965: * no links to it, so we can squash the inode and ! 966: * any space associated with it. We disallowed ! 967: * renaming over top of a directory with links to ! 968: * it above, as the remaining link would point to ! 969: * a directory without "." or ".." entries. ! 970: */ ! 971: xp->i_nlink--; ! 972: if (doingdirectory) { ! 973: if (--xp->i_nlink != 0) ! 974: panic("rename: linked directory"); ! 975: error = itrunc(xp, (u_long)0, IO_SYNC); ! 976: } ! 977: xp->i_flag |= ICHG; ! 978: iput(xp); ! 979: xp = NULL; ! 980: } ! 981: ! 982: /* ! 983: * 3) Unlink the source. ! 984: */ ! 985: unlinkit: ! 986: fndp->ni_nameiop &= ~MODMASK; ! 987: fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF; ! 988: if ((fndp->ni_nameiop & SAVESTART) == 0) ! 989: panic("ufs_rename: lost from startdir"); ! 990: (void) lookup(fndp, p); ! 991: if (fndp->ni_vp != NULL) { ! 992: xp = VTOI(fndp->ni_vp); ! 993: dp = VTOI(fndp->ni_dvp); ! 994: } else { ! 995: /* ! 996: * From name has disappeared. ! 997: */ ! 998: if (doingdirectory) ! 999: panic("rename: lost dir entry"); ! 1000: vrele(ITOV(ip)); ! 1001: return (0); ! 1002: } ! 1003: /* ! 1004: * Ensure that the directory entry still exists and has not ! 1005: * changed while the new name has been entered. If the source is ! 1006: * a file then the entry may have been unlinked or renamed. In ! 1007: * either case there is no further work to be done. If the source ! 1008: * is a directory then it cannot have been rmdir'ed; its link ! 1009: * count of three would cause a rmdir to fail with ENOTEMPTY. ! 1010: * The IRENAME flag ensures that it cannot be moved by another ! 1011: * rename. ! 1012: */ ! 1013: if (xp != ip) { ! 1014: if (doingdirectory) ! 1015: panic("rename: lost dir entry"); ! 1016: } else { ! 1017: /* ! 1018: * If the source is a directory with a ! 1019: * new parent, the link count of the old ! 1020: * parent directory must be decremented ! 1021: * and ".." set to point to the new parent. ! 1022: */ ! 1023: if (doingdirectory && newparent) { ! 1024: dp->i_nlink--; ! 1025: dp->i_flag |= ICHG; ! 1026: error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, ! 1027: sizeof (struct dirtemplate), (off_t)0, ! 1028: UIO_SYSSPACE, IO_NODELOCKED, ! 1029: tndp->ni_cred, (int *)0, (struct proc *)0); ! 1030: if (error == 0) { ! 1031: if (dirbuf.dotdot_namlen != 2 || ! 1032: dirbuf.dotdot_name[0] != '.' || ! 1033: dirbuf.dotdot_name[1] != '.') { ! 1034: dirbad(xp, 12, "rename: mangled dir"); ! 1035: } else { ! 1036: dirbuf.dotdot_ino = newparent; ! 1037: (void) vn_rdwr(UIO_WRITE, ITOV(xp), ! 1038: (caddr_t)&dirbuf, ! 1039: sizeof (struct dirtemplate), ! 1040: (off_t)0, UIO_SYSSPACE, ! 1041: IO_NODELOCKED|IO_SYNC, ! 1042: tndp->ni_cred, (int *)0, ! 1043: (struct proc *)0); ! 1044: cache_purge(ITOV(dp)); ! 1045: } ! 1046: } ! 1047: } ! 1048: error = dirremove(fndp); ! 1049: if (!error) { ! 1050: xp->i_nlink--; ! 1051: xp->i_flag |= ICHG; ! 1052: } ! 1053: xp->i_flag &= ~IRENAME; ! 1054: } ! 1055: if (dp) ! 1056: vput(ITOV(dp)); ! 1057: if (xp) ! 1058: vput(ITOV(xp)); ! 1059: vrele(ITOV(ip)); ! 1060: return (error); ! 1061: ! 1062: bad: ! 1063: if (xp) ! 1064: vput(ITOV(xp)); ! 1065: vput(ITOV(dp)); ! 1066: out: ! 1067: ip->i_nlink--; ! 1068: ip->i_flag |= ICHG; ! 1069: vrele(ITOV(ip)); ! 1070: return (error); ! 1071: } ! 1072: ! 1073: /* ! 1074: * A virgin directory (no blushing please). ! 1075: */ ! 1076: struct dirtemplate mastertemplate = { ! 1077: 0, 12, 1, ".", ! 1078: 0, DIRBLKSIZ - 12, 2, ".." ! 1079: }; ! 1080: ! 1081: /* ! 1082: * Mkdir system call ! 1083: */ ! 1084: ufs_mkdir(ndp, vap, p) ! 1085: struct nameidata *ndp; ! 1086: struct vattr *vap; ! 1087: struct proc *p; ! 1088: { ! 1089: register struct inode *ip, *dp; ! 1090: struct inode *tip; ! 1091: struct vnode *dvp; ! 1092: struct dirtemplate dirtemplate; ! 1093: int error; ! 1094: int dmode; ! 1095: ! 1096: #ifdef DIANOSTIC ! 1097: if ((ndp->ni_nameiop & HASBUF) == 0) ! 1098: panic("ufs_mkdir: no name"); ! 1099: #endif ! 1100: dvp = ndp->ni_dvp; ! 1101: dp = VTOI(dvp); ! 1102: if ((unsigned short)dp->i_nlink >= LINK_MAX) { ! 1103: free(ndp->ni_pnbuf, M_NAMEI); ! 1104: iput(dp); ! 1105: return (EMLINK); ! 1106: } ! 1107: dmode = vap->va_mode&0777; ! 1108: dmode |= IFDIR; ! 1109: /* ! 1110: * Must simulate part of maknode here to acquire the inode, but ! 1111: * not have it entered in the parent directory. The entry is made ! 1112: * later after writing "." and ".." entries. ! 1113: */ ! 1114: if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { ! 1115: free(ndp->ni_pnbuf, M_NAMEI); ! 1116: iput(dp); ! 1117: return (error); ! 1118: } ! 1119: ip = tip; ! 1120: ip->i_uid = ndp->ni_cred->cr_uid; ! 1121: ip->i_gid = dp->i_gid; ! 1122: #ifdef QUOTA ! 1123: if ((error = getinoquota(ip)) || ! 1124: (error = chkiq(ip, 1, ndp->ni_cred, 0))) { ! 1125: free(ndp->ni_pnbuf, M_NAMEI); ! 1126: ifree(ip, ip->i_number, dmode); ! 1127: iput(ip); ! 1128: iput(dp); ! 1129: return (error); ! 1130: } ! 1131: #endif ! 1132: ip->i_flag |= IACC|IUPD|ICHG; ! 1133: ip->i_mode = dmode; ! 1134: ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ ! 1135: ip->i_nlink = 2; ! 1136: error = iupdat(ip, &time, &time, 1); ! 1137: ! 1138: /* ! 1139: * Bump link count in parent directory ! 1140: * to reflect work done below. Should ! 1141: * be done before reference is created ! 1142: * so reparation is possible if we crash. ! 1143: */ ! 1144: dp->i_nlink++; ! 1145: dp->i_flag |= ICHG; ! 1146: if (error = iupdat(dp, &time, &time, 1)) ! 1147: goto bad; ! 1148: ! 1149: /* ! 1150: * Initialize directory with "." ! 1151: * and ".." from static template. ! 1152: */ ! 1153: dirtemplate = mastertemplate; ! 1154: dirtemplate.dot_ino = ip->i_number; ! 1155: dirtemplate.dotdot_ino = dp->i_number; ! 1156: error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, ! 1157: sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, ! 1158: IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); ! 1159: if (error) { ! 1160: dp->i_nlink--; ! 1161: dp->i_flag |= ICHG; ! 1162: goto bad; ! 1163: } ! 1164: if (DIRBLKSIZ > dp->i_fs->fs_fsize) { ! 1165: panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ ! 1166: } else { ! 1167: ip->i_size = DIRBLKSIZ; ! 1168: ip->i_flag |= ICHG; ! 1169: } ! 1170: /* ! 1171: * Directory all set up, now ! 1172: * install the entry for it in ! 1173: * the parent directory. ! 1174: */ ! 1175: if (error = direnter(ip, ndp)) { ! 1176: dp->i_nlink--; ! 1177: dp->i_flag |= ICHG; ! 1178: } ! 1179: bad: ! 1180: /* ! 1181: * No need to do an explicit itrunc here, ! 1182: * vrele will do this for us because we set ! 1183: * the link count to 0. ! 1184: */ ! 1185: if (error) { ! 1186: ip->i_nlink = 0; ! 1187: ip->i_flag |= ICHG; ! 1188: iput(ip); ! 1189: } else ! 1190: ndp->ni_vp = ITOV(ip); ! 1191: FREE(ndp->ni_pnbuf, M_NAMEI); ! 1192: iput(dp); ! 1193: return (error); ! 1194: } ! 1195: ! 1196: /* ! 1197: * Rmdir system call. ! 1198: */ ! 1199: ufs_rmdir(ndp, p) ! 1200: register struct nameidata *ndp; ! 1201: struct proc *p; ! 1202: { ! 1203: register struct inode *ip, *dp; ! 1204: int error = 0; ! 1205: ! 1206: ip = VTOI(ndp->ni_vp); ! 1207: dp = VTOI(ndp->ni_dvp); ! 1208: /* ! 1209: * No rmdir "." please. ! 1210: */ ! 1211: if (dp == ip) { ! 1212: vrele(ITOV(dp)); ! 1213: iput(ip); ! 1214: return (EINVAL); ! 1215: } ! 1216: /* ! 1217: * Verify the directory is empty (and valid). ! 1218: * (Rmdir ".." won't be valid since ! 1219: * ".." will contain a reference to ! 1220: * the current directory and thus be ! 1221: * non-empty.) ! 1222: */ ! 1223: if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { ! 1224: error = ENOTEMPTY; ! 1225: goto out; ! 1226: } ! 1227: /* ! 1228: * Delete reference to directory before purging ! 1229: * inode. If we crash in between, the directory ! 1230: * will be reattached to lost+found, ! 1231: */ ! 1232: if (error = dirremove(ndp)) ! 1233: goto out; ! 1234: dp->i_nlink--; ! 1235: dp->i_flag |= ICHG; ! 1236: cache_purge(ITOV(dp)); ! 1237: iput(dp); ! 1238: ndp->ni_dvp = NULL; ! 1239: /* ! 1240: * Truncate inode. The only stuff left ! 1241: * in the directory is "." and "..". The ! 1242: * "." reference is inconsequential since ! 1243: * we're quashing it. The ".." reference ! 1244: * has already been adjusted above. We've ! 1245: * removed the "." reference and the reference ! 1246: * in the parent directory, but there may be ! 1247: * other hard links so decrement by 2 and ! 1248: * worry about them later. ! 1249: */ ! 1250: ip->i_nlink -= 2; ! 1251: error = itrunc(ip, (u_long)0, IO_SYNC); ! 1252: cache_purge(ITOV(ip)); ! 1253: out: ! 1254: if (ndp->ni_dvp) ! 1255: iput(dp); ! 1256: iput(ip); ! 1257: return (error); ! 1258: } ! 1259: ! 1260: /* ! 1261: * symlink -- make a symbolic link ! 1262: */ ! 1263: ufs_symlink(ndp, vap, target, p) ! 1264: struct nameidata *ndp; ! 1265: struct vattr *vap; ! 1266: char *target; ! 1267: struct proc *p; ! 1268: { ! 1269: struct inode *ip; ! 1270: int error; ! 1271: ! 1272: error = maknode(IFLNK | vap->va_mode, ndp, &ip); ! 1273: if (error) ! 1274: return (error); ! 1275: error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, ! 1276: UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, ! 1277: (struct proc *)0); ! 1278: iput(ip); ! 1279: return (error); ! 1280: } ! 1281: ! 1282: /* ! 1283: * Vnode op for read and write ! 1284: */ ! 1285: ufs_readdir(vp, uio, cred, eofflagp) ! 1286: struct vnode *vp; ! 1287: register struct uio *uio; ! 1288: struct ucred *cred; ! 1289: int *eofflagp; ! 1290: { ! 1291: int count, lost, error; ! 1292: ! 1293: count = uio->uio_resid; ! 1294: count &= ~(DIRBLKSIZ - 1); ! 1295: lost = uio->uio_resid - count; ! 1296: if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) ! 1297: return (EINVAL); ! 1298: uio->uio_resid = count; ! 1299: uio->uio_iov->iov_len = count; ! 1300: error = ufs_read(vp, uio, 0, cred); ! 1301: uio->uio_resid += lost; ! 1302: if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) ! 1303: *eofflagp = 1; ! 1304: else ! 1305: *eofflagp = 0; ! 1306: return (error); ! 1307: } ! 1308: ! 1309: /* ! 1310: * Return target name of a symbolic link ! 1311: */ ! 1312: ufs_readlink(vp, uiop, cred) ! 1313: struct vnode *vp; ! 1314: struct uio *uiop; ! 1315: struct ucred *cred; ! 1316: { ! 1317: ! 1318: return (ufs_read(vp, uiop, 0, cred)); ! 1319: } ! 1320: ! 1321: /* ! 1322: * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually ! 1323: * done. If a buffer has been saved in anticipation of a CREATE, delete it. ! 1324: */ ! 1325: /* ARGSUSED */ ! 1326: ufs_abortop(ndp) ! 1327: struct nameidata *ndp; ! 1328: { ! 1329: ! 1330: if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) ! 1331: FREE(ndp->ni_pnbuf, M_NAMEI); ! 1332: return (0); ! 1333: } ! 1334: ! 1335: /* ! 1336: * Lock an inode. ! 1337: */ ! 1338: ufs_lock(vp) ! 1339: struct vnode *vp; ! 1340: { ! 1341: register struct inode *ip = VTOI(vp); ! 1342: ! 1343: ILOCK(ip); ! 1344: return (0); ! 1345: } ! 1346: ! 1347: /* ! 1348: * Unlock an inode. ! 1349: */ ! 1350: ufs_unlock(vp) ! 1351: struct vnode *vp; ! 1352: { ! 1353: register struct inode *ip = VTOI(vp); ! 1354: ! 1355: if (!(ip->i_flag & ILOCKED)) ! 1356: panic("ufs_unlock NOT LOCKED"); ! 1357: IUNLOCK(ip); ! 1358: return (0); ! 1359: } ! 1360: ! 1361: /* ! 1362: * Check for a locked inode. ! 1363: */ ! 1364: ufs_islocked(vp) ! 1365: struct vnode *vp; ! 1366: { ! 1367: ! 1368: if (VTOI(vp)->i_flag & ILOCKED) ! 1369: return (1); ! 1370: return (0); ! 1371: } ! 1372: ! 1373: /* ! 1374: * Get access to bmap ! 1375: */ ! 1376: ufs_bmap(vp, bn, vpp, bnp) ! 1377: struct vnode *vp; ! 1378: daddr_t bn; ! 1379: struct vnode **vpp; ! 1380: daddr_t *bnp; ! 1381: { ! 1382: struct inode *ip = VTOI(vp); ! 1383: ! 1384: if (vpp != NULL) ! 1385: *vpp = ip->i_devvp; ! 1386: if (bnp == NULL) ! 1387: return (0); ! 1388: return (bmap(ip, bn, bnp)); ! 1389: } ! 1390: ! 1391: /* ! 1392: * Calculate the logical to physical mapping if not done already, ! 1393: * then call the device strategy routine. ! 1394: */ ! 1395: int checkoverlap = 0; ! 1396: ! 1397: ufs_strategy(bp) ! 1398: register struct buf *bp; ! 1399: { ! 1400: register struct inode *ip = VTOI(bp->b_vp); ! 1401: struct vnode *vp; ! 1402: int error; ! 1403: ! 1404: if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) ! 1405: panic("ufs_strategy: spec"); ! 1406: if (bp->b_blkno == bp->b_lblkno) { ! 1407: if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) ! 1408: return (error); ! 1409: if ((long)bp->b_blkno == -1) ! 1410: clrbuf(bp); ! 1411: } ! 1412: if ((long)bp->b_blkno == -1) { ! 1413: biodone(bp); ! 1414: return (0); ! 1415: } ! 1416: #ifdef DIAGNOSTIC ! 1417: if (checkoverlap) { ! 1418: register struct buf *ep; ! 1419: struct buf *ebp; ! 1420: daddr_t start, last; ! 1421: ! 1422: ebp = &buf[nbuf]; ! 1423: start = bp->b_blkno; ! 1424: last = start + btodb(bp->b_bcount) - 1; ! 1425: for (ep = buf; ep < ebp; ep++) { ! 1426: if (ep == bp || (ep->b_flags & B_INVAL) || ! 1427: ep->b_vp == NULLVP) ! 1428: continue; ! 1429: if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) ! 1430: continue; ! 1431: if (vp != ip->i_devvp) ! 1432: continue; ! 1433: /* look for overlap */ ! 1434: if (ep->b_bcount == 0 || ep->b_blkno > last || ! 1435: ep->b_blkno + btodb(ep->b_bcount) <= start) ! 1436: continue; ! 1437: vprint("Disk overlap", vp); ! 1438: printf("\tstart %d, end %d overlap start %d, end %d\n", ! 1439: start, last, ep->b_blkno, ! 1440: ep->b_blkno + btodb(ep->b_bcount) - 1); ! 1441: panic("Disk buffer overlap"); ! 1442: } ! 1443: } ! 1444: #endif /* DIAGNOSTIC */ ! 1445: vp = ip->i_devvp; ! 1446: bp->b_dev = vp->v_rdev; ! 1447: (*(vp->v_op->vop_strategy))(bp); ! 1448: return (0); ! 1449: } ! 1450: ! 1451: /* ! 1452: * Print out the contents of an inode. ! 1453: */ ! 1454: ufs_print(vp) ! 1455: struct vnode *vp; ! 1456: { ! 1457: register struct inode *ip = VTOI(vp); ! 1458: ! 1459: printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, ! 1460: major(ip->i_dev), minor(ip->i_dev)); ! 1461: #ifdef FIFO ! 1462: if (vp->v_type == VFIFO) ! 1463: fifo_printinfo(vp); ! 1464: #endif /* FIFO */ ! 1465: printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); ! 1466: if (ip->i_spare0 == 0) ! 1467: return; ! 1468: printf("\towner pid %d", ip->i_spare0); ! 1469: if (ip->i_spare1) ! 1470: printf(" waiting pid %d", ip->i_spare1); ! 1471: printf("\n"); ! 1472: } ! 1473: ! 1474: /* ! 1475: * Read wrapper for special devices. ! 1476: */ ! 1477: ufsspec_read(vp, uio, ioflag, cred) ! 1478: struct vnode *vp; ! 1479: struct uio *uio; ! 1480: int ioflag; ! 1481: struct ucred *cred; ! 1482: { ! 1483: ! 1484: /* ! 1485: * Set access flag. ! 1486: */ ! 1487: VTOI(vp)->i_flag |= IACC; ! 1488: return (spec_read(vp, uio, ioflag, cred)); ! 1489: } ! 1490: ! 1491: /* ! 1492: * Write wrapper for special devices. ! 1493: */ ! 1494: ufsspec_write(vp, uio, ioflag, cred) ! 1495: struct vnode *vp; ! 1496: struct uio *uio; ! 1497: int ioflag; ! 1498: struct ucred *cred; ! 1499: { ! 1500: ! 1501: /* ! 1502: * Set update and change flags. ! 1503: */ ! 1504: VTOI(vp)->i_flag |= IUPD|ICHG; ! 1505: return (spec_write(vp, uio, ioflag, cred)); ! 1506: } ! 1507: ! 1508: /* ! 1509: * Close wrapper for special devices. ! 1510: * ! 1511: * Update the times on the inode then do device close. ! 1512: */ ! 1513: ufsspec_close(vp, fflag, cred, p) ! 1514: struct vnode *vp; ! 1515: int fflag; ! 1516: struct ucred *cred; ! 1517: struct proc *p; ! 1518: { ! 1519: register struct inode *ip = VTOI(vp); ! 1520: ! 1521: if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) ! 1522: ITIMES(ip, &time, &time); ! 1523: return (spec_close(vp, fflag, cred, p)); ! 1524: } ! 1525: ! 1526: #ifdef FIFO ! 1527: /* ! 1528: * Read wrapper for fifo's ! 1529: */ ! 1530: ufsfifo_read(vp, uio, ioflag, cred) ! 1531: struct vnode *vp; ! 1532: struct uio *uio; ! 1533: int ioflag; ! 1534: struct ucred *cred; ! 1535: { ! 1536: ! 1537: /* ! 1538: * Set access flag. ! 1539: */ ! 1540: VTOI(vp)->i_flag |= IACC; ! 1541: return (fifo_read(vp, uio, ioflag, cred)); ! 1542: } ! 1543: ! 1544: /* ! 1545: * Write wrapper for fifo's. ! 1546: */ ! 1547: ufsfifo_write(vp, uio, ioflag, cred) ! 1548: struct vnode *vp; ! 1549: struct uio *uio; ! 1550: int ioflag; ! 1551: struct ucred *cred; ! 1552: { ! 1553: ! 1554: /* ! 1555: * Set update and change flags. ! 1556: */ ! 1557: VTOI(vp)->i_flag |= IUPD|ICHG; ! 1558: return (fifo_write(vp, uio, ioflag, cred)); ! 1559: } ! 1560: ! 1561: /* ! 1562: * Close wrapper for fifo's. ! 1563: * ! 1564: * Update the times on the inode then do device close. ! 1565: */ ! 1566: ufsfifo_close(vp, fflag, cred, p) ! 1567: struct vnode *vp; ! 1568: int fflag; ! 1569: struct ucred *cred; ! 1570: struct proc *p; ! 1571: { ! 1572: register struct inode *ip = VTOI(vp); ! 1573: ! 1574: if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) ! 1575: ITIMES(ip, &time, &time); ! 1576: return (fifo_close(vp, fflag, cred, p)); ! 1577: } ! 1578: #endif /* FIFO */ ! 1579: ! 1580: /* ! 1581: * Allocate a new inode. ! 1582: */ ! 1583: maknode(mode, ndp, ipp) ! 1584: int mode; ! 1585: register struct nameidata *ndp; ! 1586: struct inode **ipp; ! 1587: { ! 1588: register struct inode *ip; ! 1589: struct inode *tip; ! 1590: register struct inode *pdir = VTOI(ndp->ni_dvp); ! 1591: ino_t ipref; ! 1592: int error; ! 1593: ! 1594: #ifdef DIANOSTIC ! 1595: if ((ndp->ni_nameiop & HASBUF) == 0) ! 1596: panic("maknode: no name"); ! 1597: #endif ! 1598: *ipp = 0; ! 1599: if ((mode & IFMT) == 0) ! 1600: mode |= IFREG; ! 1601: if ((mode & IFMT) == IFDIR) ! 1602: ipref = dirpref(pdir->i_fs); ! 1603: else ! 1604: ipref = pdir->i_number; ! 1605: if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { ! 1606: free(ndp->ni_pnbuf, M_NAMEI); ! 1607: iput(pdir); ! 1608: return (error); ! 1609: } ! 1610: ip = tip; ! 1611: ip->i_uid = ndp->ni_cred->cr_uid; ! 1612: ip->i_gid = pdir->i_gid; ! 1613: #ifdef QUOTA ! 1614: if ((error = getinoquota(ip)) || ! 1615: (error = chkiq(ip, 1, ndp->ni_cred, 0))) { ! 1616: free(ndp->ni_pnbuf, M_NAMEI); ! 1617: ifree(ip, ip->i_number, mode); ! 1618: iput(ip); ! 1619: iput(pdir); ! 1620: return (error); ! 1621: } ! 1622: #endif ! 1623: ip->i_flag |= IACC|IUPD|ICHG; ! 1624: ip->i_mode = mode; ! 1625: ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ ! 1626: ip->i_nlink = 1; ! 1627: if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && ! 1628: suser(ndp->ni_cred, NULL)) ! 1629: ip->i_mode &= ~ISGID; ! 1630: ! 1631: /* ! 1632: * Make sure inode goes to disk before directory entry. ! 1633: */ ! 1634: if (error = iupdat(ip, &time, &time, 1)) ! 1635: goto bad; ! 1636: if (error = direnter(ip, ndp)) ! 1637: goto bad; ! 1638: if ((ndp->ni_nameiop & SAVESTART) == 0) ! 1639: FREE(ndp->ni_pnbuf, M_NAMEI); ! 1640: iput(pdir); ! 1641: *ipp = ip; ! 1642: return (0); ! 1643: ! 1644: bad: ! 1645: /* ! 1646: * Write error occurred trying to update the inode ! 1647: * or the directory so must deallocate the inode. ! 1648: */ ! 1649: free(ndp->ni_pnbuf, M_NAMEI); ! 1650: iput(pdir); ! 1651: ip->i_nlink = 0; ! 1652: ip->i_flag |= ICHG; ! 1653: iput(ip); ! 1654: return (error); ! 1655: } ! 1656: ! 1657: /* ! 1658: * Advisory record locking support ! 1659: */ ! 1660: ufs_advlock(vp, id, op, fl, flags) ! 1661: struct vnode *vp; ! 1662: caddr_t id; ! 1663: int op; ! 1664: register struct flock *fl; ! 1665: int flags; ! 1666: { ! 1667: register struct inode *ip = VTOI(vp); ! 1668: register struct lockf *lock; ! 1669: off_t start, end; ! 1670: int error; ! 1671: ! 1672: /* ! 1673: * Avoid the common case of unlocking when inode has no locks. ! 1674: */ ! 1675: if (ip->i_lockf == (struct lockf *)0) { ! 1676: if (op != F_SETLK) { ! 1677: fl->l_type = F_UNLCK; ! 1678: return (0); ! 1679: } ! 1680: } ! 1681: /* ! 1682: * Convert the flock structure into a start and end. ! 1683: */ ! 1684: switch (fl->l_whence) { ! 1685: ! 1686: case SEEK_SET: ! 1687: case SEEK_CUR: ! 1688: /* ! 1689: * Caller is responsible for adding any necessary offset ! 1690: * when SEEK_CUR is used. ! 1691: */ ! 1692: start = fl->l_start; ! 1693: break; ! 1694: ! 1695: case SEEK_END: ! 1696: start = ip->i_size + fl->l_start; ! 1697: break; ! 1698: ! 1699: default: ! 1700: return (EINVAL); ! 1701: } ! 1702: if (start < 0) ! 1703: return (EINVAL); ! 1704: if (fl->l_len == 0) ! 1705: end = -1; ! 1706: else ! 1707: end = start + fl->l_len - 1; ! 1708: /* ! 1709: * Create the lockf structure ! 1710: */ ! 1711: MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); ! 1712: lock->lf_start = start; ! 1713: lock->lf_end = end; ! 1714: lock->lf_id = id; ! 1715: lock->lf_inode = ip; ! 1716: lock->lf_type = fl->l_type; ! 1717: lock->lf_next = (struct lockf *)0; ! 1718: lock->lf_block = (struct lockf *)0; ! 1719: lock->lf_flags = flags; ! 1720: /* ! 1721: * Do the requested operation. ! 1722: */ ! 1723: switch(op) { ! 1724: case F_SETLK: ! 1725: return (lf_setlock(lock)); ! 1726: ! 1727: case F_UNLCK: ! 1728: error = lf_clearlock(lock); ! 1729: FREE(lock, M_LOCKF); ! 1730: return (error); ! 1731: ! 1732: case F_GETLK: ! 1733: error = lf_getlock(lock, fl); ! 1734: FREE(lock, M_LOCKF); ! 1735: return (error); ! 1736: ! 1737: default: ! 1738: free(lock, M_LOCKF); ! 1739: return (EINVAL); ! 1740: } ! 1741: /* NOTREACHED */ ! 1742: } ! 1743: ! 1744: /* ! 1745: * Global vfs data structures for ufs ! 1746: */ ! 1747: struct vnodeops ufs_vnodeops = { ! 1748: ufs_lookup, /* lookup */ ! 1749: ufs_create, /* create */ ! 1750: ufs_mknod, /* mknod */ ! 1751: ufs_open, /* open */ ! 1752: ufs_close, /* close */ ! 1753: ufs_access, /* access */ ! 1754: ufs_getattr, /* getattr */ ! 1755: ufs_setattr, /* setattr */ ! 1756: ufs_read, /* read */ ! 1757: ufs_write, /* write */ ! 1758: ufs_ioctl, /* ioctl */ ! 1759: ufs_select, /* select */ ! 1760: ufs_mmap, /* mmap */ ! 1761: ufs_fsync, /* fsync */ ! 1762: ufs_seek, /* seek */ ! 1763: ufs_remove, /* remove */ ! 1764: ufs_link, /* link */ ! 1765: ufs_rename, /* rename */ ! 1766: ufs_mkdir, /* mkdir */ ! 1767: ufs_rmdir, /* rmdir */ ! 1768: ufs_symlink, /* symlink */ ! 1769: ufs_readdir, /* readdir */ ! 1770: ufs_readlink, /* readlink */ ! 1771: ufs_abortop, /* abortop */ ! 1772: ufs_inactive, /* inactive */ ! 1773: ufs_reclaim, /* reclaim */ ! 1774: ufs_lock, /* lock */ ! 1775: ufs_unlock, /* unlock */ ! 1776: ufs_bmap, /* bmap */ ! 1777: ufs_strategy, /* strategy */ ! 1778: ufs_print, /* print */ ! 1779: ufs_islocked, /* islocked */ ! 1780: ufs_advlock, /* advlock */ ! 1781: }; ! 1782: ! 1783: struct vnodeops spec_inodeops = { ! 1784: spec_lookup, /* lookup */ ! 1785: spec_create, /* create */ ! 1786: spec_mknod, /* mknod */ ! 1787: spec_open, /* open */ ! 1788: ufsspec_close, /* close */ ! 1789: ufs_access, /* access */ ! 1790: ufs_getattr, /* getattr */ ! 1791: ufs_setattr, /* setattr */ ! 1792: ufsspec_read, /* read */ ! 1793: ufsspec_write, /* write */ ! 1794: spec_ioctl, /* ioctl */ ! 1795: spec_select, /* select */ ! 1796: spec_mmap, /* mmap */ ! 1797: spec_fsync, /* fsync */ ! 1798: spec_seek, /* seek */ ! 1799: spec_remove, /* remove */ ! 1800: spec_link, /* link */ ! 1801: spec_rename, /* rename */ ! 1802: spec_mkdir, /* mkdir */ ! 1803: spec_rmdir, /* rmdir */ ! 1804: spec_symlink, /* symlink */ ! 1805: spec_readdir, /* readdir */ ! 1806: spec_readlink, /* readlink */ ! 1807: spec_abortop, /* abortop */ ! 1808: ufs_inactive, /* inactive */ ! 1809: ufs_reclaim, /* reclaim */ ! 1810: ufs_lock, /* lock */ ! 1811: ufs_unlock, /* unlock */ ! 1812: spec_bmap, /* bmap */ ! 1813: spec_strategy, /* strategy */ ! 1814: ufs_print, /* print */ ! 1815: ufs_islocked, /* islocked */ ! 1816: spec_advlock, /* advlock */ ! 1817: }; ! 1818: ! 1819: #ifdef FIFO ! 1820: struct vnodeops fifo_inodeops = { ! 1821: fifo_lookup, /* lookup */ ! 1822: fifo_create, /* create */ ! 1823: fifo_mknod, /* mknod */ ! 1824: fifo_open, /* open */ ! 1825: ufsfifo_close, /* close */ ! 1826: ufs_access, /* access */ ! 1827: ufs_getattr, /* getattr */ ! 1828: ufs_setattr, /* setattr */ ! 1829: ufsfifo_read, /* read */ ! 1830: ufsfifo_write, /* write */ ! 1831: fifo_ioctl, /* ioctl */ ! 1832: fifo_select, /* select */ ! 1833: fifo_mmap, /* mmap */ ! 1834: fifo_fsync, /* fsync */ ! 1835: fifo_seek, /* seek */ ! 1836: fifo_remove, /* remove */ ! 1837: fifo_link, /* link */ ! 1838: fifo_rename, /* rename */ ! 1839: fifo_mkdir, /* mkdir */ ! 1840: fifo_rmdir, /* rmdir */ ! 1841: fifo_symlink, /* symlink */ ! 1842: fifo_readdir, /* readdir */ ! 1843: fifo_readlink, /* readlink */ ! 1844: fifo_abortop, /* abortop */ ! 1845: ufs_inactive, /* inactive */ ! 1846: ufs_reclaim, /* reclaim */ ! 1847: ufs_lock, /* lock */ ! 1848: ufs_unlock, /* unlock */ ! 1849: fifo_bmap, /* bmap */ ! 1850: fifo_strategy, /* strategy */ ! 1851: ufs_print, /* print */ ! 1852: ufs_islocked, /* islocked */ ! 1853: fifo_advlock, /* advlock */ ! 1854: }; ! 1855: #endif /* FIFO */ ! 1856: ! 1857: enum vtype iftovt_tab[16] = { ! 1858: VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, ! 1859: VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, ! 1860: }; ! 1861: int vttoif_tab[9] = { ! 1862: 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, ! 1863: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.