/* @(#)rdwri.c	1.4 */#include "sys/param.h"#include "sys/types.h"#include "sys/sysmacros.h"#include "sys/inode.h"#include "sys/dir.h"#include "sys/signal.h"#include "sys/user.h"#include "sys/proc.h"#include "sys/errno.h"#include "sys/buf.h"#include "sys/conf.h"#include "sys/file.h"#include "sys/systm.h"#include "sys/tty.h"/* * Read the file corresponding to * the inode pointed at by the argument. * The actual read arguments are found * in the variables: *	u_base		core address for destination *	u_offset	byte offset in file *	u_count		number of bytes to read *	u_segflg	read to kernel/user/user I */readi(ip)register struct inode *ip;{	register struct user *up;	register struct buf *bp;	register dev_t dev;	register daddr_t bn;	register unsigned on, n;	register type;	register struct tty *tp;	struct cdevsw *cdevp;	up = &u;	if (up->u_count == 0)		return;	if (up->u_offset < 0) {		up->u_error = EINVAL;		return;	}	type = ip->i_mode&IFMT;	switch(type) {	case IFCHR:		dev = (dev_t)ip->i_rdev;		ip->i_flag |= IACC;		cdevp = &cdevsw[(short)major(dev)];		if (tp = cdevp->d_ttys) {			tp += (short)(minor(dev)&077);			(*linesw[(short)tp->t_line].l_read)(tp);		} else			(*cdevp->d_read)(minor(dev));		break;	case IFIFO:		while (ip->i_size == 0) {			if (ip->i_fwcnt == 0)				return;			if (up->u_fmode&FNDELAY)				return;			ip->i_fflag |= IFIR;			prele(ip);			(void) sleep((caddr_t)&ip->i_frcnt, PPIPE);			plock(ip);		}		up->u_offset = ip->i_frptr;	case IFBLK:	case IFREG:	case IFDIR:	do {		bn = bmap(ip, B_READ);		if (up->u_error)			break;		on = up->u_pboff;		if ((n = up->u_pbsize) == 0)			break;		dev = up->u_pbdev;		if ((long)bn<0) {			if (type != IFREG)				break;			bp = geteblk();			clrbuf(bp);		} else if (up->u_rablock)			bp = breada(dev, bn, up->u_rablock);		else			bp = bread(dev, bn);		if (bp->b_resid) {			n = 0;		}		if (n!=0)			iomove(bp->b_un.b_addr+on, (int)n, B_READ);		if (type == IFIFO) {			ip->i_size -= n;			if (up->u_offset >= PIPSIZ)				up->u_offset = 0;			if ((on+n) == FsBSIZE(dev) && ip->i_size < (PIPSIZ-FsBSIZE(dev)))				bp->b_flags &= ~B_DELWRI;		}		brelse(bp);		ip->i_flag |= IACC;	} while (up->u_error==0 && up->u_count!=0 && n!=0);		if (type == IFIFO) {			if (ip->i_size)				ip->i_frptr = up->u_offset;			else {				ip->i_frptr = 0;				ip->i_fwptr = 0;			}			if (ip->i_fflag&IFIW) {				ip->i_fflag &= ~IFIW;				curpri = PPIPE;				wakeup((caddr_t)&ip->i_fwcnt);			}		}		break;	default:		up->u_error = ENODEV;	}}/* * Write the file corresponding to * the inode pointed at by the argument. * The actual write arguments are found * in the variables: *	u_base		core address for source *	u_offset	byte offset in file *	u_count		number of bytes to write *	u_segflg	write to kernel/user/user I */writei(ip)register struct inode *ip;{	register struct user *up;	register struct buf *bp;	register dev_t dev;	register daddr_t bn;	register unsigned n, on;	register type;	unsigned int usave;	register struct tty *tp;	struct cdevsw *cdevp;	up = &u;	if (up->u_offset < 0) {		up->u_error = EINVAL;		return;	}	type = ip->i_mode&IFMT;	switch (type) {	case IFCHR:		dev = (dev_t)ip->i_rdev;		ip->i_flag |= IUPD|ICHG;		cdevp = &cdevsw[(short)major(dev)];		if (tp = cdevp->d_ttys) {			tp += (short)(minor(dev)&077);			(*linesw[(short)tp->t_line].l_write)(tp);		} else			(*cdevp->d_write)(minor(dev));		break;	case IFIFO:	floop:		usave = 0;		while ((up->u_count+ip->i_size) > PIPSIZ) {			if (ip->i_frcnt == 0)				break;			if ((up->u_count > PIPSIZ) && (ip->i_size < PIPSIZ)) {				usave = up->u_count;				up->u_count = PIPSIZ - ip->i_size;				usave -= up->u_count;				break;			}			if (up->u_fmode&FNDELAY)				return;			ip->i_fflag |= IFIW;			prele(ip);			(void) sleep((caddr_t)&ip->i_fwcnt, PPIPE);			plock(ip);		}		if (ip->i_frcnt == 0) {			up->u_error = EPIPE;			psignal(up->u_procp, SIGPIPE);			break;		}		up->u_offset = ip->i_fwptr;	case IFBLK:	case IFREG:	case IFDIR:	while (up->u_error==0 && up->u_count!=0) {		bn = bmap(ip, B_WRITE);		if (up->u_error)			break;		on = up->u_pboff;		n = up->u_pbsize;		dev = up->u_pbdev;		if (n == FsBSIZE(dev)) 			bp = getblk(dev, bn);		else if (type==IFIFO && on==0 && ip->i_size < (PIPSIZ-FsBSIZE(dev)))			bp = getblk(dev, bn);		else			bp = bread(dev, bn);		iomove(bp->b_un.b_addr+on, (int)n, B_WRITE);		if (up->u_error)			brelse(bp);		else if (up->u_fmode&FSYNC)			bwrite(bp);		else if (type == IFBLK) {			/* IFBLK not delayed for tapes */			bp->b_flags |= B_AGE;			bawrite(bp);		} else			bdwrite(bp);		if (type == IFREG || type == IFDIR) {			if (up->u_offset > ip->i_size)				ip->i_size = up->u_offset;		} else if (type == IFIFO) {			ip->i_size += n;			if (up->u_offset == PIPSIZ)				up->u_offset = 0;		}		ip->i_flag |= IUPD|ICHG;	}		if (type == IFIFO) {			ip->i_fwptr = up->u_offset;			if (ip->i_fflag&IFIR) {				ip->i_fflag &= ~IFIR;				curpri = PPIPE;				wakeup((caddr_t)&ip->i_frcnt);			}			if (up->u_error==0 && usave!=0) {				up->u_count = usave;				goto floop;			}		}		break;	default:		up->u_error = ENODEV;	}}/* * Move n bytes at byte location * &bp->b_un.b_addr[o] to/from (flag) the * user/kernel (u.segflg) area starting at u.base. * Update all the arguments by the number * of bytes moved. */iomove(cp, n, flag)register caddr_t cp;register n;{	register struct user *up;	register t;	if (n==0)		return;	up = &u;	if (up->u_segflg != 1)  {		if (flag==B_WRITE)			t = copyin(up->u_base, (caddr_t)cp, n);		else			t = copyout((caddr_t)cp, up->u_base, n);		if (t) {			up->u_error = EFAULT;			return;		}	}	else		if (flag == B_WRITE)			bcopy(up->u_base,(caddr_t)cp,n);		else			bcopy((caddr_t)cp,up->u_base,n);	up->u_base += n;	up->u_offset += n;	up->u_count -= n;	return;}