aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2013-02-14 17:29:59 -0800
committerH. Peter Anvin <hpa@zytor.com>2013-02-14 17:35:40 -0800
commitf90bb804889db7f425550a91a50df28be4003e33 (patch)
treef15509524bb5e121cbabbdb217d3143f7906c658
parentddd013b7f83367317cf16d529936bc6abdd4ed80 (diff)
downloadklibc-fopencookie.tar.gz
[klibc] fopencookie: Add an implementation of fopencookie()fopencookie
fopencookie() is a glibc extension which allows the stdio framework to be used with a user-defined backend. The entire implementation is 172 bytes long on x86-64. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--usr/include/stdio.h19
-rw-r--r--usr/klibc/stdio/fclose.c2
-rw-r--r--usr/klibc/stdio/fdopen.c32
-rw-r--r--usr/klibc/stdio/fflush.c2
-rw-r--r--usr/klibc/stdio/fileno.c11
-rw-r--r--usr/klibc/stdio/fread.c2
-rw-r--r--usr/klibc/stdio/fseek.c2
-rw-r--r--usr/klibc/stdio/ftell.c2
-rw-r--r--usr/klibc/stdio/fwrite.c2
-rw-r--r--usr/klibc/stdio/stdioint.h3
10 files changed, 59 insertions, 18 deletions
diff --git a/usr/include/stdio.h b/usr/include/stdio.h
index 21243cc703c65..fc70cf967532f 100644
--- a/usr/include/stdio.h
+++ b/usr/include/stdio.h
@@ -12,8 +12,19 @@
#include <stddef.h>
#include <unistd.h>
+typedef ssize_t cookie_read_function_t(void *, char *, size_t);
+typedef ssize_t cookie_write_function_t(void *, const char *, size_t);
+typedef int cookie_seek_function_t(void *, off_t, int);
+typedef int cookie_close_function_t(void *);
+struct cookie_io_functions_t {
+ cookie_read_function_t *read;
+ cookie_write_function_t *write;
+ cookie_seek_function_t *seek;
+ cookie_close_function_t *close;
+};
+typedef struct cookie_io_functions_t cookie_io_functions_t;
+
struct _IO_file {
- int _IO_fileno; /* Underlying file descriptor */
_Bool _IO_eof; /* End of file flag */
_Bool _IO_error; /* Error flag */
};
@@ -41,6 +52,7 @@ enum _IO_bufmode {
*/
__extern FILE *stdin, *stdout, *stderr;
+__extern FILE *fopencookie(void *, const char *, cookie_io_functions_t);
__extern FILE *fopen(const char *, const char *);
__extern FILE *fdopen(int, const char *);
__extern int fclose(FILE *);
@@ -110,11 +122,6 @@ fwrite(const void *__p, size_t __s, size_t __n, FILE * __f)
return _fwrite(__p, __s * __n, __f) / __s;
}
-__extern_inline int fileno(FILE *__f)
-{
- return __f->_IO_fileno;
-}
-
__extern_inline int ferror(FILE *__f)
{
return __f->_IO_error;
diff --git a/usr/klibc/stdio/fclose.c b/usr/klibc/stdio/fclose.c
index 756de4329d777..e4b5c6aeb150c 100644
--- a/usr/klibc/stdio/fclose.c
+++ b/usr/klibc/stdio/fclose.c
@@ -11,7 +11,7 @@ int fclose(FILE *file)
fflush(file);
- rv = close(f->pub._IO_fileno);
+ rv = f->funcs.close(f->cookie);
/* Remove from linked list */
f->next->prev = f->prev;
diff --git a/usr/klibc/stdio/fdopen.c b/usr/klibc/stdio/fdopen.c
index 51285baeeb123..bbfbd1f9914bb 100644
--- a/usr/klibc/stdio/fdopen.c
+++ b/usr/klibc/stdio/fdopen.c
@@ -15,7 +15,7 @@ struct _IO_file_pvt __stdio_headnode =
.next = &__stdio_headnode,
};
-FILE *fdopen(int fd, const char *mode)
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t funcs)
{
struct _IO_file_pvt *f;
const size_t bufoffs =
@@ -29,9 +29,10 @@ FILE *fdopen(int fd, const char *mode)
goto err;
f->data = f->buf = (char *)f + bufoffs;
- f->pub._IO_fileno = fd;
+ f->funcs = funcs;
+ f->cookie = cookie;
f->bufsiz = BUFSIZ;
- f->bufmode = isatty(fd) ? _IOLBF : _IOFBF;
+ f->bufmode = _IOFBF;
/* Insert into linked list */
f->prev = &__stdio_headnode;
@@ -48,6 +49,31 @@ err:
return NULL;
}
+FILE *fdopen(int fd, const char *mode)
+{
+ FILE *file;
+
+ /*
+ * Cookie operations for ordinary files. This is only safe because
+ * all Linux architectures pass integers <= sizeof(pointer) and
+ * pointers the same way, at least for non-structure arguments.
+ */
+ const struct cookie_io_functions_t file_funcs = {
+ .read = (cookie_read_function_t *)read,
+ .write = (cookie_write_function_t *)write,
+ .seek = (cookie_seek_function_t *)lseek,
+ .close = (cookie_close_function_t *)close
+ };
+
+ file = fopencookie((void *)(intptr_t)fd, mode, file_funcs);
+ if (file) {
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ f->isfile = true;
+ f->bufmode = isatty(fd) ? _IOLBF : _IOFBF;
+ }
+ return file;
+}
+
void __init_stdio(void)
{
stdin = fdopen(0, NULL);
diff --git a/usr/klibc/stdio/fflush.c b/usr/klibc/stdio/fflush.c
index dfccd24d4f8d1..2764437feae02 100644
--- a/usr/klibc/stdio/fflush.c
+++ b/usr/klibc/stdio/fflush.c
@@ -18,7 +18,7 @@ int __fflush(struct _IO_file_pvt *f)
p = f->buf;
while (f->obytes) {
- rv = write(f->pub._IO_fileno, p, f->obytes);
+ rv = f->funcs.write(f->cookie, p, f->obytes);
if (rv == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
diff --git a/usr/klibc/stdio/fileno.c b/usr/klibc/stdio/fileno.c
index b5a101618684e..d6e4e9b527ab9 100644
--- a/usr/klibc/stdio/fileno.c
+++ b/usr/klibc/stdio/fileno.c
@@ -1,7 +1,12 @@
-#define __NO_STDIO_INLINES
#include "stdioint.h"
-int fileno(FILE *__f)
+int fileno(FILE *file)
{
- return __f->_IO_fileno;
+ struct _IO_file_pvt *f = stdio_pvt(file);
+
+ if (f->isfile)
+ return (int)(intptr_t)f->cookie;
+
+ errno = EBADF;
+ return -1;
}
diff --git a/usr/klibc/stdio/fread.c b/usr/klibc/stdio/fread.c
index b0994268e7b8e..6d206b73e0fea 100644
--- a/usr/klibc/stdio/fread.c
+++ b/usr/klibc/stdio/fread.c
@@ -37,7 +37,7 @@ size_t _fread(void *buf, size_t count, FILE *file)
nb = f->bufsiz;
}
- rv = read(f->pub._IO_fileno, rdptr, nb);
+ rv = f->funcs.read(f->cookie, rdptr, nb);
if (rv == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
diff --git a/usr/klibc/stdio/fseek.c b/usr/klibc/stdio/fseek.c
index e35f85e64a632..b250efcd5532e 100644
--- a/usr/klibc/stdio/fseek.c
+++ b/usr/klibc/stdio/fseek.c
@@ -16,7 +16,7 @@ __extern int fseek(FILE *file, off_t where, int whence)
if (whence == SEEK_CUR)
where -= f->ibytes;
- rv = lseek(f->pub._IO_fileno, where, whence);
+ rv = f->funcs.seek(f->cookie, where, whence);
if (__likely(rv >= 0)) {
f->pub._IO_eof = false;
f->ibytes = 0;
diff --git a/usr/klibc/stdio/ftell.c b/usr/klibc/stdio/ftell.c
index cb1202da0bc1f..4db13dd9064cb 100644
--- a/usr/klibc/stdio/ftell.c
+++ b/usr/klibc/stdio/ftell.c
@@ -3,7 +3,7 @@
off_t ftell(FILE *file)
{
struct _IO_file_pvt *f = stdio_pvt(file);
- off_t pos = lseek(f->pub._IO_fileno, 0, SEEK_CUR);
+ off_t pos = f->funcs.seek(f->cookie, 0, SEEK_CUR);
if (pos >= 0)
pos += (int)f->obytes - (int)f->ibytes;
diff --git a/usr/klibc/stdio/fwrite.c b/usr/klibc/stdio/fwrite.c
index 5d2c3f01343eb..46cb04fa7ddc7 100644
--- a/usr/klibc/stdio/fwrite.c
+++ b/usr/klibc/stdio/fwrite.c
@@ -23,7 +23,7 @@ static size_t fwrite_noflush(const void *buf, size_t count,
* The buffer is empty and the write is large,
* so bypass the buffering entirely.
*/
- rv = write(f->pub._IO_fileno, p, count);
+ rv = f->funcs.write(f->cookie, p, count);
if (rv == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
diff --git a/usr/klibc/stdio/stdioint.h b/usr/klibc/stdio/stdioint.h
index 526c25a8f7118..aeac7a0b575b8 100644
--- a/usr/klibc/stdio/stdioint.h
+++ b/usr/klibc/stdio/stdioint.h
@@ -18,12 +18,15 @@
struct _IO_file_pvt {
struct _IO_file pub; /* Data exported to inlines */
struct _IO_file_pvt *prev, *next;
+ cookie_io_functions_t funcs;
+ void *cookie; /* Cookie or file number */
char *buf; /* Buffer */
char *data; /* Location of input data in buffer */
unsigned int ibytes; /* Input data bytes in buffer */
unsigned int obytes; /* Output data bytes in buffer */
unsigned int bufsiz; /* Total size of buffer */
enum _IO_bufmode bufmode; /* Type of buffering */
+ bool isfile; /* fileno() is valid on this file */
};
#define stdio_pvt(x) container_of(x, struct _IO_file_pvt, pub)