+ error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
+ if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
+ bp->b_flags |= B_AGE;
+ brelse(bp);
+ } while (error == 0 && uio->uio_resid > 0 && n != 0);
+ return (error);
+}
+
+/*
+ * Vnode op for writing.
+ */
+ufs_write(vp, uio, ioflag, cred)
+ register struct vnode *vp;
+ struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+ register struct inode *ip = VTOI(vp);
+ register struct fs *fs;
+ struct buf *bp;
+ daddr_t lbn, bn;
+ u_long osize;
+ int i, n, on, flags;
+ int count, size, resid, error = 0;
+
+ if (uio->uio_rw != UIO_WRITE)
+ panic("ufs_write mode");
+ switch (vp->v_type) {
+ case VREG:
+ if (ioflag & IO_APPEND)
+ uio->uio_offset = ip->i_size;
+ /* fall through */
+ case VLNK:
+ break;
+
+ case VDIR:
+ if ((ioflag & IO_SYNC) == 0)
+ panic("ufs_write nonsync dir write");
+ break;
+
+ default:
+ panic("ufs_write type");
+ }
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ if (uio->uio_resid == 0)
+ return (0);
+ /*
+ * Maybe this should be above the vnode op call, but so long as
+ * file servers have no limits, i don't think it matters
+ */
+ if (vp->v_type == VREG &&
+ uio->uio_offset + uio->uio_resid >
+ u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ psignal(u.u_procp, SIGXFSZ);
+ return (EFBIG);
+ }
+ resid = uio->uio_resid;
+ osize = ip->i_size;
+ fs = ip->i_fs;
+ do {
+ lbn = lblkno(fs, uio->uio_offset);
+ on = blkoff(fs, uio->uio_offset);
+ n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
+ if (n < fs->fs_bsize)
+ flags = B_CLRBUF;
+ else
+ flags = 0;
+ if (error = balloc(ip, lbn, (int)(on + n), &bn, flags))
+ break;
+ if (uio->uio_offset + n > ip->i_size)
+ ip->i_size = uio->uio_offset + n;
+ size = blksize(fs, ip, lbn);
+ count = howmany(size, CLBYTES);
+ for (i = 0; i < count; i++)
+ munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
+ if (n == fs->fs_bsize)
+ bp = getblk(ip->i_devvp, bn, size);
+ else
+ error = bread(ip->i_devvp, bn, size, NOCRED, &bp);
+ n = MIN(n, size - bp->b_resid);
+ if (error) {
+ brelse(bp);
+ break;
+ }
+ error = uiomove(bp->b_un.b_addr + on, n, uio);
+ if (ioflag & IO_SYNC)
+ (void) bwrite(bp);
+ else if (n + on == fs->fs_bsize) {
+ bp->b_flags |= B_AGE;
+ bawrite(bp);
+ } else
+ bdwrite(bp);
+ ip->i_flag |= IUPD|ICHG;
+ if (cred->cr_uid != 0)
+ ip->i_mode &= ~(ISUID|ISGID);
+ } while (error == 0 && uio->uio_resid > 0 && n != 0);
+ if (error && (ioflag & IO_UNIT)) {
+ (void) itrunc(ip, osize);
+ uio->uio_offset -= resid - uio->uio_resid;
+ uio->uio_resid = resid;
+ }
+ return (error);
+}
+
+/* ARGSUSED */
+ufs_ioctl(vp, com, data, fflag, cred)
+ struct vnode *vp;
+ int com;
+ caddr_t data;
+ int fflag;
+ struct ucred *cred;
+{
+
+ return (ENOTTY);
+}
+
+/* ARGSUSED */
+ufs_select(vp, which, cred)
+ struct vnode *vp;
+ int which;
+ struct ucred *cred;
+{
+
+ return (1); /* XXX */
+}
+
+/*
+ * Mmap a file
+ *
+ * NB Currently unsupported.
+ */
+/* ARGSUSED */
+ufs_mmap(vp, fflags, cred)
+ struct vnode *vp;
+ int fflags;
+ struct ucred *cred;
+{
+
+ return (EINVAL);
+}
+
+/*
+ * Synch an open file.
+ */
+/* ARGSUSED */
+ufs_fsync(vp, fflags, cred, waitfor)
+ struct vnode *vp;
+ int fflags;
+ struct ucred *cred;
+ int waitfor;
+{
+ struct inode *ip = VTOI(vp);
+
+ if (fflags&FWRITE)
+ ip->i_flag |= ICHG;
+ return (syncip(ip, waitfor));
+}
+
+/*
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
+ */
+/* ARGSUSED */
+ufs_seek(vp, oldoff, newoff, cred)
+ struct vnode *vp;
+ off_t oldoff, newoff;
+ struct ucred *cred;
+{
+
+ return (0);
+}
+
+/*
+ * ufs remove
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+ufs_remove(ndp)
+ struct nameidata *ndp;
+{
+ register struct inode *ip, *dp;
+ int error;
+
+ ip = VTOI(ndp->ni_vp);
+ dp = VTOI(ndp->ni_dvp);
+ error = dirremove(ndp);
+ if (!error) {
+ ip->i_nlink--;
+ ip->i_flag |= ICHG;