From dcfcbce856d332c8d6dac3b9e6ca4bc2914a771f Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Thu, 2 Aug 2012 15:17:24 +0200 Subject: [PATCH] libc: add support for 'ftruncate()' Fixes #307. --- libports/include/libc-plugin/plugin.h | 1 + libports/src/lib/libc/dummies.cc | 1 - libports/src/lib/libc/file_operations.cc | 4 + libports/src/lib/libc/plugin.cc | 1 + libports/src/lib/libc_ffat/plugin.cc | 27 ++++ libports/src/lib/libc_fs/plugin.cc | 19 +++ libports/src/server/ffat_fs/main.cc | 41 +++++- libports/src/test/libc_ffat/main.cc | 15 ++ os/src/server/ram_fs/file.h | 8 ++ os/src/server/ram_fs/main.cc | 10 +- ports/include/noux_session/noux_session.h | 2 + ports/include/noux_session/sysio.h | 160 +++++++++++----------- ports/src/lib/libc_noux/plugin.cc | 16 +++ ports/src/noux/dir_file_system.h | 1 + ports/src/noux/file_io_service.h | 5 +- ports/src/noux/fs_file_system.h | 21 +++ ports/src/noux/io_channel.h | 17 +-- ports/src/noux/main.cc | 10 ++ ports/src/noux/tar_file_system.h | 6 + ports/src/noux/terminal_file_system.h | 2 + ports/src/noux/vfs_handle.h | 5 +- ports/src/noux/vfs_io_channel.h | 5 + 22 files changed, 283 insertions(+), 94 deletions(-) diff --git a/libports/include/libc-plugin/plugin.h b/libports/include/libc-plugin/plugin.h index a9c9dbad9..030321e53 100644 --- a/libports/include/libc-plugin/plugin.h +++ b/libports/include/libc-plugin/plugin.h @@ -77,6 +77,7 @@ namespace Libc { virtual void freeaddrinfo(struct ::addrinfo *res); virtual int fstat(File_descriptor *, struct stat *buf); virtual int fsync(File_descriptor *); + virtual int ftruncate(File_descriptor *, ::off_t length); virtual int getaddrinfo(const char *node, const char *service, const struct ::addrinfo *hints, struct ::addrinfo **res); diff --git a/libports/src/lib/libc/dummies.cc b/libports/src/lib/libc/dummies.cc index 78293a0fe..024abe5d0 100644 --- a/libports/src/lib/libc/dummies.cc +++ b/libports/src/lib/libc/dummies.cc @@ -50,7 +50,6 @@ DUMMY(-1, _fpathconf) DUMMY(-1, fpathconf) DUMMY(-1, freebsd7___semctl) DUMMY(-1, fstatat) -DUMMY(-1, ftruncate) DUMMY(-1, getcontext) DUMMY( 0, __getcwd) DUMMY( 0, getdtablesize) diff --git a/libports/src/lib/libc/file_operations.cc b/libports/src/lib/libc/file_operations.cc index c2036e368..40620bd4a 100644 --- a/libports/src/lib/libc/file_operations.cc +++ b/libports/src/lib/libc/file_operations.cc @@ -219,6 +219,10 @@ extern "C" int fsync(int libc_fd) { FD_FUNC_WRAPPER(fsync, libc_fd); } +extern "C" int ftruncate(int libc_fd, ::off_t length) { + FD_FUNC_WRAPPER(ftruncate, libc_fd, length); } + + extern "C" int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) diff --git a/libports/src/lib/libc/plugin.cc b/libports/src/lib/libc/plugin.cc index ac8e1b096..4d473b560 100644 --- a/libports/src/lib/libc/plugin.cc +++ b/libports/src/lib/libc/plugin.cc @@ -154,6 +154,7 @@ DUMMY(int, -1, fchdir, (File_descriptor *)); DUMMY(int, -1, fcntl, (File_descriptor *, int cmd, long arg)); DUMMY(int, -1, fstat, (File_descriptor *, struct stat *)); DUMMY(int, -1, fsync, (File_descriptor *)); +DUMMY(int, -1, ftruncate, (File_descriptor *, ::off_t)); DUMMY(ssize_t, -1, getdirentries, (File_descriptor *, char *, ::size_t, ::off_t *)); DUMMY(int, -1, getpeername, (File_descriptor *, struct sockaddr *, socklen_t *)); DUMMY(int, -1, getsockname, (File_descriptor *, struct sockaddr *, socklen_t *)); diff --git a/libports/src/lib/libc_ffat/plugin.cc b/libports/src/lib/libc_ffat/plugin.cc index 52059a1f8..01e07c430 100644 --- a/libports/src/lib/libc_ffat/plugin.cc +++ b/libports/src/lib/libc_ffat/plugin.cc @@ -312,6 +312,33 @@ class Plugin : public Libc::Plugin } } + int ftruncate(Libc::File_descriptor *fd, ::off_t length) + { + using namespace Ffat; + + /* 'f_truncate()' truncates to the current seek pointer */ + + if (lseek(fd, length, SEEK_SET) == -1) + return -1; + + FRESULT res = f_truncate(_get_ffat_file(fd)); + + switch(res) { + case FR_OK: + return 0; + case FR_DISK_ERR: + case FR_INT_ERR: + case FR_NOT_READY: + case FR_INVALID_OBJECT: + errno = EIO; + return -1; + default: + /* not supposed to occur according to the libffat documentation */ + PERR("f_truncate() returned an unexpected error code"); + return -1; + } + } + ssize_t getdirentries(Libc::File_descriptor *fd, char *buf, ::size_t nbytes, ::off_t *basep) { diff --git a/libports/src/lib/libc_fs/plugin.cc b/libports/src/lib/libc_fs/plugin.cc index 6e2713c79..98bfea661 100644 --- a/libports/src/lib/libc_fs/plugin.cc +++ b/libports/src/lib/libc_fs/plugin.cc @@ -356,6 +356,25 @@ class Plugin : public Libc::Plugin return -1; } + int ftruncate(Libc::File_descriptor *fd, ::off_t length) + { + File_system::Node_handle node_handle = context(fd)->node_handle(); + File_system::File_handle &file_handle = + static_cast(node_handle); + + try { + file_system()->truncate(file_handle, length); + } catch (File_system::Invalid_handle) { + errno = EINVAL; + return -1; + } catch (File_system::Permission_denied) { + errno = EPERM; + return -1; + } + + return 0; + } + /* * *basep does not get initialized by the libc and is therefore * useless for determining a specific directory index. This diff --git a/libports/src/server/ffat_fs/main.cc b/libports/src/server/ffat_fs/main.cc index e31ebc4fa..2ffffbf14 100644 --- a/libports/src/server/ffat_fs/main.cc +++ b/libports/src/server/ffat_fs/main.cc @@ -31,6 +31,13 @@ namespace Ffat { extern "C" { #include } } +/* + * This macro is defined in later versions of the FatFs lib, but not in the + * one currently used for Genode. + */ +#define f_tell(fp) ((fp)->fptr) + + using namespace Genode; @@ -767,14 +774,44 @@ namespace File_system { using namespace Ffat; - FRESULT res = f_truncate(file->ffat_fil()); + /* 'f_truncate()' truncates to the current seek pointer */ + + FRESULT res = f_lseek(file->ffat_fil(), size); + + switch(res) { + case FR_OK: + /* according to the FatFs documentation this can happen */ + if (f_tell(file->ffat_fil()) != size) { + PERR("f_lseek() could not seek to offset %llu", size); + return; + } + break; + case FR_DISK_ERR: + PERR("f_lseek() failed with error code FR_DISK_ERR"); + return; + case FR_INT_ERR: + PERR("f_lseek() failed with error code FR_INT_ERR"); + return; + case FR_NOT_READY: + PERR("f_lseek() failed with error code FR_NOT_READY"); + return; + case FR_INVALID_OBJECT: + PERR("f_lseek() failed with error code FR_INVALID_OBJECT"); + throw Invalid_handle(); + default: + /* not supposed to occur according to the libffat documentation */ + PERR("f_lseek() returned an unexpected error code"); + return; + } + + res = f_truncate(file->ffat_fil()); switch(res) { case FR_OK: return; case FR_INVALID_OBJECT: PERR("f_truncate() failed with error code FR_INVALID_OBJECT"); - return; + throw Invalid_handle(); case FR_DISK_ERR: PERR("f_truncate() failed with error code FR_DISK_ERR"); return; diff --git a/libports/src/test/libc_ffat/main.cc b/libports/src/test/libc_ffat/main.cc index e849b29e6..63e695684 100644 --- a/libports/src/test/libc_ffat/main.cc +++ b/libports/src/test/libc_ffat/main.cc @@ -47,6 +47,7 @@ int main(int argc, char *argv[]) char const *file_name = "test.tst"; char const *file_name2 = "test2.tst"; char const *file_name3 = "test3.tst"; + char const *file_name4 = "test4.tst"; char const *pattern = "a single line of text"; size_t pattern_size = strlen(pattern) + 1; @@ -165,6 +166,20 @@ int main(int argc, char *argv[]) } } + /* test 'ftruncate()' */ + CALL_AND_CHECK(fd, open(file_name4, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name4); + CALL_AND_CHECK(ret, ftruncate(fd, 100), ret == 0, ""); /* increase size */ + CALL_AND_CHECK(ret, close(fd), ret == 0, ""); + CALL_AND_CHECK(ret, stat(file_name4, &stat_buf), + (ret == 0) && (stat_buf.st_size == 100), + "file_name=%s", file_name4); + CALL_AND_CHECK(fd, open(file_name4, O_WRONLY), fd >= 0, "file_name=%s", file_name4); + CALL_AND_CHECK(ret, ftruncate(fd, 10), ret == 0, ""); /* decrease size */ + CALL_AND_CHECK(ret, close(fd), ret == 0, ""); + CALL_AND_CHECK(ret, stat(file_name4, &stat_buf), + (ret == 0) && (stat_buf.st_size == 10), + "file_name=%s", file_name4); + if (i < (iterations - 1)) sleep(2); } diff --git a/os/src/server/ram_fs/file.h b/os/src/server/ram_fs/file.h index 5260919ec..d17215b6a 100644 --- a/os/src/server/ram_fs/file.h +++ b/os/src/server/ram_fs/file.h @@ -88,6 +88,14 @@ namespace File_system { } file_size_t length() const { return _length; } + + void truncate(file_size_t size) + { + if (size < _chunk.used_size()) + _chunk.truncate(size); + else + _length = size; + } }; } diff --git a/os/src/server/ram_fs/main.cc b/os/src/server/ram_fs/main.cc index f68fb9a66..415ca3244 100644 --- a/os/src/server/ram_fs/main.cc +++ b/os/src/server/ram_fs/main.cc @@ -373,7 +373,15 @@ namespace File_system { destroy(env()->heap(), node); } - void truncate(File_handle, file_size_t size) { } + void truncate(File_handle file_handle, file_size_t size) + { + if (!_writable) + throw Permission_denied(); + + File *file = _handle_registry.lookup_and_lock(file_handle); + Node_lock_guard file_guard(*file); + file->truncate(size); + } void move(Dir_handle from_dir_handle, Name const &from_name, Dir_handle to_dir_handle, Name const &to_name) diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h index 7a4890063..2272702b2 100644 --- a/ports/include/noux_session/noux_session.h +++ b/ports/include/noux_session/noux_session.h @@ -40,6 +40,7 @@ namespace Noux { SYSCALL_STAT, SYSCALL_LSTAT, SYSCALL_FSTAT, + SYSCALL_FTRUNCATE, SYSCALL_FCNTL, SYSCALL_OPEN, SYSCALL_CLOSE, @@ -83,6 +84,7 @@ namespace Noux { NOUX_DECL_SYSCALL_NAME(STAT) NOUX_DECL_SYSCALL_NAME(LSTAT) NOUX_DECL_SYSCALL_NAME(FSTAT) + NOUX_DECL_SYSCALL_NAME(FTRUNCATE) NOUX_DECL_SYSCALL_NAME(FCNTL) NOUX_DECL_SYSCALL_NAME(OPEN) NOUX_DECL_SYSCALL_NAME(CLOSE) diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index 97406a6d1..0c145b007 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -271,126 +271,130 @@ namespace Noux { char ai_canonname[255]; }; - enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS }; - enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS }; - enum Fchdir_error { FCHDIR_ERR_NOT_DIR = NUM_GENERAL_ERRORS }; - enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS }; - enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM, - OPEN_ERR_EXISTS }; - enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS }; - enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM }; - enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS, - RENAME_ERR_NO_PERM }; - enum Mkdir_error { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY, - MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM, - MKDIR_ERR_NAME_TOO_LONG}; + enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS }; + enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS }; + enum Fchdir_error { FCHDIR_ERR_NOT_DIR = NUM_GENERAL_ERRORS }; + enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS }; + enum Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS }; + enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM, + OPEN_ERR_EXISTS }; + enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS }; + enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM }; + enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS, + RENAME_ERR_NO_PERM }; + enum Mkdir_error { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY, + MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM, + MKDIR_ERR_NAME_TOO_LONG}; union { - General_error general; - Stat_error stat; - Fchdir_error fchdir; - Fcntl_error fcntl; - Open_error open; - Execve_error execve; - Unlink_error unlink; - Rename_error rename; - Mkdir_error mkdir; + General_error general; + Stat_error stat; + Fchdir_error fchdir; + Fcntl_error fcntl; + Ftruncate_error ftruncate; + Open_error open; + Execve_error execve; + Unlink_error unlink; + Rename_error rename; + Mkdir_error mkdir; } error; union { - SYSIO_DECL(getcwd, { }, { Path path; }); + SYSIO_DECL(getcwd, { }, { Path path; }); - SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; }, - { size_t count; }); + SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; }, + { size_t count; }); - SYSIO_DECL(stat, { Path path; }, { Stat st; }); + SYSIO_DECL(stat, { Path path; }, { Stat st; }); - SYSIO_DECL(fstat, { int fd; }, { Stat st; }); + SYSIO_DECL(fstat, { int fd; }, { Stat st; }); - SYSIO_DECL(fcntl, { int fd; long long_arg; Fcntl_cmd cmd; }, - { int result; }); + SYSIO_DECL(ftruncate, { int fd; off_t length; }, { }); - SYSIO_DECL(open, { Path path; int mode; }, { int fd; }); + SYSIO_DECL(fcntl, { int fd; long long_arg; Fcntl_cmd cmd; }, + { int result; }); - SYSIO_DECL(close, { int fd; }, { }); + SYSIO_DECL(open, { Path path; int mode; }, { int fd; }); - SYSIO_DECL(ioctl, : Ioctl_in { int fd; }, : Ioctl_out { }); + SYSIO_DECL(close, { int fd; }, { }); - SYSIO_DECL(lseek, { int fd; off_t offset; Lseek_whence whence; }, - { off_t offset; }); + SYSIO_DECL(ioctl, : Ioctl_in { int fd; }, : Ioctl_out { }); - SYSIO_DECL(dirent, { int fd; }, { Dirent entry; }); + SYSIO_DECL(lseek, { int fd; off_t offset; Lseek_whence whence; }, + { off_t offset; }); - SYSIO_DECL(fchdir, { int fd; }, { }); + SYSIO_DECL(dirent, { int fd; }, { Dirent entry; }); - SYSIO_DECL(read, { int fd; size_t count; }, - { Chunk chunk; size_t count; }); + SYSIO_DECL(fchdir, { int fd; }, { }); - SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { }); + SYSIO_DECL(read, { int fd; size_t count; }, + { Chunk chunk; size_t count; }); - SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; }, - { Select_fds fds; }); + SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { }); - SYSIO_DECL(fork, { addr_t ip; addr_t sp; - addr_t parent_cap_addr; }, - { int pid; }); + SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; }, + { Select_fds fds; }); - SYSIO_DECL(getpid, { }, { int pid; }); + SYSIO_DECL(fork, { addr_t ip; addr_t sp; + addr_t parent_cap_addr; }, + { int pid; }); - SYSIO_DECL(wait4, { int pid; bool nohang; }, - { int pid; int status; }); - SYSIO_DECL(pipe, { }, { int fd[2]; }); + SYSIO_DECL(getpid, { }, { int pid; }); - SYSIO_DECL(dup2, { int fd; int to_fd; }, { }); + SYSIO_DECL(wait4, { int pid; bool nohang; }, + { int pid; int status; }); + SYSIO_DECL(pipe, { }, { int fd[2]; }); - SYSIO_DECL(unlink, { Path path; }, { }); + SYSIO_DECL(dup2, { int fd; int to_fd; }, { }); - SYSIO_DECL(rename, { Path from_path; Path to_path; }, { }); + SYSIO_DECL(unlink, { Path path; }, { }); - SYSIO_DECL(mkdir, { Path path; int mode; }, { }); + SYSIO_DECL(rename, { Path from_path; Path to_path; }, { }); - SYSIO_DECL(socket, { int domain; int type; int protocol; }, - { int fd; }); + SYSIO_DECL(mkdir, { Path path; int mode; }, { }); + + SYSIO_DECL(socket, { int domain; int type; int protocol; }, + { int fd; }); /* XXX for now abuse Chunk for passing optval */ - SYSIO_DECL(getsockopt, { int fd; int level; int optname; Chunk optval; - socklen_t optlen; }, { int result; }); + SYSIO_DECL(getsockopt, { int fd; int level; int optname; Chunk optval; + socklen_t optlen; }, { int result; }); - SYSIO_DECL(setsockopt, { int fd; int level; - int optname; Chunk optval; - socklen_t optlen; }, { }); + SYSIO_DECL(setsockopt, { int fd; int level; + int optname; Chunk optval; + socklen_t optlen; }, { }); - SYSIO_DECL(accept, { int fd; struct sockaddr addr; socklen_t addrlen; }, - { int fd; }); + SYSIO_DECL(accept, { int fd; struct sockaddr addr; socklen_t addrlen; }, + { int fd; }); - SYSIO_DECL(bind, { int fd; struct sockaddr addr; - socklen_t addrlen; }, { int result; }); + SYSIO_DECL(bind, { int fd; struct sockaddr addr; + socklen_t addrlen; }, { int result; }); SYSIO_DECL(getpeername, { int fd; struct sockaddr addr; socklen_t addrlen; }, { }); - SYSIO_DECL(listen, { int fd; int type; int backlog; }, - { int result; }); + SYSIO_DECL(listen, { int fd; int type; int backlog; }, + { int result; }); - SYSIO_DECL(send, { int fd; Chunk buf; size_t len; int flags; }, - { ssize_t len; }); + SYSIO_DECL(send, { int fd; Chunk buf; size_t len; int flags; }, + { ssize_t len; }); - SYSIO_DECL(sendto, { int fd; Chunk buf; size_t len; int flags; - struct sockaddr dest_addr; socklen_t addrlen; }, - { ssize_t len; }); + SYSIO_DECL(sendto, { int fd; Chunk buf; size_t len; int flags; + struct sockaddr dest_addr; socklen_t addrlen; }, + { ssize_t len; }); - SYSIO_DECL(recv, { int fd; Chunk buf; size_t len; int flags; }, - { size_t len; }); + SYSIO_DECL(recv, { int fd; Chunk buf; size_t len; int flags; }, + { size_t len; }); - SYSIO_DECL(recvfrom, { int fd; Chunk buf; size_t len; int flags; - struct sockaddr src_addr; socklen_t addrlen; }, - { size_t len; }); + SYSIO_DECL(recvfrom, { int fd; Chunk buf; size_t len; int flags; + struct sockaddr src_addr; socklen_t addrlen; }, + { size_t len; }); - SYSIO_DECL(shutdown, { int fd; int how; }, { }); + SYSIO_DECL(shutdown, { int fd; int how; }, { }); - SYSIO_DECL(connect, { int fd; struct sockaddr addr; socklen_t addrlen; }, - { int result; }); + SYSIO_DECL(connect, { int fd; struct sockaddr addr; socklen_t addrlen; }, + { int result; }); SYSIO_DECL(getaddrinfo, { Hostname hostname; Servname servname; Addrinfo hints; diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 7bae6304e..e3dff63d6 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -552,6 +552,7 @@ namespace { int fstat(Libc::File_descriptor *, struct stat *); int fsync(Libc::File_descriptor *); int fstatfs(Libc::File_descriptor *, struct statfs *); + int ftruncate(Libc::File_descriptor *, ::off_t); int fcntl(Libc::File_descriptor *, int, long); ssize_t getdirentries(Libc::File_descriptor *, char *, ::size_t, ::off_t *); ::off_t lseek(Libc::File_descriptor *, ::off_t offset, int whence); @@ -855,6 +856,21 @@ namespace { } + int Plugin::ftruncate(Libc::File_descriptor *fd, ::off_t length) + { + sysio()->ftruncate_in.fd = noux_fd(fd->context); + sysio()->ftruncate_in.length = length; + if (!noux()->syscall(Noux::Session::SYSCALL_FTRUNCATE)) { + switch (sysio()->error.ftruncate) { + case Noux::Sysio::FTRUNCATE_ERR_NO_PERM: errno = EPERM; break; + } + return -1; + } + + return 0; + } + + int Plugin::fcntl(Libc::File_descriptor *fd, int cmd, long arg) { /* copy arguments to sysio */ diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h index 5572f9973..81e0973fc 100644 --- a/ports/src/noux/dir_file_system.h +++ b/ports/src/noux/dir_file_system.h @@ -518,6 +518,7 @@ namespace Noux { bool write(Sysio *sysio, Vfs_handle *handle) { return false; } bool read(Sysio *sysio, Vfs_handle *vfs_handle) { return false; } + bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return false; } }; } diff --git a/ports/src/noux/file_io_service.h b/ports/src/noux/file_io_service.h index 68268f7cd..2147c2260 100644 --- a/ports/src/noux/file_io_service.h +++ b/ports/src/noux/file_io_service.h @@ -24,8 +24,9 @@ namespace Noux { */ struct File_io_service { - virtual bool write(Sysio *sysio, Vfs_handle *vfs_handle) = 0; - virtual bool read(Sysio *sysio, Vfs_handle *vfs_handle) = 0; + virtual bool write(Sysio *sysio, Vfs_handle *vfs_handle) = 0; + virtual bool read(Sysio *sysio, Vfs_handle *vfs_handle) = 0; + virtual bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) = 0; }; } diff --git a/ports/src/noux/fs_file_system.h b/ports/src/noux/fs_file_system.h index 8277a8a89..a90c4c0d7 100644 --- a/ports/src/noux/fs_file_system.h +++ b/ports/src/noux/fs_file_system.h @@ -516,6 +516,27 @@ namespace Noux { source.release_packet(packet); return true; } + + bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) + { + Fs_vfs_handle const *handle = static_cast(vfs_handle); + + Sysio::Ftruncate_error error; + + try { + _fs.truncate(handle->file_handle(), sysio->ftruncate_in.length); + return true; + } catch (::File_system::Invalid_handle) { + /* should not happen */ + error = Sysio::FTRUNCATE_ERR_NO_PERM; + } catch (::File_system::Permission_denied) { + error = Sysio::FTRUNCATE_ERR_NO_PERM; + } + + sysio->error.ftruncate = error; + return false; + } + }; } diff --git a/ports/src/noux/io_channel.h b/ports/src/noux/io_channel.h index 9f5b3e7bf..e473cb7a8 100644 --- a/ports/src/noux/io_channel.h +++ b/ports/src/noux/io_channel.h @@ -50,14 +50,15 @@ namespace Noux { virtual ~Io_channel() { } - virtual bool write(Sysio *sysio, size_t &count) { return false; } - virtual bool read(Sysio *sysio) { return false; } - virtual bool fstat(Sysio *sysio) { return false; } - virtual bool fcntl(Sysio *sysio) { return false; } - virtual bool fchdir(Sysio *sysio, Pwd *pwd) { return false; } - virtual bool dirent(Sysio *sysio) { return false; } - virtual bool ioctl(Sysio *sysio) { return false; } - virtual bool lseek(Sysio *sysio) { return false; } + virtual bool write(Sysio *sysio, size_t &count) { return false; } + virtual bool read(Sysio *sysio) { return false; } + virtual bool fstat(Sysio *sysio) { return false; } + virtual bool ftruncate(Sysio *sysio) { return false; } + virtual bool fcntl(Sysio *sysio) { return false; } + virtual bool fchdir(Sysio *sysio, Pwd *pwd) { return false; } + virtual bool dirent(Sysio *sysio) { return false; } + virtual bool ioctl(Sysio *sysio) { return false; } + virtual bool lseek(Sysio *sysio) { return false; } /** * Return true if an unblocking condition of the channel is satisfied diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index 87a9c23f1..acd16eb40 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -121,6 +121,16 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) return true; } + case SYSCALL_FTRUNCATE: + { + Shared_pointer io = _lookup_channel(_sysio->ftruncate_in.fd); + + while (!io->check_unblock(true, false, false)) + _block_for_io_channel(io); + + return io->ftruncate(_sysio); + } + case SYSCALL_STAT: case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */ diff --git a/ports/src/noux/tar_file_system.h b/ports/src/noux/tar_file_system.h index 02f0078ee..fa4aaf56e 100644 --- a/ports/src/noux/tar_file_system.h +++ b/ports/src/noux/tar_file_system.h @@ -468,6 +468,12 @@ namespace Noux { sysio->read_out.count = count; return true; } + + bool ftruncate(Sysio *sysio, Vfs_handle *handle) + { + PDBG("called\n"); + return false; + } }; } diff --git a/ports/src/noux/terminal_file_system.h b/ports/src/noux/terminal_file_system.h index de0669750..36b500832 100644 --- a/ports/src/noux/terminal_file_system.h +++ b/ports/src/noux/terminal_file_system.h @@ -204,6 +204,8 @@ namespace Noux { sysio->read_out.count = _terminal.read(sysio->read_out.chunk, sysio->read_in.count); return true; } + + bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return false; } }; } diff --git a/ports/src/noux/vfs_handle.h b/ports/src/noux/vfs_handle.h index cf3b1d223..5ac9dcae5 100644 --- a/ports/src/noux/vfs_handle.h +++ b/ports/src/noux/vfs_handle.h @@ -74,8 +74,9 @@ namespace Noux { static bool _msg(char const *sc) { PERR("%s not supported by file system", sc); return false; } - bool write(Sysio *sysio, Vfs_handle *handle) { return _msg("write"); } - bool read(Sysio *sysio, Vfs_handle *handle) { return _msg("read"); } + bool write(Sysio *sysio, Vfs_handle *handle) { return _msg("write"); } + bool read(Sysio *sysio, Vfs_handle *handle) { return _msg("read"); } + bool ftruncate(Sysio *sysio, Vfs_handle *handle) { return _msg("ftruncate"); } }; static Pseudo_file_io_service fs; return &fs; diff --git a/ports/src/noux/vfs_io_channel.h b/ports/src/noux/vfs_io_channel.h index f6f731504..10bfd32b2 100644 --- a/ports/src/noux/vfs_io_channel.h +++ b/ports/src/noux/vfs_io_channel.h @@ -65,6 +65,11 @@ namespace Noux { return result; } + bool ftruncate(Sysio *sysio) + { + return _fh->fs()->ftruncate(sysio, _fh); + } + bool fcntl(Sysio *sysio) { switch (sysio->fcntl_in.cmd) {