Compare commits
No commits in common. "b54a7f3a802089b117bbec4e6ef6972d27d03936" and "7e655e320ac520b06e4e9076b6fdfb5a740a1e62" have entirely different histories.
b54a7f3a80
...
7e655e320a
@ -14,7 +14,7 @@ int main()
|
|||||||
atexit(bye);
|
atexit(bye);
|
||||||
printf("Welcome to %s from userspace (pid %d)!\n", "Luna", getpid());
|
printf("Welcome to %s from userspace (pid %d)!\n", "Luna", getpid());
|
||||||
|
|
||||||
int fd = open("/etc/motd", O_RDONLY);
|
int fd = open("/etc/motd", 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
perror("open");
|
perror("open");
|
||||||
|
@ -26,8 +26,6 @@ namespace VFS
|
|||||||
|
|
||||||
virtual Result<usize> write(const u8* buf, usize offset, usize length) = 0;
|
virtual Result<usize> write(const u8* buf, usize offset, usize length) = 0;
|
||||||
|
|
||||||
virtual Result<void> truncate(usize size) = 0;
|
|
||||||
|
|
||||||
// Generic methods
|
// Generic methods
|
||||||
virtual FileSystem& fs() const = 0;
|
virtual FileSystem& fs() const = 0;
|
||||||
|
|
||||||
|
@ -118,15 +118,4 @@ namespace TmpFS
|
|||||||
|
|
||||||
return length;
|
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,8 +63,6 @@ namespace TmpFS
|
|||||||
|
|
||||||
Result<usize> write(const u8*, usize, usize) override;
|
Result<usize> write(const u8*, usize, usize) override;
|
||||||
|
|
||||||
Result<void> truncate(usize size) override;
|
|
||||||
|
|
||||||
virtual ~FileInode() = default;
|
virtual ~FileInode() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -105,11 +103,6 @@ namespace TmpFS
|
|||||||
return err(EISDIR);
|
return err(EISDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
|
||||||
{
|
|
||||||
return err(EISDIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS::FileSystem& fs() const override
|
VFS::FileSystem& fs() const override
|
||||||
{
|
{
|
||||||
return *m_fs;
|
return *m_fs;
|
||||||
|
@ -15,15 +15,17 @@ Result<u64> sys_read(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
if (!MemoryManager::validate_user_write(buf, size)) return err(EFAULT);
|
if (!MemoryManager::validate_user_write(buf, size)) return err(EFAULT);
|
||||||
|
|
||||||
|
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
Option<FileDescriptor>& descriptor = current->fd_table->fds[fd];
|
||||||
|
|
||||||
if (!descriptor.is_readable()) return err(EBADF);
|
if (!descriptor.has_value()) return err(EBADF);
|
||||||
|
|
||||||
usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size));
|
usize nread = TRY(descriptor->inode->read(buf, descriptor->offset, size));
|
||||||
|
|
||||||
descriptor.offset += nread;
|
descriptor->offset += nread;
|
||||||
|
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
@ -36,17 +38,17 @@ Result<u64> sys_write(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
if (!MemoryManager::validate_user_read(buf, size)) return err(EFAULT);
|
if (!MemoryManager::validate_user_read(buf, size)) return err(EFAULT);
|
||||||
|
|
||||||
|
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
Option<FileDescriptor>& descriptor = current->fd_table->fds[fd];
|
||||||
|
|
||||||
if (!descriptor.is_writable()) return err(EBADF);
|
if (!descriptor.has_value()) return err(EBADF);
|
||||||
|
|
||||||
if (descriptor.should_append()) todo();
|
usize nwritten = TRY(descriptor->inode->write(buf, descriptor->offset, size));
|
||||||
|
|
||||||
usize nwritten = TRY(descriptor.inode->write(buf, descriptor.offset, size));
|
descriptor->offset += nwritten;
|
||||||
|
|
||||||
descriptor.offset += nwritten;
|
|
||||||
|
|
||||||
return nwritten;
|
return nwritten;
|
||||||
}
|
}
|
||||||
@ -57,23 +59,27 @@ Result<u64> sys_lseek(Registers*, SyscallArgs args)
|
|||||||
off_t offset = (long)args[1];
|
off_t offset = (long)args[1];
|
||||||
int whence = (int)args[2];
|
int whence = (int)args[2];
|
||||||
|
|
||||||
|
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
Option<FileDescriptor>& descriptor = current->fd_table->fds[fd];
|
||||||
|
|
||||||
|
if (!descriptor.has_value()) return err(EBADF);
|
||||||
|
|
||||||
off_t new_offset;
|
off_t new_offset;
|
||||||
|
|
||||||
switch (whence)
|
switch (whence)
|
||||||
{
|
{
|
||||||
case SEEK_SET: new_offset = offset; break;
|
case SEEK_SET: new_offset = offset; break;
|
||||||
case SEEK_CUR: new_offset = TRY(safe_add((long)descriptor.offset, offset)); break;
|
case SEEK_CUR: new_offset = TRY(safe_add((long)descriptor->offset, offset)); break;
|
||||||
case SEEK_END: todo();
|
case SEEK_END: todo();
|
||||||
default: return err(EINVAL);
|
default: return err(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_offset < 0) return err(EINVAL);
|
if (new_offset < 0) return err(EINVAL);
|
||||||
|
|
||||||
descriptor.offset = (usize)new_offset;
|
descriptor->offset = (usize)new_offset;
|
||||||
|
|
||||||
return (u64)new_offset;
|
return (u64)new_offset;
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,6 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.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)
|
Result<u64> sys_open(Registers*, SyscallArgs args)
|
||||||
{
|
{
|
||||||
@ -20,28 +16,11 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
kinfoln("open: trying to open file %s, flags %d", path, flags);
|
kinfoln("open: trying to open file %s, flags %d", path, flags);
|
||||||
|
|
||||||
SharedPtr<VFS::Inode> inode;
|
auto inode = TRY(VFS::resolve_path(path));
|
||||||
|
|
||||||
// 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));
|
int fd = TRY(current->allocate_fd(0));
|
||||||
|
|
||||||
current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP };
|
current->fd_table->fds[fd] = FileDescriptor { inode, 0, flags };
|
||||||
|
|
||||||
kinfoln("open: allocated file descriptor %d for inode %zu", fd, inode->inode_number());
|
kinfoln("open: allocated file descriptor %d for inode %zu", fd, inode->inode_number());
|
||||||
|
|
||||||
@ -55,7 +34,7 @@ Result<u64> sys_close(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
Option<FileDescriptor>& descriptor = current->fd_table[fd];
|
Option<FileDescriptor>& descriptor = current->fd_table->fds[fd];
|
||||||
|
|
||||||
if (!descriptor.has_value()) return err(EBADF);
|
if (!descriptor.has_value()) return err(EBADF);
|
||||||
|
|
||||||
|
@ -151,6 +151,8 @@ namespace Scheduler
|
|||||||
guard.deactivate();
|
guard.deactivate();
|
||||||
directory_guard.deactivate();
|
directory_guard.deactivate();
|
||||||
|
|
||||||
|
thread->fd_table = FileDescriptorTable {};
|
||||||
|
|
||||||
kinfoln("Created userspace thread: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(),
|
kinfoln("Created userspace thread: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(),
|
||||||
thread->sp(), thread->kernel_stack.top());
|
thread->sp(), thread->kernel_stack.top());
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "thread/Thread.h"
|
#include "thread/Thread.h"
|
||||||
#include <bits/open-flags.h>
|
|
||||||
#include <luna/Alloc.h>
|
#include <luna/Alloc.h>
|
||||||
#include <luna/Atomic.h>
|
#include <luna/Atomic.h>
|
||||||
|
|
||||||
@ -28,34 +27,8 @@ Result<int> Thread::allocate_fd(int min)
|
|||||||
{
|
{
|
||||||
// FIXME: Possible race condition if multiple threads share a FileDescriptorTable? Let's not worry about it for
|
// FIXME: Possible race condition if multiple threads share a FileDescriptorTable? Let's not worry about it for
|
||||||
// now, we're still a long way away from reaching that point.
|
// now, we're still a long way away from reaching that point.
|
||||||
if (!fd_table[i].has_value()) { return i; }
|
if (!fd_table->fds[i].has_value()) { return i; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return err(EMFILE);
|
return err(EMFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<FileDescriptor*> Thread::resolve_fd(int fd)
|
|
||||||
{
|
|
||||||
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
|
|
||||||
|
|
||||||
Option<FileDescriptor>& maybe_descriptor = fd_table[fd];
|
|
||||||
|
|
||||||
if (!maybe_descriptor.has_value()) return err(EBADF);
|
|
||||||
|
|
||||||
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,14 +27,15 @@ struct FileDescriptor
|
|||||||
SharedPtr<VFS::Inode> inode;
|
SharedPtr<VFS::Inode> inode;
|
||||||
usize offset { 0 };
|
usize offset { 0 };
|
||||||
int flags { 0 };
|
int flags { 0 };
|
||||||
|
|
||||||
bool should_append();
|
|
||||||
bool is_writable();
|
|
||||||
bool is_readable();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr int FD_MAX = 64;
|
static constexpr int FD_MAX = 64;
|
||||||
|
|
||||||
|
struct FileDescriptorTable
|
||||||
|
{
|
||||||
|
Option<FileDescriptor> fds[FD_MAX] = {};
|
||||||
|
};
|
||||||
|
|
||||||
struct Thread : public LinkedListNode<Thread>
|
struct Thread : public LinkedListNode<Thread>
|
||||||
{
|
{
|
||||||
Registers regs;
|
Registers regs;
|
||||||
@ -52,10 +53,9 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
Stack kernel_stack;
|
Stack kernel_stack;
|
||||||
|
|
||||||
OwnedPtr<UserVM> vm_allocator;
|
OwnedPtr<UserVM> vm_allocator;
|
||||||
Option<FileDescriptor> fd_table[FD_MAX] = {};
|
Option<FileDescriptorTable> fd_table;
|
||||||
|
|
||||||
Result<int> allocate_fd(int min);
|
Result<int> allocate_fd(int min);
|
||||||
Result<FileDescriptor*> resolve_fd(int fd);
|
|
||||||
|
|
||||||
FPData fp_data;
|
FPData fp_data;
|
||||||
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
/* 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,8 +3,6 @@
|
|||||||
#ifndef _FCNTL_H
|
#ifndef _FCNTL_H
|
||||||
#define _FCNTL_H
|
#define _FCNTL_H
|
||||||
|
|
||||||
#include <bits/open-flags.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,7 @@ extern "C"
|
|||||||
FILE* fopen(const char* path, const char*)
|
FILE* fopen(const char* path, const char*)
|
||||||
{
|
{
|
||||||
// FIXME: Parse the mode string.
|
// FIXME: Parse the mode string.
|
||||||
int fd = open(path, O_RDWR);
|
int fd = open(path, 0);
|
||||||
if (fd < 0) return nullptr;
|
if (fd < 0) return nullptr;
|
||||||
|
|
||||||
FILE* f = (FILE*)malloc(sizeof(FILE));
|
FILE* f = (FILE*)malloc(sizeof(FILE));
|
||||||
|
@ -116,18 +116,6 @@ template <typename T> class Option
|
|||||||
return &m_storage.fetch_reference();
|
return &m_storage.fetch_reference();
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator*()
|
|
||||||
{
|
|
||||||
expect(has_value(), "Option::operator* called on an empty Option");
|
|
||||||
return m_storage.fetch_reference();
|
|
||||||
}
|
|
||||||
|
|
||||||
T* value_ptr(SourceLocation caller = SourceLocation::current())
|
|
||||||
{
|
|
||||||
expect_at(has_value(), caller, "Option::value_ptr called on an empty Option");
|
|
||||||
return &m_storage.fetch_reference();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Option()
|
~Option()
|
||||||
{
|
{
|
||||||
if (has_value()) m_storage.destroy();
|
if (has_value()) m_storage.destroy();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user