- 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;
- extern struct cmap *mfind();
-
- 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, 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;