+rwip(ip, uio, rw)
+ register struct inode *ip;
+ register struct uio *uio;
+ enum uio_rw rw;
+{
+ dev_t dev = (dev_t)ip->i_rdev;
+ struct buf *bp;
+ struct fs *fs;
+ daddr_t lbn, bn;
+ register int on, type;
+ register unsigned n;
+ int size;
+ long bsize;
+ extern int mem_no;
+ int error = 0;
+
+ if (rw != UIO_READ && rw != UIO_WRITE)
+ panic("rwip");
+ if (uio->uio_offset < 0 &&
+ ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)))
+ return (EINVAL); if (rw == UIO_READ)
+ ip->i_flag |= IACC;
+ type = ip->i_mode&IFMT;
+ if (type == IFCHR) {
+#ifdef QUOTA
+ register c = uio->uio_resid;
+#endif
+ if (rw == UIO_READ)
+ u.u_error = (*cdevsw[major(dev)].d_read)(dev, uio);
+ else {
+ ip->i_flag |= IUPD|ICHG;
+ u.u_error = (*cdevsw[major(dev)].d_write)(dev, uio);
+ }
+ CHARGE(sc_tio * (c - uio->uio_resid));
+ return (u.u_error);
+ }
+ if (rw == UIO_WRITE && type == IFREG &&
+ uio->uio_offset + uio->uio_resid >
+ u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ psignal(u.u_procp, SIGXFSZ);
+ return (EMFILE);
+ }
+ if (type != IFBLK) {
+ dev = ip->i_dev;
+ fs = ip->i_fs;
+ bsize = fs->fs_bsize;
+ } else
+ bsize = BLKDEV_IOSIZE;
+ do {
+ lbn = uio->uio_offset / bsize;
+ on = uio->uio_offset % bsize;
+ n = MIN((unsigned)(bsize - on), uio->uio_resid);
+ if (type != IFBLK) {
+ if (rw == UIO_READ) {
+ int diff = ip->i_size - uio->uio_offset;
+ if (diff <= 0)
+ return (0);
+ if (diff < n)
+ n = diff;
+ }
+ bn = fsbtodb(fs,
+ bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n)));
+ if (u.u_error || rw == UIO_WRITE && (long)bn<0)
+ return (u.u_error);
+ if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size &&
+ (type == IFDIR || type == IFREG || type == IFLNK))
+ ip->i_size = uio->uio_offset + n;
+ size = blksize(fs, ip, lbn);
+ } else {
+ bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
+ rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
+ rasize = size = bsize;
+ }
+ if (rw == UIO_READ) {
+ if ((long)bn<0) {
+ bp = geteblk(size);
+ clrbuf(bp);
+ } else if (ip->i_lastr + 1 == lbn)
+ bp = breada(dev, bn, size, rablock, rasize);
+ else
+ bp = bread(dev, bn, size);
+ ip->i_lastr = lbn;
+ } else {
+ int i, count;
+
+ count = howmany(size, DEV_BSIZE);
+ for (i = 0; i < count; i += CLSIZE)
+ if (mfind(dev, bn + i))
+ munhash(dev, bn + i);
+ if (n == bsize)
+ bp = getblk(dev, bn, size);
+ else
+ bp = bread(dev, bn, size);
+ }
+ n = MIN(n, size - bp->b_resid);
+ if (bp->b_flags & B_ERROR) {
+ error = EIO;
+ brelse(bp);
+ goto bad;
+ }
+ u.u_error =
+ uiomove(bp->b_un.b_addr+on, (u_int)n, rw, uio);
+ if (rw == UIO_READ) {
+ if (n + on == bsize || uio->uio_offset == ip->i_size)
+ bp->b_flags |= B_AGE;
+ brelse(bp);
+ } else {
+ if ((ip->i_mode&IFMT) == IFDIR)
+ bwrite(bp);
+ else if (n + on == bsize) {
+ bp->b_flags |= B_AGE;
+ bawrite(bp);
+ } else
+ bdwrite(bp);
+ ip->i_flag |= IUPD|ICHG;
+ if (u.u_ruid != 0)
+ ip->i_mode &= ~(ISUID|ISGID);
+ }
+ } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0);
+bad:
+ return (error);
+}
+
+uiomove(cp, n, rw, uio)
+ register caddr_t cp;
+ register int n;
+ enum uio_rw rw;
+ register struct uio *uio;
+{
+ register struct iovec *iov;
+ int error;
+ u_int cnt;
+
+ while (n > 0 && uio->uio_resid) {
+ iov = uio->uio_iov;
+ cnt = iov->iov_len;
+ if (cnt == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ continue;
+ }
+ if (cnt > n)
+ cnt = n;
+ switch (uio->uio_segflg) {
+
+ case 0:
+ case 2:
+ if (rw == UIO_READ)
+ error = copyout(cp, iov->iov_base, cnt);
+ else
+ error = copyin(iov->iov_base, cp, cnt);
+ if (error)
+ return (error);
+ break;
+
+ case 1:
+ if (rw == UIO_READ)
+ bcopy((caddr_t)cp, iov->iov_base, cnt);
+ else
+ bcopy(iov->iov_base, (caddr_t)cp, cnt);
+ break;
+ }
+ iov->iov_base += cnt;
+ iov->iov_len -= cnt;
+ uio->uio_resid -= cnt;
+ uio->uio_offset += cnt;
+ cp += cnt;
+ n -= cnt;
+ }
+ return (error);
+}
+
+/*
+ * Give next character to user as result of read.
+ */
+ureadc(c, uio)
+ register int c;
+ register struct uio *uio;
+{
+ register struct iovec *iov;
+
+again:
+ if (uio->uio_iovcnt == 0)
+ panic("ureadc");
+ iov = uio->uio_iov;
+ if (iov->iov_len <= 0 || uio->uio_resid <= 0) {
+ uio->uio_iovcnt--;
+ uio->uio_iov++;
+ goto again;
+ }
+ switch (uio->uio_segflg) {
+
+ case 0:
+ if (subyte(iov->iov_base, c) < 0)
+ return (EFAULT);
+ break;
+
+ case 1:
+ *iov->iov_base = c;
+ break;
+
+ case 2:
+ if (suibyte(iov->iov_base, c) < 0)
+ return (EFAULT);
+ break;
+ }
+ iov->iov_base++;
+ iov->iov_len--;
+ uio->uio_resid--;
+ uio->uio_offset++;
+ return (0);
+}
+
+/*
+ * Get next character written in by user from uio.
+ */
+uwritec(uio)
+ struct uio *uio;