From be171d86bbad9c3efdec368b6b26e7d8777412d9 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Mon, 8 Oct 2012 15:38:35 +0200 Subject: [PATCH] libc: handle 'O_APPEND' flag for 'open()' Fixes #319. --- libports/src/lib/libc/file_operations.cc | 11 +++++-- libports/src/lib/libc_ffat/plugin.cc | 29 ++++++++++++++---- libports/src/lib/libc_fs/plugin.cc | 38 +++++++++++++++++++----- libports/src/lib/libc_log/plugin.cc | 9 ++++++ libports/src/lib/libc_terminal/plugin.cc | 36 ++++++++++++++++------ ports/src/lib/libc_noux/plugin.cc | 6 ++-- 6 files changed, 103 insertions(+), 26 deletions(-) diff --git a/libports/src/lib/libc/file_operations.cc b/libports/src/lib/libc/file_operations.cc index d72fa10c74..5b66a0c5ab 100644 --- a/libports/src/lib/libc/file_operations.cc +++ b/libports/src/lib/libc/file_operations.cc @@ -813,8 +813,15 @@ extern "C" int unlink(const char *path) } -extern "C" ssize_t _write(int libc_fd, const void *buf, ::size_t count) { - FD_FUNC_WRAPPER(write, libc_fd, buf, count); } +extern "C" ssize_t _write(int libc_fd, const void *buf, ::size_t count) +{ + int flags = fcntl(libc_fd, F_GETFL); + + if ((flags != -1) && (flags & O_APPEND)) + lseek(libc_fd, 0, SEEK_END); + + FD_FUNC_WRAPPER(write, libc_fd, buf, count); +} extern "C" ssize_t write(int libc_fd, const void *buf, ::size_t count) { diff --git a/libports/src/lib/libc_ffat/plugin.cc b/libports/src/lib/libc_ffat/plugin.cc index e21fd0bca4..4d457530c9 100644 --- a/libports/src/lib/libc_ffat/plugin.cc +++ b/libports/src/lib/libc_ffat/plugin.cc @@ -51,10 +51,13 @@ class Plugin_context : public Libc::Plugin_context private: char *_filename; /* needed for fstat() */ + int _fd_flags; + int _status_flags; public: Plugin_context(const char *filename) + : _fd_flags(0), _status_flags(0) { if (verbose) PDBG("new context at %p", this); @@ -68,6 +71,18 @@ class Plugin_context : public Libc::Plugin_context } const char *filename() { return _filename; } + + /** + * Set/get file descriptor flags + */ + void fd_flags(int flags) { _fd_flags = flags; } + int fd_flags() { return _fd_flags; } + + /** + * Set/get file status status flags + */ + void status_flags(int flags) { _status_flags = flags; } + int status_flags() { return _status_flags; } }; @@ -242,12 +257,14 @@ class Plugin : public Libc::Plugin } } - int fcntl(Libc::File_descriptor *, int cmd, long arg) + int fcntl(Libc::File_descriptor *fd, int cmd, long arg) { - /* libc's opendir() fails if fcntl() returns -1, so we return 0 here */ - if (verbose) - PDBG("fcntl() called - not yet implemented"); - return 0; + switch (cmd) { + case F_GETFD: return context(fd)->fd_flags(); + case F_SETFD: context(fd)->fd_flags(arg); return 0; + case F_GETFL: return context(fd)->status_flags(); + default: PERR("fcntl(): command %d not supported", cmd); return -1; + } } int fstat(Libc::File_descriptor *fd, struct stat *buf) @@ -478,6 +495,7 @@ class Plugin : public Libc::Plugin case FR_OK: { Plugin_context *context = new (Genode::env()->heap()) File_plugin_context(pathname, ffat_file); + context->status_flags(flags); Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context); if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) return 0; @@ -497,6 +515,7 @@ class Plugin : public Libc::Plugin case FR_OK: { Plugin_context *context = new (Genode::env()->heap()) Directory_plugin_context(pathname, ffat_dir); + context->status_flags(flags); Libc::File_descriptor *f = Libc::file_descriptor_allocator()->alloc(this, context); if (verbose) diff --git a/libports/src/lib/libc_fs/plugin.cc b/libports/src/lib/libc_fs/plugin.cc index 488d130403..8fb607908a 100644 --- a/libports/src/lib/libc_fs/plugin.cc +++ b/libports/src/lib/libc_fs/plugin.cc @@ -76,6 +76,9 @@ class Plugin_context : public Libc::Plugin_context, File_system::Node_handle _node_handle; + int _fd_flags; + int _status_flags; + /** * Current file position if manually seeked, or ~0 for append mode */ @@ -86,16 +89,31 @@ class Plugin_context : public Libc::Plugin_context, bool in_flight; Plugin_context(File_system::File_handle handle) - : _type(TYPE_FILE), _node_handle(handle), _seek_offset(~0), in_flight(false) { } + : _type(TYPE_FILE), _node_handle(handle), _fd_flags(0), + _status_flags(0), _seek_offset(~0), in_flight(false) { } Plugin_context(File_system::Dir_handle handle) - : _type(TYPE_DIR), _node_handle(handle), _seek_offset(0), in_flight(false) { } + : _type(TYPE_DIR), _node_handle(handle), _fd_flags(0), + _status_flags(0), _seek_offset(0), in_flight(false) { } Plugin_context(File_system::Symlink_handle handle) - : _type(TYPE_SYMLINK), _node_handle(handle), _seek_offset(~0), in_flight(false) { } + : _type(TYPE_SYMLINK), _node_handle(handle), _fd_flags(0), + _status_flags(0), _seek_offset(~0), in_flight(false) { } File_system::Node_handle node_handle() const { return _node_handle; } + /** + * Set/get file descriptor flags + */ + void fd_flags(int flags) { _fd_flags = flags; } + int fd_flags() { return _fd_flags; } + + /** + * Set/get file status status flags + */ + void status_flags(int flags) { _status_flags = flags; } + int status_flags() { return _status_flags; } + /** * Return true of handle is append mode */ @@ -284,12 +302,14 @@ class Plugin : public Libc::Plugin return 0; } - int fcntl(Libc::File_descriptor *, int cmd, long arg) + int fcntl(Libc::File_descriptor *fd, int cmd, long arg) { - /* libc's opendir() fails if fcntl() returns -1, so we return 0 here */ - if (verbose) - PDBG("fcntl() called - not yet implemented"); - return 0; + switch (cmd) { + case F_GETFD: return context(fd)->fd_flags(); + case F_SETFD: context(fd)->fd_flags(arg); return 0; + case F_GETFL: return context(fd)->status_flags(); + default: PERR("fcntl(): command %d not supported", cmd); return -1; + } } int fstat(Libc::File_descriptor *fd, struct stat *buf) @@ -506,6 +526,8 @@ class Plugin : public Libc::Plugin Plugin_context *context = new (Genode::env()->heap()) Plugin_context(handle); + context->status_flags(flags); + Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context); if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) return 0; diff --git a/libports/src/lib/libc_log/plugin.cc b/libports/src/lib/libc_log/plugin.cc index 11dbe09066..92a0dd211e 100644 --- a/libports/src/lib/libc_log/plugin.cc +++ b/libports/src/lib/libc_log/plugin.cc @@ -20,6 +20,7 @@ /* libc includes */ #include +#include #include /* interface to 'log_console' */ @@ -51,6 +52,14 @@ namespace { _stderr(Libc::file_descriptor_allocator()->alloc(this, &_context, 2)) { } + int fcntl(Libc::File_descriptor *fd, int cmd, long arg) + { + switch (cmd) { + case F_GETFL: return O_WRONLY; + default: PERR("fcntl(): command %d not supported", cmd); return -1; + } + } + /* * We provide fstat here because printf inqueries _fstat about stdout */ diff --git a/libports/src/lib/libc_terminal/plugin.cc b/libports/src/lib/libc_terminal/plugin.cc index 33dea5eef0..48654159b2 100644 --- a/libports/src/lib/libc_terminal/plugin.cc +++ b/libports/src/lib/libc_terminal/plugin.cc @@ -17,6 +17,7 @@ /* libc includes */ #include +#include #include #include @@ -99,12 +100,25 @@ namespace { * notifications about data available for reading are delivered to * the 'Read_sigh' thread, which cares about unblocking 'select()'. */ - struct Plugin_context : Libc::Plugin_context, Terminal::Connection + class Plugin_context : public Libc::Plugin_context, public Terminal::Connection { - Plugin_context() - { - read_avail_sigh(read_sigh()); - } + private: + + int _status_flags; + + public: + + Plugin_context() + : _status_flags(0) + { + read_avail_sigh(read_sigh()); + } + + /** + * Set/get file status status flags + */ + void status_flags(int flags) { _status_flags = flags; } + int status_flags() { return _status_flags; } }; @@ -145,6 +159,7 @@ namespace { Libc::File_descriptor *open(const char *pathname, int flags) { Plugin_context *context = new (Genode::env()->heap()) Plugin_context; + context->status_flags(flags); return Libc::file_descriptor_allocator()->alloc(this, context); } @@ -275,10 +290,13 @@ namespace { } } - /** - * Suppress dummy message of the default plugin function - */ - int fcntl(Libc::File_descriptor *, int cmd, long arg) { return -1; } + int fcntl(Libc::File_descriptor *fd, int cmd, long arg) + { + switch (cmd) { + case F_GETFL: return context(fd)->status_flags(); + default: PERR("fcntl(): command %d not supported", cmd); return -1; + } + } int ioctl(Libc::File_descriptor *, int request, char *argp) { diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 5c54dd30e1..79a02b8c8c 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -1074,12 +1074,14 @@ namespace { break; case F_GETFL: - PINF("fcntl: F_GETFL for libc_fd=%d", fd->libc_fd); + if (verbose) + PINF("fcntl: F_GETFL for libc_fd=%d", fd->libc_fd); sysio()->fcntl_in.cmd = Noux::Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS; break; case F_SETFL: - PINF("fcntl: F_SETFL for libc_fd=%d", fd->libc_fd); + if (verbose) + PINF("fcntl: F_SETFL for libc_fd=%d", fd->libc_fd); sysio()->fcntl_in.cmd = Noux::Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS; sysio()->fcntl_in.long_arg = arg; break;