From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/11992 Path: news.gmane.org!.POSTED!not-for-mail From: William Pitcock Newsgroups: gmane.linux.lib.musl.general Subject: [PATCH] stdio: implement fopencookie(3) Date: Tue, 10 Oct 2017 18:03:56 +0000 Message-ID: <20171010180356.11352-1-nenolod@dereferenced.org> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: blaine.gmane.org X-Trace: blaine.gmane.org 1507658889 26910 195.159.176.226 (10 Oct 2017 18:08:09 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 10 Oct 2017 18:08:09 +0000 (UTC) Cc: William Pitcock To: musl@lists.openwall.com Original-X-From: musl-return-12005-gllmg-musl=m.gmane.org@lists.openwall.com Tue Oct 10 20:08:05 2017 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by blaine.gmane.org with smtp (Exim 4.84_2) (envelope-from ) id 1e1ywg-0005dk-MY for gllmg-musl@m.gmane.org; Tue, 10 Oct 2017 20:07:58 +0200 Original-Received: (qmail 11950 invoked by uid 550); 10 Oct 2017 18:08:02 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Original-Received: (qmail 11871 invoked from network); 10 Oct 2017 18:08:01 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dereferenced-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=bck4QpQOoqDFA5LO18GDrZf197Ujx33CcDAep0TJkqA=; b=gN0vatInsM1NvRuiR8AXnjvBySYQg0BCup4oVCih5+CS9bpIrn+8KPEwOLNERjmmJw gYHX6cL65/wFsV2Cz60Iwna5xEZTyvqBMfTZZ9x8tP98V/vtfSKz9W29djghpI4xoA6L ill3WTjrRa4i4CypKIzUc1wYhIkIm89tbY31axrpYcXRDELqBORBuJK98y5A5y8/sdXb GswDQM070pCRQp+auQEsgJsZs8pNT1UNfE6d89TKwp3xsFj6Of8cFd1NrVw3VDcCBZ07 UjuoOaEmCcD1tdDwqNgOMVo08W8GAQgdXa7Ee1gu3uJI5ZgJ+Vje6uJCcQNKDTxdKE0e 4mRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=bck4QpQOoqDFA5LO18GDrZf197Ujx33CcDAep0TJkqA=; b=ckPJerR41x83oJzdzOrymeBZJYQpKwWfhzjWShgjEynUIzNWfVAfzKcjR+vZWTP8F9 auszQtyVEbi5xvbFMDlSfqbG/dOT9QuG/EXZBdnDFbGHsxogTYVZMwvq7rvUUlUXeEVB +WOYanmoP5V+5D8Ketidmtd9FvRvzcTlUQVB+8BdNx3ray/AirOF6wZ/jE8yODFMbDQu m5KgpHXDpA0nfu/IEFuxu3ZRnktpzd1XoQDjFP2zVBEQMXhVkxGtyrloqziv3ETMIqx+ GKezi2j1znmUkqVnNpfZol4Z1GnMIv4lIz0SQ3nLGZxMOHWpoZLPsGDsy3JtTl934TJt 477A== X-Gm-Message-State: AMCzsaXvEMZaUu4gjt271s/SlSuqOsBmqlBhAam2GL9+qSbFlkTDNaf5 eA92TGHl76414gDfGFFuGVEzHJO7 X-Google-Smtp-Source: AOwi7QBS+9JiL8Ift0ET6sS+0MUqaAEmOU7kpow4nio5bnU1G9YW6I8IfTGEye1lvqyaBUtvozCUDQ== X-Received: by 10.157.59.102 with SMTP id z93mr1919891otb.222.1507658869020; Tue, 10 Oct 2017 11:07:49 -0700 (PDT) X-Mailer: git-send-email 2.13.3 Xref: news.gmane.org gmane.linux.lib.musl.general:11992 Archived-At: The fopencookie(3) function allows the programmer to create a custom stdio implementation, using four hook functions which operate on a "cookie" data type. Changelog: v3: - remove spurious `struct winsize` - make f->lock unconditionally 0 v2: - properly implement stdio buffering v1: - initial proof of concept --- include/stdio.h | 9 +++++ src/stdio/fopencookie.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/stdio/fopencookie.c diff --git a/include/stdio.h b/include/stdio.h index 884d2e6a..998883e5 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -182,6 +182,15 @@ int vasprintf(char **, const char *, __isoc_va_list); #ifdef _GNU_SOURCE char *fgets_unlocked(char *, int, FILE *); int fputs_unlocked(const char *, FILE *); + +typedef struct { + ssize_t (*read)(void *cookie, char *buf, size_t size); + ssize_t (*write)(void *cookie, const char *buf, size_t size); + int (*seek)(void *cookie, off_t *offset, int whence); + int (*close)(void *cookie); +} cookie_io_functions_t; + +FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs); #endif #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) diff --git a/src/stdio/fopencookie.c b/src/stdio/fopencookie.c new file mode 100644 index 00000000..baad2585 --- /dev/null +++ b/src/stdio/fopencookie.c @@ -0,0 +1,96 @@ +#define _GNU_SOURCE +#include "stdio_impl.h" +#include +#include +#include +#include +#include + +struct fcookie { + void *cookie; + cookie_io_functions_t iofuncs; +}; + +static size_t cookieread(FILE *f, unsigned char *buf, size_t len) +{ + struct fcookie *fc = f->cookie; + size_t ret; + if (fc->iofuncs.read == NULL) return -1; + ret = fc->iofuncs.read(fc->cookie, (char *) buf, len); + if (ret == 0) f->flags |= F_EOF; + f->rpos = f->buf; + f->rend = f->buf + ret; + return ret; +} + +static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len) +{ + struct fcookie *fc = f->cookie; + size_t ret; + size_t len2 = f->wpos - f->wbase; + if (fc->iofuncs.write == NULL) return -1; + if (len2) { + f->wpos = f->wbase; + if (cookiewrite(f, f->wpos, len2) < len2) return 0; + } + return fc->iofuncs.write(fc->cookie, (const char *) buf, len); +} + +static off_t cookieseek(FILE *f, off_t off, int whence) +{ + struct fcookie *fc = f->cookie; + if (fc->iofuncs.seek) return fc->iofuncs.seek(fc->cookie, &off, whence); + return -1; +} + +static int cookieclose(FILE *f) +{ + struct fcookie *fc = f->cookie; + if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie); + return 0; +} + +FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs) +{ + FILE *f; + struct fcookie *fc; + + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + /* Allocate FILE+fcookie+buffer or fail */ + if (!(f=malloc(sizeof *f + sizeof *fc + UNGET + BUFSIZ))) return 0; + + /* Zero-fill only the struct, not the buffer */ + memset(f, 0, sizeof *f); + + /* Impose mode restrictions */ + if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD; + + /* Set up our fcookie */ + fc = (void *)(f + 1); + fc->cookie = cookie; + fc->iofuncs.read = iofuncs.read; + fc->iofuncs.write = iofuncs.write; + fc->iofuncs.seek = iofuncs.seek; + fc->iofuncs.close = iofuncs.close; + + f->fd = -1; + f->cookie = fc; + f->buf = (unsigned char *)f + sizeof *f + sizeof *fc + UNGET; + f->buf_size = BUFSIZ; + f->lbf = EOF; + f->lock = 0; + + /* Initialize op ptrs. No problem if some are unneeded. */ + f->read = cookieread; + f->write = cookiewrite; + f->seek = cookieseek; + f->close = cookieclose; + + /* Add new FILE to open file list */ + return __ofl_add(f); +} -- 2.13.3