libc: Add fopencookie(3) wrapper around funopen(3)
Reviewed by: jhb, oshogbo Sponsored by: EMC / Isilon Storage Division Differential Revision: https://reviews.freebsd.org/D6282
This commit is contained in:
parent
d45728b896
commit
97a44a849e
@ -58,6 +58,11 @@ typedef __ssize_t ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _OFF64_T_DECLARED
|
||||
#define _OFF64_T_DECLARED
|
||||
typedef __off_t off64_t;
|
||||
#endif
|
||||
|
||||
#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE
|
||||
#ifndef _VA_LIST_DECLARED
|
||||
typedef __va_list va_list;
|
||||
@ -427,6 +432,18 @@ FILE *funopen(const void *,
|
||||
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
||||
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
|
||||
|
||||
typedef ssize_t (cookie_read_function_t)(void *, char *, size_t);
|
||||
typedef ssize_t (cookie_write_function_t)(void *, const char *, size_t);
|
||||
typedef int (cookie_seek_function_t)(void *, off64_t *, int);
|
||||
typedef int (cookie_close_function_t)(void *);
|
||||
typedef struct {
|
||||
cookie_read_function_t *read;
|
||||
cookie_write_function_t *write;
|
||||
cookie_seek_function_t *seek;
|
||||
cookie_close_function_t *close;
|
||||
} cookie_io_functions_t;
|
||||
FILE *fopencookie(void *, const char *, cookie_io_functions_t);
|
||||
|
||||
/*
|
||||
* Portability hacks. See <sys/types.h>.
|
||||
*/
|
||||
|
@ -8,7 +8,8 @@ SRCS+= _flock_stub.c asprintf.c clrerr.c dprintf.c \
|
||||
fclose.c fcloseall.c fdopen.c \
|
||||
feof.c ferror.c fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c \
|
||||
fgetwln.c fgetws.c \
|
||||
fileno.c findfp.c flags.c fmemopen.c fopen.c fprintf.c fpurge.c \
|
||||
fileno.c findfp.c flags.c fmemopen.c fopen.c \
|
||||
fopencookie.c fprintf.c fpurge.c \
|
||||
fputc.c fputs.c \
|
||||
fputwc.c fputws.c fread.c freopen.c fscanf.c fseek.c fsetpos.c \
|
||||
ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \
|
||||
@ -35,7 +36,7 @@ SYM_MAPS+= ${LIBC_SRCTOP}/stdio/Symbol.map
|
||||
|
||||
MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \
|
||||
flockfile.3 \
|
||||
fopen.3 fputs.3 \
|
||||
fopen.3 fopencookie.3 fputs.3 \
|
||||
fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 \
|
||||
getline.3 getwc.3 mktemp.3 open_memstream.3 \
|
||||
printf.3 printf_l.3 putc.3 putwc.3 remove.3 scanf.3 scanf_l.3 setbuf.3 \
|
||||
|
156
lib/libc/stdio/fopencookie.3
Normal file
156
lib/libc/stdio/fopencookie.3
Normal file
@ -0,0 +1,156 @@
|
||||
.\" Copyright (c) 2016, EMC / Isilon Storage Division
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
.\" IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
.\" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
||||
.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 9, 2016
|
||||
.Dt FOPENCOOKIE 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm fopencookie
|
||||
.Nd open a stream
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In stdio.h
|
||||
.Ft typedef ssize_t
|
||||
.Fn (cookie_read_function_t) "void *cookie" "char *buf" "size_t size"
|
||||
.Ft typedef ssize_t
|
||||
.Fn (cookie_write_function_t) "void *cookie" "const char *buf" "size_t size"
|
||||
.Ft typedef int
|
||||
.Fn (cookie_seek_function_t) "void *cookie" "off64_t *offset" "int whence"
|
||||
.Ft typedef int
|
||||
.Fn (cookie_close_function_t) "void *cookie"
|
||||
.Bd -literal
|
||||
typedef struct {
|
||||
cookie_read_function_t *read;
|
||||
cookie_write_function_t *write;
|
||||
cookie_seek_function_t *seek;
|
||||
cookie_close_function_t *close;
|
||||
} cookie_io_functions_t;
|
||||
.Ed
|
||||
.Ft FILE *
|
||||
.Fn fopencookie "void *cookie" "const char *mode" "cookie_io_functions_t io_funcs"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
function
|
||||
associates a stream with up to four
|
||||
.Dq Tn I/O No functions .
|
||||
These
|
||||
.Tn I/O
|
||||
functions will be used to read, write, seek and
|
||||
close the new stream.
|
||||
.Pp
|
||||
In general, omitting a function means that any attempt to perform the
|
||||
associated operation on the resulting stream will fail.
|
||||
If the write function is omitted, data written to the stream is discarded.
|
||||
If the close function is omitted, closing the stream will flush
|
||||
any buffered output and then succeed.
|
||||
.Pp
|
||||
The calling conventions of
|
||||
.Fa read ,
|
||||
.Fa write ,
|
||||
and
|
||||
.Fa close
|
||||
must match those, respectively, of
|
||||
.Xr read 2 ,
|
||||
.Xr write 2 ,
|
||||
and
|
||||
.Xr close 2
|
||||
with the single exception that they are passed the
|
||||
.Fa cookie
|
||||
argument specified to
|
||||
.Nm
|
||||
in place of the traditional file descriptor argument.
|
||||
The
|
||||
.Fa seek
|
||||
function updates the current stream offset using
|
||||
.Fa *offset
|
||||
and
|
||||
.Fa whence .
|
||||
If
|
||||
.Fa *offset
|
||||
is non-NULL, it updates
|
||||
.Fa *offset
|
||||
with the current stream offset.
|
||||
.Pp
|
||||
.Nm
|
||||
is implemented as a thin shim around the
|
||||
.Xr funopen 3
|
||||
interface.
|
||||
Limitations, possibilities, and requirements of that interface apply to
|
||||
.Nm .
|
||||
.Sh RETURN VALUES
|
||||
Upon successful completion,
|
||||
.Nm
|
||||
returns a
|
||||
.Dv FILE
|
||||
pointer.
|
||||
Otherwise,
|
||||
.Dv NULL
|
||||
is returned and the global variable
|
||||
.Va errno
|
||||
is set to indicate the error.
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EINVAL
|
||||
A bogus
|
||||
.Fa mode
|
||||
was provided to
|
||||
.Nm .
|
||||
.It Bq Er ENOMEM
|
||||
The
|
||||
.Nm
|
||||
function
|
||||
may fail and set
|
||||
.Va errno
|
||||
for any of the errors
|
||||
specified for the
|
||||
.Xr malloc 3
|
||||
routine.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr fcntl 2 ,
|
||||
.Xr open 2 ,
|
||||
.Xr fclose 3 ,
|
||||
.Xr fopen 3 ,
|
||||
.Xr fseek 3 ,
|
||||
.Xr funopen 3
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn funopen
|
||||
functions first appeared in
|
||||
.Bx 4.4 .
|
||||
The
|
||||
.Nm
|
||||
function first appeared in
|
||||
.Fx 11 .
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
function is a nonstandard glibc extension and may not be portable to systems
|
||||
other than
|
||||
.Fx
|
||||
and Linux.
|
168
lib/libc/stdio/fopencookie.c
Normal file
168
lib/libc/stdio/fopencookie.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2016, EMC / Isilon Storage Division
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
struct fopencookie_thunk {
|
||||
void *foc_cookie;
|
||||
cookie_io_functions_t foc_io;
|
||||
};
|
||||
|
||||
static int _fopencookie_read(void *, char *, int);
|
||||
static int _fopencookie_write(void *, const char *, int);
|
||||
static fpos_t _fopencookie_seek(void *, fpos_t, int);
|
||||
static int _fopencookie_close(void *);
|
||||
|
||||
FILE *
|
||||
fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
|
||||
{
|
||||
int (*readfn)(void *, char *, int);
|
||||
int (*writefn)(void *, const char *, int);
|
||||
struct fopencookie_thunk *thunk;
|
||||
FILE *fp;
|
||||
int flags, oflags;
|
||||
|
||||
if ((flags = __sflags(mode, &oflags)) == 0)
|
||||
return (NULL);
|
||||
|
||||
thunk = malloc(sizeof(*thunk));
|
||||
if (thunk == NULL)
|
||||
return (NULL);
|
||||
|
||||
thunk->foc_cookie = cookie;
|
||||
thunk->foc_io = io_funcs;
|
||||
|
||||
readfn = _fopencookie_read;
|
||||
writefn = _fopencookie_write;
|
||||
if (flags == __SWR)
|
||||
readfn = NULL;
|
||||
else if (flags == __SRD)
|
||||
writefn = NULL;
|
||||
|
||||
fp = funopen(thunk, readfn, writefn, _fopencookie_seek,
|
||||
_fopencookie_close);
|
||||
if (fp == NULL) {
|
||||
free(thunk);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((oflags & O_APPEND) != 0)
|
||||
fp->_flags |= __SAPP;
|
||||
|
||||
return (fp);
|
||||
}
|
||||
|
||||
static int
|
||||
_fopencookie_read(void *cookie, char *buf, int size)
|
||||
{
|
||||
struct fopencookie_thunk *thunk;
|
||||
|
||||
thunk = cookie;
|
||||
|
||||
/* Reads from a stream with NULL read return EOF. */
|
||||
if (thunk->foc_io.read == NULL)
|
||||
return (0);
|
||||
|
||||
return ((int)thunk->foc_io.read(thunk->foc_cookie, buf, (size_t)size));
|
||||
}
|
||||
|
||||
static int
|
||||
_fopencookie_write(void *cookie, const char *buf, int size)
|
||||
{
|
||||
struct fopencookie_thunk *thunk;
|
||||
|
||||
thunk = cookie;
|
||||
|
||||
/* Writes to a stream with NULL write discard data. */
|
||||
if (thunk->foc_io.write == NULL)
|
||||
return (size);
|
||||
|
||||
return ((int)thunk->foc_io.write(thunk->foc_cookie, buf,
|
||||
(size_t)size));
|
||||
}
|
||||
|
||||
static fpos_t
|
||||
_fopencookie_seek(void *cookie, fpos_t offset, int whence)
|
||||
{
|
||||
struct fopencookie_thunk *thunk;
|
||||
off64_t off64;
|
||||
int res;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
case SEEK_CUR:
|
||||
case SEEK_END:
|
||||
break;
|
||||
default:
|
||||
/* fopencookie(3) only allows these three seek modes. */
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
thunk = cookie;
|
||||
|
||||
/*
|
||||
* If seek is NULL, it is not possible to perform seek operations on
|
||||
* the stream.
|
||||
*/
|
||||
if (thunk->foc_io.seek == NULL) {
|
||||
errno = ENOTSUP;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
off64 = (off64_t)offset;
|
||||
res = thunk->foc_io.seek(thunk->foc_cookie, &off64, whence);
|
||||
if (res < 0)
|
||||
return (res);
|
||||
|
||||
return ((fpos_t)off64);
|
||||
}
|
||||
|
||||
static int
|
||||
_fopencookie_close(void *cookie)
|
||||
{
|
||||
struct fopencookie_thunk *thunk;
|
||||
int ret, serrno;
|
||||
|
||||
ret = 0;
|
||||
thunk = cookie;
|
||||
if (thunk->foc_io.close != NULL)
|
||||
ret = thunk->foc_io.close(thunk->foc_cookie);
|
||||
|
||||
serrno = errno;
|
||||
free(thunk);
|
||||
errno = serrno;
|
||||
return (ret);
|
||||
}
|
@ -30,7 +30,7 @@
|
||||
.\" @(#)funopen.3 8.1 (Berkeley) 6/9/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 19, 2004
|
||||
.Dd May 9, 2016
|
||||
.Dt FUNOPEN 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -153,6 +153,7 @@ specified for the routine
|
||||
.Xr open 2 ,
|
||||
.Xr fclose 3 ,
|
||||
.Xr fopen 3 ,
|
||||
.Xr fopencookie 3 ,
|
||||
.Xr fseek 3 ,
|
||||
.Xr setbuf 3
|
||||
.Sh HISTORY
|
||||
|
Loading…
Reference in New Issue
Block a user