bf.c revision 90792
190792Sgshapiro/* 290792Sgshapiro * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro * 990792Sgshapiro * Contributed by Exactis.com, Inc. 1090792Sgshapiro * 1190792Sgshapiro */ 1290792Sgshapiro 1390792Sgshapiro/* 1490792Sgshapiro** This is in transition. Changed from the original bf_torek.c code 1590792Sgshapiro** to use sm_io function calls directly rather than through stdio 1690792Sgshapiro** translation layer. Will be made a built-in file type of libsm 1790792Sgshapiro** next (once safeopen() linkable from libsm). 1890792Sgshapiro*/ 1990792Sgshapiro 2090792Sgshapiro#include <sm/gen.h> 2190792SgshapiroSM_RCSID("@(#)$Id: bf.c,v 8.48 2001/11/04 17:10:49 ca Exp $") 2290792Sgshapiro 2390792Sgshapiro#include <sys/types.h> 2490792Sgshapiro#include <sys/stat.h> 2590792Sgshapiro#include <sys/uio.h> 2690792Sgshapiro#include <fcntl.h> 2790792Sgshapiro#include <unistd.h> 2890792Sgshapiro#include <stdlib.h> 2990792Sgshapiro#include <string.h> 3090792Sgshapiro#include <errno.h> 3190792Sgshapiro#include "sendmail.h" 3290792Sgshapiro#include "bf.h" 3390792Sgshapiro 3490792Sgshapiro#include <syslog.h> 3590792Sgshapiro 3690792Sgshapiro/* bf io functions */ 3790792Sgshapirostatic ssize_t sm_bfread __P((SM_FILE_T *, char *, size_t)); 3890792Sgshapirostatic ssize_t sm_bfwrite __P((SM_FILE_T *, const char *, size_t)); 3990792Sgshapirostatic off_t sm_bfseek __P((SM_FILE_T *, off_t, int)); 4090792Sgshapirostatic int sm_bfclose __P((SM_FILE_T *)); 4190792Sgshapiro 4290792Sgshapirostatic int sm_bfopen __P((SM_FILE_T *, const void *, int, const void *)); 4390792Sgshapirostatic int sm_bfsetinfo __P((SM_FILE_T *, int , void *)); 4490792Sgshapirostatic int sm_bfgetinfo __P((SM_FILE_T *, int , void *)); 4590792Sgshapiro 4690792Sgshapiro/* 4790792Sgshapiro** Data structure for storing information about each buffered file 4890792Sgshapiro** (Originally in sendmail/bf_torek.h for the curious.) 4990792Sgshapiro*/ 5090792Sgshapiro 5190792Sgshapirostruct bf 5290792Sgshapiro{ 5390792Sgshapiro bool bf_committed; /* Has this buffered file been committed? */ 5490792Sgshapiro bool bf_ondisk; /* On disk: committed or buffer overflow */ 5590792Sgshapiro long bf_flags; 5690792Sgshapiro int bf_disk_fd; /* If on disk, associated file descriptor */ 5790792Sgshapiro char *bf_buf; /* Memory buffer */ 5890792Sgshapiro int bf_bufsize; /* Length of above buffer */ 5990792Sgshapiro int bf_buffilled; /* Bytes of buffer actually filled */ 6090792Sgshapiro char *bf_filename; /* Name of buffered file, if ever committed */ 6190792Sgshapiro MODE_T bf_filemode; /* Mode of buffered file, if ever committed */ 6290792Sgshapiro off_t bf_offset; /* Currect file offset */ 6390792Sgshapiro int bf_size; /* Total current size of file */ 6490792Sgshapiro int bf_refcount; /* Reference count */ 6590792Sgshapiro}; 6690792Sgshapiro 6790792Sgshapiro#ifdef BF_STANDALONE 6890792Sgshapiro# define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode) 6990792Sgshapiro#else /* BF_STANDALONE */ 7090792Sgshapiro# define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff) 7190792Sgshapiro#endif /* BF_STANDALONE */ 7290792Sgshapiro 7390792Sgshapirostruct bf_info 7490792Sgshapiro{ 7590792Sgshapiro char *bi_filename; 7690792Sgshapiro MODE_T bi_fmode; 7790792Sgshapiro size_t bi_bsize; 7890792Sgshapiro long bi_flags; 7990792Sgshapiro}; 8090792Sgshapiro 8190792Sgshapiro/* 8290792Sgshapiro** SM_BFOPEN -- the "base" open function called by sm_io_open() for the 8390792Sgshapiro** internal, file-type-specific info setup. 8490792Sgshapiro** 8590792Sgshapiro** Parameters: 8690792Sgshapiro** fp -- file pointer being filled-in for file being open'd 8790792Sgshapiro** filename -- name of the file being open'd 8890792Sgshapiro** flags -- ignored 8990792Sgshapiro** fmode -- file mode (stored for use later) 9090792Sgshapiro** sflags -- "safeopen" flags (stored for use later) 9190792Sgshapiro** rpool -- ignored (currently) 9290792Sgshapiro** 9390792Sgshapiro** Returns: 9490792Sgshapiro** Failure: -1 and sets errno 9590792Sgshapiro** Success: 0 (zero) 9690792Sgshapiro*/ 9790792Sgshapiro 9890792Sgshapirostatic int 9990792Sgshapirosm_bfopen(fp, info, flags, rpool) 10090792Sgshapiro SM_FILE_T *fp; 10190792Sgshapiro const void *info; 10290792Sgshapiro int flags; 10390792Sgshapiro const void *rpool; 10490792Sgshapiro{ 10590792Sgshapiro char *filename; 10690792Sgshapiro MODE_T fmode; 10790792Sgshapiro size_t bsize; 10890792Sgshapiro long sflags; 10990792Sgshapiro struct bf *bfp; 11090792Sgshapiro int l; 11190792Sgshapiro struct stat st; 11290792Sgshapiro 11390792Sgshapiro filename = ((struct bf_info *) info)->bi_filename; 11490792Sgshapiro fmode = ((struct bf_info *) info)->bi_fmode; 11590792Sgshapiro bsize = ((struct bf_info *) info)->bi_bsize; 11690792Sgshapiro sflags = ((struct bf_info *) info)->bi_flags; 11790792Sgshapiro 11890792Sgshapiro /* Sanity checks */ 11990792Sgshapiro if (*filename == '\0') 12090792Sgshapiro { 12190792Sgshapiro /* Empty filename string */ 12290792Sgshapiro errno = ENOENT; 12390792Sgshapiro return -1; 12490792Sgshapiro } 12590792Sgshapiro if (stat(filename, &st) == 0) 12690792Sgshapiro { 12790792Sgshapiro /* File already exists on disk */ 12890792Sgshapiro errno = EEXIST; 12990792Sgshapiro return -1; 13090792Sgshapiro } 13190792Sgshapiro 13290792Sgshapiro /* Allocate memory */ 13390792Sgshapiro bfp = (struct bf *) sm_malloc(sizeof(struct bf)); 13490792Sgshapiro if (bfp == NULL) 13590792Sgshapiro { 13690792Sgshapiro errno = ENOMEM; 13790792Sgshapiro return -1; 13890792Sgshapiro } 13990792Sgshapiro 14090792Sgshapiro /* Assign data buffer */ 14190792Sgshapiro /* A zero bsize is valid, just don't allocate memory */ 14290792Sgshapiro if (bsize > 0) 14390792Sgshapiro { 14490792Sgshapiro bfp->bf_buf = (char *) sm_malloc(bsize); 14590792Sgshapiro if (bfp->bf_buf == NULL) 14690792Sgshapiro { 14790792Sgshapiro bfp->bf_bufsize = 0; 14890792Sgshapiro sm_free(bfp); 14990792Sgshapiro errno = ENOMEM; 15090792Sgshapiro return -1; 15190792Sgshapiro } 15290792Sgshapiro } 15390792Sgshapiro else 15490792Sgshapiro bfp->bf_buf = NULL; 15590792Sgshapiro 15690792Sgshapiro /* Nearly home free, just set all the parameters now */ 15790792Sgshapiro bfp->bf_committed = false; 15890792Sgshapiro bfp->bf_ondisk = false; 15990792Sgshapiro bfp->bf_refcount = 1; 16090792Sgshapiro bfp->bf_flags = sflags; 16190792Sgshapiro bfp->bf_bufsize = bsize; 16290792Sgshapiro bfp->bf_buffilled = 0; 16390792Sgshapiro l = strlen(filename) + 1; 16490792Sgshapiro bfp->bf_filename = (char *) sm_malloc(l); 16590792Sgshapiro if (bfp->bf_filename == NULL) 16690792Sgshapiro { 16790792Sgshapiro if (bfp->bf_buf != NULL) 16890792Sgshapiro sm_free(bfp->bf_buf); 16990792Sgshapiro sm_free(bfp); 17090792Sgshapiro errno = ENOMEM; 17190792Sgshapiro return -1; 17290792Sgshapiro } 17390792Sgshapiro (void) sm_strlcpy(bfp->bf_filename, filename, l); 17490792Sgshapiro bfp->bf_filemode = fmode; 17590792Sgshapiro bfp->bf_offset = 0; 17690792Sgshapiro bfp->bf_size = bsize; 17790792Sgshapiro bfp->bf_disk_fd = -1; 17890792Sgshapiro fp->f_cookie = bfp; 17990792Sgshapiro 18090792Sgshapiro if (tTd(58, 8)) 18190792Sgshapiro sm_dprintf("sm_bfopen(%s)\n", filename); 18290792Sgshapiro 18390792Sgshapiro return 0; 18490792Sgshapiro} 18590792Sgshapiro 18690792Sgshapiro/* 18790792Sgshapiro** BFOPEN -- create a new buffered file 18890792Sgshapiro** 18990792Sgshapiro** Parameters: 19090792Sgshapiro** filename -- the file's name 19190792Sgshapiro** fmode -- what mode the file should be created as 19290792Sgshapiro** bsize -- amount of buffer space to allocate (may be 0) 19390792Sgshapiro** flags -- if running under sendmail, passed directly to safeopen 19490792Sgshapiro** 19590792Sgshapiro** Returns: 19690792Sgshapiro** a SM_FILE_T * which may then be used with stdio functions, 19790792Sgshapiro** or NULL on failure. SM_FILE_T * is opened for writing 19890792Sgshapiro** "SM_IO_WHAT_VECTORS"). 19990792Sgshapiro** 20090792Sgshapiro** Side Effects: 20190792Sgshapiro** none. 20290792Sgshapiro** 20390792Sgshapiro** Sets errno: 20490792Sgshapiro** any value of errno specified by sm_io_setinfo_type() 20590792Sgshapiro** any value of errno specified by sm_io_open() 20690792Sgshapiro** any value of errno specified by sm_io_setinfo() 20790792Sgshapiro*/ 20890792Sgshapiro 20990792SgshapiroSM_FILE_T * 21090792Sgshapirobfopen(filename, fmode, bsize, flags) 21190792Sgshapiro char *filename; 21290792Sgshapiro MODE_T fmode; 21390792Sgshapiro size_t bsize; 21490792Sgshapiro long flags; 21590792Sgshapiro{ 21690792Sgshapiro MODE_T omask; 21790792Sgshapiro SM_FILE_T SM_IO_SET_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose, 21890792Sgshapiro sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo, 21990792Sgshapiro SM_TIME_FOREVER); 22090792Sgshapiro struct bf_info info; 22190792Sgshapiro 22290792Sgshapiro /* 22390792Sgshapiro ** Apply current umask to fmode as it may change by the time 22490792Sgshapiro ** the file is actually created. fmode becomes the true 22590792Sgshapiro ** permissions of the file, which OPEN() must obey. 22690792Sgshapiro */ 22790792Sgshapiro 22890792Sgshapiro omask = umask(0); 22990792Sgshapiro fmode &= ~omask; 23090792Sgshapiro (void) umask(omask); 23190792Sgshapiro 23290792Sgshapiro SM_IO_INIT_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose, 23390792Sgshapiro sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo, 23490792Sgshapiro SM_TIME_FOREVER); 23590792Sgshapiro info.bi_filename = filename; 23690792Sgshapiro info.bi_fmode = fmode; 23790792Sgshapiro info.bi_bsize = bsize; 23890792Sgshapiro info.bi_flags = flags; 23990792Sgshapiro 24090792Sgshapiro return sm_io_open(&vector, SM_TIME_DEFAULT, &info, SM_IO_RDWR, NULL); 24190792Sgshapiro} 24290792Sgshapiro 24390792Sgshapiro/* 24490792Sgshapiro** SM_BFGETINFO -- returns info about an open file pointer 24590792Sgshapiro** 24690792Sgshapiro** Parameters: 24790792Sgshapiro** fp -- file pointer to get info about 24890792Sgshapiro** what -- type of info to obtain 24990792Sgshapiro** valp -- thing to return the info in 25090792Sgshapiro*/ 25190792Sgshapiro 25290792Sgshapirostatic int 25390792Sgshapirosm_bfgetinfo(fp, what, valp) 25490792Sgshapiro SM_FILE_T *fp; 25590792Sgshapiro int what; 25690792Sgshapiro void *valp; 25790792Sgshapiro{ 25890792Sgshapiro struct bf *bfp; 25990792Sgshapiro 26090792Sgshapiro bfp = (struct bf *) fp->f_cookie; 26190792Sgshapiro switch (what) 26290792Sgshapiro { 26390792Sgshapiro case SM_IO_WHAT_FD: 26490792Sgshapiro return bfp->bf_disk_fd; 26590792Sgshapiro default: 26690792Sgshapiro return -1; 26790792Sgshapiro } 26890792Sgshapiro} 26990792Sgshapiro 27090792Sgshapiro/* 27190792Sgshapiro** SM_BFCLOSE -- close a buffered file 27290792Sgshapiro** 27390792Sgshapiro** Parameters: 27490792Sgshapiro** fp -- cookie of file to close 27590792Sgshapiro** 27690792Sgshapiro** Returns: 27790792Sgshapiro** 0 to indicate success 27890792Sgshapiro** 27990792Sgshapiro** Side Effects: 28090792Sgshapiro** deletes backing file, sm_frees memory. 28190792Sgshapiro** 28290792Sgshapiro** Sets errno: 28390792Sgshapiro** never. 28490792Sgshapiro*/ 28590792Sgshapiro 28690792Sgshapirostatic int 28790792Sgshapirosm_bfclose(fp) 28890792Sgshapiro SM_FILE_T *fp; 28990792Sgshapiro{ 29090792Sgshapiro struct bf *bfp; 29190792Sgshapiro 29290792Sgshapiro /* Cast cookie back to correct type */ 29390792Sgshapiro bfp = (struct bf *) fp->f_cookie; 29490792Sgshapiro 29590792Sgshapiro /* Need to clean up the file */ 29690792Sgshapiro if (bfp->bf_ondisk && !bfp->bf_committed) 29790792Sgshapiro unlink(bfp->bf_filename); 29890792Sgshapiro sm_free(bfp->bf_filename); 29990792Sgshapiro 30090792Sgshapiro if (bfp->bf_disk_fd != -1) 30190792Sgshapiro close(bfp->bf_disk_fd); 30290792Sgshapiro 30390792Sgshapiro /* Need to sm_free the buffer */ 30490792Sgshapiro if (bfp->bf_bufsize > 0) 30590792Sgshapiro sm_free(bfp->bf_buf); 30690792Sgshapiro 30790792Sgshapiro /* Finally, sm_free the structure */ 30890792Sgshapiro sm_free(bfp); 30990792Sgshapiro return 0; 31090792Sgshapiro} 31190792Sgshapiro 31290792Sgshapiro/* 31390792Sgshapiro** SM_BFREAD -- read a buffered file 31490792Sgshapiro** 31590792Sgshapiro** Parameters: 31690792Sgshapiro** cookie -- cookie of file to read 31790792Sgshapiro** buf -- buffer to fill 31890792Sgshapiro** nbytes -- how many bytes to read 31990792Sgshapiro** 32090792Sgshapiro** Returns: 32190792Sgshapiro** number of bytes read or -1 indicate failure 32290792Sgshapiro** 32390792Sgshapiro** Side Effects: 32490792Sgshapiro** none. 32590792Sgshapiro** 32690792Sgshapiro*/ 32790792Sgshapiro 32890792Sgshapirostatic ssize_t 32990792Sgshapirosm_bfread(fp, buf, nbytes) 33090792Sgshapiro SM_FILE_T *fp; 33190792Sgshapiro char *buf; 33290792Sgshapiro size_t nbytes; 33390792Sgshapiro{ 33490792Sgshapiro struct bf *bfp; 33590792Sgshapiro ssize_t count = 0; /* Number of bytes put in buf so far */ 33690792Sgshapiro int retval; 33790792Sgshapiro 33890792Sgshapiro /* Cast cookie back to correct type */ 33990792Sgshapiro bfp = (struct bf *) fp->f_cookie; 34090792Sgshapiro 34190792Sgshapiro if (bfp->bf_offset < bfp->bf_buffilled) 34290792Sgshapiro { 34390792Sgshapiro /* Need to grab some from buffer */ 34490792Sgshapiro count = nbytes; 34590792Sgshapiro if ((bfp->bf_offset + count) > bfp->bf_buffilled) 34690792Sgshapiro count = bfp->bf_buffilled - bfp->bf_offset; 34790792Sgshapiro 34890792Sgshapiro memcpy(buf, bfp->bf_buf + bfp->bf_offset, count); 34990792Sgshapiro } 35090792Sgshapiro 35190792Sgshapiro if ((bfp->bf_offset + nbytes) > bfp->bf_buffilled) 35290792Sgshapiro { 35390792Sgshapiro /* Need to grab some from file */ 35490792Sgshapiro if (!bfp->bf_ondisk) 35590792Sgshapiro { 35690792Sgshapiro /* Oops, the file doesn't exist. EOF. */ 35790792Sgshapiro if (tTd(58, 8)) 35890792Sgshapiro sm_dprintf("sm_bfread(%s): to disk\n", 35990792Sgshapiro bfp->bf_filename); 36090792Sgshapiro goto finished; 36190792Sgshapiro } 36290792Sgshapiro 36390792Sgshapiro /* Catch a read() on an earlier failed write to disk */ 36490792Sgshapiro if (bfp->bf_disk_fd < 0) 36590792Sgshapiro { 36690792Sgshapiro errno = EIO; 36790792Sgshapiro return -1; 36890792Sgshapiro } 36990792Sgshapiro 37090792Sgshapiro if (lseek(bfp->bf_disk_fd, 37190792Sgshapiro bfp->bf_offset + count, SEEK_SET) < 0) 37290792Sgshapiro { 37390792Sgshapiro if ((errno == EINVAL) || (errno == ESPIPE)) 37490792Sgshapiro { 37590792Sgshapiro /* 37690792Sgshapiro ** stdio won't be expecting these 37790792Sgshapiro ** errnos from read()! Change them 37890792Sgshapiro ** into something it can understand. 37990792Sgshapiro */ 38090792Sgshapiro 38190792Sgshapiro errno = EIO; 38290792Sgshapiro } 38390792Sgshapiro return -1; 38490792Sgshapiro } 38590792Sgshapiro 38690792Sgshapiro while (count < nbytes) 38790792Sgshapiro { 38890792Sgshapiro retval = read(bfp->bf_disk_fd, 38990792Sgshapiro buf + count, 39090792Sgshapiro nbytes - count); 39190792Sgshapiro if (retval < 0) 39290792Sgshapiro { 39390792Sgshapiro /* errno is set implicitly by read() */ 39490792Sgshapiro return -1; 39590792Sgshapiro } 39690792Sgshapiro else if (retval == 0) 39790792Sgshapiro goto finished; 39890792Sgshapiro else 39990792Sgshapiro count += retval; 40090792Sgshapiro } 40190792Sgshapiro } 40290792Sgshapiro 40390792Sgshapirofinished: 40490792Sgshapiro bfp->bf_offset += count; 40590792Sgshapiro return count; 40690792Sgshapiro} 40790792Sgshapiro 40890792Sgshapiro/* 40990792Sgshapiro** SM_BFSEEK -- seek to a position in a buffered file 41090792Sgshapiro** 41190792Sgshapiro** Parameters: 41290792Sgshapiro** fp -- fp of file to seek 41390792Sgshapiro** offset -- position to seek to 41490792Sgshapiro** whence -- how to seek 41590792Sgshapiro** 41690792Sgshapiro** Returns: 41790792Sgshapiro** new file offset or -1 indicate failure 41890792Sgshapiro** 41990792Sgshapiro** Side Effects: 42090792Sgshapiro** none. 42190792Sgshapiro** 42290792Sgshapiro*/ 42390792Sgshapiro 42490792Sgshapirostatic off_t 42590792Sgshapirosm_bfseek(fp, offset, whence) 42690792Sgshapiro SM_FILE_T *fp; 42790792Sgshapiro off_t offset; 42890792Sgshapiro int whence; 42990792Sgshapiro 43090792Sgshapiro{ 43190792Sgshapiro struct bf *bfp; 43290792Sgshapiro 43390792Sgshapiro /* Cast cookie back to correct type */ 43490792Sgshapiro bfp = (struct bf *) fp->f_cookie; 43590792Sgshapiro 43690792Sgshapiro switch (whence) 43790792Sgshapiro { 43890792Sgshapiro case SEEK_SET: 43990792Sgshapiro bfp->bf_offset = offset; 44090792Sgshapiro break; 44190792Sgshapiro 44290792Sgshapiro case SEEK_CUR: 44390792Sgshapiro bfp->bf_offset += offset; 44490792Sgshapiro break; 44590792Sgshapiro 44690792Sgshapiro case SEEK_END: 44790792Sgshapiro bfp->bf_offset = bfp->bf_size + offset; 44890792Sgshapiro break; 44990792Sgshapiro 45090792Sgshapiro default: 45190792Sgshapiro errno = EINVAL; 45290792Sgshapiro return -1; 45390792Sgshapiro } 45490792Sgshapiro return bfp->bf_offset; 45590792Sgshapiro} 45690792Sgshapiro 45790792Sgshapiro/* 45890792Sgshapiro** SM_BFWRITE -- write to a buffered file 45990792Sgshapiro** 46090792Sgshapiro** Parameters: 46190792Sgshapiro** fp -- fp of file to write 46290792Sgshapiro** buf -- data buffer 46390792Sgshapiro** nbytes -- how many bytes to write 46490792Sgshapiro** 46590792Sgshapiro** Returns: 46690792Sgshapiro** number of bytes written or -1 indicate failure 46790792Sgshapiro** 46890792Sgshapiro** Side Effects: 46990792Sgshapiro** may create backing file if over memory limit for file. 47090792Sgshapiro** 47190792Sgshapiro*/ 47290792Sgshapiro 47390792Sgshapirostatic ssize_t 47490792Sgshapirosm_bfwrite(fp, buf, nbytes) 47590792Sgshapiro SM_FILE_T *fp; 47690792Sgshapiro const char *buf; 47790792Sgshapiro size_t nbytes; 47890792Sgshapiro{ 47990792Sgshapiro struct bf *bfp; 48090792Sgshapiro ssize_t count = 0; /* Number of bytes written so far */ 48190792Sgshapiro int retval; 48290792Sgshapiro 48390792Sgshapiro /* Cast cookie back to correct type */ 48490792Sgshapiro bfp = (struct bf *) fp->f_cookie; 48590792Sgshapiro 48690792Sgshapiro /* If committed, go straight to disk */ 48790792Sgshapiro if (bfp->bf_committed) 48890792Sgshapiro { 48990792Sgshapiro if (lseek(bfp->bf_disk_fd, bfp->bf_offset, SEEK_SET) < 0) 49090792Sgshapiro { 49190792Sgshapiro if ((errno == EINVAL) || (errno == ESPIPE)) 49290792Sgshapiro { 49390792Sgshapiro /* 49490792Sgshapiro ** stdio won't be expecting these 49590792Sgshapiro ** errnos from write()! Change them 49690792Sgshapiro ** into something it can understand. 49790792Sgshapiro */ 49890792Sgshapiro 49990792Sgshapiro errno = EIO; 50090792Sgshapiro } 50190792Sgshapiro return -1; 50290792Sgshapiro } 50390792Sgshapiro 50490792Sgshapiro count = write(bfp->bf_disk_fd, buf, nbytes); 50590792Sgshapiro if (count < 0) 50690792Sgshapiro { 50790792Sgshapiro /* errno is set implicitly by write() */ 50890792Sgshapiro return -1; 50990792Sgshapiro } 51090792Sgshapiro goto finished; 51190792Sgshapiro } 51290792Sgshapiro 51390792Sgshapiro if (bfp->bf_offset < bfp->bf_bufsize) 51490792Sgshapiro { 51590792Sgshapiro /* Need to put some in buffer */ 51690792Sgshapiro count = nbytes; 51790792Sgshapiro if ((bfp->bf_offset + count) > bfp->bf_bufsize) 51890792Sgshapiro count = bfp->bf_bufsize - bfp->bf_offset; 51990792Sgshapiro 52090792Sgshapiro memcpy(bfp->bf_buf + bfp->bf_offset, buf, count); 52190792Sgshapiro if ((bfp->bf_offset + count) > bfp->bf_buffilled) 52290792Sgshapiro bfp->bf_buffilled = bfp->bf_offset + count; 52390792Sgshapiro } 52490792Sgshapiro 52590792Sgshapiro if ((bfp->bf_offset + nbytes) > bfp->bf_bufsize) 52690792Sgshapiro { 52790792Sgshapiro /* Need to put some in file */ 52890792Sgshapiro if (!bfp->bf_ondisk) 52990792Sgshapiro { 53090792Sgshapiro MODE_T omask; 53190792Sgshapiro 53290792Sgshapiro /* Clear umask as bf_filemode are the true perms */ 53390792Sgshapiro omask = umask(0); 53490792Sgshapiro retval = OPEN(bfp->bf_filename, 53590792Sgshapiro O_RDWR | O_CREAT | O_TRUNC, 53690792Sgshapiro bfp->bf_filemode, bfp->bf_flags); 53790792Sgshapiro (void) umask(omask); 53890792Sgshapiro 53990792Sgshapiro /* Couldn't create file: failure */ 54090792Sgshapiro if (retval < 0) 54190792Sgshapiro { 54290792Sgshapiro /* 54390792Sgshapiro ** stdio may not be expecting these 54490792Sgshapiro ** errnos from write()! Change to 54590792Sgshapiro ** something which it can understand. 54690792Sgshapiro ** Note that ENOSPC and EDQUOT are saved 54790792Sgshapiro ** because they are actually valid for 54890792Sgshapiro ** write(). 54990792Sgshapiro */ 55090792Sgshapiro 55190792Sgshapiro if (!(errno == ENOSPC 55290792Sgshapiro#ifdef EDQUOT 55390792Sgshapiro || errno == EDQUOT 55490792Sgshapiro#endif /* EDQUOT */ 55590792Sgshapiro )) 55690792Sgshapiro errno = EIO; 55790792Sgshapiro 55890792Sgshapiro return -1; 55990792Sgshapiro } 56090792Sgshapiro bfp->bf_disk_fd = retval; 56190792Sgshapiro bfp->bf_ondisk = true; 56290792Sgshapiro } 56390792Sgshapiro 56490792Sgshapiro /* Catch a write() on an earlier failed write to disk */ 56590792Sgshapiro if (bfp->bf_ondisk && bfp->bf_disk_fd < 0) 56690792Sgshapiro { 56790792Sgshapiro errno = EIO; 56890792Sgshapiro return -1; 56990792Sgshapiro } 57090792Sgshapiro 57190792Sgshapiro if (lseek(bfp->bf_disk_fd, 57290792Sgshapiro bfp->bf_offset + count, SEEK_SET) < 0) 57390792Sgshapiro { 57490792Sgshapiro if ((errno == EINVAL) || (errno == ESPIPE)) 57590792Sgshapiro { 57690792Sgshapiro /* 57790792Sgshapiro ** stdio won't be expecting these 57890792Sgshapiro ** errnos from write()! Change them into 57990792Sgshapiro ** something which it can understand. 58090792Sgshapiro */ 58190792Sgshapiro 58290792Sgshapiro errno = EIO; 58390792Sgshapiro } 58490792Sgshapiro return -1; 58590792Sgshapiro } 58690792Sgshapiro 58790792Sgshapiro while (count < nbytes) 58890792Sgshapiro { 58990792Sgshapiro retval = write(bfp->bf_disk_fd, buf + count, 59090792Sgshapiro nbytes - count); 59190792Sgshapiro if (retval < 0) 59290792Sgshapiro { 59390792Sgshapiro /* errno is set implicitly by write() */ 59490792Sgshapiro return -1; 59590792Sgshapiro } 59690792Sgshapiro else 59790792Sgshapiro count += retval; 59890792Sgshapiro } 59990792Sgshapiro } 60090792Sgshapiro 60190792Sgshapirofinished: 60290792Sgshapiro bfp->bf_offset += count; 60390792Sgshapiro if (bfp->bf_offset > bfp->bf_size) 60490792Sgshapiro bfp->bf_size = bfp->bf_offset; 60590792Sgshapiro return count; 60690792Sgshapiro} 60790792Sgshapiro 60890792Sgshapiro/* 60990792Sgshapiro** BFREWIND -- rewinds the SM_FILE_T * 61090792Sgshapiro** 61190792Sgshapiro** Parameters: 61290792Sgshapiro** fp -- SM_FILE_T * to rewind 61390792Sgshapiro** 61490792Sgshapiro** Returns: 61590792Sgshapiro** 0 on success, -1 on error 61690792Sgshapiro** 61790792Sgshapiro** Side Effects: 61890792Sgshapiro** rewinds the SM_FILE_T * and puts it into read mode. Normally one 61990792Sgshapiro** would bfopen() a file, write to it, then bfrewind() and 62090792Sgshapiro** fread(). If fp is not a buffered file, this is equivalent to 62190792Sgshapiro** rewind(). 62290792Sgshapiro** 62390792Sgshapiro** Sets errno: 62490792Sgshapiro** any value of errno specified by sm_io_rewind() 62590792Sgshapiro*/ 62690792Sgshapiro 62790792Sgshapiroint 62890792Sgshapirobfrewind(fp) 62990792Sgshapiro SM_FILE_T *fp; 63090792Sgshapiro{ 63190792Sgshapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 63290792Sgshapiro sm_io_clearerr(fp); /* quicker just to do it */ 63390792Sgshapiro return sm_io_seek(fp, SM_TIME_DEFAULT, 0, SM_IO_SEEK_SET); 63490792Sgshapiro} 63590792Sgshapiro 63690792Sgshapiro/* 63790792Sgshapiro** SM_BFCOMMIT -- "commits" the buffered file 63890792Sgshapiro** 63990792Sgshapiro** Parameters: 64090792Sgshapiro** fp -- SM_FILE_T * to commit to disk 64190792Sgshapiro** 64290792Sgshapiro** Returns: 64390792Sgshapiro** 0 on success, -1 on error 64490792Sgshapiro** 64590792Sgshapiro** Side Effects: 64690792Sgshapiro** Forces the given SM_FILE_T * to be written to disk if it is not 64790792Sgshapiro** already, and ensures that it will be kept after closing. If 64890792Sgshapiro** fp is not a buffered file, this is a no-op. 64990792Sgshapiro** 65090792Sgshapiro** Sets errno: 65190792Sgshapiro** any value of errno specified by open() 65290792Sgshapiro** any value of errno specified by write() 65390792Sgshapiro** any value of errno specified by lseek() 65490792Sgshapiro*/ 65590792Sgshapiro 65690792Sgshapirostatic int 65790792Sgshapirosm_bfcommit(fp) 65890792Sgshapiro SM_FILE_T *fp; 65990792Sgshapiro{ 66090792Sgshapiro struct bf *bfp; 66190792Sgshapiro int retval; 66290792Sgshapiro int byteswritten; 66390792Sgshapiro 66490792Sgshapiro /* Get associated bf structure */ 66590792Sgshapiro bfp = (struct bf *) fp->f_cookie; 66690792Sgshapiro 66790792Sgshapiro /* If already committed, noop */ 66890792Sgshapiro if (bfp->bf_committed) 66990792Sgshapiro return 0; 67090792Sgshapiro 67190792Sgshapiro /* Do we need to open a file? */ 67290792Sgshapiro if (!bfp->bf_ondisk) 67390792Sgshapiro { 67490792Sgshapiro MODE_T omask; 67590792Sgshapiro struct stat st; 67690792Sgshapiro 67790792Sgshapiro if (tTd(58, 8)) 67890792Sgshapiro { 67990792Sgshapiro sm_dprintf("bfcommit(%s): to disk\n", bfp->bf_filename); 68090792Sgshapiro if (tTd(58, 32)) 68190792Sgshapiro sm_dprintf("bfcommit(): filemode %o flags %ld\n", 68290792Sgshapiro bfp->bf_filemode, bfp->bf_flags); 68390792Sgshapiro } 68490792Sgshapiro 68590792Sgshapiro if (stat(bfp->bf_filename, &st) == 0) 68690792Sgshapiro { 68790792Sgshapiro errno = EEXIST; 68890792Sgshapiro return -1; 68990792Sgshapiro } 69090792Sgshapiro 69190792Sgshapiro /* Clear umask as bf_filemode are the true perms */ 69290792Sgshapiro omask = umask(0); 69390792Sgshapiro retval = OPEN(bfp->bf_filename, O_RDWR | O_CREAT | O_TRUNC, 69490792Sgshapiro bfp->bf_filemode, bfp->bf_flags); 69590792Sgshapiro (void) umask(omask); 69690792Sgshapiro 69790792Sgshapiro /* Couldn't create file: failure */ 69890792Sgshapiro if (retval < 0) 69990792Sgshapiro { 70090792Sgshapiro /* errno is set implicitly by open() */ 70190792Sgshapiro return -1; 70290792Sgshapiro } 70390792Sgshapiro 70490792Sgshapiro bfp->bf_disk_fd = retval; 70590792Sgshapiro bfp->bf_ondisk = true; 70690792Sgshapiro } 70790792Sgshapiro 70890792Sgshapiro /* Write out the contents of our buffer, if we have any */ 70990792Sgshapiro if (bfp->bf_buffilled > 0) 71090792Sgshapiro { 71190792Sgshapiro byteswritten = 0; 71290792Sgshapiro 71390792Sgshapiro if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0) 71490792Sgshapiro { 71590792Sgshapiro /* errno is set implicitly by lseek() */ 71690792Sgshapiro return -1; 71790792Sgshapiro } 71890792Sgshapiro 71990792Sgshapiro while (byteswritten < bfp->bf_buffilled) 72090792Sgshapiro { 72190792Sgshapiro retval = write(bfp->bf_disk_fd, 72290792Sgshapiro bfp->bf_buf + byteswritten, 72390792Sgshapiro bfp->bf_buffilled - byteswritten); 72490792Sgshapiro if (retval < 0) 72590792Sgshapiro { 72690792Sgshapiro /* errno is set implicitly by write() */ 72790792Sgshapiro return -1; 72890792Sgshapiro } 72990792Sgshapiro else 73090792Sgshapiro byteswritten += retval; 73190792Sgshapiro } 73290792Sgshapiro } 73390792Sgshapiro bfp->bf_committed = true; 73490792Sgshapiro 73590792Sgshapiro /* Invalidate buf; all goes to file now */ 73690792Sgshapiro bfp->bf_buffilled = 0; 73790792Sgshapiro if (bfp->bf_bufsize > 0) 73890792Sgshapiro { 73990792Sgshapiro /* Don't need buffer anymore; free it */ 74090792Sgshapiro bfp->bf_bufsize = 0; 74190792Sgshapiro sm_free(bfp->bf_buf); 74290792Sgshapiro } 74390792Sgshapiro return 0; 74490792Sgshapiro} 74590792Sgshapiro 74690792Sgshapiro/* 74790792Sgshapiro** SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T * 74890792Sgshapiro** 74990792Sgshapiro** Parameters: 75090792Sgshapiro** fp -- SM_FILE_T * to truncate 75190792Sgshapiro** 75290792Sgshapiro** Returns: 75390792Sgshapiro** 0 on success, -1 on error 75490792Sgshapiro** 75590792Sgshapiro** Side Effects: 75690792Sgshapiro** rewinds the SM_FILE_T *, truncates it to zero length, and puts 75790792Sgshapiro** it into write mode. 75890792Sgshapiro** 75990792Sgshapiro** Sets errno: 76090792Sgshapiro** any value of errno specified by fseek() 76190792Sgshapiro** any value of errno specified by ftruncate() 76290792Sgshapiro*/ 76390792Sgshapiro 76490792Sgshapirostatic int 76590792Sgshapirosm_bftruncate(fp) 76690792Sgshapiro SM_FILE_T *fp; 76790792Sgshapiro{ 76890792Sgshapiro struct bf *bfp; 76990792Sgshapiro 77090792Sgshapiro if (bfrewind(fp) < 0) 77190792Sgshapiro return -1; 77290792Sgshapiro 77390792Sgshapiro /* Get bf structure */ 77490792Sgshapiro bfp = (struct bf *) fp->f_cookie; 77590792Sgshapiro bfp->bf_buffilled = 0; 77690792Sgshapiro bfp->bf_size = 0; 77790792Sgshapiro 77890792Sgshapiro /* Need to zero the buffer */ 77990792Sgshapiro if (bfp->bf_bufsize > 0) 78090792Sgshapiro memset(bfp->bf_buf, '\0', bfp->bf_bufsize); 78190792Sgshapiro if (bfp->bf_ondisk) 78290792Sgshapiro { 78390792Sgshapiro#if NOFTRUNCATE 78490792Sgshapiro /* XXX: Not much we can do except rewind it */ 78590792Sgshapiro errno = EINVAL; 78690792Sgshapiro return -1; 78790792Sgshapiro#else /* NOFTRUNCATE */ 78890792Sgshapiro return ftruncate(bfp->bf_disk_fd, 0); 78990792Sgshapiro#endif /* NOFTRUNCATE */ 79090792Sgshapiro } 79190792Sgshapiro else 79290792Sgshapiro return 0; 79390792Sgshapiro} 79490792Sgshapiro 79590792Sgshapiro/* 79690792Sgshapiro** SM_BFSETINFO -- set/change info for an open file pointer 79790792Sgshapiro** 79890792Sgshapiro** Parameters: 79990792Sgshapiro** fp -- file pointer to get info about 80090792Sgshapiro** what -- type of info to set/change 80190792Sgshapiro** valp -- thing to set/change the info to 80290792Sgshapiro** 80390792Sgshapiro*/ 80490792Sgshapiro 80590792Sgshapirostatic int 80690792Sgshapirosm_bfsetinfo(fp, what, valp) 80790792Sgshapiro SM_FILE_T *fp; 80890792Sgshapiro int what; 80990792Sgshapiro void *valp; 81090792Sgshapiro{ 81190792Sgshapiro struct bf *bfp; 81290792Sgshapiro int bsize; 81390792Sgshapiro 81490792Sgshapiro /* Get bf structure */ 81590792Sgshapiro bfp = (struct bf *) fp->f_cookie; 81690792Sgshapiro switch (what) 81790792Sgshapiro { 81890792Sgshapiro case SM_BF_SETBUFSIZE: 81990792Sgshapiro bsize = *((int *) valp); 82090792Sgshapiro bfp->bf_bufsize = bsize; 82190792Sgshapiro 82290792Sgshapiro /* A zero bsize is valid, just don't allocate memory */ 82390792Sgshapiro if (bsize > 0) 82490792Sgshapiro { 82590792Sgshapiro bfp->bf_buf = (char *) sm_malloc(bsize); 82690792Sgshapiro if (bfp->bf_buf == NULL) 82790792Sgshapiro { 82890792Sgshapiro bfp->bf_bufsize = 0; 82990792Sgshapiro errno = ENOMEM; 83090792Sgshapiro return -1; 83190792Sgshapiro } 83290792Sgshapiro } 83390792Sgshapiro else 83490792Sgshapiro bfp->bf_buf = NULL; 83590792Sgshapiro return 0; 83690792Sgshapiro case SM_BF_COMMIT: 83790792Sgshapiro return sm_bfcommit(fp); 83890792Sgshapiro case SM_BF_TRUNCATE: 83990792Sgshapiro return sm_bftruncate(fp); 84090792Sgshapiro case SM_BF_TEST: 84190792Sgshapiro return 1; /* always */ 84290792Sgshapiro default: 84390792Sgshapiro errno = EINVAL; 84490792Sgshapiro return -1; 84590792Sgshapiro } 84690792Sgshapiro} 847