diff --git a/AK/BufferStream.h b/AK/BufferStream.h index 29da0b7a5f..db2907963f 100644 --- a/AK/BufferStream.h +++ b/AK/BufferStream.h @@ -1,6 +1,7 @@ #pragma once -#include "ByteBuffer.h" +#include +#include namespace AK { diff --git a/Kernel/File.h b/Kernel/File.h index 7e8ead39c3..9daa97ca79 100644 --- a/Kernel/File.h +++ b/Kernel/File.h @@ -6,6 +6,7 @@ #include #include #include +#include class FileDescriptor; class Process; @@ -28,10 +29,13 @@ public: virtual String absolute_path(FileDescriptor&) const = 0; + virtual KResult truncate(off_t) { return KResult(-EINVAL); } + virtual const char* class_name() const = 0; virtual bool is_seekable() const { return false; } + virtual bool is_inode() const { return false; } virtual bool is_shared_memory() const { return false; } virtual bool is_fifo() const { return false; } virtual bool is_device() const { return false; } diff --git a/Kernel/FileSystem/FileDescriptor.cpp b/Kernel/FileSystem/FileDescriptor.cpp index 24074afdc0..e76f7d7b6a 100644 --- a/Kernel/FileSystem/FileDescriptor.cpp +++ b/Kernel/FileSystem/FileDescriptor.cpp @@ -1,21 +1,22 @@ -#include "FileDescriptor.h" -#include -#include -#include -#include "UnixTypes.h" #include +#include +#include #include -#include -#include +#include +#include +#include #include #include -#include -#include #include +#include +#include +#include +#include +#include Retained FileDescriptor::create(RetainPtr&& inode) { - return adopt(*new FileDescriptor(move(inode))); + return adopt(*new FileDescriptor(InodeFile::create(*inode))); } Retained FileDescriptor::create(RetainPtr&& file, SocketRole role) @@ -23,14 +24,11 @@ Retained FileDescriptor::create(RetainPtr&& file, SocketRo return adopt(*new FileDescriptor(move(file), role)); } -FileDescriptor::FileDescriptor(RetainPtr&& inode) - : m_inode(move(inode)) -{ -} - FileDescriptor::FileDescriptor(RetainPtr&& file, SocketRole role) : m_file(move(file)) { + if (m_file->is_inode()) + m_inode = static_cast(*m_file).inode(); set_socket_role(role); } @@ -40,10 +38,8 @@ FileDescriptor::~FileDescriptor() socket()->detach(*this); if (is_fifo()) static_cast(m_file.ptr())->detach(m_fifo_direction); - if (m_file) { - m_file->close(); - m_file = nullptr; - } + m_file->close(); + m_file = nullptr; m_inode = nullptr; } @@ -65,12 +61,8 @@ Retained FileDescriptor::clone() if (is_fifo()) { descriptor = fifo()->open_direction(m_fifo_direction); } else { - if (m_file) { - descriptor = FileDescriptor::create(m_file.copy_ref(), m_socket_role); - descriptor->m_inode = m_inode.copy_ref(); - } else { - descriptor = FileDescriptor::create(m_inode.copy_ref()); - } + descriptor = FileDescriptor::create(m_file.copy_ref(), m_socket_role); + descriptor->m_inode = m_inode.copy_ref(); } ASSERT(descriptor); descriptor->m_current_offset = m_current_offset; @@ -80,17 +72,10 @@ Retained FileDescriptor::clone() return *descriptor; } -bool addition_would_overflow(off_t a, off_t b) -{ - ASSERT(a > 0); - uint64_t ua = a; - return (ua + b) > OFF_T_MAX; -} - KResult FileDescriptor::fstat(stat& buffer) { ASSERT(!is_fifo()); - if (!m_inode && !m_file) + if (!m_inode) return KResult(-EBADF); auto metadata = this->metadata(); @@ -122,12 +107,9 @@ KResult FileDescriptor::fchmod(mode_t mode) off_t FileDescriptor::seek(off_t offset, int whence) { - ASSERT(!is_fifo()); - if (!m_inode && !m_file) - return -EBADF; + if (!m_file->is_seekable()) + return -EINVAL; - // FIXME: The file type should be cached on the vnode. - // It's silly that we have to do a full metadata lookup here. auto metadata = this->metadata(); if (!metadata.is_valid()) return -EIO; @@ -135,86 +117,60 @@ off_t FileDescriptor::seek(off_t offset, int whence) if (metadata.is_socket() || metadata.is_fifo()) return -ESPIPE; - off_t newOffset; + off_t new_offset; switch (whence) { case SEEK_SET: - newOffset = offset; + new_offset = offset; break; case SEEK_CUR: - newOffset = m_current_offset + offset; + new_offset = m_current_offset + offset; break; case SEEK_END: - newOffset = metadata.size; + new_offset = metadata.size; break; default: return -EINVAL; } - if (newOffset < 0) + if (new_offset < 0) return -EINVAL; // FIXME: Return -EINVAL if attempting to seek past the end of a seekable device. - m_current_offset = newOffset; + m_current_offset = new_offset; return m_current_offset; } ssize_t FileDescriptor::read(byte* buffer, ssize_t count) { - if (m_file) { - int nread = m_file->read(*this, buffer, count); - if (!m_file->is_seekable()) - m_current_offset += nread; - return nread; - } - ASSERT(inode()); - ssize_t nread = inode()->read_bytes(m_current_offset, count, buffer, this); - m_current_offset += nread; + int nread = m_file->read(*this, buffer, count); + if (m_file->is_seekable()) + m_current_offset += nread; return nread; } ssize_t FileDescriptor::write(const byte* data, ssize_t size) { - if (m_file) { - int nwritten = m_file->write(*this, data, size); - if (m_file->is_seekable()) - m_current_offset += nwritten; - return nwritten; - } - ASSERT(m_inode); - ssize_t nwritten = m_inode->write_bytes(m_current_offset, size, data, this); - m_current_offset += nwritten; + int nwritten = m_file->write(*this, data, size); + if (m_file->is_seekable()) + m_current_offset += nwritten; return nwritten; } bool FileDescriptor::can_write() { - if (m_file) - return m_file->can_write(*this); - return true; + return m_file->can_write(*this); } bool FileDescriptor::can_read() { - if (m_file) - return m_file->can_read(*this); - return true; + return m_file->can_read(*this); } ByteBuffer FileDescriptor::read_entire_file() { // HACK ALERT: (This entire function) - - ASSERT(!is_fifo()); - - if (m_file) { - auto buffer = ByteBuffer::create_uninitialized(1024); - ssize_t nread = m_file->read(*this, buffer.pointer(), buffer.size()); - ASSERT(nread >= 0); - buffer.trim(nread); - return buffer; - } - + ASSERT(m_file->is_inode()); ASSERT(m_inode); return m_inode->read_entire(this); } @@ -255,12 +211,12 @@ ssize_t FileDescriptor::get_dir_entries(byte* buffer, ssize_t size) bool FileDescriptor::is_device() const { - return m_file && m_file->is_device(); + return m_file->is_device(); } bool FileDescriptor::is_tty() const { - return m_file && m_file->is_tty(); + return m_file->is_tty(); } const TTY* FileDescriptor::tty() const @@ -279,7 +235,7 @@ TTY* FileDescriptor::tty() bool FileDescriptor::is_master_pty() const { - return m_file && m_file->is_master_pty(); + return m_file->is_master_pty(); } const MasterPTY* FileDescriptor::master_pty() const @@ -301,17 +257,9 @@ int FileDescriptor::close() return 0; } -bool FileDescriptor::is_fsfile() const -{ - return !is_tty() && !is_fifo() && !is_device() && !is_socket() && !is_shared_memory(); -} - KResultOr FileDescriptor::absolute_path() { - if (m_file) - return m_file->absolute_path(*this); - ASSERT(m_inode); - return VFS::the().absolute_path(*m_inode); + return m_file->absolute_path(*this); } InodeMetadata FileDescriptor::metadata() const @@ -323,40 +271,17 @@ InodeMetadata FileDescriptor::metadata() const KResultOr FileDescriptor::mmap(Process& process, LinearAddress laddr, size_t offset, size_t size, int prot) { - if (m_file) - return m_file->mmap(process, laddr, offset, size, prot); - - if (!is_fsfile()) - return KResult(-ENODEV); - - ASSERT(m_inode); - // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. - String region_name; -#if 0 - // FIXME: I would like to do this, but it would instantiate all the damn inodes. - region_name = absolute_path(); -#else - region_name = "Memory-mapped file"; -#endif - InterruptDisabler disabler; - auto* region = process.allocate_file_backed_region(laddr, size, inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); - if (!region) - return KResult(-ENOMEM); - return region; + return m_file->mmap(process, laddr, offset, size, prot); } KResult FileDescriptor::truncate(off_t length) { - if (is_file()) { - return m_inode->truncate(length); - } - ASSERT(is_shared_memory()); - return shared_memory()->truncate(length); + return m_file->truncate(length); } bool FileDescriptor::is_shared_memory() const { - return m_file && m_file->is_shared_memory(); + return m_file->is_shared_memory(); } SharedMemory* FileDescriptor::shared_memory() @@ -375,7 +300,7 @@ const SharedMemory* FileDescriptor::shared_memory() const bool FileDescriptor::is_fifo() const { - return m_file && m_file->is_fifo(); + return m_file->is_fifo(); } FIFO* FileDescriptor::fifo() @@ -387,7 +312,7 @@ FIFO* FileDescriptor::fifo() bool FileDescriptor::is_socket() const { - return m_file && m_file->is_socket(); + return m_file->is_socket(); } Socket* FileDescriptor::socket() diff --git a/Kernel/FileSystem/FileDescriptor.h b/Kernel/FileSystem/FileDescriptor.h index 30ebbce559..60d7cc5679 100644 --- a/Kernel/FileSystem/FileDescriptor.h +++ b/Kernel/FileSystem/FileDescriptor.h @@ -47,10 +47,8 @@ public: bool is_directory() const; - // FIXME: These should go away once everything is a File. - bool is_file() const { return m_file.ptr(); } - File* file() { return m_file.ptr(); } - const File* file() const { return m_file.ptr(); } + File& file() { return *m_file; } + const File& file() const { return *m_file; } bool is_device() const; @@ -85,7 +83,6 @@ public: FIFO::Direction fifo_direction() { return m_fifo_direction; } void set_fifo_direction(Badge, FIFO::Direction direction) { m_fifo_direction = direction; } - bool is_fsfile() const; bool is_shared_memory() const; SharedMemory* shared_memory(); const SharedMemory* shared_memory() const; @@ -99,10 +96,11 @@ public: KResult truncate(off_t); + off_t offset() const { return m_current_offset; } + private: friend class VFS; - FileDescriptor(RetainPtr&&, SocketRole); - explicit FileDescriptor(RetainPtr&&); + FileDescriptor(RetainPtr&&, SocketRole = SocketRole::None); FileDescriptor(FIFO&, FIFO::Direction); RetainPtr m_inode; diff --git a/Kernel/FileSystem/InodeFile.cpp b/Kernel/FileSystem/InodeFile.cpp new file mode 100644 index 0000000000..c76c1147d7 --- /dev/null +++ b/Kernel/FileSystem/InodeFile.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +InodeFile::InodeFile(Retained&& inode) + : m_inode(move(inode)) +{ +} + +InodeFile::~InodeFile() +{ +} + +ssize_t InodeFile::read(FileDescriptor& descriptor, byte* buffer, ssize_t count) +{ + return m_inode->read_bytes(descriptor.offset(), count, buffer, &descriptor); +} + +ssize_t InodeFile::write(FileDescriptor& descriptor, const byte* data, ssize_t count) +{ + return m_inode->write_bytes(descriptor.offset(), count, data, &descriptor); +} + +KResultOr InodeFile::mmap(Process& process, LinearAddress preferred_laddr, size_t offset, size_t size, int prot) +{ + ASSERT(offset == 0); + // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. + String region_name; +#if 0 + // FIXME: I would like to do this, but it would instantiate all the damn inodes. + region_name = absolute_path(); +#else + region_name = "Memory-mapped file"; +#endif + InterruptDisabler disabler; + auto* region = process.allocate_file_backed_region(preferred_laddr, size, inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); + if (!region) + return KResult(-ENOMEM); + return region; +} + +String InodeFile::absolute_path(FileDescriptor&) const +{ + auto path_or_error = VFS::the().absolute_path(const_cast(inode())); + if (path_or_error.is_error()) + return { }; + return path_or_error.value(); +} + +KResult InodeFile::truncate(off_t size) +{ + return m_inode->truncate(size); +} diff --git a/Kernel/FileSystem/InodeFile.h b/Kernel/FileSystem/InodeFile.h new file mode 100644 index 0000000000..5c86386005 --- /dev/null +++ b/Kernel/FileSystem/InodeFile.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +class Inode; + +class InodeFile final : public File { +public: + static Retained create(Retained&& inode) + { + return adopt(*new InodeFile(move(inode))); + } + + virtual ~InodeFile() override; + + const Inode& inode() const { return *m_inode; } + Inode& inode() { return *m_inode; } + + virtual bool can_read(FileDescriptor&) const override { return true; } + virtual bool can_write(FileDescriptor&) const override { return true; } + + virtual ssize_t read(FileDescriptor&, byte*, ssize_t) override; + virtual ssize_t write(FileDescriptor&, const byte*, ssize_t) override; + virtual KResultOr mmap(Process&, LinearAddress preferred_laddr, size_t offset, size_t size, int prot) override; + + virtual String absolute_path(FileDescriptor&) const override; + + virtual KResult truncate(off_t) override; + + virtual const char* class_name() const override { return "InodeFile"; } + + virtual bool is_seekable() const override { return true; } + virtual bool is_inode() const override { return true; } + +private: + explicit InodeFile(Retained&&); + Retained m_inode; +}; diff --git a/Kernel/Makefile b/Kernel/Makefile index f622228c74..660f18fe7c 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -49,6 +49,7 @@ KERNEL_OBJS = \ Net/NetworkTask.o \ ProcessTracer.o \ Devices/PCSpeaker.o \ + FileSystem/InodeFile.o \ File.o VFS_OBJS = \ diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 4008da535f..0f82792c35 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1608,9 +1608,7 @@ int Process::sys$ioctl(int fd, unsigned request, unsigned arg) auto* descriptor = file_descriptor(fd); if (!descriptor) return -EBADF; - if (!descriptor->is_file()) - return -ENOTTY; - return descriptor->file()->ioctl(*descriptor, request, arg); + return descriptor->file().ioctl(*descriptor, request, arg); } int Process::sys$getdtablesize() @@ -2717,8 +2715,6 @@ int Process::sys$ftruncate(int fd, off_t length) if (!descriptor) return -EBADF; // FIXME: Check that fd is writable, otherwise EINVAL. - if (!descriptor->is_file() && !descriptor->is_shared_memory()) - return -EINVAL; return descriptor->truncate(length); } diff --git a/Kernel/SharedMemory.h b/Kernel/SharedMemory.h index 8fa1ac8399..2bdd13c59e 100644 --- a/Kernel/SharedMemory.h +++ b/Kernel/SharedMemory.h @@ -16,7 +16,7 @@ public: virtual ~SharedMemory() override; String name() const { return m_name; } - KResult truncate(off_t); + virtual KResult truncate(off_t) override; VMObject* vmo() { return m_vmo.ptr(); } const VMObject* vmo() const { return m_vmo.ptr(); } uid_t uid() const { return m_uid; }