diff --git a/libc/Android.mk b/libc/Android.mk index bcb4afc09..683dfa9c5 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -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 \ diff --git a/libc/include/stdio.h b/libc/include/stdio.h index a227904a3..b61809133 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -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); diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map index 9fb5db5b0..f81adca72 100644 --- a/libc/libc.arm.brillo.map +++ b/libc/libc.arm.brillo.map @@ -1229,6 +1229,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.arm.map b/libc/libc.arm.map index 4b6d172dc..45d753935 100644 --- a/libc/libc.arm.map +++ b/libc/libc.arm.map @@ -1229,6 +1229,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map index e7aac93bc..37c475f23 100644 --- a/libc/libc.arm64.map +++ b/libc/libc.arm64.map @@ -1153,6 +1153,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.map.txt b/libc/libc.map.txt index b14139ebb..317904987 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1256,6 +1256,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map index 9925be698..734f6860a 100644 --- a/libc/libc.mips.brillo.map +++ b/libc/libc.mips.brillo.map @@ -1214,6 +1214,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.mips.map b/libc/libc.mips.map index 34bc92052..86a2a5946 100644 --- a/libc/libc.mips.map +++ b/libc/libc.mips.map @@ -1214,6 +1214,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map index e7aac93bc..37c475f23 100644 --- a/libc/libc.mips64.map +++ b/libc/libc.mips64.map @@ -1153,6 +1153,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map index ae201a842..ceaa07d8d 100644 --- a/libc/libc.x86.brillo.map +++ b/libc/libc.x86.brillo.map @@ -1213,6 +1213,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.x86.map b/libc/libc.x86.map index 2af1ee450..cc35757a6 100644 --- a/libc/libc.x86.map +++ b/libc/libc.x86.map @@ -1213,6 +1213,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map index e7aac93bc..37c475f23 100644 --- a/libc/libc.x86_64.map +++ b/libc/libc.x86_64.map @@ -1153,6 +1153,7 @@ LIBC_N { freeifaddrs; fseeko64; fsetpos64; + funopen64; getgrgid_r; getgrnam_r; getifaddrs; diff --git a/libc/stdio/local.h b/libc/stdio/local.h index 524e6deb3..7fe339ac7 100644 --- a/libc/stdio/local.h +++ b/libc/stdio/local.h @@ -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 */ diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index 23b69715a..2139621cc 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -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(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; +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/funopen.c b/libc/upstream-openbsd/lib/libc/stdio/funopen.c deleted file mode 100644 index b85ee96a1..000000000 --- a/libc/upstream-openbsd/lib/libc/stdio/funopen.c +++ /dev/null @@ -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 -#include -#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); -} diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 89bf04a8e..7f412c13c 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -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 }