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) {
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) {

View File

@ -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)

View File

@ -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;

View File

@ -20,6 +20,7 @@
/* libc includes */
#include <errno.h>
#include <fcntl.h>
#include <string.h>
/* 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
*/

View File

@ -17,6 +17,7 @@
/* libc includes */
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
@ -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)
{

View File

@ -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;