[klibc] [klibc:fopencookie] fopencookie: Add an implementation of fopencookie()

klibc-bot for H. Peter Anvin hpa at zytor.com
Thu Feb 14 17:42:06 PST 2013


Commit-ID:  f90bb804889db7f425550a91a50df28be4003e33
Gitweb:     http://git.kernel.org/?p=libs/klibc/klibc.git;a=commit;h=f90bb804889db7f425550a91a50df28be4003e33
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Thu, 14 Feb 2013 17:29:59 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Thu, 14 Feb 2013 17:35:40 -0800

[klibc] fopencookie: Add an implementation of 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 at zytor.com>

---
 usr/include/stdio.h        | 19 +++++++++++++------
 usr/klibc/stdio/fclose.c   |  2 +-
 usr/klibc/stdio/fdopen.c   | 32 +++++++++++++++++++++++++++++---
 usr/klibc/stdio/fflush.c   |  2 +-
 usr/klibc/stdio/fileno.c   | 11 ++++++++---
 usr/klibc/stdio/fread.c    |  2 +-
 usr/klibc/stdio/fseek.c    |  2 +-
 usr/klibc/stdio/ftell.c    |  2 +-
 usr/klibc/stdio/fwrite.c   |  2 +-
 usr/klibc/stdio/stdioint.h |  3 +++
 10 files changed, 59 insertions(+), 18 deletions(-)

diff --git a/usr/include/stdio.h b/usr/include/stdio.h
index 21243cc..fc70cf9 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 756de43..e4b5c6a 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 51285ba..bbfbd1f 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 dfccd24..2764437 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 b5a1016..d6e4e9b 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 b099426..6d206b7 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 e35f85e..b250efc 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 cb1202d..4db13dd 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 5d2c3f0..46cb04f 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 526c25a..aeac7a0 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)


More information about the klibc mailing list