1*a765cedfSAntonio Huete Jimenez /* 2*a765cedfSAntonio Huete Jimenez * Copyright (c) 2016, EMC / Isilon Storage Division 3*a765cedfSAntonio Huete Jimenez * All rights reserved. 4*a765cedfSAntonio Huete Jimenez * 5*a765cedfSAntonio Huete Jimenez * Redistribution and use in source and binary forms, with or without 6*a765cedfSAntonio Huete Jimenez * modification, are permitted provided that the following conditions 7*a765cedfSAntonio Huete Jimenez * are met: 8*a765cedfSAntonio Huete Jimenez * 1. Redistributions of source code must retain the above copyright 9*a765cedfSAntonio Huete Jimenez * notice, this list of conditions and the following disclaimer. 10*a765cedfSAntonio Huete Jimenez * 2. Redistributions in binary form must reproduce the above copyright 11*a765cedfSAntonio Huete Jimenez * notice, this list of conditions and the following disclaimer in the 12*a765cedfSAntonio Huete Jimenez * documentation and/or other materials provided with the distribution. 13*a765cedfSAntonio Huete Jimenez * 14*a765cedfSAntonio Huete Jimenez * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 15*a765cedfSAntonio Huete Jimenez * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16*a765cedfSAntonio Huete Jimenez * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17*a765cedfSAntonio Huete Jimenez * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 18*a765cedfSAntonio Huete Jimenez * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19*a765cedfSAntonio Huete Jimenez * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20*a765cedfSAntonio Huete Jimenez * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21*a765cedfSAntonio Huete Jimenez * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22*a765cedfSAntonio Huete Jimenez * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23*a765cedfSAntonio Huete Jimenez * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24*a765cedfSAntonio Huete Jimenez * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*a765cedfSAntonio Huete Jimenez */ 26*a765cedfSAntonio Huete Jimenez 27*a765cedfSAntonio Huete Jimenez #include <sys/cdefs.h> 28*a765cedfSAntonio Huete Jimenez __FBSDID("$FreeBSD$"); 29*a765cedfSAntonio Huete Jimenez 30*a765cedfSAntonio Huete Jimenez #include <sys/fcntl.h> 31*a765cedfSAntonio Huete Jimenez 32*a765cedfSAntonio Huete Jimenez #include <errno.h> 33*a765cedfSAntonio Huete Jimenez #include <stdio.h> 34*a765cedfSAntonio Huete Jimenez #include <stdlib.h> 35*a765cedfSAntonio Huete Jimenez 36*a765cedfSAntonio Huete Jimenez #include "local.h" 37*a765cedfSAntonio Huete Jimenez 38*a765cedfSAntonio Huete Jimenez struct fopencookie_thunk { 39*a765cedfSAntonio Huete Jimenez void *foc_cookie; 40*a765cedfSAntonio Huete Jimenez cookie_io_functions_t foc_io; 41*a765cedfSAntonio Huete Jimenez }; 42*a765cedfSAntonio Huete Jimenez 43*a765cedfSAntonio Huete Jimenez static int _fopencookie_read(void *, char *, int); 44*a765cedfSAntonio Huete Jimenez static int _fopencookie_write(void *, const char *, int); 45*a765cedfSAntonio Huete Jimenez static fpos_t _fopencookie_seek(void *, fpos_t, int); 46*a765cedfSAntonio Huete Jimenez static int _fopencookie_close(void *); 47*a765cedfSAntonio Huete Jimenez 48*a765cedfSAntonio Huete Jimenez FILE * 49*a765cedfSAntonio Huete Jimenez fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs) 50*a765cedfSAntonio Huete Jimenez { 51*a765cedfSAntonio Huete Jimenez int (*readfn)(void *, char *, int); 52*a765cedfSAntonio Huete Jimenez int (*writefn)(void *, const char *, int); 53*a765cedfSAntonio Huete Jimenez struct fopencookie_thunk *thunk; 54*a765cedfSAntonio Huete Jimenez FILE *fp; 55*a765cedfSAntonio Huete Jimenez int flags, oflags; 56*a765cedfSAntonio Huete Jimenez 57*a765cedfSAntonio Huete Jimenez if ((flags = __sflags(mode, &oflags)) == 0) 58*a765cedfSAntonio Huete Jimenez return (NULL); 59*a765cedfSAntonio Huete Jimenez 60*a765cedfSAntonio Huete Jimenez thunk = malloc(sizeof(*thunk)); 61*a765cedfSAntonio Huete Jimenez if (thunk == NULL) 62*a765cedfSAntonio Huete Jimenez return (NULL); 63*a765cedfSAntonio Huete Jimenez 64*a765cedfSAntonio Huete Jimenez thunk->foc_cookie = cookie; 65*a765cedfSAntonio Huete Jimenez thunk->foc_io = io_funcs; 66*a765cedfSAntonio Huete Jimenez 67*a765cedfSAntonio Huete Jimenez readfn = _fopencookie_read; 68*a765cedfSAntonio Huete Jimenez writefn = _fopencookie_write; 69*a765cedfSAntonio Huete Jimenez if (flags == __SWR) 70*a765cedfSAntonio Huete Jimenez readfn = NULL; 71*a765cedfSAntonio Huete Jimenez else if (flags == __SRD) 72*a765cedfSAntonio Huete Jimenez writefn = NULL; 73*a765cedfSAntonio Huete Jimenez 74*a765cedfSAntonio Huete Jimenez fp = funopen(thunk, readfn, writefn, _fopencookie_seek, 75*a765cedfSAntonio Huete Jimenez _fopencookie_close); 76*a765cedfSAntonio Huete Jimenez if (fp == NULL) { 77*a765cedfSAntonio Huete Jimenez free(thunk); 78*a765cedfSAntonio Huete Jimenez return (NULL); 79*a765cedfSAntonio Huete Jimenez } 80*a765cedfSAntonio Huete Jimenez 81*a765cedfSAntonio Huete Jimenez if ((oflags & O_APPEND) != 0) 82*a765cedfSAntonio Huete Jimenez fp->pub._flags |= __SAPP; 83*a765cedfSAntonio Huete Jimenez 84*a765cedfSAntonio Huete Jimenez return (fp); 85*a765cedfSAntonio Huete Jimenez } 86*a765cedfSAntonio Huete Jimenez 87*a765cedfSAntonio Huete Jimenez static int 88*a765cedfSAntonio Huete Jimenez _fopencookie_read(void *cookie, char *buf, int size) 89*a765cedfSAntonio Huete Jimenez { 90*a765cedfSAntonio Huete Jimenez struct fopencookie_thunk *thunk; 91*a765cedfSAntonio Huete Jimenez 92*a765cedfSAntonio Huete Jimenez thunk = cookie; 93*a765cedfSAntonio Huete Jimenez 94*a765cedfSAntonio Huete Jimenez /* Reads from a stream with NULL read return EOF. */ 95*a765cedfSAntonio Huete Jimenez if (thunk->foc_io.read == NULL) 96*a765cedfSAntonio Huete Jimenez return (0); 97*a765cedfSAntonio Huete Jimenez 98*a765cedfSAntonio Huete Jimenez return ((int)thunk->foc_io.read(thunk->foc_cookie, buf, (size_t)size)); 99*a765cedfSAntonio Huete Jimenez } 100*a765cedfSAntonio Huete Jimenez 101*a765cedfSAntonio Huete Jimenez static int 102*a765cedfSAntonio Huete Jimenez _fopencookie_write(void *cookie, const char *buf, int size) 103*a765cedfSAntonio Huete Jimenez { 104*a765cedfSAntonio Huete Jimenez struct fopencookie_thunk *thunk; 105*a765cedfSAntonio Huete Jimenez 106*a765cedfSAntonio Huete Jimenez thunk = cookie; 107*a765cedfSAntonio Huete Jimenez 108*a765cedfSAntonio Huete Jimenez /* Writes to a stream with NULL write discard data. */ 109*a765cedfSAntonio Huete Jimenez if (thunk->foc_io.write == NULL) 110*a765cedfSAntonio Huete Jimenez return (size); 111*a765cedfSAntonio Huete Jimenez 112*a765cedfSAntonio Huete Jimenez return ((int)thunk->foc_io.write(thunk->foc_cookie, buf, 113*a765cedfSAntonio Huete Jimenez (size_t)size)); 114*a765cedfSAntonio Huete Jimenez } 115*a765cedfSAntonio Huete Jimenez 116*a765cedfSAntonio Huete Jimenez static fpos_t 117*a765cedfSAntonio Huete Jimenez _fopencookie_seek(void *cookie, fpos_t offset, int whence) 118*a765cedfSAntonio Huete Jimenez { 119*a765cedfSAntonio Huete Jimenez struct fopencookie_thunk *thunk; 120*a765cedfSAntonio Huete Jimenez off64_t off64; 121*a765cedfSAntonio Huete Jimenez int res; 122*a765cedfSAntonio Huete Jimenez 123*a765cedfSAntonio Huete Jimenez switch (whence) { 124*a765cedfSAntonio Huete Jimenez case SEEK_SET: 125*a765cedfSAntonio Huete Jimenez case SEEK_CUR: 126*a765cedfSAntonio Huete Jimenez case SEEK_END: 127*a765cedfSAntonio Huete Jimenez break; 128*a765cedfSAntonio Huete Jimenez default: 129*a765cedfSAntonio Huete Jimenez /* fopencookie(3) only allows these three seek modes. */ 130*a765cedfSAntonio Huete Jimenez errno = EINVAL; 131*a765cedfSAntonio Huete Jimenez return (-1); 132*a765cedfSAntonio Huete Jimenez } 133*a765cedfSAntonio Huete Jimenez 134*a765cedfSAntonio Huete Jimenez thunk = cookie; 135*a765cedfSAntonio Huete Jimenez 136*a765cedfSAntonio Huete Jimenez /* 137*a765cedfSAntonio Huete Jimenez * If seek is NULL, it is not possible to perform seek operations on 138*a765cedfSAntonio Huete Jimenez * the stream. 139*a765cedfSAntonio Huete Jimenez */ 140*a765cedfSAntonio Huete Jimenez if (thunk->foc_io.seek == NULL) { 141*a765cedfSAntonio Huete Jimenez errno = ENOTSUP; 142*a765cedfSAntonio Huete Jimenez return (-1); 143*a765cedfSAntonio Huete Jimenez } 144*a765cedfSAntonio Huete Jimenez 145*a765cedfSAntonio Huete Jimenez off64 = (off64_t)offset; 146*a765cedfSAntonio Huete Jimenez res = thunk->foc_io.seek(thunk->foc_cookie, &off64, whence); 147*a765cedfSAntonio Huete Jimenez if (res < 0) 148*a765cedfSAntonio Huete Jimenez return (res); 149*a765cedfSAntonio Huete Jimenez 150*a765cedfSAntonio Huete Jimenez return ((fpos_t)off64); 151*a765cedfSAntonio Huete Jimenez } 152*a765cedfSAntonio Huete Jimenez 153*a765cedfSAntonio Huete Jimenez static int 154*a765cedfSAntonio Huete Jimenez _fopencookie_close(void *cookie) 155*a765cedfSAntonio Huete Jimenez { 156*a765cedfSAntonio Huete Jimenez struct fopencookie_thunk *thunk; 157*a765cedfSAntonio Huete Jimenez int ret, serrno; 158*a765cedfSAntonio Huete Jimenez 159*a765cedfSAntonio Huete Jimenez ret = 0; 160*a765cedfSAntonio Huete Jimenez thunk = cookie; 161*a765cedfSAntonio Huete Jimenez if (thunk->foc_io.close != NULL) 162*a765cedfSAntonio Huete Jimenez ret = thunk->foc_io.close(thunk->foc_cookie); 163*a765cedfSAntonio Huete Jimenez 164*a765cedfSAntonio Huete Jimenez serrno = errno; 165*a765cedfSAntonio Huete Jimenez free(thunk); 166*a765cedfSAntonio Huete Jimenez errno = serrno; 167*a765cedfSAntonio Huete Jimenez return (ret); 168*a765cedfSAntonio Huete Jimenez } 169