mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-14 20:37:06 +00:00
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
f90a20b4b8
commit
877a840c08
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=299456
|
@ -58,6 +58,11 @@ typedef __ssize_t ssize_t;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _OFF64_T_DECLARED
|
||||||
|
#define _OFF64_T_DECLARED
|
||||||
|
typedef __off_t off64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE
|
#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE
|
||||||
#ifndef _VA_LIST_DECLARED
|
#ifndef _VA_LIST_DECLARED
|
||||||
typedef __va_list va_list;
|
typedef __va_list va_list;
|
||||||
|
@ -427,6 +432,18 @@ FILE *funopen(const void *,
|
||||||
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
||||||
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 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>.
|
* 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 \
|
fclose.c fcloseall.c fdopen.c \
|
||||||
feof.c ferror.c fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c \
|
feof.c ferror.c fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c \
|
||||||
fgetwln.c fgetws.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 \
|
fputc.c fputs.c \
|
||||||
fputwc.c fputws.c fread.c freopen.c fscanf.c fseek.c fsetpos.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 \
|
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 \
|
MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \
|
||||||
flockfile.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 \
|
fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 \
|
||||||
getline.3 getwc.3 mktemp.3 open_memstream.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 \
|
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
|
.\" @(#)funopen.3 8.1 (Berkeley) 6/9/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd March 19, 2004
|
.Dd May 9, 2016
|
||||||
.Dt FUNOPEN 3
|
.Dt FUNOPEN 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -153,6 +153,7 @@ specified for the routine
|
||||||
.Xr open 2 ,
|
.Xr open 2 ,
|
||||||
.Xr fclose 3 ,
|
.Xr fclose 3 ,
|
||||||
.Xr fopen 3 ,
|
.Xr fopen 3 ,
|
||||||
|
.Xr fopencookie 3 ,
|
||||||
.Xr fseek 3 ,
|
.Xr fseek 3 ,
|
||||||
.Xr setbuf 3
|
.Xr setbuf 3
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
|
|
Loading…
Reference in a new issue