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