summaryrefslogtreecommitdiff
path: root/libmailutils/streamcpy.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils/streamcpy.c')
-rw-r--r--libmailutils/streamcpy.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/libmailutils/streamcpy.c b/libmailutils/streamcpy.c
new file mode 100644
index 000000000..48126677f
--- /dev/null
+++ b/libmailutils/streamcpy.c
@@ -0,0 +1,128 @@
+/* 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 <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+
+#define STREAMCPY_MIN_BUF_SIZE 2
+#define STREAMCPY_MAX_BUF_SIZE 16384
+
+/* Copy SIZE bytes from SRC to DST. If SIZE is 0, copy everything up to
+ EOF. */
+int
+mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size,
+ mu_off_t *pcsz)
+{
+ int status;
+ size_t bufsize, n;
+ char *buf;
+ mu_off_t total = 0;
+
+ if (pcsz)
+ *pcsz = 0;
+ if (size == 0)
+ {
+ status = mu_stream_size (src, &size);
+ switch (status)
+ {
+ case 0:
+ break;
+
+ case ENOSYS:
+ size = 0;
+ break;
+
+ default:
+ return status;
+ }
+
+ if (size)
+ {
+ mu_off_t pos;
+ status = mu_stream_seek (src, 0, MU_SEEK_CUR, &pos);
+ switch (status)
+ {
+ case 0:
+ if (pos > size)
+ return ESPIPE;
+ size -= pos;
+ break;
+
+ case EACCES:
+ mu_stream_clearerr (src);
+ case ENOSYS:
+ break;
+
+ default:
+ return status;
+ }
+ }
+ }
+
+ bufsize = size;
+ if (!bufsize)
+ bufsize = STREAMCPY_MAX_BUF_SIZE;
+
+ for (; (buf = malloc (bufsize)) == NULL; bufsize >>= 1)
+ if (bufsize < STREAMCPY_MIN_BUF_SIZE)
+ return ENOMEM;
+
+ if (size)
+ while (size)
+ {
+ size_t rdsize = bufsize < size ? bufsize : size;
+
+ status = mu_stream_read (src, buf, rdsize, &n);
+ if (status)
+ break;
+ if (n == 0)
+ {
+ status = EIO;
+ break;
+ }
+ status = mu_stream_write (dst, buf, n, NULL);
+ if (status)
+ break;
+ size -= rdsize;
+ total += rdsize;
+ }
+ else
+ while ((status = mu_stream_read (src, buf, bufsize, &n)) == 0
+ && n > 0)
+ {
+ status = mu_stream_write (dst, buf, n, NULL);
+ if (status)
+ break;
+ total += n;
+ }
+
+ if (pcsz)
+ *pcsz = total;
+ free (buf);
+ return status;
+}
+
+
+
+

Return to:

Send suggestions and report system problems to the System administrator.