Implement funopen64.

Bug: http://b/24807045
Change-Id: I161920978161389be34b707cc6ce8e05f760d552
This commit is contained in:
Elliott Hughes 2016-01-26 14:13:04 -08:00
parent ced73ee45e
commit 03e65eb03b
16 changed files with 122 additions and 82 deletions

View file

@ -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 \

View file

@ -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);

View file

@ -1233,6 +1233,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1233,6 +1233,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1157,6 +1157,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1260,6 +1260,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1218,6 +1218,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1218,6 +1218,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1157,6 +1157,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1217,6 +1217,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1217,6 +1217,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -1157,6 +1157,7 @@ LIBC_N {
freeifaddrs;
fseeko64;
fsetpos64;
funopen64;
getgrgid_r;
getgrnam_r;
getifaddrs;

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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
}