diff --git a/libports/lib/mk/libc.mk b/libports/lib/mk/libc.mk index a7c7bb99f..d1eb1555b 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 000000000..053d62c1d --- /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 cb4fefd25..000000000 --- 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 ecc031f79..fa9175920 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);