/* * 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_IDSTR(id, "@(#)$Id: strio.c,v 1.44 2005/06/09 21:40:19 ca Exp $") #include #include #include #include #include #include #include #include #include #include "local.h" static int sm_strsetmode __P((SM_FILE_T*, const int *)); static int sm_strgetmode __P((SM_FILE_T*, int *)); /* ** Cookie structure for the "strio" file type */ struct sm_str_obj { char *strio_base; char *strio_end; size_t strio_size; size_t strio_offset; int strio_flags; const void *strio_rpool; }; typedef struct sm_str_obj SM_STR_OBJ_T; /* ** SM_STRGROW -- increase storage space for string ** ** Parameters: ** s -- current cookie ** size -- new storage size request ** ** Returns: ** true iff successful. */ static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t)); static bool sm_strgrow(s, size) SM_STR_OBJ_T *s; size_t size; { register void *p; if (s->strio_size >= size) return true; p = sm_realloc(s->strio_base, size); if (p == NULL) return false; s->strio_base = p; s->strio_end = s->strio_base + size; s->strio_size = size; return true; } /* ** SM_STRREAD -- read a portion of the string ** ** Parameters: ** fp -- the file pointer ** buf -- location to place read data ** n -- number of bytes to read ** ** Returns: ** Failure: -1 and sets errno ** Success: >=0, number of bytes read */ ssize_t sm_strread(fp, buf, n) SM_FILE_T *fp; char *buf; size_t n; { register SM_STR_OBJ_T *s = fp->f_cookie; int len; if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW)) { errno = EBADF; return -1; } len = SM_MIN(s->strio_size - s->strio_offset, n); (void) memmove(buf, s->strio_base + s->strio_offset, len); s->strio_offset += len; return len; } /* ** SM_STRWRITE -- write a portion of the string ** ** Parameters: ** fp -- the file pointer ** buf -- location of data for writing ** n -- number of bytes to write ** ** Returns: ** Failure: -1 and sets errno ** Success: >=0, number of bytes written */ ssize_t sm_strwrite(fp, buf, n) SM_FILE_T *fp; char const *buf; size_t n; { register SM_STR_OBJ_T *s = fp->f_cookie; if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW)) { errno = EBADF; return -1; } if (n + s->strio_offset > s->strio_size) { if (!sm_strgrow(s, n + s->strio_offset)) return 0; } (void) memmove(s->strio_base + s->strio_offset, buf, n); s->strio_offset += n; return n; } /* ** SM_STRSEEK -- position the offset pointer for the string ** ** Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid ** values for whence. ** ** Parameters: ** fp -- the file pointer ** offset -- number of bytes offset from "base" ** whence -- determines "base" for 'offset' ** ** Returns: ** Failure: -1 and sets errno ** Success: >=0, number of bytes read */ off_t sm_strseek(fp, offset, whence) SM_FILE_T *fp; off_t offset; int whence; { register off_t ret; register SM_STR_OBJ_T *s = fp->f_cookie; reseek: switch (whence) { case SM_IO_SEEK_SET: ret = offset; break; case SM_IO_SEEK_CUR: ret = s->strio_offset + offset; break; case SM_IO_SEEK_END: ret = s->strio_size; break; default: errno = EINVAL; return -1; } if (ret < 0 || ret > (off_t)(size_t)(-1)) /* XXX ugly */ return -1; if ((size_t) ret > s->strio_size) { if (sm_strgrow(s, (size_t)ret)) goto reseek; /* errno set by sm_strgrow */ return -1; } s->strio_offset = (size_t) ret; return ret; } /* ** SM_STROPEN -- open a string file type ** ** Parameters: ** fp -- file pointer open to be associated with ** info -- initial contents (NULL for none) ** flags -- flags for methods of access (was mode) ** rpool -- resource pool to use memory from (if applicable) ** ** Results: ** Success: 0 (zero) ** Failure: -1 and sets errno */ int sm_stropen(fp, info, flags, rpool) SM_FILE_T *fp; const void *info; int flags; const void *rpool; { register SM_STR_OBJ_T *s; #if SM_RPOOL s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T)); #else /* SM_RPOOL */ s = sm_malloc(sizeof(SM_STR_OBJ_T)); if (s == NULL) return -1; #endif /* SM_RPOOL */ fp->f_cookie = s; s->strio_rpool = rpool; s->strio_offset = 0; s->strio_size = 0; s->strio_base = NULL; s->strio_end = 0; switch (flags) { case SM_IO_RDWR: s->strio_flags = SMRW; break; case SM_IO_RDONLY: s->strio_flags = SMRD; break; case SM_IO_WRONLY: s->strio_flags = SMWR; break; case SM_IO_APPEND: if (s->strio_rpool == NULL) sm_free(s); errno = EINVAL; return -1; default: if (s->strio_rpool == NULL) sm_free(s); errno = EINVAL; return -1; } if (info != NULL) { s->strio_base = sm_strdup_x(info); if (s->strio_base == NULL) { int save_errno = errno; if (s->strio_rpool == NULL) sm_free(s); errno = save_errno; return -1; } s->strio_size = strlen(info); s->strio_end = s->strio_base + s->strio_size; } return 0; } /* ** SM_STRCLOSE -- close the string file type and free resources ** ** Parameters: ** fp -- file pointer ** ** Results: ** Success: 0 (zero) */ int sm_strclose(fp) SM_FILE_T *fp; { SM_STR_OBJ_T *s = fp->f_cookie; #if !SM_RPOOL sm_free(s->strio_base); s->strio_base = NULL; #endif /* !SM_RPOOL */ return 0; } /* ** SM_STRSETMODE -- set mode info for the file ** ** Note: changing the mode can be a safe way to have the "parent" ** set up a string that the "child" is not to modify ** ** Parameters: ** fp -- the file pointer ** mode -- location of new mode to set ** ** Results: ** Success: 0 (zero) ** Failure: -1 and sets errno */ static int sm_strsetmode(fp, mode) SM_FILE_T *fp; const int *mode; { register SM_STR_OBJ_T *s = fp->f_cookie; int flags; switch (*mode) { case SM_IO_RDWR: flags = SMRW; break; case SM_IO_RDONLY: flags = SMRD; break; case SM_IO_WRONLY: flags = SMWR; break; case SM_IO_APPEND: errno = EINVAL; return -1; default: errno = EINVAL; return -1; } s->strio_flags &= ~SMMODEMASK; s->strio_flags |= flags; return 0; } /* ** SM_STRGETMODE -- get mode info for the file ** ** Parameters: ** fp -- the file pointer ** mode -- location to store current mode ** ** Results: ** Success: 0 (zero) ** Failure: -1 and sets errno */ static int sm_strgetmode(fp, mode) SM_FILE_T *fp; int *mode; { register SM_STR_OBJ_T *s = fp->f_cookie; switch (s->strio_flags & SMMODEMASK) { case SMRW: *mode = SM_IO_RDWR; break; case SMRD: *mode = SM_IO_RDONLY; break; case SMWR: *mode = SM_IO_WRONLY; break; default: errno = EINVAL; return -1; } return 0; } /* ** SM_STRSETINFO -- set info for the file ** ** Currently only SM_IO_WHAT_MODE is supported for 'what'. ** ** Parameters: ** fp -- the file pointer ** what -- type of information to set ** valp -- location to data for doing set ** ** Results: ** Failure: -1 and sets errno ** Success: sm_strsetmode() return [0 (zero)] */ int sm_strsetinfo(fp, what, valp) SM_FILE_T *fp; int what; void *valp; { switch(what) { case SM_IO_WHAT_MODE: return sm_strsetmode(fp, (int *) valp); default: errno = EINVAL; return -1; } } /* ** SM_STRGETINFO -- get info for the file ** ** Currently only SM_IO_WHAT_MODE is supported for 'what'. ** ** Parameters: ** fp -- the file pointer ** what -- type of information requested ** valp -- location to return information in ** ** Results: ** Failure: -1 and sets errno ** Success: sm_strgetmode() return [0 (zero)] */ int sm_strgetinfo(fp, what, valp) SM_FILE_T *fp; int what; void *valp; { switch(what) { case SM_IO_WHAT_MODE: return sm_strgetmode(fp, (int *) valp); default: errno = EINVAL; return -1; } } /* ** SM_STRIO_INIT -- initializes a write-only string type ** ** Original comments below. This function does not appear to be used anywhere. ** The same functionality can be done by changing the mode of the file. ** ------------ ** sm_strio_init initializes an SM_FILE_T structure as a write-only file ** that writes into the specified buffer: ** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer. ** Attempts to write more than size-1 characters into the buffer will fail ** silently (no error is reported). ** - Use sm_io_fflush to nul terminate the string in the buffer ** (the write pointer is not advanced). ** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc. ** ** Parameters: ** fp -- file pointer ** buf -- memory location for stored data ** size -- size of 'buf' ** ** Results: ** none. */ void sm_strio_init(fp, buf, size) SM_FILE_T *fp; char *buf; size_t size; { fp->sm_magic = SmFileMagic; fp->f_flags = SMWR | SMSTR; fp->f_file = -1; fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf; fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0); fp->f_lbfsize = 0; fp->f_r = 0; fp->f_read = NULL; fp->f_seek = NULL; fp->f_getinfo = NULL; fp->f_setinfo = NULL; }