/*
 * Copyright (c) 2000-2002, 2004-2006 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 * Copyright (c) 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Chris Torek.
 *
 * 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: fclose.c,v 1.15 2006/07/18 02:44:21 ca Exp $")
#include "sm/error.h"
#include "sm/time.h"
#include "sm/io.h"
#include "sm/assert.h"
#include "sm/heap.h"
#include "sm/signal.h"
#include "sm/clock.h"
#include "io-int.h"

/*
**  SM_IO_CLOSE -- close a file handle/pointer
**
**	Parameters:
**		fp -- file pointer to be closed
**		flags -- ignored
**
**	Returns:
**		usual sm_error code
**
**	Side Effects:
**		file pointer 'fp' will no longer be valid.
*/

sm_ret_T
sm_io_close(sm_file_T *fp, int flags)
{
	sm_ret_T r, rc;

	if (fp == NULL)
		return sm_error_perm(SM_EM_IO, EBADF);

	SM_IS_FP(fp);

	/* Note: this won't be reached if above macro is active */
	if (SM_MAGIC_NULL == fp->sm_magic)
		return sm_error_perm(SM_EM_IO, EBADF);
	if (f_close(*fp) == NULL)
	{
		/* no close function! */
		return sm_error_perm(SM_EM_IO, ENODEV);
	}
	if (fp->f_dup_cnt > 0)
	{
		/* decrement file pointer open count */
		fp->f_dup_cnt--;
		return SM_SUCCESS;
	}

	/* No more duplicates of file pointer. Flush buffer and close */
	r = SM_SUCCESS;
	if ((f_flags(*fp) & SMWR) != 0 && (flags & SM_IO_CF_RM) == 0)
		r = sm_flush(fp);

	rc = (*f_close(*fp))(fp, flags);
	if (sm_is_err(rc))
		r = rc;

	if (sm_io_double(fp))
	{
		if (f_rd_flags(*fp) & SMMBF)
		{
			if (f_bfbase(*fp) == f_rd_bfbase(*fp))
				f_bfbase(*fp) = NULL;
			SM_FREE(f_rd_bfbase(*fp));
			f_rd_flags(*fp) = 0;
			f_rd_r(*fp) = 0;
		}
		if (f_wr_flags(*fp) & SMMBF)
		{
			if (f_bfbase(*fp) == f_wr_bfbase(*fp))
				f_bfbase(*fp) = NULL;
			SM_FREE(f_wr_bfbase(*fp));
			f_wr_flags(*fp) = 0;
			f_wr_w(*fp) = 0;
		}

		/*
		**  If the file was only used for either reading or writing
		**  then f_bf is neither the read nor the write buffer.
		**  fixme: this is a hack (see checks above), it should probably
		**  be fixed in some other place, i.e., instead of having
		**  three buffers (sm_buf_T) have only two in all cases,
		**  or use two buffers and one pointer to them (which
		**  requires another indirection).
		*/

		if (f_flags(*fp) & SMMBF && f_bfbase(*fp) != NULL)
			SM_FREE(f_bfbase(*fp));
	}
	else if (f_flags(*fp) & SMMBF)
		SM_FREE(f_bfbase(*fp));

	f_flags(*fp) = 0;		/* clear flags */
	fp->sm_magic = SM_MAGIC_NULL;	/* Release this sm_file_T for reuse. */
	f_r(*fp) = f_w(*fp) = 0;	/* Mess up if reaccessed. */
	return r;
}


syntax highlighted by Code2HTML, v. 0.9.1