summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-09-06 19:18:32 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-09-06 19:18:32 +0300
commitbfb29ced5d88dbe449347d5b8b86e6ee887c450b (patch)
tree98087985cc1d4e37554bea72f009755618077a5d
parentd0b037c48bc8ccdb0c4a094289d6489ec280c2af (diff)
downloadmailutils-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.am2
-rw-r--r--examples/mucat.c87
-rw-r--r--examples/musocio.c124
-rw-r--r--include/mailutils/stream.h5
-rw-r--r--include/mailutils/sys/Makefile.am3
-rw-r--r--include/mailutils/sys/file_stream.h4
-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.h28
-rw-r--r--mailbox/Makefile.am1
-rw-r--r--mailbox/file_stream.c54
-rw-r--r--mailbox/rdcache_stream.c201
-rw-r--r--mailbox/socket_stream.c73
-rw-r--r--mailbox/stdio_stream.c194
-rw-r--r--mailbox/streamcpy.c2
-rw-r--r--mailbox/temp_file_stream.c22
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;