diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-09-06 19:18:32 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-09-06 19:18:32 +0300 |
commit | bfb29ced5d88dbe449347d5b8b86e6ee887c450b (patch) | |
tree | 98087985cc1d4e37554bea72f009755618077a5d | |
parent | d0b037c48bc8ccdb0c4a094289d6489ec280c2af (diff) | |
download | mailutils-bfb29ced5d88dbe449347d5b8b86e6ee887c450b.tar.gz mailutils-bfb29ced5d88dbe449347d5b8b86e6ee887c450b.tar.bz2 |
Implement "read cache" streams. Rewrite stdio and socket streams.
* include/mailutils/sys/stdio_stream.h: Remove.
* include/mailutils/sys/socket_stream.h: Remove.
* include/mailutils/sys/rdcache_stream.h: New file.
* include/mailutils/sys/Makefile.am: Update.
* mailbox/rdcache_stream.c: New file.
* mailbox/Makefile.am: Update.
* examples/mucat.c: New example.
* examples/musocio.c: New example.
* examples/Makefile.am (noinst_PROGRAMS): Build new examples.
* include/mailutils/stream.h (mu_fd_stream_create): New proto.
(mu_rdcache_stream_create): New proto.
* include/mailutils/sys/file_stream.h (_mu_file_stream_create): Change
prototype.
* mailbox/file_stream.c (fd_open): Raise the MU_STREAM_AUTOCLOSE bit.
(fd_ioctl): Support MU_IOCTL_SET_TRANSPORT.
(_mu_file_stream_create): Change signature. All uses updated.
Allocate a copy of the filename argument, unless it is NULL.
(mu_fd_stream_create): New function.
* mailbox/socket_stream.c: Rewrite using file_stream directly.
* mailbox/stdio_stream.c: Rewrite. Use rdcache_stream if
the seek capability is required on an input stream.
* mailbox/streamcpy.c (mu_stream_copy): Handle eventual
EACCES return from mu_stream_seek as equivalent to ENOSYS.
-rw-r--r-- | examples/Makefile.am | 2 | ||||
-rw-r--r-- | examples/mucat.c | 87 | ||||
-rw-r--r-- | examples/musocio.c | 124 | ||||
-rw-r--r-- | include/mailutils/stream.h | 5 | ||||
-rw-r--r-- | include/mailutils/sys/Makefile.am | 3 | ||||
-rw-r--r-- | include/mailutils/sys/file_stream.h | 4 | ||||
-rw-r--r-- | include/mailutils/sys/rdcache_stream.h (renamed from include/mailutils/sys/stdio_stream.h) | 19 | ||||
-rw-r--r-- | include/mailutils/sys/socket_stream.h | 28 | ||||
-rw-r--r-- | mailbox/Makefile.am | 1 | ||||
-rw-r--r-- | mailbox/file_stream.c | 54 | ||||
-rw-r--r-- | mailbox/rdcache_stream.c | 201 | ||||
-rw-r--r-- | mailbox/socket_stream.c | 73 | ||||
-rw-r--r-- | mailbox/stdio_stream.c | 194 | ||||
-rw-r--r-- | mailbox/streamcpy.c | 2 | ||||
-rw-r--r-- | mailbox/temp_file_stream.c | 22 |
15 files changed, 549 insertions, 270 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am index f3fe13bdc..57992ac3a 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -49,9 +49,11 @@ noinst_PROGRAMS = \ mimetest\ msg-send\ mta\ + mucat\ muauth\ muemail\ murun\ + musocio\ $(NNTPCLIENT)\ $(POP3CLIENT)\ sfrom\ diff --git a/examples/mucat.c b/examples/mucat.c new file mode 100644 index 000000000..b8cb314f7 --- /dev/null +++ b/examples/mucat.c @@ -0,0 +1,87 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free Software + Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <unistd.h> +#include <stdio.h> +#include <assert.h> +#include <ctype.h> +#include <string.h> +#include <mailutils/mailutils.h> + +int +main (int argc, char * argv []) +{ + int c; + mu_stream_t in, out; + int reread_option = 0; + mu_off_t reread_off; + int skip_option = 0; + mu_off_t skip_off; + + while ((c = getopt (argc, argv, "hs:r:")) != EOF) + switch (c) + { + case 'r': + reread_option = 1; + reread_off = strtoul (optarg, NULL, 10); + break; + + case 's': + skip_option = 1; + skip_off = strtoul (optarg, NULL, 10); + break; + + case 'h': + printf ("usage: cat [-s off]\n"); + exit (0); + + default: + exit (1); + } + + + MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_SEEK)); + MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0)); + + if (skip_option) + { + mu_stream_printf (out, "skipping to %lu:\n", + (unsigned long) skip_off); + MU_ASSERT (mu_stream_seek (in, skip_off, MU_SEEK_SET, NULL)); + } + + MU_ASSERT (mu_stream_copy (out, in, 0)); + + if (reread_option) + { + mu_stream_printf (out, "rereading from %lu:\n", + (unsigned long) reread_off); + MU_ASSERT (mu_stream_seek (in, reread_off, MU_SEEK_SET, NULL)); + MU_ASSERT (mu_stream_copy (out, in, 0)); + } + + mu_stream_close (in); + mu_stream_destroy (&in); + mu_stream_close (out); + mu_stream_destroy (&out); + return 0; +} diff --git a/examples/musocio.c b/examples/musocio.c new file mode 100644 index 000000000..66bf346f3 --- /dev/null +++ b/examples/musocio.c @@ -0,0 +1,124 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free Software + Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <stdio.h> +#include <assert.h> +#include <ctype.h> +#include <string.h> +#include <mailutils/mailutils.h> + +int verbose; + +void +ioloop (char *id, mu_stream_t in, mu_stream_t out) +{ + char *buf = NULL; + size_t size = 0, n; + int rc; + + while ((rc = mu_stream_getline (in, &buf, &size, &n)) == 0 && n > 0) + { + if (rc) + { + mu_error("%s: read error: %s", id, mu_stream_strerror (in, rc)); + exit (1); + } + MU_ASSERT (mu_stream_write (out, buf, n, NULL)); + } + mu_stream_flush (out); + if (verbose) + fprintf (stderr, "%s exited\n", id); +} + +int +main (int argc, char * argv []) +{ + mu_stream_t in, out, sock; + pid_t pid; + int status, c; + + while ((c = getopt (argc, argv, "v")) != EOF) + switch (c) + { + case 'v': + verbose++; + break; + + case 'h': + printf ("usage: musocio file\n"); + return 0; + + default: + return 1; + } + + argc -= optind; + argv += optind; + + if (argc != 2) + { + mu_error ("usage: musocio file"); + return 1; + } + + MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0)); + mu_stream_set_buffer (in, mu_buffer_line, 1024); + MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0)); + mu_stream_set_buffer (out, mu_buffer_line, 1024); + MU_ASSERT (mu_socket_stream_create (&sock, argv[1], MU_STREAM_RDWR)); + mu_stream_set_buffer (sock, mu_buffer_line, 1024); + MU_ASSERT (mu_stream_open (sock)); + + pid = fork (); + if (pid == -1) + { + mu_error ("fork failed: %s", mu_strerror (errno)); + return 1; + } + + if (pid == 0) + { + mu_stream_close (in); + mu_stream_destroy (&in); + ioloop ("reader", sock, out); + exit (0); + } + + ioloop ("writer", in, sock); + + mu_stream_close (in); + mu_stream_destroy (&in); + + mu_stream_shutdown (sock, MU_STREAM_WRITE); + waitpid (pid, &status, 0); + + mu_stream_close (sock); + mu_stream_destroy (&sock); + + mu_stream_close (out); + mu_stream_destroy (&out); + return 0; +} diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index d9d3b5b41..f2af9b399 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -120,6 +120,8 @@ int mu_stream_copy (mu_stream_t dst, mu_stream_t src, size_t size); int mu_file_stream_create (mu_stream_t *pstream, const char *filename, int flags); int mu_temp_file_stream_create (mu_stream_t *pstream, const char *dir); +int mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, + int flags); #define MU_STDIN_FD 0 #define MU_STDOUT_FD 1 @@ -157,4 +159,7 @@ int mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out); int mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug, mu_log_level_t level, int flags); +int mu_rdcache_stream_create (mu_stream_t *pstream, mu_stream_t transport, + int flags); + #endif diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index e8f073ccf..57a5dc07d 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -49,9 +49,8 @@ sysinclude_HEADERS = \ pop3.h\ prog_stream.h\ property.h\ + rdcache_stream.h\ registrar.h\ - socket_stream.h\ - stdio_stream.h\ streamref.h\ streamtrans.h\ stream.h\ diff --git a/include/mailutils/sys/file_stream.h b/include/mailutils/sys/file_stream.h index 0f1f8d26f..70c576ab7 100644 --- a/include/mailutils/sys/file_stream.h +++ b/include/mailutils/sys/file_stream.h @@ -31,7 +31,7 @@ struct _mu_file_stream char *filename; }; -int _mu_file_stream_create (mu_stream_t *pstream, size_t size, - char *filename, int flags); +int _mu_file_stream_create (struct _mu_file_stream **pstream, size_t size, + const char *filename, int fd, int flags); #endif diff --git a/include/mailutils/sys/stdio_stream.h b/include/mailutils/sys/rdcache_stream.h index 3b274dc39..b6434bea6 100644 --- a/include/mailutils/sys/stdio_stream.h +++ b/include/mailutils/sys/rdcache_stream.h @@ -1,5 +1,5 @@ /* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2010 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -14,21 +14,20 @@ You should have received a copy of the GNU Lesser General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _MAILUTILS_SYS_STDIO_STREAM_H -#define _MAILUTILS_SYS_STDIO_STREAM_H +#ifndef _MAILUTILS_SYS_RDCACHE_STREAM_H +# define _MAILUTILS_SYS_RDCACHE_STREAM_H -#include <mailutils/sys/file_stream.h> +# include <mailutils/types.h> +# include <mailutils/stream.h> +# include <mailutils/sys/stream.h> -#define _MU_STDIO_SIZE_COMPUTED 0x02 - -struct _mu_stdio_stream +struct _mu_rdcache_stream { - struct _mu_file_stream file_stream; + struct _mu_stream stream; + mu_stream_t transport; mu_stream_t cache; mu_off_t size; mu_off_t offset; }; -int _mu_stdio_stream_create (mu_stream_t *pstream, size_t size, int flags); - #endif diff --git a/include/mailutils/sys/socket_stream.h b/include/mailutils/sys/socket_stream.h deleted file mode 100644 index c4e382ae5..000000000 --- a/include/mailutils/sys/socket_stream.h +++ /dev/null @@ -1,28 +0,0 @@ -/* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 2009 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef _MAILUTILS_SYS_SOCKET_STREAM_H -#define _MAILUTILS_SYS_SOCKET_STREAM_H - -#include <mailutils/sys/stdio_stream.h> - -struct _mu_socket_stream -{ - struct _mu_stdio_stream stdio_stream; - char *filename; -}; - -#endif diff --git a/mailbox/Makefile.am b/mailbox/Makefile.am index 1fd892dfa..7a8243713 100644 --- a/mailbox/Makefile.am +++ b/mailbox/Makefile.am @@ -126,6 +126,7 @@ libmailutils_la_SOURCES = \ prog_stream.c\ property.c\ qpflt.c\ + rdcache_stream.c\ registrar.c\ refcount.c\ rfc2047.c\ diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c index b74bfb038..7ffde0263 100644 --- a/mailbox/file_stream.c +++ b/mailbox/file_stream.c @@ -146,6 +146,9 @@ fd_open (struct _mu_stream *str) if (fd < 0) return errno; + /* Make sure it will be closed */ + fstr->flags |= MU_STREAM_AUTOCLOSE; + fstr->fd = fd; return 0; } @@ -207,6 +210,13 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr) ptrans[1] = NULL; break; + case MU_IOCTL_SET_TRANSPORT: + if (!ptr) + return EINVAL; + ptrans = ptr; + fstr->fd = (int) ptrans[0]; + break; + default: return EINVAL; } @@ -233,12 +243,11 @@ fd_truncate (mu_stream_t stream, mu_off_t size) } int -_mu_file_stream_create (mu_stream_t *pstream, size_t size, - char *filename, int flags) +_mu_file_stream_create (struct _mu_file_stream **pstream, size_t size, + const char *filename, int fd, int flags) { struct _mu_file_stream *str = - (struct _mu_file_stream *) - _mu_stream_create (size, flags | MU_STREAM_SEEK); + (struct _mu_file_stream *) _mu_stream_create (size, flags); if (!str) return ENOMEM; @@ -254,25 +263,38 @@ _mu_file_stream_create (mu_stream_t *pstream, size_t size, str->stream.truncate = fd_truncate; str->stream.error_string = fd_error_string; - str->filename = filename; - str->fd = -1; + if (filename) + str->filename = mu_strdup (filename); + else + str->filename = NULL; + str->fd = fd; str->flags = 0; - *pstream = (mu_stream_t) str; + *pstream = str; return 0; } int mu_file_stream_create (mu_stream_t *pstream, const char *filename, int flags) { - int rc; - char *fname = mu_strdup (filename); - if (!fname) - return ENOMEM; - rc = _mu_file_stream_create (pstream, - sizeof (struct _mu_file_stream), - fname, flags | MU_STREAM_AUTOCLOSE); - if (rc) - free (fname); + struct _mu_file_stream *fstr; + int rc = _mu_file_stream_create (&fstr, + sizeof (struct _mu_file_stream), + filename, -1, + flags | MU_STREAM_SEEK | MU_STREAM_AUTOCLOSE); + if (rc == 0) + *pstream = (mu_stream_t) fstr; + return rc; +} + +int +mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, int flags) +{ + struct _mu_file_stream *fstr; + int rc = _mu_file_stream_create (&fstr, + sizeof (struct _mu_file_stream), + filename, fd, flags); + if (rc == 0) + *pstream = (mu_stream_t) fstr; return rc; } diff --git a/mailbox/rdcache_stream.c b/mailbox/rdcache_stream.c new file mode 100644 index 000000000..8a8afbf93 --- /dev/null +++ b/mailbox/rdcache_stream.c @@ -0,0 +1,201 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <errno.h> +#include <mailutils/types.h> +#include <mailutils/sys/rdcache_stream.h> + +size_t mu_rdcache_stream_max_memory_size = 4096; + +static int +rdcache_read (struct _mu_stream *str, char *buf, size_t size, size_t *pnbytes) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + int status = 0; + size_t nbytes = 0; + + if (sp->offset < sp->size) + { + status = mu_stream_read (sp->cache, buf, size, &nbytes); + if (status) + return status; + sp->offset += nbytes; + sp->size += nbytes; + buf += nbytes; + size -= nbytes; + } + else if (sp->offset > sp->size) + { + size_t left = sp->offset - sp->size; + status = mu_stream_seek (sp->cache, 0, MU_SEEK_END, NULL); + if (status) + return status; + status = mu_stream_copy (sp->cache, sp->transport, left); + if (status) + return status; + sp->size = sp->offset; + } + + if (size) + { + size_t rdbytes; + status = mu_stream_read (sp->transport, buf, size, &rdbytes); + if (rdbytes) + { + int rc; + + sp->offset += rdbytes; + sp->size += rdbytes; + nbytes += rdbytes; + rc = mu_stream_write (sp->cache, buf, rdbytes, NULL); + if (rc) + { + if (status == 0) + status = rc; + } + } + } + if (pnbytes) + *pnbytes = nbytes; + return status; +} + +static int +rdcache_size (struct _mu_stream *str, off_t *psize) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + *psize = sp->size; + return 0; +} + +static int +rdcache_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *presult) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + + if (off < 0) + return ESPIPE; + + if (off < sp->size) + { + int status = mu_stream_seek (sp->cache, off, MU_SEEK_SET, NULL); + if (status) + return status; + } + + sp->offset = off; + *presult = sp->offset; + return 0; +} + +static int +rdcache_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + return mu_stream_wait (sp->transport, pflags, tvp); +} + +/* FIXME: Truncate? */ + +static int +rdcache_ioctl (struct _mu_stream *str, int op, void *arg) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + mu_transport_t *ptrans; + + switch (op) + { + case MU_IOCTL_GET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + ptrans[0] = (mu_transport_t) sp->transport; + ptrans[1] = NULL; + break; + + default: + return EINVAL; + } + return 0; +} + +static int +rdcache_open (struct _mu_stream *str) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + return mu_stream_open (sp->transport); +} + +static int +rdcache_close (struct _mu_stream *str) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + return mu_stream_close (sp->transport); +} + +static void +rdcache_done (struct _mu_stream *str) +{ + struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str; + mu_stream_unref (sp->transport); + mu_stream_unref (sp->cache); +} + +int +mu_rdcache_stream_create (mu_stream_t *pstream, mu_stream_t transport, + int flags) +{ + struct _mu_rdcache_stream *sp; + int rc; + int sflags = MU_STREAM_READ | MU_STREAM_SEEK | (flags & MU_STREAM_AUTOCLOSE); + + if (flags & ~sflags) + return EINVAL; + + sp = (struct _mu_rdcache_stream *) + _mu_stream_create (sizeof (*sp), sflags); + if (!sp) + return ENOMEM; + + sp->stream.read = rdcache_read; + sp->stream.open = rdcache_open; + sp->stream.close = rdcache_close; + sp->stream.done = rdcache_done; + sp->stream.seek = rdcache_seek; + sp->stream.size = rdcache_size; + sp->stream.ctl = rdcache_ioctl; + sp->stream.wait = rdcache_wait; + + if (!(flags & MU_STREAM_AUTOCLOSE)) + mu_stream_ref (transport); + sp->transport = transport; + + if ((rc = mu_memory_stream_create (&sp->cache, MU_STREAM_RDWR)) + || (rc = mu_stream_open (sp->cache))) + { + mu_stream_destroy ((mu_stream_t*) &sp); + return rc; + } + + *pstream = (mu_stream_t) sp; + return 0; +} + diff --git a/mailbox/socket_stream.c b/mailbox/socket_stream.c index 7ec4adc2e..2764b2b25 100644 --- a/mailbox/socket_stream.c +++ b/mailbox/socket_stream.c @@ -31,22 +31,13 @@ #include <mailutils/errno.h> #include <mailutils/nls.h> #include <mailutils/stream.h> -#include <mailutils/sys/socket_stream.h> - -static void -_socket_done (mu_stream_t stream) -{ - struct _mu_socket_stream *s = (struct _mu_socket_stream *) stream; - - if (s->filename) - free (s->filename); -} +#include <mailutils/sys/file_stream.h> static int _socket_open (mu_stream_t stream) { - struct _mu_socket_stream *s = (struct _mu_socket_stream *) stream; - int fd, rc; + struct _mu_file_stream *s = (struct _mu_file_stream *) stream; + int fd; struct sockaddr_un addr; if (!s) @@ -66,31 +57,15 @@ _socket_open (mu_stream_t stream) return errno; } - s->stdio_stream.file_stream.fd = fd; - s->stdio_stream.size = 0; - s->stdio_stream.offset = 0; - if (s->stdio_stream.cache) - mu_stream_truncate (s->stdio_stream.cache, 0); + s->fd = fd; - return rc; -} - -static int -_socket_close (mu_stream_t stream) -{ - struct _mu_socket_stream *s = (struct _mu_socket_stream *) stream; - if (s->stdio_stream.file_stream.fd != -1) - { - close (s->stdio_stream.file_stream.fd); - s->stdio_stream.file_stream.fd = -1; - } return 0; } int _socket_shutdown (mu_stream_t stream, int how) { - struct _mu_socket_stream *s = (struct _mu_socket_stream *) stream; + struct _mu_file_stream *s = (struct _mu_file_stream *) stream; int flag; switch (how) @@ -103,7 +78,7 @@ _socket_shutdown (mu_stream_t stream, int how) flag = SHUT_WR; } - if (shutdown (s->stdio_stream.file_stream.fd, flag)) + if (shutdown (s->fd, flag)) return errno; return 0; } @@ -111,17 +86,37 @@ _socket_shutdown (mu_stream_t stream, int how) int mu_socket_stream_create (mu_stream_t *pstream, const char *filename, int flags) { - struct _mu_socket_stream *s; int rc; + mu_stream_t transport; + int need_cache; + struct _mu_file_stream *fstr; - rc = _mu_stdio_stream_create (pstream, sizeof (*s), - flags | MU_STREAM_AUTOCLOSE); + need_cache = flags & MU_STREAM_SEEK; + if (need_cache && (flags & MU_STREAM_WRITE)) + /* Write caches are not supported */ + return EINVAL; + + /* Create transport stream. */ + rc = _mu_file_stream_create (&fstr, sizeof (*fstr), + filename, -1, + (flags | MU_STREAM_AUTOCLOSE) & ~MU_STREAM_SEEK); if (rc) return rc; - s = (struct _mu_socket_stream *) *pstream; - s->stdio_stream.file_stream.stream.done = _socket_done; - s->stdio_stream.file_stream.stream.open = _socket_open; - s->stdio_stream.file_stream.stream.close = _socket_close; - s->stdio_stream.file_stream.stream.shutdown = _socket_shutdown; + fstr->stream.open = _socket_open; + fstr->stream.shutdown = _socket_shutdown; + transport = (mu_stream_t) fstr; + + /* Wrap it in cache, if required */ + if (need_cache) + { + mu_stream_t str; + rc = mu_rdcache_stream_create (&str, transport, flags); + mu_stream_unref (transport); + if (rc) + return rc; + transport = str; + } + + *pstream = transport; return 0; } diff --git a/mailbox/stdio_stream.c b/mailbox/stdio_stream.c index ae77d1207..93ff011d6 100644 --- a/mailbox/stdio_stream.c +++ b/mailbox/stdio_stream.c @@ -22,166 +22,21 @@ #include <unistd.h> #include <fcntl.h> +#include <errno.h> #include <mailutils/types.h> -#include <mailutils/alloc.h> -#include <mailutils/error.h> -#include <mailutils/errno.h> -#include <mailutils/nls.h> #include <mailutils/stream.h> #include <mailutils/sys/stream.h> -#include <mailutils/sys/stdio_stream.h> -#include <mailutils/mutil.h> - -static int -stdin_read (struct _mu_stream *str, char *buf, size_t size, size_t *pnbytes) -{ - struct _mu_stdio_stream *fs = (struct _mu_stdio_stream *) str; - int fd = fs->file_stream.fd; - int status = 0; - size_t nbytes; - ssize_t rdbytes; - - if (fs->offset < fs->size) - { - status = mu_stream_read (fs->cache, buf, size, &nbytes); - if (status) - fs->offset += nbytes; - } - else if (fs->offset > fs->size) - { - size_t left = fs->offset - fs->size + 1; - char sbuf[1024]; - size_t bufsize; - char *tmpbuf = malloc (left); - if (tmpbuf) - bufsize = left; - else - { - tmpbuf = sbuf; - bufsize = sizeof sbuf; - } - - while (left > 0) - { - size_t n; - - rdbytes = read (fd, tmpbuf, bufsize); - if (rdbytes < 0) - { - status = errno; - break; - } - if (rdbytes == 0) - { - status = EIO; /* FIXME: EOF?? */ - break; - } - - status = mu_stream_write (fs->cache, tmpbuf, rdbytes, &n); - fs->offset += n; - left -= n; - if (status) - break; - } - if (tmpbuf != sbuf) - free (tmpbuf); - if (status) - return status; - } - - nbytes = read (fd, buf, size); - if (nbytes <= 0) - return EIO; - else - { - status = mu_stream_write (fs->cache, buf, nbytes, NULL); - if (status) - return status; - } - fs->offset += nbytes; - fs->size += nbytes; - - if (pnbytes) - *pnbytes = nbytes; - return status; -} - -static int -stdout_write (struct _mu_stream *str, const char *buf, size_t size, - size_t *pret) -{ - struct _mu_stdio_stream *fstr = (struct _mu_stdio_stream *) str; - int n = write (fstr->file_stream.fd, (char*) buf, size); - if (n == -1) - return errno; - fstr->size += n; - fstr->offset += n; - return 0; -} - -static int -stdio_size (struct _mu_stream *str, off_t *psize) -{ - struct _mu_stdio_stream *fs = (struct _mu_stdio_stream *) str; - *psize = fs->size; - return 0; -} - -static int -stdio_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *presult) -{ - struct _mu_stdio_stream *fs = (struct _mu_stdio_stream *) str; - - if (off < 0) - return ESPIPE; - - fs->offset = off; - *presult = fs->offset; - return 0; -} - -int -_mu_stdio_stream_create (mu_stream_t *pstream, size_t size, int flags) -{ - struct _mu_stdio_stream *fs; - int rc; - - rc = _mu_file_stream_create (pstream, size, NULL, flags); - if (rc) - return rc; - fs = (struct _mu_stdio_stream *) *pstream; - - if (flags & MU_STREAM_SEEK) - { - if ((rc = mu_memory_stream_create (&fs->cache, MU_STREAM_RDWR)) - || (rc = mu_stream_open (fs->cache))) - { - mu_stream_destroy ((mu_stream_t*) &fs); - return rc; - } - fs->file_stream.stream.read = stdin_read; - fs->file_stream.stream.write = stdout_write; - fs->file_stream.stream.size = stdio_size; - fs->file_stream.stream.seek = stdio_seek; - } - else - { - fs->file_stream.stream.flags &= ~MU_STREAM_SEEK; - fs->file_stream.stream.seek = NULL; - } - fs->file_stream.stream.open = NULL; - fs->file_stream.fd = -1; - return 0; -} +#include <mailutils/sys/file_stream.h> int mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags) { int rc; - struct _mu_stdio_stream *fs; - - if (flags & MU_STREAM_SEEK && lseek (fd, 0, 0) == 0) - flags &= ~MU_STREAM_SEEK; + char *filename; + mu_stream_t transport; + int need_cache; + struct _mu_file_stream *fstr; + switch (fd) { case MU_STDIN_FD: @@ -193,11 +48,36 @@ mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags) flags |= MU_STREAM_WRITE; } - rc = _mu_stdio_stream_create (pstream, sizeof (*fs), flags); - if (rc == 0) + need_cache = flags & MU_STREAM_SEEK; + if (need_cache && (flags & MU_STREAM_WRITE)) + /* Write caches are not supported */ + return EINVAL; + + if (flags & MU_STREAM_READ) + filename = "<stdin>"; + else + filename = "<stdout>"; + + /* Create transport stream. */ + rc = _mu_file_stream_create (&fstr, sizeof (*fstr), + filename, fd, flags & ~MU_STREAM_SEEK); + if (rc) + return rc; + fstr->stream.open = NULL; |