funopen.c
1 /* Copyright (c) 2014, Vsevolod Stakhov 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 */ 23 #ifndef _GNU_SOURCE 24 # define _GNU_SOURCE 25 #endif 26 #include <sys/types.h> 27 #include <stdint.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 31 #include "bsd_compat.h" 32 #include "pkg_config.h" 33 #include <xmalloc.h> 34 35 #ifndef HAVE_FUNOPEN 36 37 typedef struct { 38 int (*readfn)(void *, char *, int); 39 int (*writefn)(void *, const char *, int); 40 off_t (*seekfn)(void *, off_t, int); 41 int (*closefn)(void *); 42 void *cookie; 43 } bsd_cookie_funcs_t; 44 45 static ssize_t 46 cookie_read(void *cookie, char *buf, size_t size) 47 { 48 bsd_cookie_funcs_t *funcs = cookie; 49 return (ssize_t)funcs->readfn(funcs->cookie, buf, (int)size); 50 } 51 52 static ssize_t 53 cookie_write(void *cookie, const char *buf, size_t size) 54 { 55 bsd_cookie_funcs_t *funcs = cookie; 56 return (ssize_t)funcs->writefn(funcs->cookie, buf, (int)size); 57 } 58 59 #ifndef off64_t 60 #define off64_t off_t 61 #endif 62 63 static int 64 cookie_seek(void *cookie, off64_t *offset, int whence) 65 { 66 bsd_cookie_funcs_t *funcs = cookie; 67 off_t v = funcs->seekfn(funcs->cookie, (off_t)*offset, whence); 68 if (v < 0) 69 return -1; 70 *offset = (off64_t)v; 71 return 0; 72 } 73 74 static int 75 cookie_close(void *cookie) 76 { 77 int ret = 0; 78 bsd_cookie_funcs_t *funcs = cookie; 79 if (funcs->closefn) 80 ret = funcs->closefn(funcs->cookie); 81 free(cookie); 82 return ret; 83 } 84 85 FILE * 86 funopen(const void *cookie, int (*readfn)(void *, char *, int), 87 int (*writefn)(void *, const char *, int), 88 off_t (*seekfn)(void *, off_t, int), int (*closefn)(void *)) 89 { 90 bsd_cookie_funcs_t *cf = xmalloc(sizeof(bsd_cookie_funcs_t)); 91 cf->readfn = readfn; 92 cf->writefn = writefn; 93 cf->seekfn = seekfn; 94 cf->closefn = closefn; 95 cf->cookie = __DECONST(void *, cookie); 96 97 cookie_io_functions_t c; 98 if (readfn) c.read = cookie_read; 99 if (writefn) c.write = cookie_write; 100 if (seekfn) c.seek = cookie_seek; 101 c.close = cookie_close; 102 103 return fopencookie(cf, "a+", c); 104 } 105 106 #endif