bf.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1999-2002, 2004 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.
*
* Contributed by Exactis.com, Inc.
*
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
** This is in transition. Changed from the original bf_torek.c code
** to use sm_io function calls directly rather than through stdio
** translation layer. Will be made a built-in file type of libsm
** next (once safeopen() linkable from libsm).
*/
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "sendmail.h"
#include "bf.h"
#include <syslog.h>
/* bf io functions */
/*
** Data structure for storing information about each buffered file
** (Originally in sendmail/bf_torek.h for the curious.)
*/
struct bf
{
bool bf_committed; /* Has this buffered file been committed? */
bool bf_ondisk; /* On disk: committed or buffer overflow */
long bf_flags;
int bf_disk_fd; /* If on disk, associated file descriptor */
char *bf_buf; /* Memory buffer */
int bf_bufsize; /* Length of above buffer */
int bf_buffilled; /* Bytes of buffer actually filled */
char *bf_filename; /* Name of buffered file, if ever committed */
int bf_size; /* Total current size of file */
};
#ifdef BF_STANDALONE
#else /* BF_STANDALONE */
#endif /* BF_STANDALONE */
struct bf_info
{
char *bi_filename;
long bi_flags;
};
/*
** SM_BFOPEN -- the "base" open function called by sm_io_open() for the
** internal, file-type-specific info setup.
**
** Parameters:
** fp -- file pointer being filled-in for file being open'd
** info -- information about file being opened
** flags -- ignored
** rpool -- ignored (currently)
**
** Returns:
** Failure: -1 and sets errno
** Success: 0 (zero)
*/
static int
const void *info;
int flags;
const void *rpool;
{
char *filename;
long sflags;
int l;
/* Sanity checks */
if (*filename == '\0')
{
/* Empty filename string */
return -1;
}
{
/* File already exists on disk */
return -1;
}
/* Allocate memory */
{
return -1;
}
/* Assign data buffer */
/* A zero bsize is valid, just don't allocate memory */
if (bsize > 0)
{
{
bfp->bf_bufsize = 0;
return -1;
}
}
else
/* Nearly home free, just set all the parameters now */
bfp->bf_committed = false;
bfp->bf_buffilled = 0;
{
return -1;
}
return 0;
}
/*
** BFOPEN -- create a new buffered file
**
** Parameters:
** filename -- the file's name
** fmode -- what mode the file should be created as
** bsize -- amount of buffer space to allocate (may be 0)
** flags -- if running under sendmail, passed directly to safeopen
**
** Returns:
** a SM_FILE_T * which may then be used with stdio functions,
** or NULL on failure. SM_FILE_T * is opened for writing
** "SM_IO_WHAT_VECTORS").
**
** Side Effects:
** none.
**
** Sets errno:
** any value of errno specified by sm_io_setinfo_type()
** any value of errno specified by sm_io_open()
** any value of errno specified by sm_io_setinfo()
*/
#ifdef __STDC__
/*
** XXX This is a temporary hack since MODE_T on HP-UX 10.x is short.
** If we use K&R here, the compiler will complain about
** Inconsistent parameter list declaration
** due to the change from short to int.
*/
#else /* __STDC__ */
char *filename;
long flags;
#endif /* __STDC__ */
{
/*
** Apply current umask to fmode as it may change by the time
** the file is actually created. fmode becomes the true
** permissions of the file, which OPEN() must obey.
*/
}
/*
** SM_BFGETINFO -- returns info about an open file pointer
**
** Parameters:
** fp -- file pointer to get info about
** what -- type of info to obtain
** valp -- thing to return the info in
*/
static int
int what;
void *valp;
{
switch (what)
{
case SM_IO_WHAT_FD:
return bfp->bf_disk_fd;
case SM_IO_WHAT_SIZE:
default:
return -1;
}
}
/*
** SM_BFCLOSE -- close a buffered file
**
** Parameters:
** fp -- cookie of file to close
**
** Returns:
** 0 to indicate success
**
** Side Effects:
** deletes backing file, sm_frees memory.
**
** Sets errno:
** never.
*/
static int
{
/* Cast cookie back to correct type */
/* Need to clean up the file */
/* Need to sm_free the buffer */
if (bfp->bf_bufsize > 0)
/* Finally, sm_free the structure */
return 0;
}
/*
** SM_BFREAD -- read a buffered file
**
** Parameters:
** cookie -- cookie of file to read
** buf -- buffer to fill
** nbytes -- how many bytes to read
**
** Returns:
** number of bytes read or -1 indicate failure
**
** Side Effects:
** none.
**
*/
static ssize_t
char *buf;
{
int retval;
/* Cast cookie back to correct type */
{
/* Need to grab some from buffer */
}
{
/* Need to grab some from file */
{
/* Oops, the file doesn't exist. EOF. */
sm_dprintf("sm_bfread(%s): to disk\n",
bfp->bf_filename);
goto finished;
}
/* Catch a read() on an earlier failed write to disk */
if (bfp->bf_disk_fd < 0)
{
return -1;
}
{
{
/*
** stdio won't be expecting these
** errnos from read()! Change them
** into something it can understand.
*/
}
return -1;
}
{
if (retval < 0)
{
/* errno is set implicitly by read() */
return -1;
}
else if (retval == 0)
goto finished;
else
}
}
return count;
}
/*
** SM_BFSEEK -- seek to a position in a buffered file
**
** Parameters:
** fp -- fp of file to seek
** offset -- position to seek to
** whence -- how to seek
**
** Returns:
** new file offset or -1 indicate failure
**
** Side Effects:
** none.
**
*/
static off_t
int whence;
{
/* Cast cookie back to correct type */
switch (whence)
{
case SEEK_SET:
break;
case SEEK_CUR:
break;
case SEEK_END:
break;
default:
return -1;
}
}
/*
** SM_BFWRITE -- write to a buffered file
**
** Parameters:
** fp -- fp of file to write
** buf -- data buffer
** nbytes -- how many bytes to write
**
** Returns:
** number of bytes written or -1 indicate failure
**
** Side Effects:
** may create backing file if over memory limit for file.
**
*/
static ssize_t
const char *buf;
{
int retval;
/* Cast cookie back to correct type */
/* If committed, go straight to disk */
if (bfp->bf_committed)
{
{
{
/*
** stdio won't be expecting these
** errnos from write()! Change them
** into something it can understand.
*/
}
return -1;
}
if (count < 0)
{
/* errno is set implicitly by write() */
return -1;
}
goto finished;
}
{
/* Need to put some in buffer */
}
{
/* Need to put some in file */
{
/* Clear umask as bf_filemode are the true perms */
/* Couldn't create file: failure */
if (retval < 0)
{
/*
** stdio may not be expecting these
** errnos from write()! Change to
** something which it can understand.
** Note that ENOSPC and EDQUOT are saved
** because they are actually valid for
** write().
*/
#ifdef EDQUOT
#endif /* EDQUOT */
))
return -1;
}
}
/* Catch a write() on an earlier failed write to disk */
{
return -1;
}
{
{
/*
** stdio won't be expecting these
** errnos from write()! Change them into
** something which it can understand.
*/
}
return -1;
}
{
if (retval < 0)
{
/* errno is set implicitly by write() */
return -1;
}
else
}
}
return count;
}
/*
** BFREWIND -- rewinds the SM_FILE_T *
**
** Parameters:
** fp -- SM_FILE_T * to rewind
**
** Returns:
** 0 on success, -1 on error
**
** Side Effects:
** rewinds the SM_FILE_T * and puts it into read mode. Normally
** one would bfopen() a file, write to it, then bfrewind() and
** fread(). If fp is not a buffered file, this is equivalent to
** rewind().
**
** Sets errno:
** any value of errno specified by sm_io_rewind()
*/
int
{
}
/*
** SM_BFCOMMIT -- "commits" the buffered file
**
** Parameters:
** fp -- SM_FILE_T * to commit to disk
**
** Returns:
** 0 on success, -1 on error
**
** Side Effects:
** Forces the given SM_FILE_T * to be written to disk if it is not
** already, and ensures that it will be kept after closing. If
** fp is not a buffered file, this is a no-op.
**
** Sets errno:
** any value of errno specified by open()
** any value of errno specified by write()
** any value of errno specified by lseek()
*/
static int
{
int retval;
int byteswritten;
/* Get associated bf structure */
/* If already committed, noop */
if (bfp->bf_committed)
return 0;
/* Do we need to open a file? */
{
int save_errno;
{
sm_dprintf("bfcommit(): filemode %o flags %ld\n",
}
{
return -1;
}
/* Clear umask as bf_filemode are the true perms */
save_errno = errno;
/* Couldn't create file: failure */
if (retval < 0)
{
/* errno is set implicitly by open() */
errno = save_errno;
return -1;
}
}
/* Write out the contents of our buffer, if we have any */
if (bfp->bf_buffilled > 0)
{
byteswritten = 0;
{
/* errno is set implicitly by lseek() */
return -1;
}
{
if (retval < 0)
{
/* errno is set implicitly by write() */
return -1;
}
else
byteswritten += retval;
}
}
bfp->bf_committed = true;
/* Invalidate buf; all goes to file now */
bfp->bf_buffilled = 0;
if (bfp->bf_bufsize > 0)
{
/* Don't need buffer anymore; free it */
bfp->bf_bufsize = 0;
}
return 0;
}
/*
** SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T *
**
** Parameters:
** fp -- SM_FILE_T * to truncate
**
** Returns:
** 0 on success, -1 on error
**
** Side Effects:
** rewinds the SM_FILE_T *, truncates it to zero length, and puts
** it into write mode.
**
** Sets errno:
** any value of errno specified by fseek()
** any value of errno specified by ftruncate()
*/
static int
{
return -1;
/* Get bf structure */
bfp->bf_buffilled = 0;
/* Need to zero the buffer */
if (bfp->bf_bufsize > 0)
{
#if NOFTRUNCATE
/* XXX: Not much we can do except rewind it */
return -1;
#else /* NOFTRUNCATE */
#endif /* NOFTRUNCATE */
}
return 0;
}
/*
**
** Parameters:
** fp -- file pointer to get info about
**
*/
static int
int what;
void *valp;
{
int bsize;
/* Get bf structure */
switch (what)
{
case SM_BF_SETBUFSIZE:
/* A zero bsize is valid, just don't allocate memory */
if (bsize > 0)
{
{
bfp->bf_bufsize = 0;
return -1;
}
}
else
return 0;
case SM_BF_COMMIT:
return sm_bfcommit(fp);
case SM_BF_TRUNCATE:
return sm_bftruncate(fp);
case SM_BF_TEST:
return 1; /* always */
default:
return -1;
}
}