diff --git a/libports/lib/mk/libc.mk b/libports/lib/mk/libc.mk
index a7c7bb99ff..d1eb1555b2 100644
--- a/libports/lib/mk/libc.mk
+++ b/libports/lib/mk/libc.mk
@@ -14,7 +14,7 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.cc munmap.cc \
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.cc \
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
- libc_mem_alloc.cc writev.cc pread_pwrite.cc
+ libc_mem_alloc.cc pread_pwrite.cc readv_writev.cc
#
# Files from string library that are not included in libc-raw_string because
diff --git a/libports/src/lib/libc/readv_writev.cc b/libports/src/lib/libc/readv_writev.cc
new file mode 100644
index 0000000000..053d62c1dc
--- /dev/null
+++ b/libports/src/lib/libc/readv_writev.cc
@@ -0,0 +1,117 @@
+/*
+ * \brief 'readv()' and 'writev()' implementations
+ * \author Josef Soentgen
+ * \author Christian Prochaska
+ * \date 2012-04-10
+ */
+
+/*
+ * Copyright (C) 2012 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* libc includes */
+#include
+#include
+#include
+#include
+#include
+
+
+static Genode::Lock rw_lock;
+
+
+struct Read
+{
+ ssize_t operator()(int fd, void *buf, size_t count)
+ {
+ return read(fd, buf, count);
+ }
+};
+
+
+struct Write
+{
+ ssize_t operator()(int fd, const void *buf, size_t count)
+ {
+ return write(fd, buf, count);
+ }
+};
+
+
+template
+static ssize_t readv_writev_impl(Rw_func rw_func, int fd, const struct iovec *iov, int iovcnt)
+{
+ Genode::Lock_guard rw_lock_guard(rw_lock);
+
+ char *v;
+ ssize_t bytes_transfered_total = 0;
+ size_t v_len = 0;
+ int i;
+
+ if (iovcnt < 1 || iovcnt > IOV_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (i = 0; i < iovcnt; i++)
+ v_len += iov->iov_len;
+
+ if (v_len > SSIZE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (iovcnt > 0) {
+ v = static_cast(iov->iov_base);
+ v_len = iov->iov_len;
+
+ while (v_len > 0) {
+ ssize_t bytes_transfered = rw_func(fd, v, v_len);
+
+ if (bytes_transfered == -1)
+ return -1;
+
+ if (bytes_transfered == 0)
+ return bytes_transfered_total;
+
+ v_len -= bytes_transfered;
+ v += bytes_transfered;
+ bytes_transfered_total += bytes_transfered;
+ }
+
+ iov++;
+ iovcnt--;
+ }
+
+ return bytes_transfered_total;
+}
+
+
+extern "C" ssize_t _readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ return readv_writev_impl(Read(), fd, iov, iovcnt);
+}
+
+
+extern "C" ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ return _readv(fd, iov, iovcnt);
+}
+
+
+extern "C" ssize_t _writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ return readv_writev_impl(Write(), fd, iov, iovcnt);
+}
+
+
+extern "C" ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ return _writev(fd, iov, iovcnt);
+}
diff --git a/libports/src/lib/libc/writev.cc b/libports/src/lib/libc/writev.cc
deleted file mode 100644
index cb4fefd25f..0000000000
--- a/libports/src/lib/libc/writev.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * \brief Plugin implementation
- * \author Josef Soentgen
- * \date 2012-04-10
- */
-
-/*
- * Copyright (C) 2010-2012 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU General Public License version 2.
- */
-
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-enum { MAX_BUFFER_LEN = 2048 };
-
-extern "C" int _writev(int d, const struct iovec *iov, int iovcnt)
-{
- char buffer[MAX_BUFFER_LEN];
- char *v, *b;
- ssize_t written;
- size_t v_len, _len;
- int i;
-
- if (iovcnt < 1 || iovcnt > IOV_MAX) {
- return -EINVAL;
- }
-
- for (i = 0; i < iovcnt; i++)
- v_len += iov->iov_len;
-
- if (v_len > SSIZE_MAX) {
- return -EINVAL;
- }
-
- b = buffer;
- while (iovcnt) {
- v = static_cast(iov->iov_base);
- v_len = iov->iov_len;
-
- while (v_len > 0) {
- if (v_len < sizeof(buffer))
- _len = v_len;
- else
- _len = sizeof(buffer);
-
- // TODO error check
- memmove(b, v, _len);
- i = write(d, b, _len);
- v += _len;
- v_len -= _len;
-
- written += i;
- }
-
- iov++;
- iovcnt--;
- }
-
- return written;
-}
-
-extern "C" ssize_t writev(int d, const struct iovec *iov, int iovcnt)
-{
- return _writev(d, iov, iovcnt);
-}
-
diff --git a/libports/src/test/libc_ffat/main.cc b/libports/src/test/libc_ffat/main.cc
index ecc031f796..fa91759202 100644
--- a/libports/src/test/libc_ffat/main.cc
+++ b/libports/src/test/libc_ffat/main.cc
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -44,6 +45,7 @@ int main(int argc, char *argv[])
char const *dir_name = "/testdir";
char const *file_name = "test.tst";
char const *file_name2 = "test2.tst";
+ char const *file_name3 = "test3.tst";
char const *pattern = "a single line of text";
size_t pattern_size = strlen(pattern) + 1;
@@ -109,6 +111,35 @@ int main(int argc, char *argv[])
printf("file content is correct\n");
}
+ /* test 'readv()' and 'writev()' */
+ CALL_AND_CHECK(fd, open(file_name3, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name);
+ struct iovec iov[2];
+ /* write "a single line" */
+ iov[0].iov_base = (void*)pattern;
+ iov[0].iov_len = 13;
+ /* write " line of text" */
+ iov[1].iov_base = (void*)&pattern[8];
+ iov[1].iov_len = pattern_size - 8;
+ CALL_AND_CHECK(count, writev(fd, iov, 2), (size_t)count == (pattern_size + 5), "");
+ CALL_AND_CHECK(ret, close(fd), ret == 0, "");
+ CALL_AND_CHECK(fd, open(file_name3, O_RDONLY), fd >= 0, "file_name=%s", file_name);
+ memset(buf, 0, sizeof(buf));
+ /* read "a single line" */
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 13;
+ /* read " line of text" to offset 8 */
+ iov[1].iov_base = &buf[8];
+ iov[1].iov_len = pattern_size;
+ CALL_AND_CHECK(count, readv(fd, iov, 2), (size_t)count == (pattern_size + 5), "");
+ CALL_AND_CHECK(ret, close(fd), ret == 0, "");
+ printf("content of buffer: \"%s\"\n", buf);
+ if (strcmp(buf, pattern) != 0) {
+ printf("unexpected content of file\n");
+ return -1;
+ } else {
+ printf("file content is correct\n");
+ }
+
/* read directory entries */
DIR *dir;
CALL_AND_CHECK(dir, opendir(dir_name), dir, "dir_name=\"%s\"", dir_name);