190792Sgshapiro/*
2261363Sgshapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro * Copyright (c) 1990, 1993
590792Sgshapiro *	The Regents of the University of California.  All rights reserved.
690792Sgshapiro *
790792Sgshapiro * This code is derived from software contributed to Berkeley by
890792Sgshapiro * Chris Torek.
990792Sgshapiro *
1090792Sgshapiro * By using this file, you agree to the terms and conditions set
1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1290792Sgshapiro * the sendmail distribution.
1390792Sgshapiro */
1490792Sgshapiro
1590792Sgshapiro#include <sm/gen.h>
16266692SgshapiroSM_RCSID("@(#)$Id: fread.c,v 1.29 2013-11-22 20:51:42 ca Exp $")
1790792Sgshapiro#include <string.h>
1890792Sgshapiro#include <errno.h>
1990792Sgshapiro#include <sm/io.h>
2090792Sgshapiro#include <sm/assert.h>
2190792Sgshapiro#include "local.h"
2290792Sgshapiro
2390792Sgshapiro/*
2490792Sgshapiro**  SM_IO_READ -- read data from the file pointer
2590792Sgshapiro**
2690792Sgshapiro**	Parameters:
2790792Sgshapiro**		fp -- file pointer to read from
2890792Sgshapiro**		timeout -- time to complete the read
2990792Sgshapiro**		buf -- location to place read data
3090792Sgshapiro**		size -- size of each chunk of data
3190792Sgshapiro**
3290792Sgshapiro**	Returns:
3390792Sgshapiro**		Failure: returns 0 (zero) _and_ sets errno
3490792Sgshapiro**		Success: returns the number of whole chunks read.
3590792Sgshapiro**
3690792Sgshapiro**	A read returning 0 (zero) is only an indication of error when errno
3790792Sgshapiro**	has been set.
3890792Sgshapiro*/
3990792Sgshapiro
4090792Sgshapirosize_t
4190792Sgshapirosm_io_read(fp, timeout, buf, size)
4290792Sgshapiro	SM_FILE_T *fp;
4390792Sgshapiro	int timeout;
4490792Sgshapiro	void *buf;
4590792Sgshapiro	size_t size;
4690792Sgshapiro{
4790792Sgshapiro	register size_t resid = size;
4890792Sgshapiro	register char *p;
4990792Sgshapiro	register int r;
5090792Sgshapiro
5190792Sgshapiro	SM_REQUIRE_ISA(fp, SmFileMagic);
5290792Sgshapiro
5390792Sgshapiro	if (fp->f_read == NULL)
5490792Sgshapiro	{
5590792Sgshapiro		errno = ENODEV;
5690792Sgshapiro		return 0;
5790792Sgshapiro	}
5890792Sgshapiro
5990792Sgshapiro	/*
6090792Sgshapiro	**  The ANSI standard requires a return value of 0 for a count
6190792Sgshapiro	**  or a size of 0.  Peculiarily, it imposes no such requirements
6290792Sgshapiro	**  on fwrite; it only requires read to be broken.
6390792Sgshapiro	*/
6490792Sgshapiro
6590792Sgshapiro	if (resid == 0)
6690792Sgshapiro		return 0;
6790792Sgshapiro	if (fp->f_r < 0)
6890792Sgshapiro		fp->f_r = 0;
6990792Sgshapiro	p = buf;
7090792Sgshapiro	while ((int) resid > (r = fp->f_r))
7190792Sgshapiro	{
7290792Sgshapiro		(void) memcpy((void *) p, (void *) fp->f_p, (size_t) r);
7390792Sgshapiro		fp->f_p += r;
7490792Sgshapiro		/* fp->f_r = 0 ... done in sm_refill */
7590792Sgshapiro		p += r;
7690792Sgshapiro		resid -= r;
7790792Sgshapiro		if ((fp->f_flags & SMNOW) != 0 && r > 0)
7890792Sgshapiro		{
7990792Sgshapiro			/*
8090792Sgshapiro			**  Take whatever we have available. Spend no more time
8190792Sgshapiro			**  trying to get all that has been requested.
8290792Sgshapiro			**  This is needed on some file types (such as
8390792Sgshapiro			**  SASL) that would jam when given extra, untimely
8490792Sgshapiro			**  reads.
8590792Sgshapiro			*/
8690792Sgshapiro
8790792Sgshapiro			fp->f_r -= r;
8890792Sgshapiro			return size - resid;
8990792Sgshapiro		}
9090792Sgshapiro		if (sm_refill(fp, timeout) != 0)
9190792Sgshapiro		{
9290792Sgshapiro			/* no more input: return partial result */
9390792Sgshapiro			return size - resid;
9490792Sgshapiro		}
9590792Sgshapiro	}
9690792Sgshapiro	(void) memcpy((void *) p, (void *) fp->f_p, resid);
9790792Sgshapiro	fp->f_r -= resid;
9890792Sgshapiro	fp->f_p += resid;
9990792Sgshapiro	return size;
10090792Sgshapiro}
101