diff options
author | gshapiro <gshapiro@FreeBSD.org> | 2000-08-12 21:55:49 +0000 |
---|---|---|
committer | gshapiro <gshapiro@FreeBSD.org> | 2000-08-12 21:55:49 +0000 |
commit | c3cd75415d60bc002b20182ffd3383ea9e901a80 (patch) | |
tree | 211dfd0f771f89d6abe14fa94cab53985a9d0116 /contrib/sendmail/src/bf_portable.c | |
parent | 231592eb7942ebd4becae24ea8e018acea3742a9 (diff) | |
parent | 4332139a9a11f773ffe5109bed871561e3c290a1 (diff) | |
download | FreeBSD-src-c3cd75415d60bc002b20182ffd3383ea9e901a80.zip FreeBSD-src-c3cd75415d60bc002b20182ffd3383ea9e901a80.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r64562,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/sendmail/src/bf_portable.c')
-rw-r--r-- | contrib/sendmail/src/bf_portable.c | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/contrib/sendmail/src/bf_portable.c b/contrib/sendmail/src/bf_portable.c new file mode 100644 index 0000000..4de0af3 --- /dev/null +++ b/contrib/sendmail/src/bf_portable.c @@ -0,0 +1,482 @@ +/* + * 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_portable.c,v 8.25.4.3 2000/06/29 21:21:58 gshapiro Exp $"; +#endif /* ! lint */ + +#if SFIO +# include <sfio/stdio.h> +#endif /* SFIO */ + +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <sys/uio.h> +#include <errno.h> +#if !SFIO +# include <stdio.h> +#endif /* !SFIO */ +#ifndef BF_STANDALONE +# include "sendmail.h" +#endif /* ! BF_STANDALONE */ +#include "bf_portable.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 */ + +/* List of currently-open buffered files */ +struct bf *bflist = NULL; + +FILE * +bfopen(filename, fmode, bsize, flags) + char *filename; + int fmode; + size_t bsize; + long flags; +{ + struct bf *bfp; + FILE *retval; + int fd, l; + + fd = OPEN(filename, O_RDWR | O_CREAT | O_TRUNC, fmode, flags); + if (fd == -1) + { + /* errno is set implicitly by open */ + return NULL; + } + + retval = fdopen(fd, "w+"); + + /* If failure, return immediately */ + if (retval == NULL) + { + /* errno is set implicitly by fdopen */ + return NULL; + } + + /* Allocate memory */ + bfp = (struct bf *)malloc(sizeof(struct bf)); + if (bfp == NULL) + { + (void) fclose(retval); + + /* don't care about errors */ + (void) unlink(filename); + errno = ENOMEM; + return NULL; + } + if (tTd(58, 8)) + dprintf("bfopen(%s): malloced %ld\n", + filename, (long) sizeof(struct bf)); + + l = strlen(filename) + 1; + bfp->bf_filename = (char *)malloc(l); + if (bfp->bf_filename == NULL) + { + free(bfp); + (void) fclose(retval); + + /* don't care about errors */ + (void) unlink(filename); + errno = ENOMEM; + return NULL; + } + (void) strlcpy(bfp->bf_filename, filename, l); + + /* Fill in the other fields, then add it to the list */ + bfp->bf_key = retval; + bfp->bf_committed = FALSE; + bfp->bf_refcount = 1; + + bfinsert(bfp); + + /* Whew. Nothing bad happened. We're okay. */ + return retval; +} +/* +** BFDUP -- increase refcount on buffered file +** +** Parameters: +** fp -- FILE * to "duplicate" +** +** Returns: +** fp with increased refcount +*/ + +FILE * +bfdup(fp) + FILE *fp; +{ + struct bf *bfp; + + /* Get associated bf structure */ + bfp = bflookup(fp); + + if (bfp == NULL) + return NULL; + + /* Increase the refcount */ + 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; + + /* Get associated bf structure */ + bfp = bflookup(fp); + + /* If called on a normal FILE *, noop */ + if (bfp != NULL) + bfp->bf_committed = TRUE; + + 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; +{ + int ret; + + if (bfrewind(fp) == -1) + { + /* errno is set implicitly by bfrewind() */ + return -1; + } + +#if NOFTRUNCATE + /* XXX */ + errno = EINVAL; + ret = -1; +#else /* NOFTRUNCATE */ + /* errno is set implicitly by ftruncate() before return */ + ret = ftruncate(fileno(fp), 0); +#endif /* NOFTRUNCATE */ + return ret; +} + +/* +** 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 +** already been committed. If fp is not a buffered file, this is +** equivalent to fclose(). +** +** Sets errno: +** any value of errno specified by fclose() +*/ + +int +bfclose(fp) + FILE *fp; +{ + int retval; + struct bf *bfp = NULL; + + /* Get associated bf structure */ + bfp = bflookup(fp); + + /* Decrement and check refcount */ + if (bfp != NULL && --bfp->bf_refcount > 0) + return 0; + + /* If bf, get bf structure and remove from list */ + if (bfp != NULL) + bfp = bfdelete(fp); + + if (fclose(fp) == EOF) + { + if (tTd(58, 8)) + dprintf("bfclose: fclose failed\n"); + /* errno is set implicitly by fclose() */ + return -1; + } + + if (bfp == NULL) + return 0; + + /* Success unless we determine otherwise in next block */ + retval = 0; + + if (bfp != NULL) + { + /* Might have to unlink; certainly will have to deallocate */ + if (!bfp->bf_committed) + retval = unlink(bfp->bf_filename); + + free(bfp->bf_filename); + free(bfp); + if (tTd(58, 8)) + dprintf("bfclose: freed %ld\n", + (long) sizeof(struct bf)); + } + else + { + if (tTd(58, 8)) + dprintf("bfclose: bfp was NULL\n"); + } + + return retval; +} + +/* +** BFTEST -- test if a FILE * is a buffered file +** +** Parameters: +** fp -- FILE * to test +** +** Returns: +** TRUE if fp is a buffered file, FALSE otherwise. +** +** Side Effects: +** none. +** +** Sets errno: +** never. +*/ + +bool +bftest(fp) + FILE *fp; +{ + return (bflookup(fp) != NULL); +} + +/* +** BFINSERT -- insert item in linking list +** +** Parameters: +** datum -- item to insert +** +** Returns: +** none. +** +** Side Effects: +** none. +** +** Sets errno: +** never. +*/ + +void +bfinsert(datum) + struct bf *datum; +{ + datum->bf_cdr = bflist; + bflist = datum; +} + +/* +** BFLOOKUP -- lookup FILE * in list +** +** Parameters: +** fp -- FILE * to lookup +** +** Returns: +** bf struct for the FILE *, NULL if not found +** +** Side Effects: +** none. +** +** Sets errno: +** never. +*/ + +struct bf * +bflookup(key) + FILE *key; +{ + struct bf *t; + + for (t = bflist; t != NULL; t = t->bf_cdr) + { + if (t->bf_key == key) + { + return t; + } + } + + /* If we got this far, we didn't find it */ + return NULL; +} + +/* +** BFDELETE -- delete a FILE * in list +** +** Parameters: +** fp -- FILE * to delete +** +** Returns: +** bf struct for deleted FILE *, NULL if not found, +** +** Side Effects: +** none. +** +** Sets errno: +** never. +*/ + +struct bf * +bfdelete(key) + FILE *key; +{ + struct bf *t, *u; + + if (bflist == NULL) + return NULL; + + /* if first element, special case */ + if (bflist->bf_key == key) + { + u = bflist; + bflist = bflist->bf_cdr; + return u; + } + + for (t = bflist; t->bf_cdr != NULL; t = t->bf_cdr) + { + if (t->bf_cdr->bf_key == key) + { + u = t->bf_cdr; + t->bf_cdr = u->bf_cdr; + return u; + } + } + + /* If we got this far, we didn't find it */ + return NULL; +} |