📄 bf_torek.c
字号:
/*
* Copyright (c) 1999-2000 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.
*
*/
#ifndef lint
static char id[] = "@(#)$Id: bf_torek.c,v 8.19.18.2 2000/09/17 17:04:26 gshapiro Exp $";
#endif /* ! lint */
#if SFIO
ERROR README: Can not use bf_torek.c with SFIO.
#endif /* SFIO */
#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#ifndef BF_STANDALONE
# include "sendmail.h"
#endif /* ! BF_STANDALONE */
#include "bf_torek.h"
#include "bf.h"
/*
** 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 FILE * which may then be used with stdio functions, or NULL
** on failure. FILE * is opened for writing (mode "w+").
**
** Side Effects:
** none.
**
** Sets errno:
** ENOMEM -- out of memory
** ENOENT -- illegal empty filename specified
** any value of errno specified by open()
** any value of errno specified by fdopen()
** any value of errno specified by funopen()
*/
#ifdef BF_STANDALONE
# define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode)
#else /* BF_STANDALONE */
# define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff)
#endif /* BF_STANDALONE */
FILE *
bfopen(filename, fmode, bsize, flags)
char *filename;
int fmode;
size_t bsize;
long flags;
{
struct bf *bfp;
FILE *retval;
int save_errno, l;
struct stat st;
/* Sanity checks */
/* Empty filename string */
if (*filename == '\0')
{
errno = ENOENT;
return NULL;
}
if (stat(filename, &st) == 0)
{
/* file already exists on disk */
errno = EEXIST;
return NULL;
}
/* Allocate memory */
bfp = (struct bf *)malloc(sizeof(struct bf));
if (bfp == NULL)
{
errno = ENOMEM;
return NULL;
}
/* A zero bsize is valid, just don't allocate memory */
if (bsize > 0)
{
bfp->bf_buf = (char *)malloc(bsize);
if (bfp->bf_buf == NULL)
{
free(bfp);
errno = ENOMEM;
return NULL;
}
}
else
bfp->bf_buf = NULL;
/* Nearly home free, just set all the parameters now */
bfp->bf_committed = FALSE;
bfp->bf_ondisk = FALSE;
bfp->bf_refcount = 1;
bfp->bf_flags = flags;
bfp->bf_bufsize = bsize;
bfp->bf_buffilled = 0;
l = strlen(filename) + 1;
bfp->bf_filename = (char *)malloc(l);
if (bfp->bf_filename == NULL)
{
free(bfp);
if (bfp->bf_buf != NULL)
free(bfp->bf_buf);
errno = ENOMEM;
return NULL;
}
(void) strlcpy(bfp->bf_filename, filename, l);
bfp->bf_filemode = fmode;
bfp->bf_offset = 0;
bfp->bf_size = 0;
if (tTd(58, 8))
dprintf("bfopen(%s, %d)\n", filename, bsize);
/* The big test: will funopen accept it? */
retval = funopen((void *)bfp, _bfread, _bfwrite, _bfseek, _bfclose);
if (retval == NULL)
{
/* Just in case free() sets errno */
save_errno = errno;
free(bfp);
free(bfp->bf_filename);
if (bfp->bf_buf != NULL)
free(bfp->bf_buf);
errno = save_errno;
return NULL;
}
else
{
/* Success */
return retval;
}
}
/*
** BFDUP -- increase refcount on buffered file
**
** Parameters:
** fp -- FILE * to "duplicate"
**
** Returns:
** If file is memory buffered, fp with increased refcount
** If file is on disk, NULL (need to use link())
*/
FILE *
bfdup(fp)
FILE *fp;
{
struct bf *bfp;
/* If called on a normal FILE *, noop */
if (!bftest(fp))
return NULL;
/* Get associated bf structure */
bfp = (struct bf *)fp->_cookie;
/* Increase ref count */
bfp->bf_refcount++;
return fp;
}
/*
** BFCOMMIT -- "commits" the buffered file
**
** Parameters:
** fp -- FILE * to commit to disk
**
** Returns:
** 0 on success, -1 on error
**
** Side Effects:
** Forces the given FILE * 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()
*/
int
bfcommit(fp)
FILE *fp;
{
struct bf *bfp;
int retval;
int byteswritten;
/* If called on a normal FILE *, noop */
if (!bftest(fp))
return 0;
/* Get associated bf structure */
bfp = (struct bf *)fp->_cookie;
/* If already committed, noop */
if (bfp->bf_committed)
return 0;
/* Do we need to open a file? */
if (!bfp->bf_ondisk)
{
struct stat st;
if (tTd(58, 8))
dprintf("bfcommit(%s): to disk\n", bfp->bf_filename);
if (stat(bfp->bf_filename, &st) == 0)
{
errno = EEXIST;
return -1;
}
retval = OPEN(bfp->bf_filename, O_RDWR | O_CREAT | O_TRUNC,
bfp->bf_filemode, bfp->bf_flags);
/* Couldn't create file: failure */
if (retval < 0)
{
/* errno is set implicitly by open() */
return -1;
}
bfp->bf_disk_fd = retval;
bfp->bf_ondisk = TRUE;
}
/* Write out the contents of our buffer, if we have any */
if (bfp->bf_buffilled > 0)
{
byteswritten = 0;
if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0)
{
/* errno is set implicitly by lseek() */
return -1;
}
while (byteswritten < bfp->bf_buffilled)
{
retval = write(bfp->bf_disk_fd,
bfp->bf_buf + byteswritten,
bfp->bf_buffilled - byteswritten);
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;
free(bfp->bf_buf);
}
return 0;
}
/*
** BFREWIND -- rewinds the FILE *
**
** Parameters:
** fp -- FILE * to rewind
**
** Returns:
** 0 on success, -1 on error
**
** Side Effects:
** rewinds the FILE * 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 fseek()
*/
int
bfrewind(fp)
FILE *fp;
{
int err;
/* check to see if there is an error on the stream */
err = ferror(fp);
(void) fflush(fp);
/*
** Clear error if tried to fflush()
** a read-only file pointer and
** there wasn't a previous error.
*/
if (err == 0)
clearerr(fp);
/* errno is set implicitly by fseek() before return */
return fseek(fp, 0, SEEK_SET);
}
/*
** BFTRUNCATE -- rewinds and truncates the FILE *
**
** Parameters:
** fp -- FILE * to truncate
**
** Returns:
** 0 on success, -1 on error
**
** Side Effects:
** rewinds the FILE *, truncates it to zero length, and puts it
** into write mode. If fp is not a buffered file, this is
** equivalent to a rewind() and then an ftruncate(fileno(fp), 0).
**
** Sets errno:
** any value of errno specified by fseek()
** any value of errno specified by ftruncate()
*/
int
bftruncate(fp)
FILE *fp;
{
struct bf *bfp;
if (bfrewind(fp) < 0)
return -1;
if (bftest(fp))
{
/* Get bf structure */
bfp = (struct bf *)fp->_cookie;
bfp->bf_buffilled = 0;
bfp->bf_size = 0;
/* Need to zero the buffer */
if (bfp->bf_bufsize > 0)
memset(bfp->bf_buf, '\0', bfp->bf_bufsize);
if (bfp->bf_ondisk)
return ftruncate(bfp->bf_disk_fd, 0);
else
return 0;
}
else
return ftruncate(fileno(fp), 0);
}
/*
** BFCLOSE -- close a buffered file
**
** Parameters:
** fp -- FILE * to close
**
** Returns:
** 0 on success, EOF on failure
**
** Side Effects:
** Closes fp. If fp is a buffered file, unlink it if it has not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -