/*
 * Copyright (c) 2002, 2004, 2005 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: fpad.c,v 1.5 2005/03/15 19:56:07 ca Exp $")
#include "sm/error.h"
#include "sm/time.h"
#include "sm/fcntl.h"
#include "sm/io.h"
#include "sm/setjmp.h"
#include "io-int.h"
#include "fvwrite.h"

/*
**  SM_IO_FPAD -- fill up file (buffer)
**
**	This routine can be used to move the file write pointer for
**	fixed size records.
**
**	Parameters:
**		fp -- the file pointer to write to
**		len -- number of bytes for padding, must be less or equal
**			remaining space in buffer
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
sm_io_fpad(sm_file_T *fp, size_t len)
{
	int w;
	sm_ret_T ret;

	/* make sure we can write */
	if (cantwrite(fp))
		return sm_error_perm(SM_EM_IO, EBADF);
	if (len == 0)
		return SM_SUCCESS;
	if (f_flags(*fp) & SMNBF)
		return sm_error_perm(SM_EM_IO, EINVAL);

	/* not enough space? */
	if ((size_t) f_w(*fp) < len)
		return sm_error_perm(SM_EM_IO, EINVAL);

	/* this isn't really useful, but keep it for now */
	if ((f_flags(*fp) & (SMALC | SMSTR)) == (SMALC | SMSTR))
	{
		size_t blen;
		int tsize;
		uchar *tbase;

		/* Allocate space exponentially. */
		tsize = f_bfsize(*fp);
		blen = f_p(*fp) - f_bfbase(*fp);
		do
		{
			tsize = (tsize << 1) + 1;
		} while ((size_t) tsize < blen + len);
		tbase = (uchar *) sm_realloc(f_bfbase(*fp),
					     tsize + 1);
		if (tbase == NULL)
		{
			ret = sm_error_temp(SM_EM_IO, ENOMEM);
			goto err;
		}
		f_w(*fp) += tsize - f_bfsize(*fp);
		f_bfbase(*fp) = tbase;
		f_bfsize(*fp) = tsize;
		f_p(*fp) = tbase + blen;
	}

	w = f_w(*fp);
	if (f_flags(*fp) & SMSTR)
	{
		if (len < (size_t) w)
			w = len;
		if (w > 0)
		{
			sm_memzero((void *)f_p(*fp), (size_t)(w));
			f_w(*fp) -= w;
			f_p(*fp) += w;
		}
		w = len;	/* but pretend copied all */
	}
#ifdef SMSTRSTR
	/* str? */
	else if (f_flags(*fp) & SMSTRSTR)
	{
		if (len < (size_t) w)
			w = len;
		if (w > 0)
		{
/*
			ret = sm_str_spadn(f_cookie(*fp),
					(char *) p, w);
*/
			ret = sm_error_perm(SM_EM_IO, EINVAL);
			if (sm_is_err(ret))
				goto err;
			f_w(*fp) -= w;
			f_p(*fp) += w;
		}
		w = len;	/* but pretend copied all */
	}
#endif /* SMSTRSTR */
	else
	{
		/* fill and done */
		w = len;
		sm_memzero((void *)f_p(*fp), (size_t)(w));
		f_w(*fp) -= w;
		f_p(*fp) += w;
	}
	return SM_SUCCESS;

err:
	/* ret set before goto places us here */
	f_flags(*fp) |= SMERR;
#if SM_IO_ERR_VAL
	f_error(*fp) = res;
#endif
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1