/*
* Copyright (c) 2000-2002, 2004, 2005 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: fopen.c,v 1.28 2006/07/18 02:45:02 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/varargs.h"
#include "sm/time.h"
#include "sm/heap.h"
#include "sm/limits.h"
#include "sm/io.h"
#include "io-int.h"
/*
** SM_FLAGS -- translate external (user) flags into internal flags
**
** Paramters:
** flags -- user select flags
**
** Returns:
** Internal flag value matching user selected flags
*/
/* fixme: Can't we use a simpler (direct) mapping?? */
static int
sm_flags(int flags)
{
int ret;
switch (flags)
{
case SM_IO_RDONLY: /* open for reading */
ret = SMRD;
break;
case SM_IO_WRONLY: /* open for writing */
case SM_IO_WREXCL: /* exclusive open for writing */
ret = SMWR;
break;
case SM_IO_APPEND: /* open for appending */
ret = SMWR;
break;
case SM_IO_RDWR: /* open for read and write */
case SM_IO_RDWRCR:
case SM_IO_RDWRTR:
case SM_IO_RDWRCRX:
ret = SMRW;
break;
default:
ret = 0;
break;
}
return ret;
}
/*
** SM_IO_OPEN -- open a file of a specific type
**
** Parameters:
** type -- type of file to open
** info -- info describing what is to be opened (type dependent)
** flags -- user selected flags
** newfp -- pointer to new fp (in/out parameter)
**
** Returns:
** usual sm_error code
*/
sm_ret_T
sm_io_open(const sm_stream_T *type, const void *info, int flags, sm_file_T **newfp, ...)
{
sm_ret_T res;
sm_f_flags_T ioflags;
sm_file_T *fp;
va_list ap;
SM_REQUIRE(newfp != NULL);
*newfp = NULL; /* just being friendly... */
ioflags = sm_flags(flags);
if (ioflags == 0)
{
/* must give some indication/intent */
return sm_error_perm(SM_EM_IO, EINVAL);
}
res = sm_fp(type, ioflags, NULL, &fp);
if (sm_is_err(res))
return res;
/* paranoia? SM_IS_FP(fp); */
va_start(ap, newfp);
res = f_open(*fp)(fp, info, flags, ap);
va_end(ap);
if (sm_is_err(res))
{
fp->sm_magic = SM_MAGIC_NULL; /* release */
f_flags(*fp) = 0; /* release */
return res;
}
#if SM_RPOOL
if (rpool != NULL)
sm_rpool_attach(rpool, sm_io_fclose, fp);
#endif
*newfp = fp;
return SM_SUCCESS;
}
/*
** SM_IO_DUP -- duplicate a file pointer
**
** Parameters:
** fp -- file pointer to duplicate
**
** Returns:
** usual sm_error code
**
** Increments the duplicate counter (dup_cnt) for the open file pointer.
** The counter counts the number of duplicates. When the duplicate
** counter is 0 (zero) then the file pointer is the only one left
** (no duplicates, it is the only one).
*/
sm_ret_T
sm_io_dup(sm_file_T *fp)
{
SM_IS_FP(fp);
/* Note: this won't be reached if above macro is active */
if (fp->sm_magic != SM_FILE_MAGIC)
return sm_error_perm(SM_EM_IO, EBADF);
if (fp->f_dup_cnt >= INT_MAX - 1)
{
/* Can't let f_dup_cnt wrap! */
return sm_error_perm(SM_EM_IO, EMFILE);
}
fp->f_dup_cnt++;
return SM_SUCCESS;
}
#if 0
/*
** SM_IO_REOPEN -- open a new file using the old file pointer
**
** Parameters:
** type -- file type to be opened
** timeout -- time to complete the reopen
** info -- infomation about what is to be "re-opened" (type dep.)
** flags -- user flags to map to internal flags
** fp -- the file pointer to reuse
** newfp -- pointer to new file pointer
** rpool -- rpool file to be associated with
**
** Returns:
** usual sm_error type
*/
sm_ret_T
sm_io_reopen(const sm_stream_T *type, const void *info, int flags,
sm_file_T *fp, sm_file_T **newfp, sm_rpool_P rpool)
{
sm_f_flags_T ioflags;
sm_ret_T res;
sm_file_T *fp2;
ioflags = sm_flags(flags);
if (ioflags == 0)
{
(void) sm_io_close(fp, SM_IO_CF_NONE);
*newfp = NULL;
return sm_error_perm(SM_EM_IO, EINVAL);
}
/*
** There are actually programs that depend on being able to "reopen"
** descriptors that weren't originally open. Keep this from breaking.
** Remember whether the stream was open to begin with, and which file
** descriptor (if any) was associated with it. If it was attached to
** a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin)
** should work. This is unnecessary if it was not a Unix file.
*/
if (fp != NULL)
{
if (fp->sm_magic != SM_FILE_MAGIC)
f_flags(*fp) = SMFEOF; /* hold on to it */
else
{
/* flush the stream; ANSI doesn't require this. */
(void) sm_io_flush(fp);
(void) sm_io_close(fp, SM_IO_CF_NONE);
}
}
res = sm_fp(type, ioflags, NULL, &fp2);
if (sm_is_err(res))
return res;
res = f_open(*fp2)(fp2, info, flags, SM_IO_WHAT_END);
if (sm_is_err(res))
{
f_flags(*fp2) = 0; /* release */
fp->sm_magic = SM_MAGIC_NULL; /* release */
return res;
}
/*
** We're not preserving this logic (below) for sm_io because it is now
** abstracted at least one "layer" away. By closing and reopening
** the 1st fd used should be the just released one (when Unix
** behavior followed). Old comment::
** If reopening something that was open before on a real file, try
** to maintain the descriptor. Various C library routines (perror)
** assume stderr is always fd STDERR_FILENO, even if being reopen'd.
*/
#if SM_RPOOL
if (rpool != NULL)
sm_rpool_attach(rpool, sm_io_close, fp2);
#endif
*newfp = fp2;
return SM_SUCCESS;
}
#endif /* 0 */
syntax highlighted by Code2HTML, v. 0.9.1