Commit 62c5c62a 62c5c62a7e8fd3524227cd241986d6ce4711b239 by Sergey Poznyakoff

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.
1 parent 69f7dcae
......@@ -49,9 +49,11 @@ noinst_PROGRAMS = \
mimetest\
msg-send\
mta\
mucat\
muauth\
muemail\
murun\
musocio\
$(NNTPCLIENT)\
$(POP3CLIENT)\
sfrom\
......
/* 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;
}
/* 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;
}
......@@ -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
......
......@@ -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\
......
......@@ -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
......
/* 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
......
/* 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
......@@ -126,6 +126,7 @@ libmailutils_la_SOURCES = \
prog_stream.c\
property.c\
qpflt.c\
rdcache_stream.c\
registrar.c\
refcount.c\
rfc2047.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,
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),
fname, flags | MU_STREAM_AUTOCLOSE);
if (rc)
free (fname);
filename, fd, flags);
if (rc == 0)
*pstream = (mu_stream_t) fstr;
return rc;
}
......
/* 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;
}
......@@ -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);
return rc;
}
s->fd = fd;
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;
need_cache = flags & MU_STREAM_SEEK;
if (need_cache && (flags & MU_STREAM_WRITE))
/* Write caches are not supported */
return EINVAL;
rc = _mu_stdio_stream_create (pstream, sizeof (*s),
flags | MU_STREAM_AUTOCLOSE);
/* 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;
}
......
......@@ -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;
char *filename;
mu_stream_t transport;
int need_cache;
struct _mu_file_stream *fstr;
if (flags & MU_STREAM_SEEK && lseek (fd, 0, 0) == 0)
flags &= ~MU_STREAM_SEEK;
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;
transport = (mu_stream_t) fstr;
/* Wrap it in cache, if required */
if (need_cache)
{
fs = (struct _mu_stdio_stream *) *pstream;
fs->file_stream.fd = fd;
}
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;
}
......
......@@ -69,6 +69,8 @@ mu_stream_copy (mu_stream_t dst, mu_stream_t src, size_t size)
size -= pos;
break;
case EACCES:
mu_stream_clearerr (src);
case ENOSYS:
break;
......
......@@ -48,28 +48,18 @@ int
mu_temp_file_stream_create (mu_stream_t *pstream, const char *dir)
{
int rc;
char *fname;
struct _mu_file_stream *str;
if (!dir)
fname = NULL;
else if ((fname = mu_strdup (dir)) == NULL)
return ENOMEM;
rc = _mu_file_stream_create (pstream,
rc = _mu_file_stream_create (&str,
sizeof (struct _mu_file_stream),
fname,
MU_STREAM_RDWR | MU_STREAM_CREAT |
dir,
-1,
MU_STREAM_RDWR | MU_STREAM_SEEK |
MU_STREAM_CREAT |
MU_STREAM_AUTOCLOSE);
if (rc)
{
free (fname);
return rc;
}
str = (struct _mu_file_stream *) *pstream;
str->stream.open = fd_temp_open;
str->flags = _MU_FILE_STREAM_TEMP;
*pstream = (mu_stream_t) str;
return 0;
}
......