/* * Copyright (c) 2000-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: refill.c,v 1.30 2005/07/25 20:19:45 ca Exp $") #include "sm/error.h" #include "sm/io.h" #include "sm/assert.h" #include "sm/memops.h" #include "io-int.h" /* ** SM_REFILL -- refill a buffer ** ** This should be called if the read buffer is empty. ** However, when we switch from write to read and we use double buffering ** the read buffer may not actually be empty. In that case just return ** with the old buffer. ** ** Parameters: ** fp -- file pointer for buffer refill ** ** Returns: ** usual return type (including EOF). */ sm_ret_T sm_refill(sm_file_T *fp) { ssize_t r; sm_ret_T res; /* largely a convenience for callers */ f_r(*fp) = 0; /* XXX double buffering: keep EOF? */ if (f_flags(*fp) & SMFEOF) return SM_IO_EOF; /* if not already reading, have to be reading and writing */ if ((f_flags(*fp) & SMRD) == 0) { if ((f_flags(*fp) & SMRW) == 0) { f_flags(*fp) |= SMERR; #if SM_IO_ERR_VAL f_error(*fp) = sm_error_perm(SM_EM_IO, EBADF); #endif return sm_error_perm(SM_EM_IO, EBADF); } /* switch to reading */ if (f_flags(*fp) & SMWR) { if (!sm_io_double(fp) || sm_io_getinfo(fp, SM_IO_IS_READABLE, NULL) <= 0) { res = sm_flush(fp); if (sm_is_err(res)) return SM_IO_EOF; /* XXX res? */ } f_flags(*fp) &= ~SMWR; } SM_IO_TO_RD(fp); f_flags(*fp) |= SMRD; /* shortcut: still something in the read buffer? */ if (sm_io_double(fp) && f_r(*fp) > 0) return SM_SUCCESS; } /* invariant: read buffer is empty */ if (f_bfbase(*fp) == NULL) sm_makefilebuf(fp); /* needed to ensure EOF correctly found (unless f_read does it) */ errno = 0; /* reset buffer pointer (always), see invariant above */ f_p(*fp) = f_bfbase(*fp); res = (*f_read(*fp))(fp, f_p(*fp), f_bfsize(*fp), &r); if (sm_is_err(res)) { /* ** Should we distinguish the error here? ** E.g, timeout, dropped connection? */ if (r <= 0) { f_flags(*fp) |= SMERR; #if SM_IO_ERR_VAL f_error(*fp) = res; #endif } else f_r(*fp) += r; #if 0 if (sm_io_double(fp) && f_r(*fp) > 0) return SM_SUCCESS; #endif return res; } if (r <= 0) { if (r == 0) f_flags(*fp) |= SMFEOF; else { f_flags(*fp) |= SMERR; /* should be caught above */ #if SM_IO_ERR_VAL f_error(*fp) = sm_error_perm(SM_EM_IO, EINVAL); /* correct error? */ #endif } if (!sm_io_double(fp)) f_r(*fp) = 0; return SM_IO_EOF; } f_r(*fp) += r; return SM_SUCCESS; } /* ** SM_RGET -- refills buffer and returns first character ** ** Handle sm_getc() when the buffer ran out: ** Refill, then return the first character in the newly-filled buffer. ** ** Parameters: ** fp -- file pointer to work on ** ** Returns: ** Success: first character in refilled buffer as an int ** Failure: SM_IO_EOF */ int sm_rget(sm_file_T *fp) { sm_ret_T res; res = sm_refill(fp); if (sm_is_success(res)) { f_r(*fp)--; return *f_p(*fp)++; } /* return res of EOF? */ return res; }