/*
* Copyright (c) 2000-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_IDSTR(id, "@(#)$Id: smstdio.c,v 1.20 2006/07/16 02:07:40 ca Exp $")
#include "sm/stdio.h"
#include "sm/fcntl.h"
#include "sm/stat.h"
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/io.h"
#include "sm/string.h"
#include "io-int.h"
/*
** Overall:
** This is a file type which implements a layer on top of the system
** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
** "bound late" because of the manner which Linux implements stdio.
** When binding late (when fp->f_cookie==NULL) then the value of
** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
** stderr.
*/
/*
** SM_STDIOOPEN -- open a file to system stdio implementation
**
** Parameters:
** fp -- file pointer assign for this open
** info -- info about file to open
** flags -- indicating method of opening
**
** Returns:
** Failure: -1
** Success: 0 (zero)
*/
sm_ret_T
sm_stdioopen(sm_file_T *fp, const void *info, int flags, va_list ap)
{
FILE *s;
const char *stdiomode;
switch (flags)
{
case SM_IO_RDONLY:
stdiomode = "r";
break;
case SM_IO_WREXCL: /* XXX Wrong! Maybe return error instead? */
case SM_IO_WRONLY:
stdiomode = "w";
break;
case SM_IO_APPEND:
stdiomode = "a";
break;
case SM_IO_APPENDRW:
stdiomode = "a+";
break;
case SM_IO_RDWR:
default:
stdiomode = "r+";
break;
}
errno = 0;
if ((s = fopen((const char *)info, stdiomode)) == NULL)
return sm_error_perm(SM_EM_IO, errno);
fp->f_cookie = s;
return SM_SUCCESS;
}
/*
** SETUP -- assign file type cookie when not already assigned
**
** Parameters:
** fp -- the file pointer to get the cookie assigned
**
** Return:
** none.
*/
static void
setup(sm_file_T *fp)
{
if (fp->f_cookie == NULL)
{
switch (fp->f_ival)
{
case 0:
f_cookie(*fp) = stdin;
break;
case 1:
f_cookie(*fp) = stdout;
break;
case 2:
f_cookie(*fp) = stderr;
break;
default:
SM_PANIC(("fp->f_ival=%d: out of range (0...2)", fp->f_ival));
break;
}
}
}
/*
** SM_STDIOREAD -- read from the file
**
** Parameters:
** fp -- the file pointer
** buf -- location to place the read data
** n -- number of bytes to read
** bytesread -- number of bytes read (output)
**
** Returns:
** failure: errno as sm_error code
** otherwise: SM_SUCCESS
*/
sm_ret_T
sm_stdioread(sm_file_T *fp, uchar *buf, size_t n, ssize_t *bytesread)
{
FILE *s;
size_t r;
SM_REQUIRE(bytesread != NULL);
if (f_cookie(*fp) == NULL)
setup(fp);
s = f_cookie(*fp);
/* XXX no timeout! */
errno = 0;
r = fread(buf, 1, n, s);
*bytesread = r;
if (r != n)
return sm_error_perm(SM_EM_IO, errno);
return SM_SUCCESS;
}
/*
** SM_STDIOWRITE -- write to the file
**
** Parameters:
** fp -- the file pointer
** buf -- location of data to write
** n -- number of bytes to write
** byteswritten -- number of bytes written (output)
**
** Returns:
** failure: errno as sm_error code
** otherwise: SM_SUCCESS
*/
sm_ret_T
sm_stdiowrite(sm_file_T *fp, const uchar *buf, size_t n, ssize_t *byteswritten)
{
FILE *s;
size_t r;
SM_REQUIRE(byteswritten != NULL);
if (f_cookie(*fp) == NULL)
setup(fp);
s = f_cookie(*fp);
/* XXX no timeout! */
errno = 0;
r = fwrite(buf, 1, n, s);
*byteswritten = r;
if (r != n)
return sm_error_perm(SM_EM_IO, errno);
return SM_SUCCESS;
}
/*
** SM_STDIOSEEK -- set position within file
**
** Parameters:
** fp -- the file pointer
** offset -- new location based on 'whence'
** whence -- indicates "base" for 'offset'
**
** Returns:
** result from fseek().
*/
sm_ret_T
sm_stdioseek(sm_file_T *fp, off_t offset, int whence)
{
FILE *s;
int r;
if (f_cookie(*fp) == NULL)
setup(fp);
s = f_cookie(*fp);
errno = 0;
r = fseek(s, offset, whence);
if (r != 0)
return sm_error_perm(SM_EM_IO, errno);
return SM_SUCCESS;
}
/*
** SM_STDIOCLOSE -- close the file
**
** Parameters:
** fp -- close file pointer
** flags -- ignored
**
** Return:
** status from fclose()
*/
sm_ret_T
sm_stdioclose(sm_file_T *fp, int flags)
{
FILE *s;
int r;
if (f_cookie(*fp) == NULL)
setup(fp);
s = f_cookie(*fp);
errno = 0;
r = fclose(s);
if (r != 0)
return sm_error_gen(0, SM_ERR_PERM, errno);
return SM_SUCCESS;
}
/*
** SM_STDIOSETINFO -- set info for this open file
**
** Parameters:
** fp -- the file pointer
** what -- type of information setting
** valp -- memory location of info to set
**
** Return:
** Failure: -1 and sets errno
** Success: none (currently).
*/
/* ARGSUSED0 */
sm_ret_T
sm_stdiosetinfo(sm_file_T *fp, int what, void *valp)
{
#if 0
switch (what)
{
case SM_IO_WHAT_MODE:
default:
}
#endif
return sm_error_perm(SM_EM_IO, EINVAL);
}
/*
** SM_STDIOGETINFO -- get info for this open file
**
** Parameters:
** fp -- the file pointer
** what -- type of information request
** valp -- memory location to place info
**
** Return:
** Failure: -1 and sets errno
** Success: none (currently).
*/
/* ARGSUSED2 */
int
sm_stdiogetinfo(sm_file_T *fp, int what, void *valp)
{
switch (what)
{
case SM_IO_WHAT_SIZE:
{
int fd;
struct stat st;
if (f_cookie(*fp) == NULL)
setup(fp);
fd = fileno((FILE *) f_cookie(*fp));
if (fd < 0)
return sm_error_perm(SM_EM_IO, EINVAL);
if (fstat(fd, &st) < 0)
return sm_error_perm(SM_EM_IO, errno);
return st.st_size;
}
case SM_IO_WHAT_MODE:
default:
return sm_error_perm(SM_EM_IO, EINVAL);
}
}
#if 0
/*
** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
**
** Parameters:
** stream -- an open stdio stream, as returned by fopen()
** mode -- the mode argument to fopen() which describes stream
**
** Return:
** On success, return a pointer to an SM_FILE object which
** can be used for reading and writing 'stream'.
** Abort if mode is gibberish or stream is bad.
** Raise an exception if we can't allocate memory.
*/
sm_ret_T
sm_io_stdioopen(FILE *stream, char *mode)
{
int fd;
bool r, w;
int ioflags;
sm_ret_T res;
sm_file_T *fp;
fd = fileno(stream);
SM_REQUIRE(fd >= 0);
r = w = false;
switch (mode[0])
{
case 'r':
r = true;
break;
case 'w':
case 'a':
w = true;
break;
default:
sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
}
if (strchr(&mode[1], '+') != NULL)
r = w = true;
if (r && w)
ioflags = SMRW;
else if (r)
ioflags = SMRD;
else
ioflags = SMWR;
res = sm_fp(&(SmFtRealStdio->f_stream), ioflags, NULL, &fp);
if (sm_is_err(res))
return res;
f_fd(*fp) = fd;
f_cookie(*fp) = stream;
return SM_SUCCESS;
}
#endif /* 0 */
syntax highlighted by Code2HTML, v. 0.9.1