static char rcsid[] = "$Header: efs_subr.c,v 820.1 86/12/04 19:47:50 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * Subroutines for the Extended Filesystem
 * which are not specific to it.
 *
 * jam 840209-11
 */

#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/mbuf.h"
#include "../h/uio.h"

#define UIO_SEG_KD	1	/* Kernel data */

/*
 * Fill a uio structure and it's iovec
 * structures with values that represent
 * the data in the mbuf chain whose top is
 * supplied.  Return the total number of
 * bytes of data on success and -1 on failure.
 */
int
mbuftouio(base, len, uio, maxiov)
   register caddr_t base;
   register int len;
   register struct uio *uio;
   register int maxiov;
{
	register struct iovec *iov = uio->uio_iov;
	register struct mbuf *m;
	register int size;

	uio->uio_segflg = UIO_SEG_KD;
	uio->uio_iovcnt = 0;
	uio->uio_resid = 0;
	/*
	 * First one is a special case since data does not
	 * necessarily begin at the first byte of data in
	 * the mbuf.
	 */
	m = dtom(base);
	size = m->m_len - ((int)base - mtod(m, int));
	if (size <= 0)
		panic("mbuftouio");
	while (len) {
		if (++uio->uio_iovcnt > maxiov)
			return(-1);
		size = MIN(size, len);
		uio->uio_resid += size;
		iov->iov_len = size;
		iov->iov_base = base;
		++iov;
		len -= size;
		if ((m = m->m_next) == 0)
			break;
		size = m->m_len;
		base = mtod(m, caddr_t);
	}
	return(uio->uio_resid);
}
/*
 * Copy data from one uio to another uio.
 * This is done one iov at a time using
 * whichever iov has the smaller amount
 * of data.  Return an error code if any
 * errors are encountered.  Note: one of
 * the uios must represent data in kernel
 * space.
 */
uiocopy(suio, duio, count)
   register struct uio *suio,*duio;
   register int count;
{
	if (suio->uio_segflg != UIO_SEG_KD && duio->uio_segflg != UIO_SEG_KD ||
	    suio->uio_resid < count || duio->uio_resid < count)
		panic("uiocopy");
	while (count) {
		register struct iovec *siov = suio->uio_iov;
		register struct iovec *diov = duio->uio_iov;
		register int size = MIN(siov->iov_len, diov->iov_len);
		register int error;

		size = MIN(size, count);
		if (suio->uio_segflg == UIO_SEG_KD) {
			error = uiomove(siov->iov_base, size, UIO_READ, duio);
			uioflush(size, suio);
		} else {
			error = uiomove(diov->iov_base, size, UIO_WRITE, suio);
			uioflush(size, duio);
		}
		if (error)
			return(error);
		count -= size;
	}
	return(0);
}
/*
 * mbufchar is analogous to uchar and schar
 * in that it returns the next character from
 * u.u_dirp in the appropriate address space.
 * It does, however, perform an mtod and
 * guarantee that mbuf chains are followed.
 */
mbufchar()
{
	register struct mbuf *m;
	register char c;

	if (!u.u_dirp) {
		u.u_error = EFAULT;
		return 0;
	}
	c = *u.u_dirp++;
	m = dtom(u.u_dirp);
	if (u.u_dirp  >= mtod(m, caddr_t) + m->m_len) {
		m = m->m_next;
		u.u_dirp = m ? mtod(m, caddr_t) : NULL;
	}
	return c;
}

/*
 * Copy data from an mbuf into user space.
 * Return 0 or EFAULT depending on whether
 * the user data space was valid or not.
 */
int
mbuftouser(from, to, count)
   register caddr_t from;
   register caddr_t to;
   register int count;
{
	register struct mbuf *m;
	register int size;

	if (count == 0)
		return(0);

	/*
	 * First one is a special case since data does not
	 * necessarily begin at the first byte of data in
	 * the mbuf.
	 */
	m = dtom(from);
	size = m->m_len - ((int)from - mtod(m, int));
	if (size <= 0)
		panic("mbuftouser");
	while (count) {
		size = MIN(size, count);
		if (copyout(from, to, size))
			return(EFAULT);
		to += size;
		count -= size;
		if ((m = m->m_next) == 0)
			break;
		size = m->m_len;
		from = mtod(m, caddr_t);
	}
	if (count != 0)
		panic("mbuftouser: mbuf list too short");
	return(0);
}

/*
 * Copy data from user space into an mbuf.
 * Return 0 or EFAULT depending on whether
 * the user data space was valid or not.
 */
int
usertombuf(from, to, count)
   register caddr_t from;
   register caddr_t to;
   register int count;
{
	register struct mbuf *m;
	register int size;

	if (count == 0)
		return(0);

	/*
	 * First one is a special case since data does not
	 * necessarily begin at the first byte of data in
	 * the mbuf.
	 */
	m = dtom(to);
	size = m->m_len - ((int)to - mtod(m, int));
	if (size <= 0)
		panic("usertombuf");
	while (count) {
		size = MIN(size, count);
		copyin(from, to, size);
		from += size;
		count -= size;
		if ((m = m->m_next) == 0)
			break;
		size = m->m_len;
		to = mtod(m, caddr_t);
	}
	if (count != 0)
		panic("usertombuf: mbuf list too short");
	return(0);
}

/*
 * Fill in a uio structure to reflect transfer
 * to/from a single contiguous user virtual
 * address.
 */
uiofilluser(uio, iov, offset, base, count)
   register struct uio *uio;
   register struct iovec *iov;
   int offset;
   caddr_t base;
   register int count;
{
	uio->uio_iov = iov;
	uio->uio_iovcnt = 1;
	uio->uio_offset = offset;
	uio->uio_segflg = 0;
	uio->uio_resid = count;
	iov->iov_base = base;
	iov->iov_len = count;
}
