/* * Copyright (c) 2000-2002, 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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_RCSID("@(#)$Id: makebuf.c,v 1.7 2006/07/08 05:30:25 ca Exp $") #include "sm/io.h" #include "sm/heap.h" #include "io-int.h" /* ** SM_WHATBUF -- determine proper buffer for a file (internal) ** ** fills in 'bufsize' for recommended buffer size. ** ** Parameters: ** fp -- file pointer to be buffered ** bufsize -- new buffer size (a return) ** ** Returns: ** SMNPT -- not seek opimized ** SMOPT -- seek opimized */ sm_f_flags_T sm_whatbuf(sm_file_T *fp, size_t *bufsize) { struct stat st; if (f_fd(*fp) < 0 || fstat(f_fd(*fp), &st) < 0) { *bufsize = SM_IO_BUFSIZ; return SMNPT; } if (st.st_blksize == 0) { *bufsize = SM_IO_BUFSIZ; return SMNPT; } #if SM_IO_MAX_BUF_FILE > 0 if (S_ISREG(st.st_mode) && st.st_blksize > SM_IO_MAX_BUF_FILE) st.st_blksize = SM_IO_MAX_BUF_FILE; #endif #if SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0 if (!S_ISREG(st.st_mode)) { # if SM_IO_MAX_BUF > 0 if (st.st_blksize > SM_IO_MAX_BUF) st.st_blksize = SM_IO_MAX_BUF; # if SM_IO_MIN_BUF > 0 else # endif # endif /* SM_IO_MAX_BUF > 0 */ # if SM_IO_MIN_BUF > 0 if (st.st_blksize < SM_IO_MIN_BUF) st.st_blksize = SM_IO_MIN_BUF; # endif } #endif /* SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0 */ /* ** Optimise fseek() only if it is a regular file. (The test for ** sm_std_seek is mainly paranoia.) It is safe to set _blksize ** unconditionally; it will only be used if SMOPT is also set. */ if ((f_flags(*fp) & SMSTR) == 0) { *bufsize = st.st_blksize; fp->f_blksize = st.st_blksize; } else *bufsize = SM_IO_BUFSIZ; if ((st.st_mode & S_IFMT) == S_IFREG && f_seek(*fp) == sm_stdseek) return SMOPT; else return SMNPT; } /* ** SM_MAKEFILEBUF -- make a buffer for the file ** ** Parameters: ** fp -- the file to be buffered ** ** Returns: ** allocation succeeded? ** ** Allocate a file buffer, or switch to unbuffered I/O. */ sm_ret_T sm_makefilebuf(sm_file_T *fp) { void *p; sm_f_flags_T flags; size_t size; /* this may have been set when the file was opened... */ if (f_flags(*fp) & SMNBF) { /* unbuffered: use "buffer" of size 1 */ f_bfbase(*fp) = f_p(*fp) = fp->f_nbuf; f_bfsize(*fp) = sizeof(fp->f_nbuf); return SM_SUCCESS; } flags = sm_whatbuf(fp, &size); p = sm_malloc(size); if (p == NULL) { /* ** todo: We could check this in the application and ** maybe terminate the connection */ /* no memory: set unbuffered, use "buffer" of size 1 */ f_flags(*fp) |= SMNBF; f_bfbase(*fp) = f_p(*fp) = fp->f_nbuf; f_bfsize(*fp) = sizeof(fp->f_nbuf); return sm_error_warn(SM_EM_IO, ENOMEM); } flags |= SMMBF; f_bfbase(*fp) = f_p(*fp) = p; f_bfsize(*fp) = size; f_flags(*fp) |= flags; return SM_SUCCESS; }