kernel+libc: Add O_* flags and parse them in open()
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
O_RDONLY, O_WRONLY, O_RDWR, O_TRUNC, O_CREAT and O_EXCL are fully implemented. O_APPEND is partially implemented. Other flags are not here yet.
This commit is contained in:
parent
bd572473ad
commit
b54a7f3a80
@ -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");
|
||||
|
@ -26,6 +26,8 @@ namespace VFS
|
||||
|
||||
virtual Result<usize> write(const u8* buf, usize offset, usize length) = 0;
|
||||
|
||||
virtual Result<void> truncate(usize size) = 0;
|
||||
|
||||
// Generic methods
|
||||
virtual FileSystem& fs() const = 0;
|
||||
|
||||
|
@ -118,4 +118,15 @@ namespace TmpFS
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
Result<void> 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 {};
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,8 @@ namespace TmpFS
|
||||
|
||||
Result<usize> write(const u8*, usize, usize) override;
|
||||
|
||||
Result<void> truncate(usize size) override;
|
||||
|
||||
virtual ~FileInode() = default;
|
||||
|
||||
private:
|
||||
@ -103,6 +105,11 @@ namespace TmpFS
|
||||
return err(EISDIR);
|
||||
}
|
||||
|
||||
Result<void> truncate(usize) override
|
||||
{
|
||||
return err(EISDIR);
|
||||
}
|
||||
|
||||
VFS::FileSystem& fs() const override
|
||||
{
|
||||
return *m_fs;
|
||||
|
@ -19,6 +19,8 @@ Result<u64> 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<u64> 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;
|
||||
|
@ -3,6 +3,10 @@
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "sys/Syscall.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include <bits/open-flags.h>
|
||||
|
||||
// These flags are needed after open(), the rest only affect open().
|
||||
constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND;
|
||||
|
||||
Result<u64> sys_open(Registers*, SyscallArgs args)
|
||||
{
|
||||
@ -16,11 +20,28 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
|
||||
|
||||
kinfoln("open: trying to open file %s, flags %d", path, flags);
|
||||
|
||||
auto inode = TRY(VFS::resolve_path(path));
|
||||
SharedPtr<VFS::Inode> 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());
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "thread/Thread.h"
|
||||
#include <bits/open-flags.h>
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/Atomic.h>
|
||||
|
||||
@ -43,3 +44,18 @@ Result<FileDescriptor*> 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;
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ struct FileDescriptor
|
||||
SharedPtr<VFS::Inode> inode;
|
||||
usize offset { 0 };
|
||||
int flags { 0 };
|
||||
|
||||
bool should_append();
|
||||
bool is_writable();
|
||||
bool is_readable();
|
||||
};
|
||||
|
||||
static constexpr int FD_MAX = 64;
|
||||
|
14
libc/include/bits/open-flags.h
Normal file
14
libc/include/bits/open-flags.h
Normal file
@ -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
|
@ -3,6 +3,8 @@
|
||||
#ifndef _FCNTL_H
|
||||
#define _FCNTL_H
|
||||
|
||||
#include <bits/open-flags.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user