diff --git a/apps/app.c b/apps/app.c index ea977091..3794c0e6 100644 --- a/apps/app.c +++ b/apps/app.c @@ -14,7 +14,7 @@ int main() atexit(bye); printf("Welcome to %s from userspace (pid %d)!\n", "Luna", getpid()); - int fd = open("/etc/motd", 0); + int fd = open("/etc/motd", O_RDONLY); if (fd < 0) { perror("open"); diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index b2e26326..c01c2db1 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -26,6 +26,8 @@ namespace VFS virtual Result write(const u8* buf, usize offset, usize length) = 0; + virtual Result truncate(usize size) = 0; + // Generic methods virtual FileSystem& fs() const = 0; diff --git a/kernel/src/fs/tmpfs/FileSystem.cpp b/kernel/src/fs/tmpfs/FileSystem.cpp index a31fd707..ccd8b152 100644 --- a/kernel/src/fs/tmpfs/FileSystem.cpp +++ b/kernel/src/fs/tmpfs/FileSystem.cpp @@ -118,4 +118,15 @@ namespace TmpFS return length; } + + Result FileInode::truncate(usize size) + { + usize old_size = m_data_buffer.size(); + + TRY(m_data_buffer.try_resize(size)); + + if (size > old_size) memset(m_data_buffer.data() + old_size, 0, size - old_size); + + return {}; + } } diff --git a/kernel/src/fs/tmpfs/FileSystem.h b/kernel/src/fs/tmpfs/FileSystem.h index 8e029eb4..0a217486 100644 --- a/kernel/src/fs/tmpfs/FileSystem.h +++ b/kernel/src/fs/tmpfs/FileSystem.h @@ -63,6 +63,8 @@ namespace TmpFS Result write(const u8*, usize, usize) override; + Result truncate(usize size) override; + virtual ~FileInode() = default; private: @@ -103,6 +105,11 @@ namespace TmpFS return err(EISDIR); } + Result truncate(usize) override + { + return err(EISDIR); + } + VFS::FileSystem& fs() const override { return *m_fs; diff --git a/kernel/src/sys/file.cpp b/kernel/src/sys/file.cpp index 9c7979bb..65c886e9 100644 --- a/kernel/src/sys/file.cpp +++ b/kernel/src/sys/file.cpp @@ -19,6 +19,8 @@ Result sys_read(Registers*, SyscallArgs args) auto& descriptor = *TRY(current->resolve_fd(fd)); + if (!descriptor.is_readable()) return err(EBADF); + usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size)); descriptor.offset += nread; @@ -38,6 +40,10 @@ Result sys_write(Registers*, SyscallArgs args) auto& descriptor = *TRY(current->resolve_fd(fd)); + if (!descriptor.is_writable()) return err(EBADF); + + if (descriptor.should_append()) todo(); + usize nwritten = TRY(descriptor.inode->write(buf, descriptor.offset, size)); descriptor.offset += nwritten; diff --git a/kernel/src/sys/open.cpp b/kernel/src/sys/open.cpp index f5cb7a0c..0fb0d481 100644 --- a/kernel/src/sys/open.cpp +++ b/kernel/src/sys/open.cpp @@ -3,6 +3,10 @@ #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" +#include + +// These flags are needed after open(), the rest only affect open(). +constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND; Result sys_open(Registers*, SyscallArgs args) { @@ -16,11 +20,28 @@ Result sys_open(Registers*, SyscallArgs args) kinfoln("open: trying to open file %s, flags %d", path, flags); - auto inode = TRY(VFS::resolve_path(path)); + SharedPtr inode; + + // Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR + if ((flags & O_RDWR) == 0) { return err(EINVAL); } + + auto maybe_inode = VFS::resolve_path(path); + if (maybe_inode.has_error()) + { + if (maybe_inode.error() == ENOENT && (flags & O_CREAT)) inode = TRY(VFS::create_file(path)); + else + return maybe_inode.release_error(); + } + else if (flags & O_EXCL) + return err(EEXIST); + else + inode = maybe_inode.release_value(); + + if ((flags & O_WRONLY) && (flags & O_TRUNC)) inode->truncate(0); int fd = TRY(current->allocate_fd(0)); - current->fd_table[fd] = FileDescriptor { inode, 0, flags }; + current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP }; kinfoln("open: allocated file descriptor %d for inode %zu", fd, inode->inode_number()); diff --git a/kernel/src/thread/Thread.cpp b/kernel/src/thread/Thread.cpp index f01c70c0..f2992adc 100644 --- a/kernel/src/thread/Thread.cpp +++ b/kernel/src/thread/Thread.cpp @@ -1,4 +1,5 @@ #include "thread/Thread.h" +#include #include #include @@ -43,3 +44,18 @@ Result Thread::resolve_fd(int fd) return maybe_descriptor.value_ptr(); } + +bool FileDescriptor::should_append() +{ + return flags & O_APPEND; +} + +bool FileDescriptor::is_readable() +{ + return flags & O_RDONLY; +} + +bool FileDescriptor::is_writable() +{ + return flags & O_WRONLY; +} diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 58787351..5f745012 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -27,6 +27,10 @@ struct FileDescriptor SharedPtr inode; usize offset { 0 }; int flags { 0 }; + + bool should_append(); + bool is_writable(); + bool is_readable(); }; static constexpr int FD_MAX = 64; diff --git a/libc/include/bits/open-flags.h b/libc/include/bits/open-flags.h new file mode 100644 index 00000000..bfdfda2a --- /dev/null +++ b/libc/include/bits/open-flags.h @@ -0,0 +1,14 @@ +/* bits/open-flags.h: O_* constants for open(). */ + +#ifndef _BITS_OPEN_FLAGS_H +#define _BITS_OPEN_FLAGS_H + +#define O_RDONLY 1 +#define O_WRONLY 2 +#define O_RDWR 3 +#define O_APPEND 4 +#define O_CREAT 8 +#define O_EXCL 16 +#define O_TRUNC 32 + +#endif diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index 401f936b..b6760cf2 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -3,6 +3,8 @@ #ifndef _FCNTL_H #define _FCNTL_H +#include + #ifdef __cplusplus extern "C" { diff --git a/libc/src/stdio.cpp b/libc/src/stdio.cpp index 6ccc932e..be4210f1 100644 --- a/libc/src/stdio.cpp +++ b/libc/src/stdio.cpp @@ -21,7 +21,7 @@ extern "C" FILE* fopen(const char* path, const char*) { // FIXME: Parse the mode string. - int fd = open(path, 0); + int fd = open(path, O_RDWR); if (fd < 0) return nullptr; FILE* f = (FILE*)malloc(sizeof(FILE));