/ compat / funopen.c
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