libc: handle 'O_APPEND' flag for 'open()'

Fixes #319.
This commit is contained in:
Christian Prochaska 2012-10-08 15:38:35 +02:00 committed by Norman Feske
parent 4a3d852b65
commit be171d86bb
6 changed files with 103 additions and 26 deletions

View File

@ -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) { extern "C" ssize_t _write(int libc_fd, const void *buf, ::size_t count)
FD_FUNC_WRAPPER(write, libc_fd, buf, 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) { extern "C" ssize_t write(int libc_fd, const void *buf, ::size_t count) {

View File

@ -51,10 +51,13 @@ class Plugin_context : public Libc::Plugin_context
private: private:
char *_filename; /* needed for fstat() */ char *_filename; /* needed for fstat() */
int _fd_flags;
int _status_flags;
public: public:
Plugin_context(const char *filename) Plugin_context(const char *filename)
: _fd_flags(0), _status_flags(0)
{ {
if (verbose) if (verbose)
PDBG("new context at %p", this); PDBG("new context at %p", this);
@ -68,6 +71,18 @@ class Plugin_context : public Libc::Plugin_context
} }
const char *filename() { return _filename; } 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 */ switch (cmd) {
if (verbose) case F_GETFD: return context(fd)->fd_flags();
PDBG("fcntl() called - not yet implemented"); case F_SETFD: context(fd)->fd_flags(arg); return 0;
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) int fstat(Libc::File_descriptor *fd, struct stat *buf)
@ -478,6 +495,7 @@ class Plugin : public Libc::Plugin
case FR_OK: { case FR_OK: {
Plugin_context *context = new (Genode::env()->heap()) Plugin_context *context = new (Genode::env()->heap())
File_plugin_context(pathname, ffat_file); File_plugin_context(pathname, ffat_file);
context->status_flags(flags);
Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context); Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context);
if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1))
return 0; return 0;
@ -497,6 +515,7 @@ class Plugin : public Libc::Plugin
case FR_OK: { case FR_OK: {
Plugin_context *context = new (Genode::env()->heap()) Plugin_context *context = new (Genode::env()->heap())
Directory_plugin_context(pathname, ffat_dir); Directory_plugin_context(pathname, ffat_dir);
context->status_flags(flags);
Libc::File_descriptor *f = Libc::File_descriptor *f =
Libc::file_descriptor_allocator()->alloc(this, context); Libc::file_descriptor_allocator()->alloc(this, context);
if (verbose) if (verbose)

View File

@ -76,6 +76,9 @@ class Plugin_context : public Libc::Plugin_context,
File_system::Node_handle _node_handle; File_system::Node_handle _node_handle;
int _fd_flags;
int _status_flags;
/** /**
* Current file position if manually seeked, or ~0 for append mode * 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; bool in_flight;
Plugin_context(File_system::File_handle handle) 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) 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) 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; } 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 * Return true of handle is append mode
*/ */
@ -284,12 +302,14 @@ class Plugin : public Libc::Plugin
return 0; 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 */ switch (cmd) {
if (verbose) case F_GETFD: return context(fd)->fd_flags();
PDBG("fcntl() called - not yet implemented"); case F_SETFD: context(fd)->fd_flags(arg); return 0;
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) 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 *context = new (Genode::env()->heap())
Plugin_context(handle); Plugin_context(handle);
context->status_flags(flags);
Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context); Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context);
if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1))
return 0; return 0;

View File

@ -20,6 +20,7 @@
/* libc includes */ /* libc includes */
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <string.h> #include <string.h>
/* interface to 'log_console' */ /* interface to 'log_console' */
@ -51,6 +52,14 @@ namespace {
_stderr(Libc::file_descriptor_allocator()->alloc(this, &_context, 2)) _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 * We provide fstat here because printf inqueries _fstat about stdout
*/ */

View File

@ -17,6 +17,7 @@
/* libc includes */ /* libc includes */
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
@ -99,12 +100,25 @@ namespace {
* notifications about data available for reading are delivered to * notifications about data available for reading are delivered to
* the 'Read_sigh' thread, which cares about unblocking 'select()'. * 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() private:
{
read_avail_sigh(read_sigh()); 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) Libc::File_descriptor *open(const char *pathname, int flags)
{ {
Plugin_context *context = new (Genode::env()->heap()) Plugin_context; Plugin_context *context = new (Genode::env()->heap()) Plugin_context;
context->status_flags(flags);
return Libc::file_descriptor_allocator()->alloc(this, context); return Libc::file_descriptor_allocator()->alloc(this, context);
} }
@ -275,10 +290,13 @@ namespace {
} }
} }
/** int fcntl(Libc::File_descriptor *fd, int cmd, long arg)
* Suppress dummy message of the default plugin function {
*/ switch (cmd) {
int fcntl(Libc::File_descriptor *, int cmd, long arg) { return -1; } 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) int ioctl(Libc::File_descriptor *, int request, char *argp)
{ {

View File

@ -1074,12 +1074,14 @@ namespace {
break; break;
case F_GETFL: 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; sysio()->fcntl_in.cmd = Noux::Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS;
break; break;
case F_SETFL: 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.cmd = Noux::Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS;
sysio()->fcntl_in.long_arg = arg; sysio()->fcntl_in.long_arg = arg;
break; break;