Implement funopen64.
Bug: http://b/24807045 Change-Id: I161920978161389be34b707cc6ce8e05f760d552
This commit is contained in:
parent
ced73ee45e
commit
03e65eb03b
16 changed files with 122 additions and 82 deletions
|
@ -461,7 +461,6 @@ libc_upstream_openbsd_ndk_src_files := \
|
|||
upstream-openbsd/lib/libc/stdio/fputwc.c \
|
||||
upstream-openbsd/lib/libc/stdio/fputws.c \
|
||||
upstream-openbsd/lib/libc/stdio/fscanf.c \
|
||||
upstream-openbsd/lib/libc/stdio/funopen.c \
|
||||
upstream-openbsd/lib/libc/stdio/fvwrite.c \
|
||||
upstream-openbsd/lib/libc/stdio/fwalk.c \
|
||||
upstream-openbsd/lib/libc/stdio/fwide.c \
|
||||
|
|
|
@ -170,21 +170,43 @@ int renameat(int, const char*, int, const char*);
|
|||
|
||||
int fseek(FILE*, long, int);
|
||||
long ftell(FILE*);
|
||||
|
||||
#if defined(__USE_FILE_OFFSET64)
|
||||
int fgetpos(FILE*, fpos_t*) __RENAME(fgetpos64);
|
||||
int fsetpos(FILE*, const fpos_t*) __RENAME(fsetpos64);
|
||||
int fseeko(FILE*, off_t, int) __RENAME(fseeko64);
|
||||
off_t ftello(FILE*) __RENAME(ftello64);
|
||||
# if defined(__USE_BSD)
|
||||
FILE* funopen(const void*,
|
||||
int (*)(void*, char*, int),
|
||||
int (*)(void*, const char*, int),
|
||||
fpos_t (*)(void*, fpos_t, int),
|
||||
int (*)(void*)) __RENAME(funopen64);
|
||||
# endif
|
||||
#else
|
||||
int fgetpos(FILE*, fpos_t*);
|
||||
int fsetpos(FILE*, const fpos_t*);
|
||||
int fseeko(FILE*, off_t, int);
|
||||
off_t ftello(FILE*);
|
||||
# if defined(__USE_BSD)
|
||||
FILE* funopen(const void*,
|
||||
int (*)(void*, char*, int),
|
||||
int (*)(void*, const char*, int),
|
||||
fpos_t (*)(void*, fpos_t, int),
|
||||
int (*)(void*));
|
||||
# endif
|
||||
#endif
|
||||
int fgetpos64(FILE*, fpos64_t*);
|
||||
int fsetpos64(FILE*, const fpos64_t*);
|
||||
int fseeko64(FILE*, off64_t, int);
|
||||
off64_t ftello64(FILE*);
|
||||
#if defined(__USE_BSD)
|
||||
FILE* funopen64(const void*,
|
||||
int (*)(void*, char*, int),
|
||||
int (*)(void*, const char*, int),
|
||||
fpos64_t (*)(void*, fpos64_t, int),
|
||||
int (*)(void*));
|
||||
#endif
|
||||
|
||||
#if __ISO_C_VISIBLE >= 1999 || __BSD_VISIBLE
|
||||
int snprintf(char * __restrict, size_t, const char * __restrict, ...)
|
||||
|
@ -254,18 +276,8 @@ int feof_unlocked(FILE*);
|
|||
int ferror_unlocked(FILE*);
|
||||
int fileno_unlocked(FILE*);
|
||||
|
||||
/*
|
||||
* Stdio function-access interface.
|
||||
* TODO: __USE_FILE_OFFSET64
|
||||
*/
|
||||
FILE *funopen(const void *,
|
||||
int (*)(void *, char *, int),
|
||||
int (*)(void *, const char *, int),
|
||||
fpos_t (*)(void *, fpos_t, int),
|
||||
int (*)(void *));
|
||||
|
||||
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
||||
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
|
||||
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
||||
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
|
||||
#endif /* __BSD_VISIBLE */
|
||||
|
||||
extern char* __fgets_chk(char*, int, FILE*, size_t);
|
||||
|
|
|
@ -1233,6 +1233,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1233,6 +1233,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1157,6 +1157,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1260,6 +1260,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1218,6 +1218,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1218,6 +1218,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1157,6 +1157,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1217,6 +1217,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1217,6 +1217,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1157,6 +1157,7 @@ LIBC_N {
|
|||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
funopen64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -72,7 +72,6 @@ struct __sFILE {
|
|||
|
||||
// Function pointers used by `funopen`.
|
||||
// Note that `_seek` is ignored if `_seek64` (in __sfileext) is set.
|
||||
// TODO: implement `funopen64`.
|
||||
// TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s.
|
||||
// TODO: glibc has `fopencookie` which passes the function pointers in a struct.
|
||||
void* _cookie; /* cookie passed to io functions */
|
||||
|
|
|
@ -538,3 +538,56 @@ int fgetpos64(FILE* fp, fpos64_t* pos) {
|
|||
*pos = ftello64(fp);
|
||||
return (*pos == -1);
|
||||
}
|
||||
|
||||
static FILE* __funopen(const void* cookie,
|
||||
int (*read_fn)(void*, char*, int),
|
||||
int (*write_fn)(void*, const char*, int),
|
||||
int (*close_fn)(void*)) {
|
||||
if (read_fn == nullptr && write_fn == nullptr) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FILE* fp = __sfp();
|
||||
if (fp == nullptr) return nullptr;
|
||||
|
||||
if (read_fn != nullptr && write_fn != nullptr) {
|
||||
fp->_flags = __SRW;
|
||||
} else if (read_fn != nullptr) {
|
||||
fp->_flags = __SRD;
|
||||
} else if (write_fn != nullptr) {
|
||||
fp->_flags = __SWR;
|
||||
}
|
||||
|
||||
fp->_file = -1;
|
||||
fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
|
||||
fp->_read = read_fn;
|
||||
fp->_write = write_fn;
|
||||
fp->_close = close_fn;
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
FILE* funopen(const void* cookie,
|
||||
int (*read_fn)(void*, char*, int),
|
||||
int (*write_fn)(void*, const char*, int),
|
||||
fpos_t (*seek_fn)(void*, fpos_t, int),
|
||||
int (*close_fn)(void*)) {
|
||||
FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
|
||||
if (fp != nullptr) {
|
||||
fp->_seek = seek_fn;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
FILE* funopen64(const void* cookie,
|
||||
int (*read_fn)(void*, char*, int),
|
||||
int (*write_fn)(void*, const char*, int),
|
||||
fpos64_t (*seek_fn)(void*, fpos64_t, int),
|
||||
int (*close_fn)(void*)) {
|
||||
FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
|
||||
if (fp != nullptr) {
|
||||
_EXT(fp)->_seek64 = seek_fn;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/* $OpenBSD: funopen.c,v 1.8 2005/08/08 08:05:36 espie Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "local.h"
|
||||
|
||||
FILE *
|
||||
funopen(const void *cookie, int (*readfn)(void *, char *, int),
|
||||
int (*writefn)(void *, const char *, int),
|
||||
fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *))
|
||||
{
|
||||
FILE *fp;
|
||||
int flags;
|
||||
|
||||
if (readfn == NULL) {
|
||||
if (writefn == NULL) { /* illegal */
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
} else
|
||||
flags = __SWR; /* write only */
|
||||
} else {
|
||||
if (writefn == NULL)
|
||||
flags = __SRD; /* read only */
|
||||
else
|
||||
flags = __SRW; /* read-write */
|
||||
}
|
||||
if ((fp = __sfp()) == NULL)
|
||||
return (NULL);
|
||||
fp->_flags = flags;
|
||||
fp->_file = -1;
|
||||
fp->_cookie = (void *)cookie; /* SAFE: cookie not modified */
|
||||
fp->_read = readfn;
|
||||
fp->_write = writefn;
|
||||
fp->_seek = seekfn;
|
||||
fp->_close = closefn;
|
||||
return (fp);
|
||||
}
|
|
@ -1091,6 +1091,41 @@ TEST(STDIO_TEST, fseek_ftell_unseekable) {
|
|||
ASSERT_EQ(ESPIPE, errno);
|
||||
|
||||
fclose(fp);
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, funopen_EINVAL) {
|
||||
#if defined(__BIONIC__)
|
||||
errno = 0;
|
||||
ASSERT_EQ(nullptr, funopen(nullptr, nullptr, nullptr, nullptr, nullptr));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, funopen_seek) {
|
||||
#if defined(__BIONIC__)
|
||||
auto read_fn = [](void*, char*, int) { return -1; };
|
||||
|
||||
auto seek_fn = [](void*, fpos_t, int) -> fpos_t { return 0xfedcba12; };
|
||||
auto seek64_fn = [](void*, fpos64_t, int) -> fpos64_t { return 0xfedcba12345678; };
|
||||
|
||||
FILE* fp = funopen(nullptr, read_fn, nullptr, seek_fn, nullptr);
|
||||
ASSERT_TRUE(fp != nullptr);
|
||||
fpos_t pos;
|
||||
ASSERT_EQ(0, fgetpos(fp, &pos));
|
||||
ASSERT_EQ(0xfedcba12LL, pos);
|
||||
|
||||
FILE* fp64 = funopen64(nullptr, read_fn, nullptr, seek64_fn, nullptr);
|
||||
ASSERT_TRUE(fp64 != nullptr);
|
||||
fpos64_t pos64;
|
||||
ASSERT_EQ(0, fgetpos64(fp64, &pos64));
|
||||
ASSERT_EQ(0xfedcba12345678, pos64);
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue