| From 47c6f1b4332a9e4935c48cca826786a6b8fe6f59 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Neal=20Gompa=20=28=E3=83=8B=E3=83=BC=E3=83=AB=E3=83=BB?= |
| =?UTF-8?q?=E3=82=B3=E3=82=99=E3=83=B3=E3=83=8F=E3=82=9A=29?= |
| <ngompa13@gmail.com> |
| Date: Wed, 11 Nov 2015 20:32:17 -0500 |
| Subject: [PATCH 1/2] Add fallback fopencookie() implementation |
| |
| In environments where neither fopencookie() nor funopen() |
| are implemented, we need to provide a suitable implementation |
| of fopencookie() that we can use. |
| |
| Alex Kanavin: rebased CMakeLists.txt change to apply to latest upstream code. |
| |
| Upstream-Status: Denied [https://github.com/openSUSE/libsolv/pull/112] |
| Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com> |
| |
| --- |
| ext/CMakeLists.txt | 7 ++ |
| ext/solv_xfopen.c | 10 +-- |
| ext/solv_xfopen_fallback_fopencookie.c | 123 +++++++++++++++++++++++++++++++++ |
| ext/solv_xfopen_fallback_fopencookie.h | 28 ++++++++ |
| 4 files changed, 164 insertions(+), 4 deletions(-) |
| create mode 100644 ext/solv_xfopen_fallback_fopencookie.c |
| create mode 100644 ext/solv_xfopen_fallback_fopencookie.h |
| |
| diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt |
| index b8917a2..fac6c32 100644 |
| --- a/ext/CMakeLists.txt |
| +++ b/ext/CMakeLists.txt |
| @@ -4,6 +4,13 @@ SET (libsolvext_SRCS |
| SET (libsolvext_HEADERS |
| tools_util.h solv_xfopen.h testcase.h) |
| |
| +IF (NOT HAVE_FOPENCOOKIE AND NOT HAVE_FUNOPEN) |
| + SET (libsolvext_SRCS ${libsolvext_SRCS} |
| + solv_xfopen_fallback_fopencookie.c) |
| + SET (libsolvext_HEADERS ${libsolvext_HEADERS} |
| + solv_xfopen_fallback_fopencookie.h) |
| +ENDIF (NOT HAVE_FOPENCOOKIE AND NOT HAVE_FUNOPEN) |
| + |
| IF (ENABLE_RPMDB OR ENABLE_RPMPKG) |
| SET (libsolvext_SRCS ${libsolvext_SRCS} |
| pool_fileconflicts.c repo_rpmdb.c) |
| diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c |
| index 2c64bb6..eb3a3ad 100644 |
| --- a/ext/solv_xfopen.c |
| +++ b/ext/solv_xfopen.c |
| @@ -12,6 +12,10 @@ |
| #include <string.h> |
| #include <fcntl.h> |
| |
| +#if !defined(HAVE_FUNOPEN) && !defined(HAVE_FOPENCOOKIE) |
| +#include "solv_xfopen_fallback_fopencookie.h" |
| +#endif |
| + |
| #include "solv_xfopen.h" |
| #include "util.h" |
| |
| @@ -21,7 +25,7 @@ static FILE *cookieopen(void *cookie, const char *mode, |
| ssize_t (*cwrite)(void *, const char *, size_t), |
| int (*cclose)(void *)) |
| { |
| -#ifdef HAVE_FUNOPEN |
| +#if defined(HAVE_FUNOPEN) && !defined(HAVE_FOPENCOOKIE) |
| if (!cookie) |
| return 0; |
| return funopen(cookie, |
| @@ -30,7 +34,7 @@ static FILE *cookieopen(void *cookie, const char *mode, |
| (fpos_t (*)(void *, fpos_t, int))NULL, /* seekfn */ |
| cclose |
| ); |
| -#elif defined(HAVE_FOPENCOOKIE) |
| +#else |
| cookie_io_functions_t cio; |
| |
| if (!cookie) |
| @@ -42,8 +46,6 @@ static FILE *cookieopen(void *cookie, const char *mode, |
| cio.write = cwrite; |
| cio.close = cclose; |
| return fopencookie(cookie, *mode == 'w' ? "w" : "r", cio); |
| -#else |
| -# error Need to implement custom I/O |
| #endif |
| } |
| |
| diff --git a/ext/solv_xfopen_fallback_fopencookie.c b/ext/solv_xfopen_fallback_fopencookie.c |
| new file mode 100644 |
| index 0000000..0ce2571 |
| --- /dev/null |
| +++ b/ext/solv_xfopen_fallback_fopencookie.c |
| @@ -0,0 +1,123 @@ |
| +/* |
| + * Provides a very limited fopencookie() for environments with a libc |
| + * that lacks it. |
| + * |
| + * Author: zhasha |
| + * Modified for libsolv by Neal Gompa |
| + * |
| + * This program is licensed under the BSD license, read LICENSE.BSD |
| + * for further information. |
| + * |
| + */ |
| + |
| +#define _LARGEFILE64_SOURCE 1 |
| +#include <pthread.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <unistd.h> |
| +#include <fcntl.h> |
| +#include <sys/types.h> |
| +#include <errno.h> |
| +#include "solv_xfopen_fallback_fopencookie.h" |
| + |
| +extern int pipe2(int[2], int); |
| + |
| +struct ctx { |
| + int fd; |
| + void *cookie; |
| + struct cookie_io_functions_t io; |
| + char buf[1024]; |
| +}; |
| + |
| +static void *proxy(void *arg) |
| +{ |
| + struct ctx *ctx = arg; |
| + ssize_t r; |
| + size_t n; |
| + |
| + pthread_detach(pthread_self()); |
| + |
| + while (1) { |
| + r = ctx->io.read ? |
| + (ctx->io.read)(ctx->cookie, ctx->buf, sizeof(ctx->buf)) : |
| + read(ctx->fd, ctx->buf, sizeof(ctx->buf)); |
| + if (r < 0) { |
| + if (errno != EINTR) { break; } |
| + continue; |
| + } |
| + if (r == 0) { break; } |
| + |
| + while (n > 0) { |
| + r = ctx->io.write ? |
| + (ctx->io.write)(ctx->cookie, ctx->buf + ((size_t)r - n), n) : |
| + write(ctx->fd, ctx->buf + ((size_t)r - n), n); |
| + if (r < 0) { |
| + if (errno != EINTR) { break; } |
| + continue; |
| + } |
| + if (r == 0) { break; } |
| + |
| + n -= (size_t)r; |
| + } |
| + if (n > 0) { break; } |
| + } |
| + |
| + if (ctx->io.close) { (ctx->io.close)(ctx->cookie); } |
| + close(ctx->fd); |
| + return NULL; |
| +} |
| + |
| +FILE *fopencookie(void *cookie, const char *mode, struct cookie_io_functions_t io) |
| +{ |
| + struct ctx *ctx = NULL; |
| + int rd = 0, wr = 0; |
| + int p[2] = { -1, -1 }; |
| + FILE *f = NULL; |
| + pthread_t dummy; |
| + |
| + switch (mode[0]) { |
| + case 'a': |
| + case 'r': rd = 1; break; |
| + case 'w': wr = 1; break; |
| + default: |
| + errno = EINVAL; |
| + return NULL; |
| + } |
| + switch (mode[1]) { |
| + case '\0': break; |
| + case '+': |
| + if (mode[2] == '\0') { |
| + errno = ENOTSUP; |
| + return NULL; |
| + } |
| + default: |
| + errno = EINVAL; |
| + return NULL; |
| + } |
| + if (io.seek) { |
| + errno = ENOTSUP; |
| + return NULL; |
| + } |
| + |
| + ctx = malloc(sizeof(*ctx)); |
| + if (!ctx) { return NULL; } |
| + if (pipe2(p, O_CLOEXEC) != 0) { goto err; } |
| + if ((f = fdopen(p[wr], mode)) == NULL) { goto err; } |
| + p[wr] = -1; |
| + ctx->fd = p[rd]; |
| + ctx->cookie = cookie; |
| + ctx->io.read = rd ? io.read : NULL; |
| + ctx->io.write = wr ? io.write : NULL; |
| + ctx->io.seek = NULL; |
| + ctx->io.close = io.close; |
| + if (pthread_create(&dummy, NULL, proxy, ctx) != 0) { goto err; } |
| + |
| + return f; |
| + |
| +err: |
| + if (p[0] >= 0) { close(p[0]); } |
| + if (p[1] >= 0) { close(p[1]); } |
| + if (f) { fclose(f); } |
| + free(ctx); |
| + return NULL; |
| +} |
| diff --git a/ext/solv_xfopen_fallback_fopencookie.h b/ext/solv_xfopen_fallback_fopencookie.h |
| new file mode 100644 |
| index 0000000..6a7bfee |
| --- /dev/null |
| +++ b/ext/solv_xfopen_fallback_fopencookie.h |
| @@ -0,0 +1,28 @@ |
| +/* |
| + * Provides a very limited fopencookie() for environments with a libc |
| + * that lacks it. |
| + * |
| + * Author: zhasha |
| + * Modified for libsolv by Neal Gompa |
| + * |
| + * This program is licensed under the BSD license, read LICENSE.BSD |
| + * for further information. |
| + * |
| + */ |
| + |
| +#ifndef SOLV_XFOPEN_FALLBACK_FOPENCOOKIE_H |
| +#define SOLV_XFOPEN_FALLBACK_FOPENCOOKIE_H |
| + |
| +#include <stdio.h> |
| +#include <stdint.h> |
| + |
| +typedef struct cookie_io_functions_t { |
| + ssize_t (*read)(void *, char *, size_t); |
| + ssize_t (*write)(void *, const char *, size_t); |
| + int (*seek)(void *, off64_t, int); |
| + int (*close)(void *); |
| +} cookie_io_functions_t; |
| + |
| +FILE *fopencookie(void *cookie, const char *mode, struct cookie_io_functions_t io); |
| + |
| +#endif |
| -- |
| 2.4.0 |
| |