diff --git a/.vscode/c_boilerplates.code-snippets b/.vscode/c_boilerplates.code-snippets index cd135d4..7baae13 100644 --- a/.vscode/c_boilerplates.code-snippets +++ b/.vscode/c_boilerplates.code-snippets @@ -42,18 +42,6 @@ ], "description": "Create kernel documentation brief." }, - "For Iteration": { - "prefix": [ - "foritr", - ], - "body": [ - "forItr(${1:itr}, ${2:container})", - "{", - "\t$0", - "}" - ], - "description": "Create for loop with iterator." - }, "License": { "prefix": [ "license", @@ -77,134 +65,5 @@ "*/" ], "description": "Create kernel license." - }, - "Driver Code": { - "prefix": [ - "driver", - ], - "body": [ - "/*", - "\tThis file is part of Fennix Kernel.", - "", - "\tFennix Kernel is free software: you can redistribute it and/or", - "\tmodify it under the terms of the GNU General Public License as", - "\tpublished by the Free Software Foundation, either version 3 of", - "\tthe License, or (at your option) any later version.", - "", - "\tFennix Kernel is distributed in the hope that it will be useful,", - "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of", - "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", - "\tGNU General Public License for more details.", - "", - "\tYou should have received a copy of the GNU General Public License", - "\talong with Fennix Kernel. If not, see .", - "*/", - "", - "#include \"${1:driver}.hpp\"", - "", - "#include ", - "", - "#include \"../../../kernel.h\"", - "", - "namespace Driver", - "{", - "\tint ${2:driver}::drvOpen(int Flags, mode_t Mode) { return 0; }", - "", - "\tint ${2:driver}::drvClose() { return 0; }", - "", - "\tsize_t ${2:driver}::drvRead(uint8_t *Buffer, size_t Size, off_t Offset) { return 0; }", - "", - "\tsize_t ${2:driver}::drvWrite(uint8_t *Buffer, size_t Size, off_t Offset) { return 0; }", - "", - "\tint ${2:driver}::drvIoctl(unsigned long Request, void *Argp) { return 0; }", - "", - "\tvoid ${2:driver}::OnInterruptReceived(CPU::TrapFrame *) {}", - "", - "\tvoid ${2:driver}::Panic() {}", - "", - "\t${2:driver}::${2:driver}(PCI::PCIDevice dev)", - "\t\t: Object(dev),", - "\t\t Interrupts::Handler(dev)", - "\t{", - "\t}", - "", - "\t${2:driver}::${2:driver}(int irq)", - "\t\t: Object(irq),", - "\t\t Interrupts::Handler(irq)", - "\t{", - "\t}", - "", - "\t${2:driver}::${2:driver}()", - "\t{", - "\t}", - "", - "\t${2:driver}::~${2:driver}()", - "\t{", - "\t\tif (GetError() != 0)", - "\t\t\treturn;", - "\t}", - "}", - "", - - ], - "description": "Kernel driver code template." - }, - "Driver Header": { - "prefix": [ - "driver", - ], - "body": [ - "/*", - "\tThis file is part of Fennix Kernel.", - "", - "\tFennix Kernel is free software: you can redistribute it and/or", - "\tmodify it under the terms of the GNU General Public License as", - "\tpublished by the Free Software Foundation, either version 3 of", - "\tthe License, or (at your option) any later version.", - "", - "\tFennix Kernel is distributed in the hope that it will be useful,", - "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of", - "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", - "\tGNU General Public License for more details.", - "", - "\tYou should have received a copy of the GNU General Public License", - "\talong with Fennix Kernel. If not, see .", - "*/", - "", - "#pragma once", - "#include ", - "", - "namespace Driver", - "{", - "\tclass ${1:driver} : public Object, public Interrupts::Handler", - "\t{", - "\tprivate:", - "\t\tvoid OnInterruptReceived(CPU::TrapFrame *Frame) final;", - "\t\tvoid Panic(Driver::DriverContext *ctx) final;", - "", - "\tpublic:", - "\t\tint drvOpen(int Flags, mode_t Mode);", - "\t\tint drvClose();", - "\t\tsize_t drvRead(uint8_t *Buffer, size_t Size, off_t Offset);", - "\t\tsize_t drvWrite(uint8_t *Buffer, size_t Size, off_t Offset);", - "\t\tint drvIoctl(unsigned long Request, void *Argp);", - "", - "\t\tconst char *drvName() final { return \"${2:MyDriver}\"; }", - "\t\tconst char *drvDescription() final { return \"${3:MyDescription}\"; }", - "\t\tconst char *drvVersion() final { return \"${4:0.0.0}\"; }", - "\t\tconst char *drvAuthor() final { return \"${5:Author}\"; }", - "\t\tconst char *drvLicense() final { return \"${6:License}\"; }", - "\t\tDriverType drvType() final { return DriverType_${7:Generic}; }", - "", - "\t\t${1:driver}(PCI::PCIDevice dev);", - "\t\t${1:driver}(int irq);", - "\t\t${1:driver}();", - "\t\t~${1:driver}();", - "\t};", - "}", - "", - - ], - "description": "Kernel driver header template." } } \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f7afb05..a94312a 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -6,15 +6,10 @@ "${workspaceFolder}/include", "${workspaceFolder}/include/**", "${workspaceFolder}/include_std", - "${workspaceFolder}/include_std/**" + "${workspaceFolder}/include_std/**", + "${workspaceFolder}/arch/amd64/include" ], "defines": [ - "__debug_vscode__", - "KERNEL_NAME=\"Fennix\"", - "KERNEL_ARCH=\"amd64\"", - "KERNEL_VERSION=\"1.0\"", - "GIT_COMMIT=\"0000000000000000000000000000000000000000\"", - "GIT_COMMIT_SHORT=\"0000000\"", "a64", "a86", "DEBUG=\"1\"" @@ -79,15 +74,13 @@ "${workspaceFolder}/include", "${workspaceFolder}/include/**", "${workspaceFolder}/include_std", - "${workspaceFolder}/include_std/**" + "${workspaceFolder}/include_std/**", + "${workspaceFolder}/arch/i386/include" + ], + "forcedInclude": [ + "${workspaceFolder}/.vscode/preinclude.h" ], "defines": [ - "__debug_vscode__", - "KERNEL_NAME=\"Fennix\"", - "KERNEL_ARCH=\"i386\"", - "KERNEL_VERSION=\"1.0\"", - "GIT_COMMIT=\"0000000000000000000000000000000000000000\"", - "GIT_COMMIT_SHORT=\"0000000\"", "a32", "a86", "DEBUG=\"1\"" @@ -152,15 +145,13 @@ "${workspaceFolder}/include", "${workspaceFolder}/include/**", "${workspaceFolder}/include_std", - "${workspaceFolder}/include_std/**" + "${workspaceFolder}/include_std/**", + "${workspaceFolder}/arch/aarch64/include" + ], + "forcedInclude": [ + "${workspaceFolder}/.vscode/preinclude.h" ], "defines": [ - "__debug_vscode__", - "KERNEL_NAME=\"Fennix\"", - "KERNEL_ARCH=\"aarch64\"", - "KERNEL_VERSION=\"1.0\"", - "GIT_COMMIT=\"0000000000000000000000000000000000000000\"", - "GIT_COMMIT_SHORT=\"0000000\"", "aa64", "DEBUG=\"1\"" ], diff --git a/.vscode/preinclude.h b/.vscode/preinclude.h index b1940aa..5f59e59 100644 --- a/.vscode/preinclude.h +++ b/.vscode/preinclude.h @@ -5,3 +5,10 @@ #undef _WIN64 #undef __APPLE__ #undef __clang__ +#define __vscode__ 1 +#define __kernel__ 1 +#define KERNEL_NAME "Fennix" +#define KERNEL_ARCH "amd64" +#define KERNEL_VERSION "1.0" +#define GIT_COMMIT "0000000000000000000000000000000000000000" +#define GIT_COMMIT_SHORT "0000000" diff --git a/.vscode/settings.json b/.vscode/settings.json index 2d09fa1..f1b2296 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "C_Cpp.errorSquiggles": "Enabled", + "C_Cpp.errorSquiggles": "enabled", "C_Cpp.autocompleteAddParentheses": true, "C_Cpp.codeAnalysis.clangTidy.enabled": true, "C_Cpp.clang_format_style": "Visual Studio", @@ -14,6 +14,10 @@ "clang-diagnostic-unknown-warning-option", "clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling", "clang-diagnostic-implicit-exception-spec-mismatch", - "clang-diagnostic-unknown-attributes" + "clang-diagnostic-unknown-attributes", + "clang-diagnostic-user-defined-literals", + "clang-diagnostic-non-pod-varargs", + "clang-diagnostic-non-pod-varargs", + "clang-diagnostic-non-pod-varargs" ] } \ No newline at end of file diff --git a/Makefile b/Makefile index 1d763ec..2fb1332 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,9 @@ RUST_TARGET_PATH = arch/$(OSARCH)/rust-target.json GIT_COMMIT = $(shell git rev-parse HEAD) GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD) +HEADERS = $(sort $(dir $(wildcard ./include/*))) $(sort $(dir $(wildcard ./include_std/*))) +INCLUDE_DIR = -I./include -I./include_std + BMP_SOURCES = $(shell find ./ -type f -name '*.bmp') PSF_SOURCES = $(shell find ./ -type f -name '*.psf') ifeq ($(OSARCH), amd64) @@ -24,43 +27,47 @@ S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*") C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*") CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*") +HEADERS += $(sort $(dir $(wildcard ./arch/amd64/include/*))) +INCLUDE_DIR += -I./arch/amd64/include else ifeq ($(OSARCH), i386) S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +HEADERS += $(sort $(dir $(wildcard ./arch/i386/include/*))) +INCLUDE_DIR += -I./arch/i386/include else ifeq ($(OSARCH), aarch64) S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*") s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./arch/amd64/*" -not -path "./arch/i386/*") C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*") CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*") +HEADERS += $(sort $(dir $(wildcard ./arch/aarch64/include/*))) +INCLUDE_DIR += -I./arch/aarch64/include endif -HEADERS = $(sort $(dir $(wildcard ./include/*))) $(sort $(dir $(wildcard ./include_std/*))) OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(s_SOURCES:.s=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o) STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su) GCNO_OBJ = $(C_SOURCES:.c=.gcno) $(CPP_SOURCES:.cpp=.gcno) -INCLUDE_DIR = -I./include -I./include_std LDFLAGS := -Wl,-Map kernel.map -static -nostdlib -nodefaultlibs -nolibc # Disable all warnings by adding "-w" in WARNCFLAG and if you want to treat the warnings as errors, add "-Werror" +# -Wconversion this may be re-added later WARNCFLAG = -Wall -Wextra \ -Wfloat-equal -Wpointer-arith -Wcast-align \ -Wredundant-decls -Winit-self -Wswitch-default \ - -Wstrict-overflow=5 -Wconversion -Wno-error=cpp -Werror \ + -Wstrict-overflow=5 -Wno-error=cpp -Werror \ -Wno-unused-parameter # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html CFLAGS := \ $(INCLUDE_DIR) \ + -D__kernel__='1' \ -DKERNEL_NAME='"$(OSNAME)"' \ -DKERNEL_ARCH='"$(OSARCH)"' \ -DKERNEL_VERSION='"$(KERNEL_VERSION)"' \ -DGIT_COMMIT='"$(GIT_COMMIT)"' \ -DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"' -SIMD_FLAGS := -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -mavx2 -mavx512f - ifeq ($(OSARCH), amd64) CFLAGS += -fno-pic -fno-pie -mno-red-zone -march=core2 \ @@ -131,6 +138,7 @@ endif $(KERNEL_FILENAME): $(OBJ) $(info Linking $@) $(CC) $(LDFLAGS) $(OBJ) -o $@ +# $(CC) $(LDFLAGS) $(OBJ) -mno-red-zone -lgcc -o $@ %.o: %.c $(HEADERS) $(info Compiling $<) @@ -139,7 +147,7 @@ $(KERNEL_FILENAME): $(OBJ) # https://gcc.gnu.org/projects/cxx-status.html %.o: %.cpp $(HEADERS) $(info Compiling $<) - $(CPP) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-exceptions -fno-rtti + $(CPP) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti %.o: %.S $(info Compiling $<) diff --git a/arch/aarch64/include/.gitkeep b/arch/aarch64/include/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/arch/amd64/include/.gitkeep b/arch/amd64/include/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/arch/amd64/linker.ld b/arch/amd64/linker.ld index 14cdd2c..006ca57 100644 --- a/arch/amd64/linker.ld +++ b/arch/amd64/linker.ld @@ -62,6 +62,16 @@ SECTIONS { *(.data .data.*) } :data + + .eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RW + { + KEEP (*(.eh_frame .eh_frame.*)) + } :data + + .gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RW + { + KEEP (*(.gcc_except_table .gcc_except_table.*)) + } :data _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE)); _kernel_rodata_start = ALIGN(CONSTANT(MAXPAGESIZE)); @@ -85,6 +95,21 @@ SECTIONS KEEP(*(.fini_array .dtors)) PROVIDE_HIDDEN (__fini_array_end = .); } :rodata + + .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA) + { + *(.eh_frame_hdr .eh_frame_hdr.*) + } :rodata + + .eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RO + { + KEEP (*(.eh_frame .eh_frame.*)) + } :rodata + + .gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RO + { + KEEP (*(.gcc_except_table .gcc_except_table.*)) + } :rodata _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE)); _kernel_bss_start = ALIGN(CONSTANT(MAXPAGESIZE)); diff --git a/arch/amd64/memory/vmm.cpp b/arch/amd64/memory/vmm.cpp index f08a8d0..61086d6 100644 --- a/arch/amd64/memory/vmm.cpp +++ b/arch/amd64/memory/vmm.cpp @@ -149,30 +149,30 @@ namespace Memory PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; if (!PML4->Present) - goto ReturnError; + goto ReturnLogError; PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12); if (!PDPTE || !PDPTE->Entries[Index.PDPTEIndex].Present) - goto ReturnError; + goto ReturnLogError; if (PDPTE->Entries[Index.PDPTEIndex].PageSize) return MapType::OneGiB; PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); if (!PDE || !PDE->Entries[Index.PDEIndex].Present) - goto ReturnError; + goto ReturnLogError; if (PDE->Entries[Index.PDEIndex].PageSize) return MapType::TwoMiB; PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); if (!PTE) - goto ReturnError; + goto ReturnLogError; if (PTE->Entries[Index.PTEIndex].Present) return MapType::FourKiB; - ReturnError: + ReturnLogError: return MapType::NoMapType; } diff --git a/arch/i386/include/.gitkeep b/arch/i386/include/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/arch/i386/linker.ld b/arch/i386/linker.ld index b4ed457..6455183 100644 --- a/arch/i386/linker.ld +++ b/arch/i386/linker.ld @@ -62,6 +62,16 @@ SECTIONS { *(.data .data.*) } :data + + .eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RW + { + KEEP (*(.eh_frame .eh_frame.*)) + } :data + + .gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RW + { + KEEP (*(.gcc_except_table .gcc_except_table.*)) + } :data _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE)); _kernel_rodata_start = ALIGN(CONSTANT(MAXPAGESIZE)); @@ -85,6 +95,21 @@ SECTIONS KEEP(*(.fini_array .dtors)) PROVIDE_HIDDEN (__fini_array_end = .); } :rodata + + .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA) + { + *(.eh_frame_hdr .eh_frame_hdr.*) + } :rodata + + .eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RO + { + KEEP (*(.eh_frame .eh_frame.*)) + } :rodata + + .gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RO + { + KEEP (*(.gcc_except_table .gcc_except_table.*)) + } :rodata _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE)); _kernel_bss_start = ALIGN(CONSTANT(MAXPAGESIZE)); diff --git a/core/console.cpp b/core/console.cpp new file mode 100644 index 0000000..7294ae2 --- /dev/null +++ b/core/console.cpp @@ -0,0 +1,172 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include + +namespace KernelConsole +{ + termios term{}; + winsize termSize{}; + + ssize_t KConRead(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + fixme("Reading %d bytes... \"%.*s\"", Size, Size, (char *)Buffer); + return Size; + } + + ssize_t KConWrite(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) + { + fixme("Writing %d bytes... \"%.*s\"", Size, Size, (char *)Buffer); + return Size; + } + + int KConIoctl(struct Inode *Node, unsigned long Request, void *Argp) + { + switch (Request) + { + case TCGETS: + { + struct termios *t = (struct termios *)Argp; + memcpy(t, &term, sizeof(struct termios)); + return 0; + } + case TCSETS: + { + debug("TCSETS not supported"); + return -EINVAL; + + struct termios *t = (struct termios *)Argp; + memcpy(&term, t, sizeof(struct termios)); + return 0; + } + case TIOCGPGRP: + { + *((pid_t *)Argp) = 0; + return 0; + } + case TIOCSPGRP: + { + *((pid_t *)Argp) = 0; + return 0; + } + case TIOCGWINSZ: + { + struct winsize *ws = (struct winsize *)Argp; + memcpy(ws, &termSize, sizeof(struct winsize)); + return 0; + } + case TIOCSWINSZ: + { + debug("TIOCSWINSZ not supported"); + return -EINVAL; + + struct winsize *ws = (struct winsize *)Argp; + memcpy(&termSize, ws, sizeof(struct winsize)); + return 0; + } + case TCSETSW: + case TCSETSF: + case TCGETA: + case TCSETA: + case TCSETAW: + case TCSETAF: + case TCSBRK: + case TCXONC: + case TCFLSH: + case TIOCEXCL: + case TIOCNXCL: + case TIOCSCTTY: + case TIOCOUTQ: + case TIOCSTI: + case TIOCMGET: + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + { + fixme("ioctl %#lx not implemented", Request); + return -ENOSYS; + } + case TIOCGPTN: + case 0xffffffff80045430: /* FIXME: ???? */ + { + fixme("stub ioctl %#lx", Request); + + int *n = (int *)Argp; + *n = -1; + break; + } + case TIOCSPTLCK: + { + fixme("stub ioctl %#lx", Request); + + int *n = (int *)Argp; + *n = 0; + break; + } + default: + { + debug("Unknown ioctl %#lx", Request); + return -EINVAL; + } + } + + return 0; + } + + void EarlyInit() + { + /* + - ICRNL - Map Carriage Return to New Line + - IXON - Enable XON/XOFF flow control + + - OPOST - Enable output processing + - ONLCR - Map New Line to Carriage Return - New Line + + - CS8 - 8-bit characters + - CREAD - Enable receiver + - HUPCL - Hang up on last close + + - ECHO - Echo input characters + - ICANON - Enable canonical input (enable line editing) + */ + term.c_iflag = /*ICRNL |*/ IXON; + term.c_oflag = OPOST | ONLCR; + term.c_cflag = CS8 | CREAD | HUPCL; + term.c_lflag = ECHO | ICANON; + term.c_cc[VEOF] = 0x04; /* ^D */ + term.c_cc[VEOL] = 0x00; /* NUL */ + term.c_cc[VERASE] = 0x7f; /* DEL */ + term.c_cc[VINTR] = 0x03; /* ^C */ + term.c_cc[VKILL] = 0x15; /* ^U */ + term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */ + term.c_cc[VQUIT] = 0x1c; /* ^\ */ + term.c_cc[VSTART] = 0x11; /* ^Q */ + term.c_cc[VSTOP] = 0x13; /* ^S */ + term.c_cc[VSUSP] = 0x1a; /* ^Z */ + term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ + term.c_cc[VWERASE] = 0x17; /* ^W */ + } + + void LateInit() + { + } +} diff --git a/core/driver/api.cpp b/core/driver/api.cpp index 71b475e..7f2c6cb 100644 --- a/core/driver/api.cpp +++ b/core/driver/api.cpp @@ -16,14 +16,16 @@ */ #include +#include +#include +#include #include "../../kernel.h" -#include "../../driver.h" // #define DEBUG_API #ifdef DEBUG_API -#define dbg_api(Format, ...) function(Format, ##__VA_ARGS__) +#define dbg_api(Format, ...) func(Format, ##__VA_ARGS__) #else #define dbg_api(Format, ...) #endif @@ -53,19 +55,19 @@ namespace Driver { case _drf_Entry: drv->Entry = (int (*)())Function; - debug("Entry %#lx for %s", (uintptr_t)Function, drv->Path); + debug("Entry %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); break; case _drf_Final: drv->Final = (int (*)())Function; - debug("Finalize %#lx for %s", (uintptr_t)Function, drv->Path); + debug("Finalize %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); break; case _drf_Panic: drv->Panic = (int (*)())Function; - debug("Panic %#lx for %s", (uintptr_t)Function, drv->Path); + debug("Panic %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); break; case _drf_Probe: drv->Probe = (int (*)())Function; - debug("Probe %#lx for %s", (uintptr_t)Function, drv->Path); + debug("Probe %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); break; default: assert(!"Invalid driver function type"); @@ -134,7 +136,7 @@ namespace Driver { if (ih.first == IRQ) { - debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path); + debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path.c_str()); Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))ih.second, IRQ); drv->InterruptHandlers->erase(IRQ); break; @@ -177,7 +179,7 @@ namespace Driver foreach (auto &i in * drv->InterruptHandlers) { Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, i.first); - debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path); + debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path.c_str()); } drv->InterruptHandlers->clear(); return 0; @@ -185,217 +187,6 @@ namespace Driver /* --------- */ - dev_t RegisterInputDevice(dev_t MajorID, DeviceDriverType Type) - { - dbg_api("%d, %d", MajorID, Type); - - switch (Type) - { - case ddt_Keyboard: - return DriverManager->InputKeyboardDev->Register(MajorID); - case ddt_Mouse: - return DriverManager->InputMouseDev->Register(MajorID); - /* ... */ - default: - assert(!"Invalid input device type"); - } - } - - int UnregisterInputDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) - { - dbg_api("%d, %d, %d", MajorID, MinorID, Type); - - switch (Type) - { - case ddt_Keyboard: - return DriverManager->InputKeyboardDev->Unregister(MajorID, MinorID); - case ddt_Mouse: - return DriverManager->InputMouseDev->Unregister(MajorID, MinorID); - /* ... */ - default: - assert(!"Invalid input device type"); - } - } - - int ReportKeyboardEvent(dev_t MajorID, dev_t MinorID, uint8_t ScanCode) - { - dbg_api("%d, %d, %d", MajorID, MinorID, ScanCode); - - return DriverManager->InputKeyboardDev->ReportKeyEvent(MajorID, MinorID, ScanCode); - } - - int ReportRelativeMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z) - { - dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z); - - return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID, - Button.LeftButton, Button.RightButton, Button.MiddleButton, - Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8, - X, Y, Z, true); - } - - int ReportAbsoluteMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z) - { - dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z); - - return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID, - Button.LeftButton, Button.RightButton, Button.MiddleButton, - Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8, - X, Y, Z, false); - } - - /* --------- */ - - dev_t RegisterBlockDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl) - { - dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl); - - switch (Type) - { - case ddt_SATA: - { - dev_t ret = DriverManager->BlockSATADev->Register(MajorID); - DriverManager->BlockSATADev->NewBlock(MajorID, ret, - (SlaveDeviceFile::drvOpen_t)Open, - (SlaveDeviceFile::drvClose_t)Close, - (SlaveDeviceFile::drvRead_t)Read, - (SlaveDeviceFile::drvWrite_t)Write, - (SlaveDeviceFile::drvIoctl_t)Ioctl); - return ret; - } - case ddt_ATA: - { - dev_t ret = DriverManager->BlockHDDev->Register(MajorID); - DriverManager->BlockHDDev->NewBlock(MajorID, ret, - (SlaveDeviceFile::drvOpen_t)Open, - (SlaveDeviceFile::drvClose_t)Close, - (SlaveDeviceFile::drvRead_t)Read, - (SlaveDeviceFile::drvWrite_t)Write, - (SlaveDeviceFile::drvIoctl_t)Ioctl); - return ret; - } - case ddt_NVMe: - { - dev_t ret = DriverManager->BlockNVMeDev->Register(MajorID); - DriverManager->BlockNVMeDev->NewBlock(MajorID, ret, - (SlaveDeviceFile::drvOpen_t)Open, - (SlaveDeviceFile::drvClose_t)Close, - (SlaveDeviceFile::drvRead_t)Read, - (SlaveDeviceFile::drvWrite_t)Write, - (SlaveDeviceFile::drvIoctl_t)Ioctl); - return ret; - } - /* ... */ - default: - assert(!"Invalid storage device type"); - } - } - - int UnregisterBlockDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) - { - dbg_api("%d, %d, %d", MajorID, MinorID, Type); - - switch (Type) - { - case ddt_SATA: - return DriverManager->BlockSATADev->Unregister(MajorID, MinorID); - case ddt_ATA: - return DriverManager->BlockHDDev->Unregister(MajorID, MinorID); - case ddt_NVMe: - return DriverManager->BlockNVMeDev->Unregister(MajorID, MinorID); - /* ... */ - default: - assert(!"Invalid storage device type"); - } - } - - /* --------- */ - - dev_t RegisterAudioDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl) - { - dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl); - - switch (Type) - { - case ddt_Audio: - { - dev_t ret = DriverManager->AudioDev->Register(MajorID); - DriverManager->AudioDev->NewAudio(MajorID, ret, - (SlaveDeviceFile::drvOpen_t)Open, - (SlaveDeviceFile::drvClose_t)Close, - (SlaveDeviceFile::drvRead_t)Read, - (SlaveDeviceFile::drvWrite_t)Write, - (SlaveDeviceFile::drvIoctl_t)Ioctl); - return ret; - } - /* ... */ - default: - assert(!"Invalid audio device type"); - } - } - - int UnregisterAudioDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) - { - dbg_api("%d, %d, %d", MajorID, MinorID, Type); - - switch (Type) - { - case ddt_Audio: - return DriverManager->AudioDev->Unregister(MajorID, MinorID); - /* ... */ - default: - assert(!"Invalid audio device type"); - } - } - - /* --------- */ - - dev_t RegisterNetDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl) - { - dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl); - - switch (Type) - { - case ddt_Network: - { - dev_t ret = DriverManager->NetDev->Register(MajorID); - DriverManager->NetDev->NewNet(MajorID, ret, - (SlaveDeviceFile::drvOpen_t)Open, - (SlaveDeviceFile::drvClose_t)Close, - (SlaveDeviceFile::drvRead_t)Read, - (SlaveDeviceFile::drvWrite_t)Write, - (SlaveDeviceFile::drvIoctl_t)Ioctl); - return ret; - } - /* ... */ - default: - assert(!"Invalid audio device type"); - } - } - - int UnregisterNetDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) - { - dbg_api("%d, %d, %d", MajorID, MinorID, Type); - - switch (Type) - { - case ddt_Network: - return DriverManager->NetDev->Unregister(MajorID, MinorID); - /* ... */ - default: - assert(!"Invalid audio device type"); - } - } - - int ReportNetworkPacket(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size) - { - dbg_api("%d, %d, %#lx, %d", MajorID, MinorID, Buffer, Size); - - return DriverManager->NetDev->ReportNetworkPacket(MajorID, MinorID, Buffer, Size); - } - - /* --------- */ - void d_KPrint(dev_t MajorID, const char *Format, va_list args) { dbg_api("%d %s, %#lx", MajorID, Format, args); @@ -891,22 +682,6 @@ namespace Driver api->UnregisterInterruptHandler = UnregisterInterruptHandler; api->UnregisterAllInterruptHandlers = UnregisterAllInterruptHandlers; - api->RegisterInputDevice = RegisterInputDevice; - api->UnregisterInputDevice = UnregisterInputDevice; - api->ReportKeyboardEvent = ReportKeyboardEvent; - api->ReportRelativeMouseEvent = ReportRelativeMouseEvent; - api->ReportAbsoluteMouseEvent = ReportAbsoluteMouseEvent; - - api->RegisterBlockDevice = RegisterBlockDevice; - api->UnregisterBlockDevice = UnregisterBlockDevice; - - api->RegisterAudioDevice = RegisterAudioDevice; - api->UnregisterAudioDevice = UnregisterAudioDevice; - - api->RegisterNetDevice = RegisterNetDevice; - api->UnregisterNetDevice = UnregisterNetDevice; - api->ReportNetworkPacket = ReportNetworkPacket; - api->KPrint = d_KPrint; api->KernelLog = KernelLog; @@ -944,3 +719,28 @@ namespace Driver api->strstr = api__strstr; } } + +dev_t __api_RegisterFileSystem(FileSystemInfo *Info, struct Inode *Root) +{ + return fs->RegisterFileSystem(Info, Root); +} + +int __api_UnregisterFileSystem(dev_t Device) +{ + return fs->UnregisterFileSystem(Device); +} + +struct APISymbols +{ + const char *Name; + void *Function; +}; + +static struct APISymbols APISymbols[] = { + {"RegisterFileSystem", (void *)__api_RegisterFileSystem}, + {"UnregisterFileSystem", (void *)__api_UnregisterFileSystem}, +}; + +/* Checking functions signatures */ +static_assert(std::is_same_v); +static_assert(std::is_same_v); diff --git a/core/driver/devfile/master.cpp b/core/driver/devfile/master.cpp deleted file mode 100644 index 9c3b504..0000000 --- a/core/driver/devfile/master.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../../../kernel.h" -#include "../../../driver.h" - -using namespace vfs; - -namespace Driver -{ - int MasterDeviceFile::open(int Flags, mode_t Mode) - { - switch (this->DeviceType) - { - default: - if (this->SlavesMap.empty()) - return -ENOSYS; - Slaves slave = this->SlavesMap.begin()->second; - return slave->begin()->second->open(Flags, Mode); - } - } - - int MasterDeviceFile::close() - { - switch (this->DeviceType) - { - default: - if (this->SlavesMap.empty()) - return -ENOSYS; - Slaves slave = this->SlavesMap.begin()->second; - return slave->begin()->second->close(); - } - } - - size_t MasterDeviceFile::read(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - switch (this->DeviceType) - { - case ddt_Keyboard: - { - while (KeyQueue.empty()) - TaskManager->Yield(); - - /* Request scancode */ - if (Size == 2 && Buffer[1] == 0x00) - { - while (RawKeyQueue.empty()) - TaskManager->Yield(); - - Buffer[0] = RawKeyQueue.front(); - RawKeyQueue.pop_front(); - return 1; - } - - Buffer[0] = KeyQueue.front(); - KeyQueue.pop_front(); - return 1; - } - default: - if (this->SlavesMap.empty()) - return 0; - Slaves slave = this->SlavesMap.begin()->second; - return slave->begin()->second->read(Buffer, Size, Offset); - } - } - - size_t MasterDeviceFile::write(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - switch (this->DeviceType) - { - default: - if (this->SlavesMap.empty()) - return 0; - Slaves slave = this->SlavesMap.begin()->second; - return slave->begin()->second->write(Buffer, Size, Offset); - } - } - - int MasterDeviceFile::ioctl(unsigned long Request, - void *Argp) - { - switch (this->DeviceType) - { - default: - if (this->SlavesMap.empty()) - return -ENOSYS; - Slaves slave = this->SlavesMap.begin()->second; - return slave->begin()->second->ioctl(Request, Argp); - } - } - - void MasterDeviceFile::ClearBuffers() - { - this->RawKeyQueue.clear(); - this->KeyQueue.clear(); - /* ... */ - - foreach (auto &sm in this->SlavesMap) - { - Slaves slave = sm.second; - foreach (auto &sdf in *slave) - sdf.second->ClearBuffers(); - } - } - - int MasterDeviceFile::ReportKeyEvent(maj_t ID, min_t MinorID, uint8_t ScanCode) - { - debug("New key event: %02x", ScanCode); - if (this->SlavesMap.find(ID) == this->SlavesMap.end()) - return -EINVAL; - - std::unordered_map *slave = this->SlavesMap[ID]; - if ((*slave).find(MinorID) == (*slave).end()) - return -EINVAL; - - /* We are master, keep a copy of the scancode and - converted key */ - - if (RawKeyQueue.size() > 16) - RawKeyQueue.pop_front(); - RawKeyQueue.push_back(ScanCode); - - if (KeyQueue.size() > 16) - KeyQueue.pop_front(); - - switch (ScanCode & ~KEY_PRESSED) - { - case KEY_LEFT_SHIFT: - case KEY_RIGHT_SHIFT: - { - if (ScanCode & KEY_PRESSED) - UpperCase = true; - else - UpperCase = false; - break; - } - case KEY_CAPS_LOCK: - { - if (ScanCode & KEY_PRESSED) - CapsLock = !CapsLock; - break; - } - default: - break; - } - - if (ScanCode & KEY_PRESSED) - KeyQueue.push_back(GetScanCode(ScanCode, UpperCase || CapsLock)); - - SlaveDeviceFile *sdf = (*slave)[MinorID]; - return sdf->ReportKeyEvent(ScanCode); - } - - int MasterDeviceFile::ReportMouseEvent(maj_t ID, min_t MinorID, - bool LeftButton, bool RightButton, bool MiddleButton, - bool Button4, bool Button5, bool Button6, bool Button7, bool Button8, - uintptr_t X, uintptr_t Y, int8_t Z, bool Relative) - { - return -ENOSYS; - } - - int MasterDeviceFile::ReportNetworkPacket(maj_t ID, min_t MinorID, void *Buffer, size_t Size) - { - /* TODO: Buffer must be allocated by the kernel */ - return -ENOSYS; - } - - int MasterDeviceFile::NewBlock(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, - drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl) - { - assert(this->SlavesMap.find(ID) != this->SlavesMap.end()); - Slaves slave = this->SlavesMap[ID]; - assert((*slave).find(MinorID) != (*slave).end()); - SlaveDeviceFile *sdf = (*slave)[MinorID]; - sdf->Open = Open; - sdf->Close = Close; - sdf->Read = Read; - sdf->Write = Write; - sdf->Ioctl = Ioctl; - return 0; - } - - int MasterDeviceFile::NewAudio(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, - drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl) - { - assert(this->SlavesMap.find(ID) != this->SlavesMap.end()); - Slaves slave = this->SlavesMap[ID]; - assert((*slave).find(MinorID) != (*slave).end()); - SlaveDeviceFile *sdf = (*slave)[MinorID]; - sdf->Open = Open; - sdf->Close = Close; - sdf->Read = Read; - sdf->Write = Write; - sdf->Ioctl = Ioctl; - return 0; - } - - int MasterDeviceFile::NewNet(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, - drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl) - { - assert(this->SlavesMap.find(ID) != this->SlavesMap.end()); - Slaves slave = this->SlavesMap[ID]; - assert((*slave).find(MinorID) != (*slave).end()); - SlaveDeviceFile *sdf = (*slave)[MinorID]; - sdf->Open = Open; - sdf->Close = Close; - sdf->Read = Read; - sdf->Write = Write; - sdf->Ioctl = Ioctl; - return 0; - } - - dev_t MasterDeviceFile::Register(maj_t ID) - { - debug("Registering slave device %d", ID); - Slaves slave; - if (this->SlavesMap.find(ID) != this->SlavesMap.end()) - slave = this->SlavesMap[ID]; - else - slave = new std::unordered_map(); - - char name[24]; - sprintf(name, "%s%ld", this->SlaveName, this->SlaveIDCounter); - SlaveDeviceFile *sdf = new SlaveDeviceFile(name, - this->SlaveParent, - this->DeviceType, - this->Type); - - sdf->DeviceMajor = ID; - sdf->DeviceMinor = this->SlaveIDCounter; - - (*slave)[this->SlaveIDCounter] = sdf; - this->SlavesMap[ID] = slave; - return this->SlaveIDCounter++; - } - - int MasterDeviceFile::Unregister(maj_t ID, min_t MinorID) - { - debug("Unregistering slave device %d:%d", ID, MinorID); - if (this->SlavesMap.find(ID) == this->SlavesMap.end()) - return -EINVAL; - - std::unordered_map *slave = this->SlavesMap[ID]; - if ((*slave).find(MinorID) == (*slave).end()) - return -EINVAL; - - SlaveDeviceFile *sdf = (*slave)[MinorID]; - delete sdf; - slave->erase(MinorID); - if (slave->empty()) - { - delete slave; - this->SlavesMap.erase(ID); - } - return 0; - } - - MasterDeviceFile::MasterDeviceFile(const char *MasterName, - const char *_SlaveName, - Node *Parent, - int Type) - : Node(Parent, MasterName, NodeType::FILE) - { - strncpy(this->SlaveName, _SlaveName, sizeof(this->Name)); - this->DeviceType = Type; - this->SlaveParent = Parent; - - switch (Type) - { - case ddt_Keyboard: - case ddt_Mouse: - case ddt_Joystick: - case ddt_Gamepad: - case ddt_Touchpad: - case ddt_Touchscreen: - this->Type = NodeType::CHARDEVICE; - break; - case ddt_SATA: - case ddt_ATA: - case ddt_NVMe: - this->Type = NodeType::BLOCKDEVICE; - break; - default: - break; - } - } - - MasterDeviceFile::~MasterDeviceFile() - { - foreach (auto &sm in this->SlavesMap) - { - Slaves slave = sm.second; - foreach (auto &sdf in *slave) - delete sdf.second; - delete slave; - } - this->SlavesMap.clear(); - } -} diff --git a/core/driver/devfile/slave.cpp b/core/driver/devfile/slave.cpp deleted file mode 100644 index f1e79db..0000000 --- a/core/driver/devfile/slave.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../../../kernel.h" -#include "../../../driver.h" - -using namespace vfs; - -namespace Driver -{ - int SlaveDeviceFile::open(int Flags, mode_t Mode) - { - switch (this->DeviceType) - { - default: - if (this->Open) - return this->Open(this->DeviceMajor, this->DeviceMinor, - Flags, Mode); - return -ENOSYS; - } - } - - int SlaveDeviceFile::close() - { - switch (this->DeviceType) - { - default: - if (this->Close) - return this->Close(this->DeviceMajor, this->DeviceMinor); - return -ENOSYS; - } - } - - size_t SlaveDeviceFile::read(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - switch (this->DeviceType) - { - case ddt_Keyboard: - { - while (KeyQueue.empty()) - TaskManager->Yield(); - - Buffer[0] = KeyQueue.front(); - KeyQueue.pop_front(); - return 1; - } - default: - if (this->Read) - return this->Read(this->DeviceMajor, this->DeviceMinor, - Buffer, Size, Offset); - return 0; - } - } - - size_t SlaveDeviceFile::write(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - switch (this->DeviceType) - { - default: - if (this->Write) - return this->Write(this->DeviceMajor, this->DeviceMinor, - Buffer, Size, Offset); - return 0; - } - } - - int SlaveDeviceFile::ioctl(unsigned long Request, - void *Argp) - { - switch (this->DeviceType) - { - default: - if (this->Ioctl) - return this->Ioctl(this->DeviceMajor, this->DeviceMinor, - Request, Argp); - return -ENOSYS; - } - } - - void SlaveDeviceFile::ClearBuffers() - { - KeyQueue.clear(); - /* ... */ - } - - int SlaveDeviceFile::ReportKeyEvent(uint8_t ScanCode) - { - if (KeyQueue.size() > 16) - KeyQueue.pop_front(); - KeyQueue.push_back(ScanCode); - return 0; - } - - SlaveDeviceFile::SlaveDeviceFile(const char *Name, vfs::Node *Parent, int Type, vfs::NodeType NType) - : Node(Parent, Name, NType) - { - this->DeviceType = Type; - } - - SlaveDeviceFile::~SlaveDeviceFile() - { - } -} diff --git a/core/driver/driver.cpp b/core/driver/driver.cpp index 9c4e8ef..3db8f65 100644 --- a/core/driver/driver.cpp +++ b/core/driver/driver.cpp @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -26,12 +27,64 @@ #include #include "../../kernel.h" -#include "../../driver.h" using namespace vfs; namespace Driver { + void Manager::PreloadDrivers() + { + debug("Initializing driver manager"); + const char *DriverDirectory = Config.DriverDirectory; + FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr); + if (!drvDirNode) + { + error("Failed to open driver directory %s", DriverDirectory); + KPrint("Failed to open driver directory %s", DriverDirectory); + return; + } + + foreach (const auto &drvNode in drvDirNode->Children) + { + debug("Checking driver %s", drvNode->Path.c_str()); + if (!drvNode->IsRegularFile()) + continue; + + if (Execute::GetBinaryType(drvNode->Path) != Execute::BinTypeELF) + { + error("Driver %s is not an ELF binary", drvNode->Path.c_str()); + continue; + } + + Memory::VirtualMemoryArea *dVma = new Memory::VirtualMemoryArea(thisProcess->PageTable); + + uintptr_t EntryPoint, BaseAddress; + int err = this->LoadDriverFile(EntryPoint, BaseAddress, dVma, drvNode); + debug("err = %d (%s)", err, strerror(err)); + if (err != 0) + { + error("Failed to load driver %s: %s", + drvNode->Path.c_str(), strerror(err)); + + delete dVma; + continue; + } + + Drivers[DriverIDCounter++] = { + .BaseAddress = BaseAddress, + .EntryPoint = EntryPoint, + .vma = dVma, + .Path = drvNode->Path, + .InterruptHandlers = new std::unordered_map}; + + dev_t countr = DriverIDCounter - 1; + const char *drvName; + size_t drvNameLen; + cwk_path_get_basename(drvNode->Path.c_str(), &drvName, &drvNameLen); + strncpy(Drivers[countr].Name, drvName, sizeof(Drivers[countr].Name)); + } + } + void Manager::LoadAllDrivers() { if (Drivers.empty()) @@ -56,7 +109,7 @@ namespace Driver dApi->Base = Drv->BaseAddress; PopulateDriverAPI(dApi); - debug("Calling driver %s at %#lx", Drv->Path, Drv->EntryPoint); + debug("Calling driver %s at %#lx", Drv->Path.c_str(), Drv->EntryPoint); int (*DrvInit)(__driverAPI *) = (int (*)(__driverAPI *))Drv->EntryPoint; Drv->ErrorCode = DrvInit(dApi); if (Drv->ErrorCode < 0) @@ -64,7 +117,7 @@ namespace Driver KPrint("FATAL: _start() failed for %s: %s", Drv->Name, strerror(Drv->ErrorCode)); error("Failed to load driver %s: %s", - Drv->Path, strerror(Drv->ErrorCode)); + Drv->Path.c_str(), strerror(Drv->ErrorCode)); Drv->vma->FreeAllPages(); continue; @@ -73,48 +126,36 @@ namespace Driver KPrint("Loading driver %s", Drv->Name); debug("Calling Probe()=%#lx on driver %s", - Drv->Probe, Drv->Path); + Drv->Probe, Drv->Path.c_str()); Drv->ErrorCode = Drv->Probe(); if (Drv->ErrorCode < 0) { KPrint("Probe() failed for %s: %s", Drv->Name, strerror(Drv->ErrorCode)); error("Failed to probe driver %s: %s", - Drv->Path, strerror(Drv->ErrorCode)); + Drv->Path.c_str(), strerror(Drv->ErrorCode)); Drv->vma->FreeAllPages(); continue; } debug("Calling driver Entry()=%#lx function on driver %s", - Drv->Entry, Drv->Path); + Drv->Entry, Drv->Path.c_str()); Drv->ErrorCode = Drv->Entry(); if (Drv->ErrorCode < 0) { KPrint("Entry() failed for %s: %s", Drv->Name, strerror(Drv->ErrorCode)); error("Failed to initialize driver %s: %s", - Drv->Path, strerror(Drv->ErrorCode)); + Drv->Path.c_str(), strerror(Drv->ErrorCode)); Drv->vma->FreeAllPages(); continue; } - debug("Loaded driver %s", Drv->Path); + debug("Loaded driver %s", Drv->Path.c_str()); Drv->Initialized = true; } - - InputMouseDev->ClearBuffers(); - InputKeyboardDev->ClearBuffers(); - - BlockSATADev->ClearBuffers(); - BlockHDDev->ClearBuffers(); - BlockNVMeDev->ClearBuffers(); - - AudioDev->ClearBuffers(); - - NetDev->ClearBuffers(); - /* ... */ } void Manager::UnloadAllDrivers() @@ -151,6 +192,9 @@ namespace Driver void Manager::Panic() { Memory::Virtual vmm; + if (Drivers.size() == 0) + return; + foreach (auto Driver in Drivers) { if (!Driver.second.Initialized) @@ -168,21 +212,18 @@ namespace Driver } } - int Manager::LoadDriverFile(uintptr_t &EntryPoint, - uintptr_t &BaseAddress, - Memory::VirtualMemoryArea *dVma, - RefNode *rDrv) + int Manager::LoadDriverFile(uintptr_t &EntryPoint, uintptr_t &BaseAddress, + Memory::VirtualMemoryArea *dVma, FileNode *rDrv) { Elf64_Ehdr ELFHeader; - rDrv->seek(0, SEEK_SET); - rDrv->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + rDrv->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); if (ELFHeader.e_type != ET_DYN) { - error("Driver %s is not a shared object", rDrv->node->FullPath); + error("Driver %s is not a shared object", rDrv->Path.c_str()); return -ENOEXEC; } - trace("Loading driver %s in memory", rDrv->node->Name); + trace("Loading driver %s in memory", rDrv->Name.c_str()); BaseAddress = 0; { @@ -192,8 +233,7 @@ namespace Driver size_t SegmentsSize = 0; for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); - rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + rDrv->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); if (ProgramHeader.p_type == PT_LOAD || ProgramHeader.p_type == PT_DYNAMIC) @@ -217,8 +257,7 @@ namespace Driver for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); - rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + rDrv->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); switch (ProgramHeader.p_type) { @@ -237,8 +276,7 @@ namespace Driver if (ProgramHeader.p_filesz > 0) { - rDrv->seek(ProgramHeader.p_offset, SEEK_SET); - rDrv->read((uint8_t *)SegmentDestination, ProgramHeader.p_filesz); + rDrv->Read(SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -264,8 +302,7 @@ namespace Driver if (ProgramHeader.p_filesz > 0) { - rDrv->seek(ProgramHeader.p_offset, SEEK_SET); - rDrv->read((uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz); + rDrv->Read(DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -288,8 +325,7 @@ namespace Driver Elf64_Phdr ProgramHeader; for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); - rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + rDrv->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); if (ProgramHeader.p_type == PT_DYNAMIC) { @@ -381,14 +417,11 @@ namespace Driver break; } - vfs::RefNode *fd = fs->Open(rDrv->node->FullPath); - - std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); - std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_STRTAB); + std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_SYMTAB); + std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_STRTAB); Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); UNUSED(DynStr); - delete fd; Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr); for (size_t i = 0; i < (PltRelSize->d_un.d_val / sizeof(Elf64_Rela)); i++) @@ -431,14 +464,12 @@ namespace Driver { fixme("DT_SYMTAB"); break; - vfs::RefNode *fd = fs->Open(rDrv->node->FullPath); - std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); - std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_STRTAB); + std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_SYMTAB); + std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_STRTAB); Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); UNUSED(DynStr); - delete fd; size_t symtabEntrySize = 0; Elf64_Dyn *entrySizeDyn = Dynamic; @@ -476,8 +507,8 @@ namespace Driver * this will create more issues :/ */ // if (strcmp(SymbolName, "DriverProbe") == 0) // { - // Drivers[MajorIDCounter].Probe = (int (*)())(BaseAddress + s->st_value); - // debug("Found probe function at %#lx", Drivers[MajorIDCounter].Probe); + // Drivers[DriverIDCounter].Probe = (int (*)())(BaseAddress + s->st_value); + // debug("Found probe function at %#lx", Drivers[DriverIDCounter].Probe); // } } break; @@ -498,7 +529,7 @@ namespace Driver EntryPoint += BaseAddress; debug("Driver %s has entry point %#lx and base %#lx", - rDrv->node->FullPath, EntryPoint, BaseAddress); + rDrv->Path.c_str(), EntryPoint, BaseAddress); /* FIXME: Do not add to the KernelSymbolTable! */ // Memory::SmartHeap sh(rDrv->Size); @@ -510,79 +541,11 @@ namespace Driver Manager::Manager() { - debug("Initializing driver manager"); - const char *DriverDirectory = Config.DriverDirectory; - RefNode *drvDirNode = fs->Open(DriverDirectory); - if (!drvDirNode) - { - error("Failed to open driver directory %s", DriverDirectory); - KPrint("Failed to open driver directory %s", DriverDirectory); - return; - } - - foreach (auto drvNode in drvDirNode->node->Children) - { - if (drvNode->Type != vfs::FILE) - continue; - - if (Execute::GetBinaryType(drvNode->FullPath) != Execute::BinTypeELF) - { - error("Driver %s is not an ELF binary", drvNode->FullPath); - continue; - } - - RefNode *rDrv = drvNode->CreateReference(); - - Memory::VirtualMemoryArea *dVma = - new Memory::VirtualMemoryArea(thisProcess->PageTable); - - uintptr_t EntryPoint, BaseAddress; - int err = this->LoadDriverFile(EntryPoint, BaseAddress, dVma, rDrv); - debug("err = %d (%s)", err, strerror(err)); - if (err != 0) - { - error("Failed to load driver %s: %s", - drvNode->FullPath, strerror(err)); - - delete rDrv; - delete dVma; - continue; - } - delete rDrv; - - Drivers[MajorIDCounter++] = { - .BaseAddress = BaseAddress, - .EntryPoint = EntryPoint, - .vma = dVma, - .Path = drvNode->FullPath, - .InterruptHandlers = new std::unordered_map}; - - dev_t countr = MajorIDCounter - 1; - const char *drvName; - size_t drvNameLen; - cwk_path_get_basename(drvNode->FullPath, &drvName, &drvNameLen); - strncpy(Drivers[countr].Name, drvName, sizeof(Drivers[countr].Name)); - } - - delete drvDirNode; - - InputMouseDev = new MasterDeviceFile("mice", "mouse", DevFS, ddt_Mouse); - InputKeyboardDev = new MasterDeviceFile("key", "kbd", DevFS, ddt_Keyboard); - - BlockSATADev = new MasterDeviceFile("sd", "sd", DevFS, ddt_SATA); - BlockHDDev = new MasterDeviceFile("hd", "hd", DevFS, ddt_ATA); - BlockNVMeDev = new MasterDeviceFile("nvme", "nvme", DevFS, ddt_NVMe); - - AudioDev = new MasterDeviceFile("audio", "snd", DevFS, ddt_Audio); - - NetDev = new MasterDeviceFile("network", "net", DevFS, ddt_Network); } Manager::~Manager() { debug("Unloading drivers"); UnloadAllDrivers(); - delete InputMouseDev; - delete InputKeyboardDev; } } diff --git a/core/driver/scancode.cpp b/core/driver/scancode.cpp index 5cfd730..4728fea 100644 --- a/core/driver/scancode.cpp +++ b/core/driver/scancode.cpp @@ -15,10 +15,9 @@ along with Fennix Kernel. If not, see . */ +#include #include -#include "../../driver.h" - static char ScanCodeConversionTableLower[] = { [KEY_1] = '1', [KEY_2] = '2', diff --git a/core/interrupts_manager.cpp b/core/interrupts_manager.cpp index eb12604..1a973c0 100644 --- a/core/interrupts_manager.cpp +++ b/core/interrupts_manager.cpp @@ -345,15 +345,15 @@ namespace Interrupts #ifdef DEBUG foreach (auto ev in RegisteredEvents) { - void *func = ev.IsHandler - ? ev.Data - : (void *)ev.Callback; + void *fct = ev.IsHandler + ? ev.Data + : (void *)ev.Callback; const char *symbol = ev.IsHandler ? "class" - : KernelSymbolTable->GetSymbol((uintptr_t)func); + : KernelSymbolTable->GetSymbol((uintptr_t)fct); debug("Event IRQ%d [%#lx %s] has priority %ld", - ev.IRQ, func, symbol, ev.Priority); + ev.IRQ, fct, symbol, ev.Priority); } #endif } diff --git a/core/memory/heap_allocators/rpmalloc/rpmalloc.c b/core/memory/heap_allocators/rpmalloc/rpmalloc.c index 68bc2a0..11e6b0f 100644 --- a/core/memory/heap_allocators/rpmalloc/rpmalloc.c +++ b/core/memory/heap_allocators/rpmalloc/rpmalloc.c @@ -173,7 +173,7 @@ typedef volatile _Atomic(int64_t) atomic64_t; typedef volatile _Atomic(void *) atomicptr_t; /* Intellisense errors */ -#ifndef __debug_vscode__ +#ifndef __vscode__ static FORCEINLINE int32_t atomic_load32(atomic32_t *src) { return atomic_load_explicit(src, memory_order_relaxed); } static FORCEINLINE void atomic_store32(atomic32_t *dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_relaxed); } diff --git a/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.cpp b/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.cpp index c366f51..58bd648 100644 --- a/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.cpp +++ b/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.cpp @@ -86,6 +86,6 @@ EXTERNC int __rpmalloc_munmap(void *addr, size_t length) EXTERNC int __rpmalloc_posix_madvise(void *addr, size_t length, int advice) { - function("%#lx %d %d", addr, length, advice); + func("%#lx %d %d", addr, length, advice); return 0; } diff --git a/core/memory/memory.cpp b/core/memory/memory.cpp index 7a69f5c..db2b470 100644 --- a/core/memory/memory.cpp +++ b/core/memory/memory.cpp @@ -427,7 +427,11 @@ NIF void InitializeMemoryManagement() void *malloc(size_t Size) { - assert(Size > 0); + if (Size == 0) + { + warn("Attempt to allocate 0 bytes"); + Size = 16; + } memdbg("malloc(%d)->[%s]", Size, KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) @@ -474,7 +478,11 @@ void *malloc(size_t Size) void *calloc(size_t n, size_t Size) { - assert(Size > 0); + if (Size == 0) + { + warn("Attempt to allocate 0 bytes"); + Size = 16; + } memdbg("calloc(%d, %d)->[%s]", n, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) @@ -521,7 +529,11 @@ void *calloc(size_t n, size_t Size) void *realloc(void *Address, size_t Size) { - assert(Size > 0); + if (Size == 0) + { + warn("Attempt to allocate 0 bytes"); + Size = 16; + } memdbg("realloc(%#lx, %d)->[%s]", Address, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) @@ -568,7 +580,11 @@ void *realloc(void *Address, size_t Size) void free(void *Address) { - assert(Address != nullptr); + if (Address == nullptr) + { + warn("Attempt to free a null pointer"); + return; + } memdbg("free(%#lx)->[%s]", Address, KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) @@ -609,105 +625,3 @@ void free(void *Address) } } } - -void *operator new(std::size_t Size) -{ - assert(Size > 0); - - memdbg("new(%d)->[%s]", Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - void *ret = malloc(Size); - return ret; -} - -void *operator new[](std::size_t Size) -{ - assert(Size > 0); - - memdbg("new[](%d)->[%s]", Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - void *ret = malloc(Size); - return ret; -} - -void *operator new(std::size_t Size, std::align_val_t Alignment) -{ - assert(Size > 0); - - memdbg("new(%d, %d)->[%s]", Size, Alignment, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - fixme("operator new with alignment(%#lx) is not implemented", - Alignment); - - void *ret = malloc(Size); - return ret; -} - -void operator delete(void *Pointer) -{ - assert(Pointer != nullptr); - - memdbg("delete(%#lx)->[%s]", Pointer, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - free(Pointer); -} - -void operator delete[](void *Pointer) -{ - assert(Pointer != nullptr); - - memdbg("delete[](%#lx)->[%s]", Pointer, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - free(Pointer); -} - -void operator delete(void *Pointer, long unsigned int Size) -{ - assert(Pointer != nullptr); - assert(Size > 0); - - memdbg("delete(%#lx, %d)->[%s]", - Pointer, Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - free(Pointer); -} - -void operator delete[](void *Pointer, long unsigned int Size) -{ - assert(Pointer != nullptr); - assert(Size > 0); - - memdbg("delete[](%#lx, %d)->[%s]", - Pointer, Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - free(Pointer); -} - -void operator delete(void *Pointer, unsigned long Size, std::align_val_t Alignment) -{ - assert(Pointer != nullptr); - assert(Size > 0); - - memdbg("delete(%#lx, %d, %d)->[%s]", - Pointer, Size, Alignment, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) - : "Unknown"); - - fixme("operator delete with alignment is not implemented"); - - free(Pointer); -} diff --git a/core/memory/va.cpp b/core/memory/va.cpp index f0325b6..3e6e935 100644 --- a/core/memory/va.cpp +++ b/core/memory/va.cpp @@ -27,7 +27,7 @@ namespace Memory { VirtualAllocation::AllocatedPages VirtualAllocation::RequestPages(size_t Count) { - function("%lld", Count); + func("%lld", Count); void *pAddress = KernelAllocator.RequestPages(Count); memset(pAddress, 0, FROM_PAGES(Count)); @@ -79,7 +79,7 @@ namespace Memory void VirtualAllocation::FreePages(void *Address, size_t Count) { - function("%#lx, %lld", Address, Count); + func("%#lx, %lld", Address, Count); SmartLock(MgrLock); foreach (auto &apl in AllocatedPagesList) @@ -110,7 +110,7 @@ namespace Memory void VirtualAllocation::MapTo(AllocatedPages ap, PageTable *TargetTable) { - function("%#lx, %#lx", ap.VirtualAddress, TargetTable); + func("%#lx, %#lx", ap.VirtualAddress, TargetTable); Virtual vmm(TargetTable); vmm.Map(ap.VirtualAddress, ap.PhysicalAddress, FROM_PAGES(ap.PageCount), RW | KRsv | G); @@ -120,7 +120,7 @@ namespace Memory : BaseAddress(Base), CurrentBase(Base), Table((PageTable *)CPU::PageTable()) { - function("%#lx", Base); + func("%#lx", Base); } VirtualAllocation::~VirtualAllocation() diff --git a/core/memory/vma.cpp b/core/memory/vma.cpp index fbae18f..acb72e5 100644 --- a/core/memory/vma.cpp +++ b/core/memory/vma.cpp @@ -36,9 +36,9 @@ namespace Memory void *VirtualMemoryArea::RequestPages(size_t Count, bool User, bool Protect) { - function("%lld, %s, %s", Count, - User ? "true" : "false", - Protect ? "true" : "false"); + func("%lld, %s, %s", Count, + User ? "true" : "false", + Protect ? "true" : "false"); void *Address = KernelAllocator.RequestPages(Count); memset(Address, 0, Count * PAGE_SIZE); @@ -61,7 +61,7 @@ namespace Memory void VirtualMemoryArea::FreePages(void *Address, size_t Count) { - function("%#lx, %lld", Address, Count); + func("%#lx, %lld", Address, Count); SmartLock(MgrLock); forItr(itr, AllocatedPagesList) @@ -104,7 +104,7 @@ namespace Memory void VirtualMemoryArea::DetachAddress(void *Address) { - function("%#lx", Address); + func("%#lx", Address); SmartLock(MgrLock); forItr(itr, AllocatedPagesList) @@ -128,12 +128,12 @@ namespace Memory bool Read, bool Write, bool Exec, bool Fixed, bool Shared) { - function("%#lx, %lld, %s, %s, %s, %s, %s", Address, Length, - Read ? "true" : "false", - Write ? "true" : "false", - Exec ? "true" : "false", - Fixed ? "true" : "false", - Shared ? "true" : "false"); + func("%#lx, %lld, %s, %s, %s, %s, %s", Address, Length, + Read ? "true" : "false", + Write ? "true" : "false", + Exec ? "true" : "false", + Fixed ? "true" : "false", + Shared ? "true" : "false"); Virtual vmm(this->Table); @@ -191,7 +191,7 @@ namespace Memory bool VirtualMemoryArea::HandleCoW(uintptr_t PFA) { - function("%#lx", PFA); + func("%#lx", PFA); Virtual vmm(this->Table); PageTableEntry *pte = vmm.GetPTE((void *)PFA); @@ -269,7 +269,7 @@ namespace Memory void VirtualMemoryArea::Fork(VirtualMemoryArea *Parent) { - function("%#lx", Parent); + func("%#lx", Parent); assert(Parent); debug("parent apl:%d sr:%d [P:%#lx C:%#lx]", diff --git a/core/panic/diag.cpp b/core/panic/diag.cpp index 3bacd89..cf5c7e8 100644 --- a/core/panic/diag.cpp +++ b/core/panic/diag.cpp @@ -65,7 +65,7 @@ struct DiagnosticFile } Data; }; -nsa bool WriteDiagDataToNode(vfs::RefNode *refFile) +nsa bool WriteDiagDataToNode(FileNode *node) { uintptr_t KStart = (uintptr_t)&_kernel_start; uintptr_t kEnd = (uintptr_t)&_kernel_end; @@ -89,8 +89,8 @@ nsa bool WriteDiagDataToNode(vfs::RefNode *refFile) file->Data.KernelMemoryLength = uint32_t(kSize); memcpy(file->Data.KernelMemory, (void *)KStart, kSize); - ExPrint("\eFAFAFAWriting to %s\n", refFile->node->FullPath); - size_t w = refFile->write(buf, fileSize); + ExPrint("\eFAFAFAWriting to %s\n", node->Path.c_str()); + size_t w = node->Write(buf, fileSize, 0); if (w != fileSize) { debug("%d out of %d bytes written", w, fileSize); @@ -111,7 +111,12 @@ nsa void DiagnosticDataCollection() ExPrint("\n\eFAFAFAPlease wait while we collect some diagnostic information...\n"); ExPrint("This may take a while...\n"); - vfs::Node *panicDir = fs->CreateIfNotExists("/var/panic", vfs::DIRECTORY); + mode_t mode = S_IRWXU | + S_IRWXG | + S_IROTH | + S_IFDIR; + + FileNode *panicDir = fs->ForceCreate(nullptr, "/var/panic", mode); if (!panicDir) { ExPrint("\eFF0000Failed to create /var/panic\n"); @@ -119,6 +124,7 @@ nsa void DiagnosticDataCollection() return; } + FileNode *dumpFile; Time::Clock clock = Time::ReadClock(); char filename[64]; for (int i = 0; i < INT32_MAX; i++) @@ -128,18 +134,18 @@ nsa void DiagnosticDataCollection() if (fs->PathExists(filename, panicDir)) continue; - fs->Create(filename, vfs::FILE, panicDir); + mode = S_IRWXU | + S_IRWXG | + S_IROTH | + S_IFREG; + + dumpFile = fs->Create(panicDir, filename, mode); break; } - vfs::RefNode *refFile = fs->Open(filename, panicDir); - if (!WriteDiagDataToNode(refFile)) - { - delete refFile; + if (!WriteDiagDataToNode(dumpFile)) return; - } ExPrint("You can find the diagnostic file in /var/panic/%s\n", filename); Display->UpdateBuffer(); - delete refFile; } diff --git a/core/panic/ui.cpp b/core/panic/ui.cpp index 94fe1ef..f9380b7 100644 --- a/core/panic/ui.cpp +++ b/core/panic/ui.cpp @@ -517,7 +517,7 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) sym, offset); } else - ExPrint("\eFF5555???\n"); + ExPrint("\eFF5555??? \eFFAAAA<- Exception\n"); if (!sf || !sf->ip || !sf->bp) { @@ -591,7 +591,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru if (Display->GetWidth > 800 && Display->GetHeight > 600) textLimit = 128; - std::list Plist = TaskManager->GetProcessList(); + std::vector Plist = TaskManager->GetProcessList(); ExPrint("\n\eFAFAFAProcess list (%ld):\n", Plist.size()); bool pRdy = false; @@ -626,7 +626,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru Process->ID, StatusColor[Process->State.load()], StatusString[Process->State.load()], Process->Executable - ? Process->Executable->Name + ? Process->Executable->Name.c_str() : "none"); bool tRdy = false; @@ -766,6 +766,29 @@ nsa void DisplayAssertionFailed(const char *File, int Line, const char *Expressi ExPrint(" This is a kernel bug.\n"); ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n"); + CPU::ExceptionFrame ef; + // Fill only the necessary fields + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wframe-address" + + /* Jump over HandleAssertionFailed, and ip will be the function where it failed */ + void *fun = __builtin_return_address(1); + /* Jump over this, HandleAssertionFailed & ip */ + void *stk = __builtin_frame_address(2); + +#pragma GCC diagnostic pop + +#ifdef __x86_64__ + asmv("movq %%cr3, %0" : "=r"(ef.cr3)); + ef.rip = (uint64_t)fun; + ef.rbp = ef.rsp = (uint64_t)stk; +#elif defined(__i386__) + asmv("movl %%cr3, %0" : "=r"(ef.cr3)); + ef.eip = (uint32_t)fun; + ef.ebp = ef.esp = (uint32_t)stk; +#endif + DisplayStackScreen(&ef); Display->UpdateBuffer(); /* TODO: Add additional info */ diff --git a/core/symbols.cpp b/core/symbols.cpp index fc4b348..8f25a51 100644 --- a/core/symbols.cpp +++ b/core/symbols.cpp @@ -40,15 +40,11 @@ namespace SymbolResolver return Result.FunctionName; } - std::vector rSymTable = this->SymTable; - rSymTable.reverse(); - - foreach (auto st in rSymTable) + for (auto it = this->SymTable.rbegin(); it != this->SymTable.rend(); ++it) { - if (unlikely(st.Address <= Address && - st.Address > Result.Address)) + if (unlikely(it->Address <= Address && it->Address > Result.Address)) { - Result = st; + Result = *it; break; } } @@ -72,14 +68,11 @@ namespace SymbolResolver return Result.Address; } - std::vector rSymTable = this->SymTable; - rSymTable.reverse(); - - foreach (auto st in rSymTable) + for (auto it = this->SymTable.rbegin(); it != this->SymTable.rend(); ++it) { - if (unlikely(strcmp(st.FunctionName, Name) == 0)) + if (unlikely(strcmp(it->FunctionName, Name) == 0)) { - Result = st; + Result = *it; break; } } diff --git a/exec/binary_parse.cpp b/exec/binary_parse.cpp index 1fccc49..cf61535 100644 --- a/exec/binary_parse.cpp +++ b/exec/binary_parse.cpp @@ -18,63 +18,65 @@ #include #include +#include +#include #include "../kernel.h" namespace Execute { - BinaryType GetBinaryType(const char *Path) + BinaryType GetBinaryType(FileNode *Node) { - debug("Checking binary type of %s(ptr: %#lx)", - Path, Path); + debug("Checking binary type of %s", Node->Path.c_str()); BinaryType Type; - vfs::RefNode *fd = fs->Open(Path); - if (fd == nullptr) - { - debug("Failed to open file %s", Path); - return (BinaryType)-ENOENT; - } + if (Node == nullptr) + ReturnLogError((BinaryType)-ENOENT, "Node is null"); - debug("File opened: %s, descriptor %d", Path, fd); - Memory::SmartHeap sh = Memory::SmartHeap(1024); - fd->read(sh, 128); + Elf32_Ehdr ELFHeader; + Node->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0); - Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.Get(); - IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)sh.Get(); + mach_header MachHeader; + Node->Read(&MachHeader, sizeof(mach_header), 0); + + IMAGE_DOS_HEADER MZHeader; + Node->Read(&MZHeader, sizeof(IMAGE_DOS_HEADER), 0); /* Check ELF header. */ - if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 && - ELFHeader->e_ident[EI_MAG1] == ELFMAG1 && - ELFHeader->e_ident[EI_MAG2] == ELFMAG2 && - ELFHeader->e_ident[EI_MAG3] == ELFMAG3) + if (ELFHeader.e_ident[EI_MAG0] == ELFMAG0 && + ELFHeader.e_ident[EI_MAG1] == ELFMAG1 && + ELFHeader.e_ident[EI_MAG2] == ELFMAG2 && + ELFHeader.e_ident[EI_MAG3] == ELFMAG3) { debug("Image - ELF"); Type = BinaryType::BinTypeELF; goto Success; } - /* Check MZ header. */ - else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE) + if (MachHeader.magic == MH_MAGIC || MachHeader.magic == MH_CIGAM) { - fd->seek(MZHeader->e_lfanew, SEEK_SET); - fd->read(sh, 512); - IMAGE_NT_HEADERS *PEHeader = - (IMAGE_NT_HEADERS *)(((char *)sh.Get()) + - MZHeader->e_lfanew); + debug("Image - Mach-O"); + Type = BinaryType::BinTypeMachO; + goto Success; + } - IMAGE_OS2_HEADER *NEHeader = - (IMAGE_OS2_HEADER *)(((char *)sh.Get()) + - MZHeader->e_lfanew); + /* Check MZ header. */ + else if (MZHeader.e_magic == IMAGE_DOS_SIGNATURE) + { + IMAGE_NT_HEADERS PEHeader; + Node->Read(&PEHeader, sizeof(IMAGE_NT_HEADERS), MZHeader.e_lfanew); + + IMAGE_OS2_HEADER NEHeader; + Node->Read(&NEHeader, sizeof(IMAGE_OS2_HEADER), MZHeader.e_lfanew); /* TODO: LE, EDOS */ - if (PEHeader->Signature == IMAGE_NT_SIGNATURE) + if (PEHeader.Signature == IMAGE_NT_SIGNATURE) { debug("Image - PE"); Type = BinaryType::BinTypePE; goto Success; } - else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE) + else if (NEHeader.ne_magic == IMAGE_OS2_SIGNATURE) { debug("Image - NE"); Type = BinaryType::BinTypeNE; @@ -92,7 +94,12 @@ namespace Execute Type = BinaryType::BinTypeUnknown; Success: - delete fd; return Type; } + + BinaryType GetBinaryType(std::string Path) + { + FileNode *node = fs->GetByPath(Path.c_str(), nullptr); + return GetBinaryType(node); + } } diff --git a/exec/elf/elf_loader.cpp b/exec/elf/elf_loader.cpp index 4eff8f1..8c60315 100644 --- a/exec/elf/elf_loader.cpp +++ b/exec/elf/elf_loader.cpp @@ -33,15 +33,16 @@ using namespace vfs; namespace Execute { void ELFObject::GenerateAuxiliaryVector_x86_32(Memory::VirtualMemoryArea *vma, - vfs::RefNode *fd, + FileNode *fd, Elf32_Ehdr ELFHeader, uint32_t EntryPoint, uint32_t BaseAddress) { + assert(!"Function not implemented"); } void ELFObject::GenerateAuxiliaryVector_x86_64(Memory::VirtualMemoryArea *vma, - vfs::RefNode *fd, + FileNode *fd, Elf64_Ehdr ELFHeader, uint64_t EntryPoint, uint64_t BaseAddress) @@ -50,8 +51,8 @@ namespace Execute char *aux_platform = (char *)vma->RequestPages(1, true); /* TODO: 4KiB is too much for this */ strcpy(aux_platform, "x86_64"); - void *execfn_str = vma->RequestPages(TO_PAGES(strlen(fd->node->FullPath) + 1), true); - strcpy((char *)execfn_str, fd->node->FullPath); + void *execfn_str = vma->RequestPages(TO_PAGES(fd->Path.size() + 1), true); + strcpy((char *)execfn_str, fd->Path.c_str()); void *at_random = vma->RequestPages(1, true); *(uint64_t *)at_random = Random::rand16(); @@ -93,22 +94,21 @@ namespace Execute #endif } - void ELFObject::LoadExec_x86_32(vfs::RefNode *, PCB *) + void ELFObject::LoadExec_x86_32(FileNode *, PCB *) { - stub; + assert(!"Function not implemented"); } - void ELFObject::LoadExec_x86_64(vfs::RefNode *fd, PCB *TargetProcess) + void ELFObject::LoadExec_x86_64(FileNode *fd, PCB *TargetProcess) { #if defined(a64) std::vector PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP); foreach (auto Interp in PhdrINTERP) { Memory::SmartHeap InterpreterPath = Memory::SmartHeap(256); - fd->seek(Interp.p_offset, SEEK_SET); - fd->read(InterpreterPath, 256); + fd->Read(InterpreterPath, 256, Interp.p_offset); - vfs::RefNode *ifd = fs->Open((const char *)InterpreterPath.Get()); + FileNode *ifd = fs->GetByPath((const char *)InterpreterPath.Get(), TargetProcess->Info.RootNode); if (ifd == nullptr) { warn("Failed to open interpreter file: %s", @@ -121,7 +121,6 @@ namespace Execute { warn("Interpreter %s is not an ELF file", (const char *)InterpreterPath.Get()); - delete ifd; continue; } @@ -130,15 +129,13 @@ namespace Execute /* FIXME: specify argv[1] as the location for the interpreter */ debug("Interpreter loaded successfully"); - delete ifd; return; } } } - Elf64_Ehdr ELFHeader; - fd->seek(0, SEEK_SET); - fd->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + Elf64_Ehdr ELFHeader{}; + fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); uintptr_t EntryPoint = ELFHeader.e_entry; debug("Entry point is %#lx", EntryPoint); @@ -152,8 +149,7 @@ namespace Execute Elf64_Phdr ProgramHeader; for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - fd->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); - fd->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + fd->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); switch (ProgramHeader.p_type) { case PT_LOAD: @@ -182,10 +178,8 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { - debug("%d %#lx %d", ProgramHeader.p_offset, - (uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz); - fd->seek(ProgramHeader.p_offset, SEEK_SET); - fd->read((uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz); + debug("%d %#lx %d", ProgramHeader.p_offset, (uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz); + fd->Read((uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -203,40 +197,35 @@ namespace Execute case PT_NOTE: { Elf64_Nhdr NoteHeader; - fd->seek(ProgramHeader.p_offset, SEEK_SET); - fd->read((uint8_t *)&NoteHeader, sizeof(Elf64_Nhdr)); + fd->Read(&NoteHeader, sizeof(Elf64_Nhdr), ProgramHeader.p_offset); switch (NoteHeader.n_type) { case NT_PRSTATUS: { Elf64_Prstatus prstatus; - fd->seek(ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); - fd->read((uint8_t *)&prstatus, sizeof(Elf64_Prstatus)); + fd->Read(&prstatus, sizeof(Elf64_Prstatus), ProgramHeader.p_offset + sizeof(Elf64_Nhdr)); debug("PRSTATUS: %#lx", prstatus.pr_reg[0]); break; } case NT_PRPSINFO: { Elf64_Prpsinfo prpsinfo; - fd->seek(ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); - fd->read((uint8_t *)&prpsinfo, sizeof(Elf64_Prpsinfo)); + fd->Read(&prpsinfo, sizeof(Elf64_Prpsinfo), ProgramHeader.p_offset + sizeof(Elf64_Nhdr)); debug("PRPSINFO: %s", prpsinfo.pr_fname); break; } case NT_PLATFORM: { char platform[256]; - fd->seek(ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); - fd->read((uint8_t *)&platform, 256); + fd->Read(&platform, sizeof(platform), ProgramHeader.p_offset + sizeof(Elf64_Nhdr)); debug("PLATFORM: %s", platform); break; } case NT_AUXV: { Elf64_auxv_t auxv; - fd->seek(ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); - fd->read((uint8_t *)&auxv, sizeof(Elf64_auxv_t)); + fd->Read(&auxv, sizeof(Elf64_auxv_t), ProgramHeader.p_offset + sizeof(Elf64_Nhdr)); debug("AUXV: %#lx", auxv.a_un.a_val); break; } @@ -254,8 +243,7 @@ namespace Execute debug("TLS Size: %ld (%ld pages)", tlsSize, TO_PAGES(tlsSize)); void *tlsMemory = vma->RequestPages(TO_PAGES(tlsSize)); - fd->seek(ProgramHeader.p_offset, SEEK_SET); - fd->read((uint8_t *)tlsMemory, tlsSize); + fd->Read(tlsMemory, tlsSize, ProgramHeader.p_offset); TargetProcess->TLS = { .pBase = uintptr_t(tlsMemory), .vBase = ProgramHeader.p_vaddr, @@ -323,23 +311,22 @@ namespace Execute #endif } - void ELFObject::LoadDyn_x86_32(vfs::RefNode *, PCB *) + void ELFObject::LoadDyn_x86_32(FileNode *, PCB *) { - stub; + assert(!"Function not implemented"); } - void ELFObject::LoadDyn_x86_64(vfs::RefNode *fd, PCB *TargetProcess) + void ELFObject::LoadDyn_x86_64(FileNode *fd, PCB *TargetProcess) { #if defined(a64) std::vector PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP); foreach (auto Interp in PhdrINTERP) { Memory::SmartHeap InterpreterPath = Memory::SmartHeap(256); - fd->seek(Interp.p_offset, SEEK_SET); - fd->read(InterpreterPath, 256); + fd->Read(InterpreterPath, 256, Interp.p_offset); InterpreterPath = InterpreterPath; - vfs::RefNode *ifd = fs->Open((const char *)InterpreterPath.Get()); + FileNode *ifd = fs->GetByPath((const char *)InterpreterPath.Get(), TargetProcess->Info.RootNode); if (ifd == nullptr) { warn("Failed to open interpreter file: %s", @@ -352,22 +339,19 @@ namespace Execute { warn("Interpreter %s is not an ELF file", (const char *)InterpreterPath.Get()); - delete ifd; continue; } if (LoadInterpreter(ifd, TargetProcess)) { debug("Interpreter loaded successfully"); - delete ifd; return; } } } Elf64_Ehdr ELFHeader; - fd->seek(0, SEEK_SET); - fd->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); uintptr_t EntryPoint = ELFHeader.e_entry; debug("Entry point is %#lx", EntryPoint); @@ -383,8 +367,7 @@ namespace Execute size_t SegmentsSize = 0; for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - fd->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); - fd->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + fd->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); if (ProgramHeader.p_type == PT_LOAD || ProgramHeader.p_type == PT_DYNAMIC) @@ -408,8 +391,7 @@ namespace Execute for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - fd->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); - fd->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + fd->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); switch (ProgramHeader.p_type) { @@ -428,8 +410,7 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { - fd->seek(ProgramHeader.p_offset, SEEK_SET); - fd->read((uint8_t *)SegmentDestination, ProgramHeader.p_filesz); + fd->Read(SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -455,8 +436,7 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { - fd->seek(ProgramHeader.p_offset, SEEK_SET); - fd->read((uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz); + fd->Read(DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -559,14 +539,11 @@ namespace Execute // Elf64_Shdr shdr; // for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++) // { - // fd->seek(ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET); - // fd->read((uint8_t *)&shdr, sizeof(Elf64_Shdr)); + // fd->Read(&shdr, sizeof(Elf64_Shdr), ELFHeader.e_shoff + i * sizeof(Elf64_Shdr)); // char sectionName[32]; // Elf64_Shdr n_shdr; - // fd->seek(ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr), SEEK_SET); - // fd->read((uint8_t *)&n_shdr, sizeof(Elf64_Shdr)); - // fd->seek(n_shdr.sh_offset + shdr.sh_name, SEEK_SET); - // fd->read((uint8_t *)sectionName, 32); + // fd->Read(&n_shdr, sizeof(Elf64_Shdr), ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr)); + // fd->Read(sectionName, sizeof(sectionName), n_shdr.sh_offset + shdr.sh_name); // debug("shdr: %s", sectionName); // if (strcmp(sectionName, ".rela.plt") == 0) // { @@ -692,8 +669,7 @@ namespace Execute // // STT_OBJECT // Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; // Elf64_Sym *SymArray = new Elf64_Sym[numEntries]; - // fd->seek(shdr.sh_offset, SEEK_SET); - // fd->read((uint8_t *)SymArray, shdr.sh_size); + // fd->Read(SymArray, shdr.sh_size, shdr.sh_offset); // debug("start %#lx (off %#lx), entries %ld", // SymArray, shdr.sh_addr, numEntries); // for (Elf64_Xword j = 0; j < numEntries; j++) @@ -734,10 +710,10 @@ namespace Execute #endif } - bool ELFObject::LoadInterpreter(vfs::RefNode *fd, PCB *TargetProcess) + bool ELFObject::LoadInterpreter(FileNode *fd, PCB *TargetProcess) { Elf32_Ehdr ELFHeader; - fd->read((uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr)); + fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0); switch (ELFHeader.e_type) { @@ -805,24 +781,24 @@ namespace Execute return false; } - ELFObject::ELFObject(char *AbsolutePath, + ELFObject::ELFObject(std::string AbsolutePath, PCB *TargetProcess, const char **argv, const char **envp) { if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF) { - error("%s is not an ELF file or is invalid.", AbsolutePath); + error("%s is not an ELF file or is invalid.", AbsolutePath.c_str()); return; } - vfs::RefNode *fd = fs->Open(AbsolutePath); + FileNode *fd = fs->GetByPath(AbsolutePath.c_str(), TargetProcess->Info.RootNode); if (fd == nullptr) { - error("Failed to open %s, errno: %d", AbsolutePath, fd); + error("Failed to open %s, errno: %d", AbsolutePath.c_str(), fd); return; } - debug("Opened %s", AbsolutePath); + debug("Opened %s", AbsolutePath.c_str()); int argc = 0; int envc = 0; @@ -833,17 +809,15 @@ namespace Execute envc++; Elf32_Ehdr ELFHeader; - fd->read((uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr)); + fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0); std::vector PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP); const char *ElfInterpPath = nullptr; if (!PhdrINTERP.empty() && ELFHeader.e_type == ET_DYN) { - fd->seek(PhdrINTERP.front().p_offset, SEEK_SET); ElfInterpPath = new char[256]; - fd->read((uint8_t *)ElfInterpPath, 256); + fd->Read(ElfInterpPath, 256, PhdrINTERP.front().p_offset); debug("Interpreter: %s", ElfInterpPath); - fd->seek(0, SEEK_SET); argc++; } @@ -945,8 +919,6 @@ namespace Execute break; } } - - delete fd; } ELFObject::~ELFObject() diff --git a/exec/elf/elf_parse.cpp b/exec/elf/elf_parse.cpp index d7e8698..64e8a24 100644 --- a/exec/elf/elf_parse.cpp +++ b/exec/elf/elf_parse.cpp @@ -58,7 +58,7 @@ namespace Execute return StringTable + Offset; } - Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name) + Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, std::string Name) { Elf64_Shdr *SymbolTable = nullptr; Elf64_Shdr *StringTable = nullptr; @@ -86,36 +86,31 @@ namespace Execute { Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym))); char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name); - if (strcmp(String, Name) == 0) + if (strcmp(String, Name.c_str()) == 0) return Symbol; } return nullptr; } - Elf64_Sym ELFLookupSymbol(vfs::RefNode *fd, const char *Name) + Elf64_Sym ELFLookupSymbol(FileNode *fd, std::string Name) { #if defined(a64) - off_t OldOffset = fd->seek(0, SEEK_CUR); + Elf64_Ehdr Header{}; + fd->Read(&Header, sizeof(Elf64_Ehdr), 0); - Elf64_Ehdr Header; - fd->seek(0, SEEK_SET); - fd->read((uint8_t *)&Header, sizeof(Elf64_Ehdr)); - - Elf64_Shdr SymbolTable; - Elf64_Shdr StringTable; + Elf64_Shdr SymbolTable{}; + Elf64_Shdr StringTable{}; for (Elf64_Half i = 0; i < Header.e_shnum; i++) { Elf64_Shdr shdr; - fd->seek(Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET); - fd->read((uint8_t *)&shdr, sizeof(Elf64_Shdr)); + fd->Read(&shdr, sizeof(Elf64_Shdr), Header.e_shoff + (i * sizeof(Elf64_Shdr))); switch (shdr.sh_type) { case SHT_SYMTAB: SymbolTable = shdr; - fd->seek(Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET); - fd->read((uint8_t *)&StringTable, sizeof(Elf64_Shdr)); + fd->Read(&StringTable, sizeof(Elf64_Shdr), Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr))); break; default: { @@ -124,11 +119,9 @@ namespace Execute } } - if (SymbolTable.sh_name == 0 || - StringTable.sh_name == 0) + if (SymbolTable.sh_name == 0 || StringTable.sh_name == 0) { error("Symbol table not found."); - fd->seek(OldOffset, SEEK_SET); return {}; } @@ -136,22 +129,16 @@ namespace Execute { // Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym))); Elf64_Sym Symbol; - fd->seek(SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET); - fd->read((uint8_t *)&Symbol, sizeof(Elf64_Sym)); + fd->Read(&Symbol, sizeof(Elf64_Sym), SymbolTable.sh_offset + (i * sizeof(Elf64_Sym))); // char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name); char String[256]; - fd->seek(StringTable.sh_offset + Symbol.st_name, SEEK_SET); - fd->read((uint8_t *)&String, 256); + fd->Read(&String, sizeof(String), StringTable.sh_offset + Symbol.st_name); - if (strcmp(String, Name) == 0) - { - fd->seek(OldOffset, SEEK_SET); + if (strcmp(String, Name.c_str()) == 0) return Symbol; - } } error("Symbol not found."); - fd->seek(OldOffset, SEEK_SET); #endif return {}; } diff --git a/exec/elf/parse/elf_get_dynamic_tag.cpp b/exec/elf/parse/elf_get_dynamic_tag.cpp index 0f46e40..f66a424 100644 --- a/exec/elf/parse/elf_get_dynamic_tag.cpp +++ b/exec/elf/parse/elf_get_dynamic_tag.cpp @@ -21,16 +21,14 @@ namespace Execute { - std::vector ELFGetDynamicTag_x86_64(vfs::RefNode *fd, + std::vector ELFGetDynamicTag_x86_64(FileNode *fd, DynamicArrayTags Tag) { #if defined(a64) || defined(aa64) - off_t OldOffset = fd->seek(0, SEEK_CUR); std::vector Ret; - Elf64_Ehdr ELFHeader; - fd->seek(0, SEEK_SET); - fd->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + Elf64_Ehdr ELFHeader{}; + fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); std::vector DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC); @@ -42,11 +40,10 @@ namespace Execute foreach (auto Phdr in DYNAMICPhdrs) { - Elf64_Dyn Dynamic; + Elf64_Dyn Dynamic{}; for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++) { - fd->seek(Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET); - fd->read((uint8_t *)&Dynamic, sizeof(Elf64_Dyn)); + fd->Read(&Dynamic, sizeof(Elf64_Dyn), Phdr.p_offset + (i * sizeof(Elf64_Dyn))); if (Dynamic.d_tag != Tag) continue; @@ -57,7 +54,6 @@ namespace Execute } } - fd->seek(OldOffset, SEEK_SET); return Ret; #elif defined(a32) return {}; diff --git a/exec/elf/parse/elf_get_sections.cpp b/exec/elf/parse/elf_get_sections.cpp index 86e8c2f..e078988 100644 --- a/exec/elf/parse/elf_get_sections.cpp +++ b/exec/elf/parse/elf_get_sections.cpp @@ -21,24 +21,20 @@ namespace Execute { - std::vector ELFGetSections_x86_64(vfs::RefNode *fd, + std::vector ELFGetSections_x86_64(FileNode *fd, const char *SectionName) { #if defined(a64) || defined(aa64) - off_t OldOffset = fd->seek(0, SEEK_CUR); std::vector Ret; - Elf64_Ehdr ELFHeader; - fd->seek(0, SEEK_SET); - fd->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + Elf64_Ehdr ELFHeader{}; + fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum]; - fd->seek(ELFHeader.e_shoff, SEEK_SET); - fd->read((uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum); + fd->Read(SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum, ELFHeader.e_shoff); char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size]; - fd->seek(SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET); - fd->read((uint8_t *)SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size); + fd->Read(SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size, SectionHeaders[ELFHeader.e_shstrndx].sh_offset); for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i) { @@ -47,7 +43,6 @@ namespace Execute Ret.push_back(SectionHeaders[i]); } - fd->seek(OldOffset, SEEK_SET); delete[] SectionHeaders; delete[] SectionNames; return Ret; diff --git a/exec/elf/parse/elf_get_symbol_type.cpp b/exec/elf/parse/elf_get_symbol_type.cpp index d6446b3..4adeac1 100644 --- a/exec/elf/parse/elf_get_symbol_type.cpp +++ b/exec/elf/parse/elf_get_symbol_type.cpp @@ -21,31 +21,28 @@ namespace Execute { - std::vector ELFGetSymbolType_x86_64(vfs::RefNode *fd, + std::vector ELFGetSymbolType_x86_64(FileNode *fd, SegmentTypes Tag) { #if defined(a64) || defined(aa64) - off_t OldOffset = fd->seek(0, SEEK_CUR); std::vector Ret; - Elf64_Ehdr ELFHeader; - fd->seek(0, SEEK_SET); - fd->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + Elf64_Ehdr ELFHeader{}; + fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); - Elf64_Phdr ProgramHeaders; - fd->seek(ELFHeader.e_phoff, SEEK_SET); - fd->read((uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr)); + Elf64_Phdr ProgramHeaders{}; + fd->Read(&ProgramHeaders, sizeof(Elf64_Phdr), ELFHeader.e_phoff); + off_t currentOffset = ELFHeader.e_phoff; for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { if (ProgramHeaders.p_type == Tag) Ret.push_back(ProgramHeaders); - fd->seek(sizeof(Elf64_Phdr), SEEK_CUR); - fd->read((uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr)); + currentOffset += sizeof(Elf64_Phdr); + fd->Read(&ProgramHeaders, sizeof(Elf64_Phdr), currentOffset); } - fd->seek(OldOffset, SEEK_SET); return Ret; #elif defined(a32) return {}; diff --git a/exec/spawn.cpp b/exec/spawn.cpp index 3d548a3..7885f25 100644 --- a/exec/spawn.cpp +++ b/exec/spawn.cpp @@ -35,15 +35,12 @@ namespace Execute Tasking::TaskCompatibility Compatibility, bool Critical) { - vfs::RefNode *fd = fs->Open(Path); + FileNode *fd = fs->GetByPath(Path, nullptr); if (fd == nullptr) return -ENOENT; - if (fd->node->Type == vfs::NodeType::DIRECTORY) - { - delete fd; - return -EISDIR; - } + if (!fd->IsRegularFile()) + return -ENOEXEC; switch (GetBinaryType(Path)) { @@ -53,7 +50,7 @@ namespace Execute const char *BaseName; cwk_path_get_basename(Path, &BaseName, nullptr); Elf32_Ehdr ELFHeader; - fd->read((uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr)); + fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0); switch (ELFHeader.e_machine) { @@ -119,22 +116,20 @@ namespace Execute if (Parent == nullptr) Parent = thisProcess; - Process = TaskManager->CreateProcess(Parent, - BaseName, + Process = TaskManager->CreateProcess(Parent, BaseName, TaskExecutionMode::User, false, 0, 0); Process->Info.Compatibility = Compatibility; Process->Info.Architecture = Arch; } - Process->SetWorkingDirectory(fs->GetNodeFromPath(Path)->Parent); + Process->SetWorkingDirectory(fs->GetByPath(Path, nullptr)->Parent); Process->SetExe(Path); ELFObject *obj = new ELFObject(Path, Process, argv, envp); if (!obj->IsValid) { error("Failed to load ELF object"); - delete fd; delete Process; return -ENOEXEC; } @@ -142,23 +137,20 @@ namespace Execute vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors; vfs::FileDescriptorTable *fdt = Process->FileDescriptors; - auto ForkStdio = [pfdt, fdt](Node *SearchNode) + auto ForkStdio = [pfdt, fdt](FileNode *SearchNode) { if (unlikely(SearchNode == nullptr)) return false; - std::vector - pfds = pfdt->GetFileDescriptors(); - - foreach (auto ffd in pfds) + foreach (const auto &ffd in pfdt->FileMap) { - if (ffd.Flags & O_CLOEXEC) + if (ffd.second.Flags & O_CLOEXEC) continue; - if (ffd.Handle->node == SearchNode) + if (ffd.second.Node == SearchNode) { - fdt->_open(ffd.Handle->node->FullPath, - ffd.Flags, ffd.Mode); + fdt->usr_open(ffd.second.Node->Path.c_str(), + ffd.second.Flags, ffd.second.Mode); return true; } } @@ -166,37 +158,31 @@ namespace Execute }; if (!ForkStdio(Parent->stdin)) - fdt->_open("/dev/kcon", O_RDWR, 0666); + fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (!ForkStdio(Parent->stdout)) - fdt->_open("/dev/kcon", O_RDWR, 0666); + fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (!ForkStdio(Parent->stderr)) - fdt->_open("/dev/kcon", O_RDWR, 0666); + fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); TCB *Thread = nullptr; { CriticalSection cs; - Thread = TaskManager->CreateThread(Process, - obj->InstructionPointer, + Thread = TaskManager->CreateThread(Process, obj->InstructionPointer, obj->argv, obj->envp, obj->auxv, - Arch, - Compatibility); + Arch, Compatibility); Thread->SetCritical(Critical); } - delete fd; return Thread->ID; } default: { - debug("Unknown binary type: %d", - GetBinaryType(Path)); - delete fd; + debug("Unknown binary type: %d", GetBinaryType(Path)); return -ENOEXEC; } } - delete fd; return -ENOEXEC; } } diff --git a/syscalls/native/lseek.cpp b/include/cbuf.hpp similarity index 57% rename from syscalls/native/lseek.cpp rename to include/cbuf.hpp index 9380788..c81d459 100644 --- a/syscalls/native/lseek.cpp +++ b/include/cbuf.hpp @@ -15,25 +15,31 @@ along with Fennix Kernel. If not, see . */ -#include +#ifndef __FENNIX_KERNEL_CIRCULAR_BUFFER_H__ +#define __FENNIX_KERNEL_CIRCULAR_BUFFER_H__ -#include +#include #include -#include -#include -#include -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/lseek.html */ -off_t sys_lseek(SysFrm *, int fildes, - off_t offset, int whence) +class CircularBuffer { - function("%d, %d, %d", fildes, offset, whence); - PCB *pcb = thisProcess; - vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_lseek(fildes, offset, whence); -} +private: + spin_lock Lock; + uint8_t *Buffer; + size_t BufferSize; + size_t BufferCount; + + size_t Head; + size_t Tail; + +public: + CircularBuffer(size_t Size); + ~CircularBuffer(); + size_t Write(const uint8_t *Data, size_t Size); + size_t Read(uint8_t *Data, size_t Size); + size_t Peek(uint8_t *Data, size_t Size); + size_t Count(); + size_t Free(); +}; + +#endif // !__FENNIX_KERNEL_CIRCULAR_BUFFER_H__ diff --git a/include/convert.h b/include/convert.h index 5f3cf0f..b78891c 100644 --- a/include/convert.h +++ b/include/convert.h @@ -17,6 +17,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" @@ -31,11 +32,7 @@ extern "C" #define NAN (__builtin_nanf("")) - int isdigit(int c); - int isspace(int c); int isempty(char *str); - int isalpha(int c); - int isupper(int c); unsigned int isdelim(char c, const char *delim); long abs(long i); void swap(char *x, char *y); diff --git a/include/cwalk.h b/include/cwalk.h index 463db64..18d6c23 100644 --- a/include/cwalk.h +++ b/include/cwalk.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2020 Leonard Iklé +Copyright (c) 2024 Leonard Iklé Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,8 @@ SOFTWARE. #ifndef CWK_LIBRARY_H #define CWK_LIBRARY_H -#include +#include +#include #if defined(_WIN32) || defined(__CYGWIN__) #define CWK_EXPORT __declspec(dllexport) @@ -344,9 +345,10 @@ CWK_PUBLIC size_t cwk_path_change_extension(const char *path, * This function creates a normalized version of the path within the specified * buffer. This function will not write out more than the specified buffer can * contain. However, the generated string is always null-terminated - even if - * not the whole path is written out. The function returns the total number of - * characters the complete buffer would have, even if it was not written out - * completely. The path may be the same memory address as the buffer. + * not the whole path is written out. The returned value is the amount of + * characters which the resulting path would take if it was not truncated + * (excluding the null-terminating character). The path may be the same memory + * address as the buffer. * * The following will be true for the normalized path: * 1) "../" will be resolved. @@ -518,4 +520,4 @@ CWK_PUBLIC enum cwk_path_style cwk_path_get_style(void); } // extern "C" #endif -#endif \ No newline at end of file +#endif diff --git a/include/debug.h b/include/debug.h index 4d6ce79..3db02ad 100644 --- a/include/debug.h +++ b/include/debug.h @@ -50,11 +50,11 @@ namespace SysDbg #ifdef DEBUG #define debug(Format, ...) SysDbg::WriteLine(DebugLevelDebug, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) #define ubsan(Format, ...) SysDbg::WriteLine(DebugLevelUbsan, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) -#define function(Format, ...) SysDbg::WriteLine(DebugLevelFunction, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) +#define func(Format, ...) SysDbg::WriteLine(DebugLevelFunction, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) #else #define debug(Format, ...) #define ubsan(Format, ...) -#define function(Format, ...) +#define func(Format, ...) #endif #define trace(Format, ...) SysDbg::WriteLine(DebugLevelTrace, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) #define fixme(Format, ...) SysDbg::WriteLine(DebugLevelFixme, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) @@ -89,11 +89,11 @@ void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, co #ifdef DEBUG #define debug(Format, ...) SysDbgWriteLine(DebugLevelDebug, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) #define ubsan(Format, ...) SysDbgWriteLine(DebugLevelUbsan, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) -#define function(Format, ...) SysDbgWriteLine(DebugLevelFunction, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) +#define func(Format, ...) SysDbgWriteLine(DebugLevelFunction, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) #else #define debug(Format, ...) #define ubsan(Format, ...) -#define function(Format, ...) +#define func(Format, ...) #endif #define trace(Format, ...) SysDbgWriteLine(DebugLevelTrace, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) #define fixme(Format, ...) SysDbgWriteLine(DebugLevelFixme, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__) diff --git a/include/display.hpp b/include/display.hpp index 5a93fae..34ea83e 100644 --- a/include/display.hpp +++ b/include/display.hpp @@ -24,6 +24,7 @@ #include #include #include +#include extern uintptr_t _binary_files_tamsyn_font_1_11_Tamsyn10x20b_psf_end; extern uintptr_t _binary_files_tamsyn_font_1_11_Tamsyn10x20b_psf_size; diff --git a/include/driver.hpp b/include/driver.hpp index b5bdc0c..f6db9ee 100644 --- a/include/driver.hpp +++ b/include/driver.hpp @@ -38,111 +38,6 @@ namespace Driver char GetScanCode(uint8_t ScanCode, bool Upper); bool IsValidChar(uint8_t ScanCode); - class SlaveDeviceFile : public vfs::Node - { - private: - int /* DeviceDriverType */ DeviceType; - - std::list KeyQueue; - - public: - typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t); - typedef int (*drvClose_t)(dev_t, dev_t); - typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t); - typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t); - typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *); - - drvOpen_t Open; - drvClose_t Close; - drvRead_t Read; - drvWrite_t Write; - drvIoctl_t Ioctl; - - int open(int Flags, mode_t Mode) final; - int close() final; - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - int ioctl(unsigned long Request, - void *Argp) final; - - void ClearBuffers(); - - int ReportKeyEvent(uint8_t ScanCode); - - SlaveDeviceFile(const char *Name, vfs::Node *Parent, int Type, vfs::NodeType NType); - ~SlaveDeviceFile(); - }; - - class MasterDeviceFile : private vfs::Node - { - private: - typedef dev_t maj_t; - typedef dev_t min_t; - char SlaveName[16]; - vfs::Node *SlaveParent; - int /* DeviceDriverType */ DeviceType; - min_t SlaveIDCounter = 0; - - typedef std::unordered_map *Slaves; - std::unordered_map SlavesMap; - - std::list RawKeyQueue; - std::list KeyQueue; - bool UpperCase = false; - bool CapsLock = false; - - public: - typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t); - typedef int (*drvClose_t)(dev_t, dev_t); - typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t); - typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t); - typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *); - - int open(int Flags, mode_t Mode) final; - int close() final; - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - int ioctl(unsigned long Request, - void *Argp) final; - - void ClearBuffers(); - - int ReportKeyEvent(maj_t ID, min_t MinorID, uint8_t ScanCode); - int ReportMouseEvent(maj_t ID, min_t MinorID, - bool LeftButton, bool RightButton, bool MiddleButton, - bool Button4, bool Button5, bool Button6, - bool Button7, bool Button8, - uintptr_t X, uintptr_t Y, int8_t Z, bool Relative); - - int ReportNetworkPacket(maj_t ID, min_t MinorID, void *Buffer, size_t Size); - - int NewBlock(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, - drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl); - - int NewAudio(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, - drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl); - - int NewNet(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, - drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl); - - dev_t Register(maj_t ID); - int Unregister(maj_t ID, min_t MinorID); - - MasterDeviceFile(const char *MasterName, - const char *SlaveName, - vfs::Node *Parent, - int Type); - ~MasterDeviceFile(); - }; - struct DriverObject { uintptr_t BaseAddress = 0; @@ -150,7 +45,7 @@ namespace Driver Memory::VirtualMemoryArea *vma = nullptr; /* Path has the same pointer as in the Node */ - const char *Path = nullptr; + std::string Path; std::unordered_map *InterruptHandlers; char Name[32] = {'\0'}; @@ -172,28 +67,18 @@ namespace Driver private: NewLock(ModuleInitLock); std::unordered_map Drivers; - dev_t MajorIDCounter = 0; + dev_t DriverIDCounter = 0; int LoadDriverFile(uintptr_t &EntryPoint, uintptr_t &BaseAddress, Memory::VirtualMemoryArea *dVma, - vfs::RefNode *rDrv); + FileNode *rDrv); public: - MasterDeviceFile *InputMouseDev = nullptr; - MasterDeviceFile *InputKeyboardDev = nullptr; - - MasterDeviceFile *BlockSATADev = nullptr; - MasterDeviceFile *BlockHDDev = nullptr; - MasterDeviceFile *BlockNVMeDev = nullptr; - - MasterDeviceFile *AudioDev = nullptr; - - MasterDeviceFile *NetDev = nullptr; - std::unordered_map & GetDrivers() { return Drivers; } + void PreloadDrivers(); void LoadAllDrivers(); void UnloadAllDrivers(); void Panic(); diff --git a/include/exec.hpp b/include/exec.hpp index a78c340..30a0720 100644 --- a/include/exec.hpp +++ b/include/exec.hpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -36,6 +35,7 @@ namespace Execute BinTypePE, BinTypeNE, BinTypeMZ, + BinTypeMachO, BinTypeUnknown }; @@ -67,20 +67,20 @@ namespace Execute void *ELFProgramHeaders; void GenerateAuxiliaryVector_x86_32(Memory::VirtualMemoryArea *vma, - vfs::RefNode *fd, Elf32_Ehdr ELFHeader, + FileNode *fd, Elf32_Ehdr ELFHeader, uint32_t EntryPoint, uint32_t BaseAddress); void GenerateAuxiliaryVector_x86_64(Memory::VirtualMemoryArea *vma, - vfs::RefNode *fd, Elf64_Ehdr ELFHeader, + FileNode *fd, Elf64_Ehdr ELFHeader, uint64_t EntryPoint, uint64_t BaseAddress); - void LoadExec_x86_32(vfs::RefNode *fd, Tasking::PCB *TargetProcess); - void LoadExec_x86_64(vfs::RefNode *fd, Tasking::PCB *TargetProcess); - void LoadDyn_x86_32(vfs::RefNode *fd, Tasking::PCB *TargetProcess); - void LoadDyn_x86_64(vfs::RefNode *fd, Tasking::PCB *TargetProcess); - bool LoadInterpreter(vfs::RefNode *fd, Tasking::PCB *TargetProcess); + void LoadExec_x86_32(FileNode *fd, Tasking::PCB *TargetProcess); + void LoadExec_x86_64(FileNode *fd, Tasking::PCB *TargetProcess); + void LoadDyn_x86_32(FileNode *fd, Tasking::PCB *TargetProcess); + void LoadDyn_x86_64(FileNode *fd, Tasking::PCB *TargetProcess); + bool LoadInterpreter(FileNode *fd, Tasking::PCB *TargetProcess); public: decltype(IsElfValid) &IsValid = IsElfValid; @@ -89,14 +89,15 @@ namespace Execute decltype(ELFenvp) &envp = ELFenvp; decltype(Elfauxv) &auxv = Elfauxv; - ELFObject(char *AbsolutePath, + ELFObject(std::string AbsolutePath, Tasking::PCB *TargetProcess, const char **argv, const char **envp); ~ELFObject(); }; - BinaryType GetBinaryType(const char *Path); + BinaryType GetBinaryType(FileNode *Path); + BinaryType GetBinaryType(std::string Path); int Spawn(char *Path, const char **argv, const char **envp, Tasking::PCB *Parent = nullptr, bool Fork = false, @@ -108,18 +109,18 @@ namespace Execute Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index); char *GetELFStringTable(Elf64_Ehdr *Header); char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset); - Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name); - Elf64_Sym ELFLookupSymbol(vfs::RefNode *fd, const char *Name); + Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, std::string Name); + Elf64_Sym ELFLookupSymbol(FileNode *fd, std::string Name); uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index); - std::vector ELFGetSymbolType_x86_64(vfs::RefNode *fd, SegmentTypes Tag); - std::vector ELFGetSymbolType_x86_32(vfs::RefNode *fd, SegmentTypes Tag); + std::vector ELFGetSymbolType_x86_64(FileNode *fd, SegmentTypes Tag); + std::vector ELFGetSymbolType_x86_32(FileNode *fd, SegmentTypes Tag); - std::vector ELFGetSections_x86_64(vfs::RefNode *fd, const char *SectionName); - std::vector ELFGetSections_x86_32(vfs::RefNode *fd, const char *SectionName); + std::vector ELFGetSections_x86_64(FileNode *fd, std::string SectionName); + std::vector ELFGetSections_x86_32(FileNode *fd, std::string SectionName); - std::vector ELFGetDynamicTag_x86_64(vfs::RefNode *fd, DynamicArrayTags Tag); - std::vector ELFGetDynamicTag_x86_32(vfs::RefNode *fd, DynamicArrayTags Tag); + std::vector ELFGetDynamicTag_x86_64(FileNode *fd, DynamicArrayTags Tag); + std::vector ELFGetDynamicTag_x86_32(FileNode *fd, DynamicArrayTags Tag); } #endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__ diff --git a/include/filesystem.hpp b/include/filesystem.hpp index a5f093b..c718dbf 100644 --- a/include/filesystem.hpp +++ b/include/filesystem.hpp @@ -20,309 +20,136 @@ #include -#include +#include +#include #include #include -#include #include #include +#include -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 +static_assert(DTTOIF(DT_FIFO) == S_IFIFO); +static_assert(IFTODT(S_IFCHR) == DT_CHR); -/** Other users have execute permission. */ -#define S_IXOTH 0001 -/** Other users have write permission. */ -#define S_IWOTH 0002 -/** Other users have read permission. */ -#define S_IROTH 0004 -/** Other users have read, write, and execute permissions. */ -#define S_IRWXO 0007 -/** Group members have execute permission. */ -#define S_IXGRP 0010 -/** Group members have write permission. */ -#define S_IWGRP 0020 -/** Group members have read permission. */ -#define S_IRGRP 0040 -/** Group members have read, write, and execute permissions. */ -#define S_IRWXG 0070 -/** The file owner has execute permission. */ -#define S_IXUSR 0100 -/** The file owner has write permission. */ -#define S_IWUSR 0200 -/** The file owner has read permission. */ -#define S_IRUSR 0400 -/** The file owner has read, write, - * and execute permissions. */ -#define S_IRWXU 0700 +#define __check_op(op, ...) \ + if (fsi->Ops.op == nullptr) \ + return -ENOTSUP; \ + else \ + return fsi->Ops.op(this->Node, ##__VA_ARGS__) -#define O_RDONLY 00 -#define O_WRONLY 01 -#define O_RDWR 02 -#define O_CREAT 0100 -#define O_EXCL 0200 -#define O_TRUNC 01000 -#define O_APPEND 02000 -#define O_CLOEXEC 02000000 - -#define S_IFIFO 0010000 -#define S_IFCHR 0020000 -#define S_IFDIR 0040000 -#define S_IFBLK 0060000 -#define S_IFREG 0100000 -#define S_IFLNK 0120000 -#define S_IFSOCK 0140000 - -#define S_IFMT 0170000 - -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) -#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) -#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) -#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) -#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) - -struct kstat +class FileNode { - /** Device ID of the file. */ - dev_t st_dev; - /** Inode number. */ - ino_t st_ino; - /** File type and mode. */ - mode_t st_mode; - /** Number of hard links. */ - nlink_t st_nlink; - /** User ID of the file's owner. */ - uid_t st_uid; - /** Group ID of the file's owner. */ - gid_t st_gid; - /** Device ID for special files. */ - dev_t st_rdev; - /** Size of the file in bytes. */ - off_t st_size; - /** Time of last access. */ - time_t st_atime; - /** Time of last modification. */ - time_t st_mtime; - /** Time of last status change. */ - time_t st_ctime; - /** Optimal I/O block size. */ - blksize_t st_blksize; - /** Number of blocks allocated. */ - blkcnt_t st_blocks; - /** Additional file attributes. */ - mode_t st_attr; +public: + std::string Name, Path; + FileNode *Parent; + std::vector Children; + Inode *Node; + FileSystemInfo *fsi; + + bool IsDirectory() { return S_ISDIR(Node->Mode); } + bool IsCharacterDevice() { return S_ISCHR(Node->Mode); } + bool IsBlockDevice() { return S_ISBLK(Node->Mode); } + bool IsRegularFile() { return S_ISREG(Node->Mode); } + bool IsFIFO() { return S_ISFIFO(Node->Mode); } + bool IsSymbolicLink() { return S_ISLNK(Node->Mode); } + bool IsSocket() { return S_ISSOCK(Node->Mode); } + + int Lookup(const char *Name, Inode **Node) { __check_op(Lookup, Name, Node); } + int Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, Name, Mode, Node); } + int Remove(const char *Name) { __check_op(Remove, Name); } + int Rename(const char *OldName, const char *NewName) { __check_op(Rename, OldName, NewName); } + ssize_t Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, (void *)Buffer, Size, Offset); } + ssize_t Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, (const void *)Buffer, Size, Offset); } + int Truncate(off_t Size) { __check_op(Truncate, Size); } + int Open(int Flags, mode_t Mode) { __check_op(Open, Flags, Mode); } + int Close() { __check_op(Close); } + int Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, Request, Argp); } + ssize_t ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, Buffer, Size, Offset, Entries); } + int MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, Name, Mode, Result); } + int RmDir(const char *Name) { __check_op(RmDir, Name); } + int SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, Name, Target, Result); } + ssize_t ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, (char *)Buffer, Size); } + off_t Seek(off_t Offset) { __check_op(Seek, Offset); } + int Stat(struct kstat *Stat) { __check_op(Stat, Stat); } + + ~FileNode() = delete; }; -static inline int ConvertFileFlags(const char *Mode) -{ - int Flags = 0; - - if (strchr(Mode, '+')) - Flags |= O_RDWR; - else if (*Mode == 'r') - Flags |= O_RDONLY; - else - Flags |= O_WRONLY; - - if (strchr(Mode, 'x')) - Flags |= O_EXCL; - - if (strchr(Mode, 'e')) - Flags |= O_CLOEXEC; - - if (*Mode != 'r') - Flags |= O_CREAT; - - if (*Mode == 'w') - Flags |= O_TRUNC; - - if (*Mode == 'a') - Flags |= O_APPEND; - - return Flags; -} +#undef __check_op namespace vfs { - enum NodeType : mode_t + struct vfsInode { - NODE_TYPE_NONE = 0x0, - FILE = S_IFREG, - DIRECTORY = S_IFDIR, - CHARDEVICE = S_IFCHR, - BLOCKDEVICE = S_IFBLK, - PIPE = S_IFIFO, - SYMLINK = S_IFLNK, - MOUNTPOINT = S_IFDIR - }; - - class RefNode; - - /** - * Virtual filesystem node - * - * @note https://isocpp.org/wiki/faq/freestore-mgmt#delete-this - */ - class Node - { - private: - NewLock(NodeLock); - - public: - virtual int open(int Flags, mode_t Mode); - virtual int close(); - virtual size_t read(uint8_t *Buffer, size_t Size, off_t Offset); - virtual size_t write(uint8_t *Buffer, size_t Size, off_t Offset); - virtual int ioctl(unsigned long Request, void *Argp); - // virtual int stat(struct kstat *Stat); - // virtual int lstat(struct kstat *Stat); - // virtual int fstat(struct kstat *Stat); - // virtual int unlink(); - // virtual int mkdir(mode_t Mode); - // virtual int rmdir(); - // virtual int rename(const char *NewName); - // virtual int chmod(mode_t Mode); - // virtual int chown(uid_t User, gid_t Group); - // virtual int truncate(off_t Size); - // virtual int symlink(const char *Target); - // virtual int readlink(char *Buffer, size_t Size); - // virtual int mount(Node *Target); - // virtual int umount(); - - typedef int (*open_t)(int, mode_t); - typedef int (*close_t)(); - typedef size_t (*read_t)(uint8_t *, size_t, off_t); - typedef size_t (*write_t)(uint8_t *, size_t, off_t); - typedef int (*ioctl_t)(unsigned long, void *); - - open_t open_ptr = nullptr; - close_t close_ptr = nullptr; - read_t read_ptr = nullptr; - write_t write_ptr = nullptr; - ioctl_t ioctl_ptr = nullptr; - - class Virtual *vFS = nullptr; - Node *Parent = nullptr; - const char *Name; - const char *FullPath; - NodeType Type; - ino_t IndexNode; - - const char *Symlink; - Node *SymlinkTarget; - - mode_t Mode; - uid_t UserIdentifier; - gid_t GroupIdentifier; - - dev_t DeviceMajor; - dev_t DeviceMinor; - - time_t AccessTime; - time_t ModifyTime; - time_t ChangeTime; - - off_t Size; - std::vector Children; - - std::vector References; - RefNode *CreateReference(); - void RemoveReference(RefNode *Reference); - - /** - * Create a new node - * - * @param Parent The parent node - * @param Name The name of the node - * @param Type The type of the node - * @param NoParent If true, the Parent will - * be used as a hint for the parent node, but it - * won't be set as the parent node. - * @param fs The virtual filesystem (only if - * NoParent is set) - * @param Err If not nullptr, the function will - * write the error code to the given address. - */ - Node(Node *Parent, - const char *Name, - NodeType Type, - bool NoParent = false, - Virtual *fs = nullptr, - int *Err = nullptr); - - virtual ~Node(); - }; - - class RefNode - { - private: - std::atomic_int64_t FileOffset = 0; - off_t FileSize = 0; - Node *n; - RefNode *SymlinkTo; - - public: - void *SpecialData; - - decltype(FileSize) &Size = FileSize; - decltype(n) &node = n; - - size_t read(uint8_t *Buffer, size_t Size); - size_t write(uint8_t *Buffer, size_t Size); - off_t seek(off_t Offset, int Whence); - int ioctl(unsigned long Request, void *Argp); - - RefNode(Node *node); - ~RefNode(); - - friend class Virtual; - friend class FileDescriptorTable; + Inode Node; + std::string Name; + std::vector Children; }; class Virtual { private: - Node *FileSystemRoot = nullptr; NewLock(VirtualLock); - Node *GetParent(const char *Path, Node *Parent); - /** @note This function is NOT thread safe */ - Node *GetNodeFromPath_Unsafe(const char *Path, Node *Parent = nullptr); + struct FSMountInfo + { + FileSystemInfo *fsi; + Inode *Root; + }; + + struct CacheNode + { + FileNode *fn; + std::atomic_int References; + }; + + std::unordered_map DeviceMap; + std::atomic_bool RegisterLock = false; + + FileNode *__CacheRecursiveSearch(FileNode *, const char *, bool); + FileNode *CacheLookup(const char *Path); + FileNode *CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode); + + int RemoveCacheNode(FileNode *Node); public: - Node *nRoot = nullptr; - Node *GetNodeFromPath(const char *Path, Node *Parent = nullptr); + vfsInode *FileSystemRoots = nullptr; bool PathIsRelative(const char *Path); - - Node *GetRootNode() { return FileSystemRoot; } - - const char *NormalizePath(const char *Path, Node *Parent = nullptr); - bool PathExists(const char *Path, Node *Parent = nullptr); - - Node *Create(const char *Path, NodeType Type, Node *Parent = nullptr); - Node *CreateLink(const char *Path, const char *Target, Node *Parent); - - int Delete(const char *Path, bool Recursive = false, Node *Parent = nullptr); - int Delete(Node *Path, bool Recursive = false, Node *Parent = nullptr); + bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); } /** - * Open a file - * @param Path The path to the file, relative or absolute. The buffer shouldn't be modified while the function is running. - * @param Parent Pointer to the parent node, if nullptr, the root node will be used. - * @return A pointer to the vfs::ReferenceNode, or nullptr if the file doesn't exist. + * Reserve a device number for a filesystem + * + * @note After this function is called, the filesystem must + * call LateRegisterFileSystem to release the lock */ - RefNode *Open(const char *Path, Node *Parent = nullptr); + dev_t EarlyReserveDevice(); - Node *CreateIfNotExists(const char *Path, NodeType Type, Node *Parent = nullptr); + /** + * Register a filesystem after the device number has been reserved + */ + int LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root); + dev_t RegisterFileSystem(FileSystemInfo *fsi, Inode *Root); + int UnregisterFileSystem(dev_t Device); + + void AddRoot(Inode *Root); + FileNode *GetRoot(size_t Index); + + FileNode *Create(FileNode *Parent, const char *Name, mode_t Mode); + FileNode *ForceCreate(FileNode *Parent, const char *Name, mode_t Mode); + + FileNode *GetByPath(const char *Path, FileNode *Parent); + FileNode *CreateLink(const char *Path, FileNode *Parent, const char *Target); + FileNode *CreateLink(const char *Path, FileNode *Parent, FileNode *Target); + bool PathExists(const char *Path, FileNode *Parent); + + int Remove(FileNode *Node); + + void Initialize(); Virtual(); ~Virtual(); - - friend class Node; }; class FileDescriptorTable @@ -330,63 +157,59 @@ namespace vfs public: struct Fildes { - RefNode *Handle = nullptr; + enum FildesType + { + FD_INODE, + FD_PIPE, + FD_SOCKET, + } Type; mode_t Mode = 0; int Flags = 0; - int Descriptor = -1; + FileNode *Node = nullptr; + int References = 0; + off_t Offset = 0; int operator==(const Fildes &other) { - return this->Handle == other.Handle && - this->Mode == other.Mode && - this->Flags == other.Flags && - this->Descriptor == other.Descriptor; + return Type == other.Type && + Mode == other.Mode && + Flags == other.Flags && + Node == other.Node && + References == other.References && + Offset == other.Offset; } - - int operator!=(const Fildes &other) - { - return !(*this == other); - } - } __attribute__((packed)) nullfd; + }; private: - std::vector FileDescriptors; - std::vector FildesDuplicates; - vfs::Node *fdDir = nullptr; + FileNode *fdDir = nullptr; + void *Owner; - Fildes &GetFileDescriptor(int FileDescriptor); - FileDescriptorTable::Fildes &GetDupFildes(int FileDescriptor); - - int ProbeMode(mode_t Mode, int Flags); int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags); int RemoveFileDescriptor(int FileDescriptor); int GetFreeFileDescriptor(); public: - Fildes &GetDescriptor(int FileDescriptor); - const char *GetAbsolutePath(int FileDescriptor); - std::vector &GetFileDescriptors() { return FileDescriptors; } - std::vector &GetFileDescriptorsDuplicates() { return FildesDuplicates; } - RefNode *GetRefNode(int FileDescriptor); + std::unordered_map FileMap; + int GetFlags(int FileDescriptor); int SetFlags(int FileDescriptor, int Flags); void Fork(FileDescriptorTable *Parent); - int _open(const char *pathname, int flags, mode_t mode); - int _creat(const char *pathname, mode_t mode); - ssize_t _read(int fd, void *buf, size_t count); - ssize_t _write(int fd, const void *buf, size_t count); - int _close(int fd); - off_t _lseek(int fd, off_t offset, int whence); - int _stat(const char *pathname, struct kstat *statbuf); - int _fstat(int fd, struct kstat *statbuf); - int _lstat(const char *pathname, struct kstat *statbuf); - int _dup(int oldfd); - int _dup2(int oldfd, int newfd); - int _ioctl(int fd, unsigned long request, void *argp); + int usr_open(const char *pathname, int flags, mode_t mode); + int usr_creat(const char *pathname, mode_t mode); + ssize_t usr_read(int fd, void *buf, size_t count); + ssize_t usr_write(int fd, const void *buf, size_t count); + int usr_close(int fd); + off_t usr_lseek(int fd, off_t offset, int whence); + int usr_stat(const char *pathname, struct kstat *statbuf); + int usr_fstat(int fd, struct kstat *statbuf); + int usr_lstat(const char *pathname, struct kstat *statbuf); + int usr_dup(int oldfd); + int usr_dup2(int oldfd, int newfd); + int usr_ioctl(int fd, unsigned long request, void *argp); FileDescriptorTable(void *Owner); - ~FileDescriptorTable(); + ~FileDescriptorTable() = default; }; } diff --git a/include/filesystem/fat.hpp b/include/filesystem/fat.hpp deleted file mode 100644 index 5c58054..0000000 --- a/include/filesystem/fat.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_FILESYSTEM_FAT_H__ -#define __FENNIX_KERNEL_FILESYSTEM_FAT_H__ - -#include - -#include - -namespace vfs -{ - class FAT - { - public: - enum FatType - { - Unknown, - FAT12, - FAT16, - FAT32 - }; - - /* https://wiki.osdev.org/FAT */ - struct BIOSParameterBlock - { - /** The first three bytes EB 3C 90 disassemble to JMP SHORT 3C NOP. - * (The 3C value may be different.) The reason for this is to jump - * over the disk format information (the BPB and EBPB). Since the - * first sector of the disk is loaded into ram at location - * 0x0000:0x7c00 and executed, without this jump, the processor - * would attempt to execute data that isn't code. Even for - * non-bootable volumes, code matching this pattern (or using the - * E9 jump opcode) is required to be present by both Windows and - * OS X. To fulfil this requirement, an infinite loop can be placed - * here with the bytes EB FE 90. */ - uint8_t JumpBoot[3]; - - /** OEM identifier. The first 8 Bytes (3 - 10) is the version of DOS - * being used. The next eight Bytes 29 3A 63 7E 2D 49 48 and 43 read - * out the name of the version. The official FAT Specification from - * Microsoft says that this field is really meaningless and is ignored - * by MS FAT Modules, however it does recommend the value "MSWIN4.1" - * as some 3rd party drivers supposedly check it and expect it to - * have that value. Older versions of dos also report MSDOS5.1, - * linux-formatted floppy will likely to carry "mkdosfs" here, and - * FreeDOS formatted disks have been observed to have "FRDOS5.1" here. - * If the string is less than 8 bytes, it is padded with spaces. */ - uint8_t OEM[8]; - - /** The number of Bytes per sector (remember, all numbers are in the - * little-endian format). */ - uint16_t BytesPerSector; - - /** Number of sectors per cluster. */ - uint8_t SectorsPerCluster; - - /** Number of reserved sectors. The boot record sectors are included - * in this value. */ - uint16_t ReservedSectors; - - /** Number of File Allocation Tables (FAT's) on the storage media. - * Often this value is 2. */ - uint8_t NumberOfFATs; - - /** Number of root directory entries (must be set so that the root - * directory occupies entire sectors). */ - uint16_t RootDirectoryEntries; - - /** The total sectors in the logical volume. If this value is 0, it - * means there are more than 65535 sectors in the volume, and the - * actual count is stored in the Large Sector Count entry at 0x20. */ - uint16_t Sectors16; - - /** This Byte indicates the media descriptor type. */ - uint8_t Media; - - /** Number of sectors per FAT. FAT12/FAT16 only. */ - uint16_t SectorsPerFAT; - - /** Number of sectors per track. */ - uint16_t SectorsPerTrack; - - /** Number of heads or sides on the storage media. */ - uint16_t NumberOfHeads; - - /** Number of hidden sectors. (i.e. the LBA of the beginning of - * the partition). */ - uint32_t HiddenSectors; - - /** Large sector count. This field is set if there are more than - * 65535 sectors in the volume, resulting in a value which does not - * fit in the Number of Sectors entry at 0x13. */ - uint32_t Sectors32; - } __packed; - - FatType GetFATType(BIOSParameterBlock *bpb); - FAT(void *partition); - ~FAT(); - }; -} - -#endif // !__FENNIX_KERNEL_FILESYSTEM_FAT_H__ diff --git a/include/filesystem/ioctl.hpp b/include/filesystem/ioctl.hpp index ee5ae64..8c23231 100644 --- a/include/filesystem/ioctl.hpp +++ b/include/filesystem/ioctl.hpp @@ -20,7 +20,7 @@ #include #include -#include +#include #define _IOC_NRBITS 8 #define _IOC_TYPEBITS 8 diff --git a/include/filesystem/mounts.hpp b/include/filesystem/mounts.hpp index feb2c8f..793a451 100644 --- a/include/filesystem/mounts.hpp +++ b/include/filesystem/mounts.hpp @@ -20,184 +20,53 @@ #include -#include #include #include -#include +#include #include #include namespace vfs { - class vfsRoot : public Node - { - public: - vfsRoot(const char *Name, Virtual *vfs_ctx); - ~vfsRoot() {} - }; - - class NullDevice : public Node - { - public: - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - - NullDevice(); - ~NullDevice(); - }; - - class RandomDevice : public Node - { - public: - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - - RandomDevice(); - ~RandomDevice(); - }; - - class ZeroDevice : public Node - { - public: - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - - ZeroDevice(); - ~ZeroDevice(); - }; - - class KConDevice : public Node - { - public: - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - int ioctl(unsigned long Request, - void *Argp) final; - - termios term{}; - winsize termSize{}; - - KConDevice(); - ~KConDevice(); - }; - - class TTYDevice : public Node - { - public: - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - int ioctl(unsigned long Request, - void *Argp) final; - - TTYDevice(); - ~TTYDevice(); - }; - - class MasterPTY - { - NewLock(PTYLock); - - public: - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); - - MasterPTY(); - ~MasterPTY(); - }; - - class SlavePTY - { - NewLock(PTYLock); - - public: - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); - - SlavePTY(); - ~SlavePTY(); - }; - - class PTYDevice : public Node + class PTYDevice { private: - Node *pts; + Inode *pts; int id; - int fildes; - bool isMaster; termios term{}; winsize termSize{}; - MasterPTY *MasterDev; - SlavePTY *SlaveDev; + class PTYSlave + { + }; + + class PTYMaster + { + }; public: decltype(id) &ptyId = id; - decltype(fildes) &fd = fildes; - int open(int Flags, mode_t Mode) final; - int close() final; - size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset) final; - int ioctl(unsigned long Request, - void *Argp) final; + ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset); + ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset); + int Ioctl(struct Inode *Node, unsigned long Request, void *Argp); - int OpenMaster(int Flags, mode_t Mode); - - PTYDevice(Node *pts, int id); + PTYDevice(Inode *pts, int id); ~PTYDevice(); }; - class PTMXDevice : public Node + class PTMXDevice { private: NewLock(PTMXLock); - Node *pts; + FileNode *ptmx; + FileNode *pts; Bitmap ptysId; - std::vector ptysList; + std::unordered_map ptysList; public: - int open(int Flags, mode_t Mode) final; - - /** - * Remove a PTY from the list - * - * @param fd The file descriptor of the PTY - * @param pcb The process that owns the PTY - * - * @note if pcb is nullptr, the current process - * will be used. - * - */ - void RemovePTY(int fd, Tasking::PCB *pcb = nullptr); + int Open(struct Inode *Node, int Flags, mode_t Mode, struct Inode *Result); + int Close(struct Inode *Node); PTMXDevice(); ~PTMXDevice(); diff --git a/include/filesystem/ustar.hpp b/include/filesystem/ustar.hpp index f87e7e7..58ac8cb 100644 --- a/include/filesystem/ustar.hpp +++ b/include/filesystem/ustar.hpp @@ -18,38 +18,40 @@ #ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__ #define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__ -#include - #include namespace vfs { - class USTARNode : public Node - { - private: - uintptr_t Address; - - public: - size_t read(uint8_t *Buffer, size_t Size, off_t Offset) final; - - USTARNode(uintptr_t Address, const char *Name, NodeType Type, - Virtual *vfs_ctx); - - ~USTARNode(); - }; - class USTAR { - - enum FileType + public: + enum TypeFlag { - REGULAR_FILE = '0', - HARDLINK = '1', - SYMLINK = '2', - CHARDEV = '3', - BLOCKDEV = '4', - DIRECTORY = '5', - FIFO = '6' + AREGTYPE = '\0', + REGTYPE = '0', + LNKTYPE = '1', + SYMTYPE = '2', + CHRTYPE = '3', + BLKTYPE = '4', + DIRTYPE = '5', + FIFOTYPE = '6', + CONTTYPE = '7' + }; + + enum ModeFlag + { + TSUID = 04000, + TSGID = 02000, + TSVTX = 01000, + TUREAD = 00400, + TUWRITE = 00200, + TUEXEC = 00100, + TGREAD = 00040, + TGWRITE = 00020, + TGEXEC = 00010, + TOREAD = 00004, + TOWRITE = 00002, + TOEXEC = 00001, }; struct FileHeader @@ -73,7 +75,23 @@ namespace vfs char pad[12]; }; + constexpr static int INODE_CHECKSUM = 0x7757A4; + + struct USTARInode + { + struct Inode Node; + FileHeader *Header; + USTARInode *Parent; + std::string Name; + std::string Path; + std::vector Children; + bool Deleted; + int Checksum; + }; + private: + std::unordered_map Files; + inline uint32_t GetSize(const char *String) { uint32_t ret = 0; @@ -95,11 +113,25 @@ namespace vfs } public: + dev_t DeviceID = -1; + ino_t NextInode = 0; + + int Lookup(struct Inode *Parent, const char *Name, struct Inode **Result); + int Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); + ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset); + ssize_t ReadDir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries); + int SymLink(struct Inode *Node, const char *Name, const char *Target, struct Inode **Result); + ssize_t ReadLink(struct Inode *Node, char *Buffer, size_t Size); + int Stat(struct Inode *Node, struct kstat *Stat); + bool TestArchive(uintptr_t Address); - void ReadArchive(uintptr_t Address, Virtual *vfs_ctx); - USTAR(); - ~USTAR(); + void ReadArchive(uintptr_t Address, size_t Size); + + USTAR(){}; + ~USTAR(){}; }; } +bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size); + #endif // !__FENNIX_KERNEL_FILESYSTEM_USTAR_H__ diff --git a/driver.h b/include/interface/driver.h similarity index 78% rename from driver.h rename to include/interface/driver.h index ad5c26d..0644b21 100644 --- a/driver.h +++ b/include/interface/driver.h @@ -194,40 +194,22 @@ typedef enum typedef enum { - ddt_Keyboard, - ddt_Mouse, - ddt_Joystick, - ddt_Gamepad, - ddt_Touchpad, - ddt_Touchscreen, + IOCTL_AUDIO_GET_VOLUME = 0, + IOCTL_AUDIO_SET_VOLUME = 1, - ddt_SATA, - ddt_ATA, - ddt_NVMe, + IOCTL_AUDIO_GET_MUTE = 2, + IOCTL_AUDIO_SET_MUTE = 3, - ddt_Audio, + IOCTL_AUDIO_GET_SAMPLE_RATE = 4, + IOCTL_AUDIO_SET_SAMPLE_RATE = 5, - ddt_Network, -} DeviceDriverType; - -typedef enum -{ - IOCTL_AUDIO_GET_VOLUME, - IOCTL_AUDIO_SET_VOLUME, - - IOCTL_AUDIO_GET_MUTE, - IOCTL_AUDIO_SET_MUTE, - - IOCTL_AUDIO_GET_SAMPLE_RATE, - IOCTL_AUDIO_SET_SAMPLE_RATE, - - IOCTL_AUDIO_GET_CHANNELS, - IOCTL_AUDIO_SET_CHANNELS, + IOCTL_AUDIO_GET_CHANNELS = 6, + IOCTL_AUDIO_SET_CHANNELS = 7, } AudioIoctl; typedef enum { - IOCTL_NET_GET_MAC, + IOCTL_NET_GET_MAC = 0, } NetIoctl; typedef enum @@ -261,25 +243,9 @@ typedef struct int (*UnregisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); int (*UnregisterAllInterruptHandlers)(dev_t MajorID, void *Handler); - /* Input */ - dev_t (*RegisterInputDevice)(dev_t MajorID, DeviceDriverType Type); - int (*UnregisterInputDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); - int (*ReportKeyboardEvent)(dev_t MajorID, dev_t MinorID, uint8_t ScanCode); - int (*ReportRelativeMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z); - int (*ReportAbsoluteMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z); - - /* Storage */ - dev_t (*RegisterBlockDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl); - int (*UnregisterBlockDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); - - /* Audio */ - dev_t (*RegisterAudioDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl); - int (*UnregisterAudioDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); - - /* Network */ - dev_t (*RegisterNetDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl); - int (*UnregisterNetDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); - int (*ReportNetworkPacket)(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size); + /* /dev/... */ + dev_t (*RegisterDevice)(dev_t MajorID, char Prefix[8], void *Open, void *Close, void *Read, void *Write, void *Ioctl); + int (*UnregisterDevice)(dev_t MajorID, dev_t MinorID); /* Logging */ void (*KPrint)(dev_t MajorID, const char *Format, va_list args); diff --git a/include/interface/errno.h b/include/interface/errno.h new file mode 100644 index 0000000..38aea8c --- /dev/null +++ b/include/interface/errno.h @@ -0,0 +1,604 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_ERRNO_H__ +#define __FENNIX_KERNEL_ERRNO_H__ + +/** + * The documentation for these error codes are from: + * https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html + * + * Full list: + * https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/errno.h.html + */ +typedef enum +{ + /** + * No Error + */ + EOK = 0, + + /** + * Argument list too long. The sum of the number of bytes used by the + * new process image's argument list and environment list is greater + * than the system-imposed limit of {ARG_MAX} bytes. + * or: + * Lack of space in an output buffer. + * or: + * Argument is greater than the system-imposed maximum. + */ + E2BIG = 1, + + /** + * Permission denied. An attempt was made to access a file in a way + * forbidden by its file access permissions. + */ + EACCES = 2, + + /** + * Address in use. The specified address is in use. + */ + EADDRINUSE = 3, + + /** + * Address not available. The specified address is not available from + * the local system. + */ + EADDRNOTAVAIL = 4, + + /** + * Address family not supported. The implementation does not support + * the specified address family, or the specified address is not a + * valid address for the address family of the specified socket. + */ + EAFNOSUPPORT = 5, + + /** + * Resource temporarily unavailable. This is a temporary condition + * and later calls to the same routine may complete normally. + */ + EAGAIN = 6, + + /** + * Connection already in progress. A connection request is already in + * progress for the specified socket. + */ + EALREADY = 7, + + /** + * Bad file descriptor. A file descriptor argument is out of range, + * refers to no open file, or a read (write) request is made to a + * file that is only open for writing (reading). + */ + EBADF = 8, + + /** + * Bad message. During a read(), getmsg(), getpmsg(), or ioctl() + * I_RECVFD request to a STREAMS device, a message arrived at the + * head of the STREAM that is inappropriate for the function + * receiving the message. + * read() + * Message waiting to be read on a STREAM is not a data message. + * getmsg() or getpmsg() + * A file descriptor was received instead of a control message. + * ioctl() + * Control or data information was received instead of a file + * descriptor when I_RECVFD was specified. + */ + EBADMSG = 9, + + /** + * Resource busy. An attempt was made to make use of a system + * resource that is not currently available, as it is being + * used by another process in a manner that would have + * conflicted with the request being made by this process. + */ + EBUSY = 10, + + /** + * Operation canceled. The associated asynchronous operation was + * canceled before completion. + */ + ECANCELED = 11, + + /** + * No child process. A wait(), waitid(), or waitpid() function was + * executed by a process that had no existing or unwaited-for + * child process. + */ + ECHILD = 12, + + /** + * Connection aborted. The connection has been aborted. + */ + ECONNABORTED = 13, + + /** + * Connection refused. An attempt to connect to a socket was refused + * because there was no process listening or because the queue of + * connection requests was full and the underlying protocol does not + * support retransmissions. + */ + ECONNREFUSED = 14, + + /** + * Connection reset. The connection was forcibly closed by the peer. + */ + ECONNRESET = 15, + + /** + * Resource deadlock would occur. An attempt was made to lock a system + * resource that would have resulted in a deadlock situation. + */ + EDEADLK = 16, + + /** + * Destination address required. No bind address was established. + */ + EDESTADDRREQ = 17, + + /** + * Domain error. An input argument is outside the defined domain of the + * mathematical function (defined in the ISO C standard). + */ + EDOM = 18, + + /** + * Reserved. + */ + EDQUOT = 19, + + /** + * File exists. An existing file was mentioned in an inappropriate + * context; for example, as a new link name in the link() function. + */ + EEXIST = 20, + + /** + * Bad address. The system detected an invalid address in attempting + * to use an argument of a call. The reliable detection of this error + * cannot be guaranteed, and when not detected may result in the + * generation of a signal, indicating an address violation, which is + * sent to the process. + */ + EFAULT = 21, + + /** + * File too large. The size of a file would exceed the maximum file + * size of an implementation or offset maximum established in the + * corresponding file description. + */ + EFBIG = 22, + + /** + * Host is unreachable. The destination host cannot be reached + * (probably because the host is down or a remote router cannot + * reach it). + */ + EHOSTUNREACH = 23, + + /** + * Identifier removed. Returned during XSI interprocess communication + * if an identifier has been removed from the system. + */ + EIDRM = 24, + + /** + * Illegal byte sequence. A wide-character code has been detected that + * does not correspond to a valid character, or a byte sequence does + * not form a valid wide-character code (defined in the ISO C standard). + */ + EILSEQ = 25, + + /** + * Operation in progress. This code is used to indicate that an + * asynchronous operation has not yet completed. + * or: + * O_NONBLOCK is set for the socket file descriptor and the connection + * cannot be immediately established. + */ + EINPROGRESS = 26, + + /** + * Interrupted function call. An asynchronous signal was caught by the + * process during the execution of an interruptible function. If the + * signal handler performs a normal return, the interrupted function + * call may return this condition (see the Base Definitions volume + * of POSIX.1-2017, ). + */ + EINTR = 27, + + /** + * Invalid argument. Some invalid argument was supplied; for example, + * specifying an undefined signal in a signal() function or a + * kill() function. + */ + EINVAL = 28, + + /** + * Input/output error. Some physical input or output error has occurred. + * This error may be reported on a subsequent operation on the same + * file descriptor. Any other error-causing operation on the same file + * descriptor may cause the [EIO] error indication to be lost. + */ + EIO = 29, + + /** + * Socket is connected. The specified socket is already connected. + */ + EISCONN = 30, + + /** + * Is a directory. An attempt was made to open a directory with write + * mode specified. + */ + EISDIR = 31, + + /** + * Symbolic link loop. A loop exists in symbolic links encountered + * during pathname resolution. This error may also be returned if + * more than {SYMLOOP_MAX} symbolic links are encountered during + * pathname resolution. + */ + ELOOP = 32, + + /** + * File descriptor value too large or too many open streams. An + * attempt was made to open a file descriptor with a value greater + * than or equal to {OPEN_MAX}, or an attempt was made to open more + * than the maximum number of streams allowed in the process. + */ + EMFILE = 33, + + /** + * Too many links. An attempt was made to have the link count of a + * single file exceed {LINK_MAX}. + */ + EMLINK = 34, + + /** + * Message too large. A message sent on a transport provider was + * larger than an internal message buffer or some other network limit. + * or: + * Inappropriate message buffer length. + */ + EMSGSIZE = 35, + + /** + * Reserved. + */ + EMULTIHOP = 36, + + /** + * Filename too long. The length of a pathname exceeds {PATH_MAX} and + * the implementation considers this to be an error, or a pathname + * component is longer than {NAME_MAX}. This error may also occur + * when pathname substitution, as a result of encountering a + * symbolic link during pathname resolution, results in a pathname + * string the size of which exceeds {PATH_MAX}. + */ + ENAMETOOLONG = 37, + + /** + * Network is down. The local network interface used to reach the + * destination is down. + */ + ENETDOWN = 38, + + /** + * The connection was aborted by the network. + */ + ENETRESET = 39, + + /** + * Network unreachable. No route to the network is present. + */ + ENETUNREACH = 40, + + /** + * Too many files open in system. Too many files are currently open + * in the system. The system has reached its predefined limit for + * simultaneously open files and temporarily cannot accept requests + * to open another one. + */ + ENFILE = 41, + + /** + * No buffer space available. Insufficient buffer resources were + * available in the system to perform the socket operation. + */ + ENOBUFS = 42, + + /** + * No message available. No message is available on the STREAM head + * read queue. + */ + ENODATA = 43, + + /** + * No such device. An attempt was made to apply an inappropriate + * function to a device; for example, trying to read a write-only + * device such as a printer. + */ + ENODEV = 44, + + /** + * No such file or directory. A component of a specified pathname + * does not exist, or the pathname is an empty string. + */ + ENOENT = 45, + + /** + * Executable file format error. A request is made to execute a file + * that, although it has appropriate privileges, is not in the + * format required by the implementation for executable files. + */ + ENOEXEC = 46, + + /** + * No locks available. A system-imposed limit on the number of + * simultaneous file and record locks has been reached and no more + * are currently available. + */ + ENOLCK = 47, + + /** + * Reserved. + */ + ENOLINK = 48, + + /** + * Not enough space. The new process image requires more memory than + * is allowed by the hardware or system-imposed memory management + * constraints. + */ + ENOMEM = 49, + + /** + * No message of the desired type. The message queue does not contain + * a message of the required type during XSI interprocess communication. + */ + ENOMSG = 50, + + /** + * Protocol not available. The protocol option specified to + * setsockopt() is not supported by the implementation. + */ + ENOPROTOOPT = 51, + + /** + * No space left on a device. During the write() function on a + * regular file or when extending a directory, there is no free + * space left on the device. + */ + ENOSPC = 52, + + /** + * No STREAM resources. Insufficient STREAMS memory resources are + * available to perform a STREAMS-related function. This is a + * temporary condition; it may be recovered from if other + * processes release resources. + */ + ENOSR = 53, + + /** + * Not a STREAM. A STREAM function was attempted on a file descriptor + * that was not associated with a STREAMS device. + */ + ENOSTR = 54, + + /** + * Functionality not supported. An attempt was made to use optional + * functionality that is not supported in this implementation. + */ + ENOSYS = 55, + + /** + * Socket not connected. The socket is not connected. + */ + ENOTCONN = 56, + + /** + * Not a directory. A component of the specified pathname exists, but + * it is not a directory, when a directory was expected; or an + * attempt was made to create a non-directory file, and the specified + * pathname contains at least one non- character and ends + * with one or more trailing characters. + */ + ENOTDIR = 57, + + /** + * Directory not empty. A directory other than an empty directory + * was supplied when an empty directory was expected. + */ + ENOTEMPTY = 58, + + /** + * State not recoverable. The state protected by a robust mutex + * is not recoverable. + */ + ENOTRECOVERABLE = 59, + + /** + * Not a socket. The file descriptor does not refer to a socket. + */ + ENOTSOCK = 60, + + /** + * Not supported. The implementation does not support the requested + * feature or value. + */ + ENOTSUP = 61, + + /** + * Inappropriate I/O control operation. A control function has been + * attempted for a file or special file for which the operation + * is inappropriate. + */ + ENOTTY = 62, + + /** + * No such device or address. Input or output on a special file + * refers to a device that does not exist, or makes a request + * beyond the capabilities of the device. It may also occur when, + * for example, a tape drive is not on-line. + */ + ENXIO = 63, + + /** + * Operation not supported on socket. The type of socket (address + * family or protocol) does not support the requested operation. + */ + EOPNOTSUPP = 64, + + /** + * Value too large to be stored in data type. An operation was + * attempted which would generate a value that is outside the + * range of values that can be represented in the relevant data + * type or that are allowed for a given data item. + */ + EOVERFLOW = 65, + + /** + * Previous owner died. The owner of a robust mutex terminated + * while holding the mutex lock. + */ + EOWNERDEAD = 66, + + /** + * Operation not permitted. An attempt was made to perform an + * operation limited to processes with appropriate privileges or + * to the owner of a file or other resource. + */ + EPERM = 67, + + /** + * Broken pipe. A write was attempted on a socket, pipe, or FIFO + * for which there is no process to read the data. + */ + EPIPE = 68, + + /** + * Protocol error. Some protocol error occurred. This error is + * device-specific, but is generally not related to a + * hardware failure. + */ + EPROTO = 69, + + /** + * Protocol not supported. The protocol is not supported by the + * address family, or the protocol is not supported by + * the implementation. + */ + EPROTONOSUPPORT = 70, + + /** + * Protocol wrong type for socket. The socket type is not + * supported by the protocol. + */ + EPROTOTYPE = 71, + + /** + * Result too large or too small. The result of the function + * is too large (overflow) or too small (underflow) to be + * represented in the available space. + */ + ERANGE = 72, + + /** + * Read-only file system. An attempt was made to modify a file + * or directory on a file system that is read-only. + */ + EROFS = 73, + + /** + * Invalid seek. An attempt was made to access the file offset + * associated with a pipe or FIFO. + */ + ESPIPE = 74, + + /** + * No such process. No process can be found corresponding to that + * specified by the given process ID. + */ + ESRCH = 75, + + /** + * Reserved. + */ + ESTALE = 76, + + /** + * STREAM ioctl() timeout. The timer set for a STREAMS ioctl() call + * has expired. The cause of this error is device-specific and could + * indicate either a hardware or software failure, or a timeout + * value that is too short for the specific operation. The status + * of the ioctl() operation is unspecified. + */ + ETIME = 77, + + /** + * Connection timed out. The connection to a remote machine has + * timed out. + * If the connection timed out during execution of the function that + * reported this error (as opposed to timing out prior to the + * function being called), it is unspecified whether the function + * has completed some or all of the documented behavior associated + * with a successful completion of the function. + * or: + * Operation timed out. The time limit associated with the operation + * was exceeded before the operation completed. + */ + ETIMEDOUT = 78, + + /** + * Text file busy. An attempt was made to execute a pure-procedure + * program that is currently open for writing, or an attempt has + * been made to open for writing a pure-procedure program that + * is being executed. + */ + ETXTBSY = 79, + + /** + * Operation would block. An operation on a socket marked as + * non-blocking has encountered a situation such as no data available + * that otherwise would have caused the function to suspend execution. + */ + EWOULDBLOCK = 80, + + /** + * Improper link. A link to a file on another file system was attempted. + */ + EXDEV = 81, + + __ERRNO_MAX +} KernelErrors; + +#include +EXTERNC int *__errno_location(void) __attribute__((const)); +#define errno (*__errno_location()) + +#ifdef __cplusplus +extern "C" +{ +#endif + char *strerror(int errnum); +#ifdef __cplusplus +} +#endif + +#endif // !__FENNIX_KERNEL_ERRNO_H__ diff --git a/include/interface/fs.h b/include/interface/fs.h new file mode 100644 index 0000000..a60f2a6 --- /dev/null +++ b/include/interface/fs.h @@ -0,0 +1,378 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_API_FILESYSTEM_H__ +#define __FENNIX_API_FILESYSTEM_H__ + +#ifdef __kernel__ +#include +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/** + * File type mask for the upper 32 bits of mode_t. + * + * @note Maybe it will be used in the future. + */ +#define S_IFMT32 037777600000 + +/** + * File type mask. + * + * This mask is used to extract the file type + * from the mode field of a stat structure. + * + * Doing bitwise AND with this mask will return + * the file type. + * Example: st_mode & S_IFMT + * + * Doing bitwise negation and AND with this mask + * will return the permissions. + * Example: st_mode & ~S_IFMT + */ +#define S_IFMT 0170000 + +/* Whiteout */ +#define S_IFWHT 0160000 +/* Socket */ +#define S_IFSOCK 0140000 +/* Symbolic link */ +#define S_IFLNK 0120000 +/* Regular file */ +#define S_IFREG 0100000 +/* Block device */ +#define S_IFBLK 0060000 +/* Directory */ +#define S_IFDIR 0040000 +/* Character device */ +#define S_IFCHR 0020000 +/* FIFO */ +#define S_IFIFO 0010000 + +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +/** Owner: RWX */ +#define S_IRWXU 0700 +/** Owner: R */ +#define S_IRUSR 0400 +/** Owner: W */ +#define S_IWUSR 0200 +/** Owner: X */ +#define S_IXUSR 0100 + +/** Group: RWX */ +#define S_IRWXG 0070 +/** Group: R */ +#define S_IRGRP 0040 +/** Group: W */ +#define S_IWGRP 0020 +/** Group: X */ +#define S_IXGRP 0010 + +/** Other: RWX */ +#define S_IRWXO 0007 +/** Other: R */ +#define S_IROTH 0004 +/** Other: W */ +#define S_IWOTH 0002 +/** Other: X */ +#define S_IXOTH 0001 + +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) + +#define DT_UNKNOWN 0x0 +#define DT_FIFO 0x1 +#define DT_CHR 0x2 +#define DT_DIR 0x4 +#define DT_BLK 0x6 +#define DT_REG 0x8 +#define DT_LNK 0xA +#define DT_SOCK 0xC +#define DT_WHT 0xE + +#define IFTODT(x) ((x) >> 12 & 0xF) +#define DTTOIF(x) ((x) << 12) + +#define SYMLOOP_MAX 40 + +#ifndef __cplusplus +#define static_assert _Static_assert +#endif + +#ifdef __LP64__ +static_assert(sizeof(dev_t) == 8, "dev_t must be 64 bits"); +static_assert(sizeof(ino_t) == 8, "ino_t must be 64 bits"); +static_assert(sizeof(mode_t) == 4, "mode_t must be 32 bits"); +static_assert(sizeof(nlink_t) == 4, "nlink_t must be 32 bits"); +static_assert(sizeof(uid_t) == 4, "uid_t must be 32 bits"); +static_assert(sizeof(gid_t) == 4, "gid_t must be 32 bits"); +static_assert(sizeof(off_t) == 8, "off_t must be 64 bits"); +static_assert(sizeof(time_t) == 8, "time_t must be 64 bits"); +static_assert(sizeof(blksize_t) == 8, "blksize_t must be 64 bits"); +static_assert(sizeof(blkcnt_t) == 8, "blkcnt_t must be 64 bits"); +#else +static_assert(sizeof(dev_t) == 4, "dev_t must be 32 bits"); +static_assert(sizeof(ino_t) == 4, "ino_t must be 32 bits"); +static_assert(sizeof(mode_t) == 2, "mode_t must be 16 bits"); +static_assert(sizeof(nlink_t) == 2, "nlink_t must be 16 bits"); +static_assert(sizeof(uid_t) == 2, "uid_t must be 16 bits"); +static_assert(sizeof(gid_t) == 2, "gid_t must be 16 bits"); +static_assert(sizeof(off_t) == 4, "off_t must be 32 bits"); +static_assert(sizeof(time_t) == 4, "time_t must be 32 bits"); +static_assert(sizeof(blksize_t) == 4, "blksize_t must be 32 bits"); +static_assert(sizeof(blkcnt_t) == 4, "blkcnt_t must be 32 bits"); +#endif + +#undef static_assert + +struct kstat +{ + /** Device ID of the file. */ + dev_t Device; + + /** Inode number. */ + ino_t Index; + + /** File type and mode. */ + mode_t Mode; + + /** Number of hard links. */ + nlink_t HardLinks; + + /** User ID of the file's owner. */ + uid_t UserID; + + /** Group ID of the file's owner. */ + gid_t GroupID; + + /** Device ID for special files. */ + dev_t RawDevice; + + /** Size of the file in bytes. */ + off_t Size; + + /** Time of last access. */ + time_t AccessTime; + + /** Time of last modification. */ + time_t ModifyTime; + + /** Time of last status change. */ + time_t ChangeTime; + + /** Optimal I/O block size. */ + blksize_t BlockSize; + + /** Number of blocks allocated. */ + blkcnt_t Blocks; + + /** Additional file attributes. */ + mode_t Attribute; + +#ifdef __cplusplus + + dev_t MakeDevice(int Major, int Minor) + { + return ((Major & 0xFFF) << 8) | + (Minor & 0xFF); + } + + int GetMajor() + { + return ((unsigned int)(Device) >> 8) & 0xFFF; + } + + int GetMinor() + { + return Device & 0xFF; + } + + void SetFileType(mode_t Type) + { + Mode = (Mode & ~S_IFMT) | + (Type & S_IFMT); + } + + mode_t GetFileType() { return Mode & S_IFMT; } + void ClearFileType() { Mode = Mode & ~S_IFMT; } + bool IsType(mode_t Type) { return (Mode & S_IFMT) == Type; } + + void SetPermissions(mode_t Permissions) + { + Mode = (Mode & S_IFMT) | + (Permissions & ~S_IFMT); + } + + mode_t GetPermissions() { return Mode & ~S_IFMT; } + void ClearPermissions() { Mode = Mode & S_IFMT; } + +#endif // __cplusplus +}; + +struct kdirent +{ + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; +}; + +struct InodeOperations +{ + int (*Lookup)(struct Inode *Parent, const char *Name, struct Inode **Result); + int (*Create)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); + int (*Remove)(struct Inode *Parent, const char *Name); + int (*Rename)(struct Inode *Parent, const char *OldName, const char *NewName); + ssize_t (*Read)(struct Inode *Node, void *Buffer, size_t Size, off_t Offset); + ssize_t (*Write)(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset); + int (*Truncate)(struct Inode *Node, off_t Size); + int (*Open)(struct Inode *Node, int Flags, mode_t Mode); + int (*Close)(struct Inode *Node); + int (*Ioctl)(struct Inode *Node, unsigned long Request, void *Argp); + ssize_t (*ReadDir)(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries); + int (*MkDir)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); + int (*RmDir)(struct Inode *Parent, const char *Name); + int (*SymLink)(struct Inode *Parent, const char *Name, const char *Target, struct Inode **Result); + ssize_t (*ReadLink)(struct Inode *Node, char *Buffer, size_t Size); + off_t (*Seek)(struct Inode *Node, off_t Offset); + int (*Stat)(struct Inode *Node, struct kstat *Stat); +} __attribute__((packed)); + +#define I_FLAG_MOUNTPOINT 0x1 +#define I_FLAG_CACHE_KEEP 0x2 + +struct Inode +{ + dev_t Device, RawDevice; + ino_t Index; + mode_t Mode; + uint32_t Flags; + off_t Offset; + + void *PrivateData; + +#ifdef __cplusplus + + /* ... */ + + void SetDevice(int Major, int Minor) + { + this->RawDevice = ((Major & 0xFFF) << 8) | + (Minor & 0xFF); + } + + int GetMajor() + { + return ((unsigned int)(this->RawDevice) >> 8) & 0xFFF; + } + + int GetMinor() + { + return this->RawDevice & 0xFF; + } + + Inode() + { + Index = 0; + Mode = 0; + Device = 0; + RawDevice = 0; + Flags = 0; + PrivateData = nullptr; + } + + ~Inode() = default; + +#else // __cplusplus + +#define INODE_MAKEDEV(major, minor) \ + ((dev_t)(((major & 0xFFF) << 8) | \ + (minor & 0xFF))) + +#define INODE_MAJOR(rdev) \ + ((int)(((rdev) >> 8) & 0xFFF)) + +#define INODE_MINOR(rdev) \ + ((int)((rdev) & 0xFF)) + +#endif // __cplusplus +}; + +struct SuperBlockOperations +{ + int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result); + int (*DeleteInode)(struct FileSystemInfo *Info, struct Inode *Node); + + /** + * Synchronize the filesystem. + * + * Write all pending changes to the disk. + * + * @param Info Inode to synchronize. If NULL, synchronize all inodes. + * + * @return Zero on success, otherwise an error code. + */ + int (*Synchronize)(struct FileSystemInfo *Info, struct Inode *Node); + + /** + * Destroy the filesystem. + * + * Unregister the filesystem and free all resources. + * + * @param Info Filesystem to destroy. + * + * @return Zero on success, otherwise an error code. + */ + int (*Destroy)(FileSystemInfo *Info); +} __attribute__((packed)); + +struct FileSystemInfo +{ + const char *Name; + int Flags; + struct SuperBlockOperations SuperOps; + struct InodeOperations Ops; + + void *PrivateData; +} __attribute__((packed)); + +dev_t RegisterFileSystem(FileSystemInfo *Info, struct Inode *Root); +int UnregisterFileSystem(dev_t Device); + +#endif // !__FENNIX_API_FILESYSTEM_H__ diff --git a/include/interface/syscalls.h b/include/interface/syscalls.h new file mode 100644 index 0000000..f5936f7 --- /dev/null +++ b/include/interface/syscalls.h @@ -0,0 +1,111 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_API_SYSCALLS_LIST_H__ +#define __FENNIX_API_SYSCALLS_LIST_H__ + +#ifndef syscall0 +static inline long syscall0(long syscall) +{ + long ret; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#ifndef syscall1 +static inline long syscall1(long syscall, long arg1) +{ + long ret; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall), "D"(arg1) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#ifndef syscall2 +static inline long syscall2(long syscall, long arg1, long arg2) +{ + long ret; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall), "D"(arg1), "S"(arg2) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#ifndef syscall3 +static inline long syscall3(long syscall, long arg1, long arg2, long arg3) +{ + long ret; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#ifndef syscall4 +static inline long syscall4(long syscall, long arg1, long arg2, long arg3, long arg4) +{ + long ret; + register long r10 __asm__("r10") = arg4; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#ifndef syscall5 +static inline long syscall5(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5) +{ + long ret; + register long r10 __asm__("r10") = arg4; + register long r8 __asm__("r8") = arg5; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#ifndef syscall6 +static inline long syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) +{ + long ret; + register long r10 __asm__("r10") = arg4; + register long r8 __asm__("r8") = arg5; + register long r9 __asm__("r9") = arg6; + __asm__ __volatile__("syscall" + : "=a"(ret) + : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +#endif // !__FENNIX_API_SYSCALLS_LIST_H__ diff --git a/include/kcon.hpp b/include/kcon.hpp new file mode 100644 index 0000000..fd0df5e --- /dev/null +++ b/include/kcon.hpp @@ -0,0 +1,29 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_KERNEL_CONSOLE_H__ +#define __FENNIX_KERNEL_KERNEL_CONSOLE_H__ + +#include + +namespace KernelConsole +{ + void EarlyInit(); + void LateInit(); +} + +#endif // !__FENNIX_KERNEL_KERNEL_CONSOLE_H__ diff --git a/include_std/cxxabi.h b/include/kexcept/cxxabi.h similarity index 55% rename from include_std/cxxabi.h rename to include/kexcept/cxxabi.h index 8e46836..f9b0955 100644 --- a/include_std/cxxabi.h +++ b/include/kexcept/cxxabi.h @@ -19,7 +19,7 @@ #define __FENNIX_KERNEL_CXXABI_H__ #include -#include +#include #include namespace __cxxabiv1 @@ -37,33 +37,82 @@ namespace __cxxabiv1 struct __cxa_exception { +#ifdef __LP64__ + char __padding[8]; + uintptr_t referenceCount; +#endif std::type_info *exceptionType; void (*exceptionDestructor)(void *); std::terminate_handler unexpectedHandler; std::terminate_handler terminateHandler; __cxa_exception *nextException; int handlerCount; -#ifdef __ARM_EABI_UNWINDER__ +#ifdef __arm__ __cxa_exception *nextPropagatingException; int propagationCount; #else int handlerSwitchValue; const unsigned char *actionRecord; const unsigned char *languageSpecificData; - _Unwind_Ptr catchTemp; + void *catchTemp; void *adjustedPtr; +#endif +#ifndef __LP64__ + uintptr_t referenceCount; #endif _Unwind_Exception unwindHeader; }; + + struct __cxa_dependent_exception + { +#ifdef __LP64__ + char __padding[8]; + void *primaryException; +#endif + std::type_info *exceptionType; + void (*exceptionDestructor)(void *); + std::unexpected_handler unexpectedHandler; + std::terminate_handler terminateHandler; + __cxa_exception *nextException; + int handlerCount; +#ifdef __arm__ + _Unwind_Exception *nextCleanup; + int cleanupCount; +#endif + int handlerSwitchValue; + const char *actionRecord; + const char *languageSpecificData; + void *catchTemp; + void *adjustedPtr; +#ifndef __LP64__ + void *primaryException; +#endif + _Unwind_Exception unwindHeader; + }; + + struct __cxa_eh_globals + { + __cxa_exception *caughtExceptions; + unsigned int uncaughtExceptions; + }; + + enum ExceptionState + { + ES_None, + ES_Caught, + ES_Rethrown + }; } -struct __cxa_eh_globals +struct ExceptionInfo { - __cxxabiv1::__cxa_exception *caughtExceptions; - unsigned int uncaughtExceptions; -#ifdef __ARM_EABI_UNWINDER__ - __cxxabiv1::__cxa_exception *propagatingExceptions; -#endif + std::terminate_handler terminateHandler; + std::unexpected_handler unexpectedHandler; + _Unwind_Exception *exceptionObject; + __cxxabiv1::ExceptionState state; + __cxxabiv1::__cxa_eh_globals globals; }; +ExceptionInfo *GetExceptionInfo(); + #endif // !__FENNIX_KERNEL_CXXABI_H__ diff --git a/include_std/unwind.h b/include/kexcept/unwind.h similarity index 81% rename from include_std/unwind.h rename to include/kexcept/unwind.h index 8c44540..f562a1f 100644 --- a/include_std/unwind.h +++ b/include/kexcept/unwind.h @@ -20,7 +20,7 @@ #include -enum _Unwind_Reason_Code +typedef enum { _URC_NO_REASON = 0, _URC_FOREIGN_EXCEPTION_CAUGHT = 1, @@ -31,7 +31,7 @@ enum _Unwind_Reason_Code _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8 -}; +} _Unwind_Reason_Code; typedef void *_Unwind_Context_Reg_Val; typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__))); @@ -40,20 +40,15 @@ typedef unsigned _Unwind_Word __attribute__((__mode__(__unwind_word__))); typedef signed _Unwind_Sword __attribute__((__mode__(__unwind_word__))); typedef int _Unwind_Action; -enum _UA : _Unwind_Action -{ - _UA_SEARCH_PHASE = 1, - _UA_CLEANUP_PHASE = 2, - _UA_HANDLER_FRAME = 4, - _UA_FORCE_UNWIND = 8, - _UA_END_OF_STACK = 16 -}; +#define _UA_SEARCH_PHASE 1 +#define _UA_CLEANUP_PHASE 2 +#define _UA_HANDLER_FRAME 4 +#define _UA_FORCE_UNWIND 8 +#define _UA_END_OF_STACK 16 -typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, - struct _Unwind_Exception *); +typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, struct _Unwind_Exception *); -typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(int, - _Unwind_Action, +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, struct _Unwind_Context *); @@ -66,13 +61,14 @@ struct _Unwind_Exception _Unwind_Word private_2; } __attribute__((__aligned__)); -struct _Unwind_Context; +struct _Unwind_Context +{ + int __stub; +}; struct _Unwind_FrameState { _Unwind_Personality_Fn personality; }; -EXTERNC _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *Exception); - #endif // !__FENNIX_KERNEL_UNWIND_H__ diff --git a/include/lock.hpp b/include/lock.hpp index a60be96..8d9ebb3 100644 --- a/include/lock.hpp +++ b/include/lock.hpp @@ -94,6 +94,25 @@ public: ~spin_lock() = default; }; +class __sl_guard +{ +private: + spin_lock &sl; + +public: + __sl_guard(spin_lock &sl, const char *FunctionName) : sl(sl) + { + this->sl.lock(FunctionName); + } + + ~__sl_guard() + { + this->sl.unlock(); + } +}; + +#define sl_guard(sl) __sl_guard CONCAT(sl_guard_, __COUNTER__)(sl, __FUNCTION__) + /** @brief Please use this macro to create a new smart lock. */ class SmartLockClass { diff --git a/include/macho.h b/include/macho.h new file mode 100644 index 0000000..ab87732 --- /dev/null +++ b/include/macho.h @@ -0,0 +1,76 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_MACH_O_H__ +#define __FENNIX_KERNEL_MACH_O_H__ + +#include + +#define MH_MAGIC 0xfeedface +#define MH_CIGAM 0xcefaedfe + +#define CPU_TYPE_ANY ((cpu_type_t) - 1) + +#define CPU_TYPE_VAX ((cpu_type_t)1) +#define CPU_TYPE_ROMP ((cpu_type_t)2) +#define CPU_TYPE_NS32032 ((cpu_type_t)4) +#define CPU_TYPE_NS32332 ((cpu_type_t)5) +#define CPU_TYPE_MC680x0 ((cpu_type_t)6) +#define CPU_TYPE_I386 ((cpu_type_t)7) +#define CPU_TYPE_X86_64 ((cpu_type_t)(CPU_TYPE_I386 | CPU_ARCH_ABI64)) +#define CPU_TYPE_MIPS ((cpu_type_t)8) +#define CPU_TYPE_NS32532 ((cpu_type_t)9) +#define CPU_TYPE_HPPA ((cpu_type_t)11) +#define CPU_TYPE_ARM ((cpu_type_t)12) +#define CPU_TYPE_MC88000 ((cpu_type_t)13) +#define CPU_TYPE_SPARC ((cpu_type_t)14) +#define CPU_TYPE_I860 ((cpu_type_t)15) +#define CPU_TYPE_I860_LITTLE ((cpu_type_t)16) +#define CPU_TYPE_RS6000 ((cpu_type_t)17) +#define CPU_TYPE_MC98000 ((cpu_type_t)18) +#define CPU_TYPE_POWERPC ((cpu_type_t)18) +#define CPU_ARCH_ABI64 0x1000000 +#define CPU_TYPE_POWERPC64 ((cpu_type_t)(CPU_TYPE_POWERPC | CPU_ARCH_ABI64)) +#define CPU_TYPE_VEO ((cpu_type_t)255) + +typedef int cpu_type_t; +typedef int cpu_subtype_t; + +struct mach_header +{ + uint32_t magic; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; +}; + +struct mach_header_64 +{ + uint32_t magic; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; + uint32_t reserved; +}; + +#endif // !__FENNIX_KERNEL_MACH_O_H__ diff --git a/include/memory.hpp b/include/memory.hpp index 162237c..d37884e 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -23,9 +23,9 @@ #include #include #include -#include -#include #include +#include +#include #endif // __cplusplus #include @@ -53,7 +53,7 @@ namespace Memory /** * @warning Not working as expected. - * + * * FIXME: This allocator is not working as expected. */ rpmalloc_, @@ -73,24 +73,20 @@ namespace Memory void InitializeMemoryManagement(); void CreatePageTable(Memory::PageTable *pt); -void *operator new(std::size_t Size); -void *operator new[](std::size_t Size); -void *operator new(std::size_t Size, std::align_val_t Alignment); -void operator delete(void *Pointer); -void operator delete[](void *Pointer); -void operator delete(void *Pointer, long unsigned int Size); -void operator delete[](void *Pointer, long unsigned int Size); - extern Memory::Physical KernelAllocator; extern Memory::PageTable *KernelPageTable; #endif // __cplusplus +#ifndef __FENNIX_KERNEL_STDLIB_H__ + EXTERNC void *malloc(size_t Size); EXTERNC void *calloc(size_t n, size_t Size); EXTERNC void *realloc(void *Address, size_t Size); EXTERNC void free(void *Address); +#endif // !__FENNIX_KERNEL_STDLIB_H__ + #define kmalloc(Size) malloc(Size) #define kcalloc(n, Size) calloc(n, Size) #define krealloc(Address, Size) realloc(Address, Size) diff --git a/include/memory/brk.hpp b/include/memory/brk.hpp index 857ad9c..c5fea97 100644 --- a/include/memory/brk.hpp +++ b/include/memory/brk.hpp @@ -44,7 +44,7 @@ namespace Memory void InitBrk(uintptr_t Address) { - function("%#lx", Address); + func("%#lx", Address); HeapStart = Address; Break = Address; } diff --git a/include/net/ipv4.hpp b/include/net/ipv4.hpp index 5ac2cd6..b7dbb17 100644 --- a/include/net/ipv4.hpp +++ b/include/net/ipv4.hpp @@ -128,7 +128,7 @@ namespace NetworkIPv4 UNUSED(DestinationIP); UNUSED(Data); UNUSED(Length); - warn("Not implemented."); + warn("Not implemented"); return false; } }; diff --git a/include/net/udp.hpp b/include/net/udp.hpp index 25dc6a9..798565b 100644 --- a/include/net/udp.hpp +++ b/include/net/udp.hpp @@ -53,7 +53,7 @@ namespace NetworkUDP UNUSED(Socket); UNUSED(Data); UNUSED(Length); - warn("Not implemented."); + warn("Not implemented"); } }; diff --git a/include/scheduler.hpp b/include/scheduler.hpp index 4c83c83..bd8640f 100644 --- a/include/scheduler.hpp +++ b/include/scheduler.hpp @@ -58,12 +58,12 @@ namespace Tasking::Scheduler assert(!"GetProcessByID not implemented"); } - virtual TCB *GetThreadByID(TID ID, PCB* Parent) + virtual TCB *GetThreadByID(TID ID, PCB *Parent) { assert(!"GetThreadByID not implemented"); } - virtual std::list &GetProcessList() + virtual std::vector &GetProcessList() { assert(!"GetProcessList not implemented"); } @@ -111,7 +111,7 @@ namespace Tasking::Scheduler NewLock(SchedulerLock); public: - std::list ProcessList; + std::vector ProcessList; PCB *IdleProcess = nullptr; TCB *IdleThread = nullptr; @@ -119,8 +119,8 @@ namespace Tasking::Scheduler bool RemoveThread(TCB *tcb) final; bool RemoveProcess(PCB *pcb) final; PCB *GetProcessByID(TID ID) final; - TCB *GetThreadByID(TID ID, PCB* Parent) final; - std::list &GetProcessList() final; + TCB *GetThreadByID(TID ID, PCB *Parent) final; + std::vector &GetProcessList() final; void StartIdleProcess() final; void StartScheduler() final; void Yield() final; diff --git a/include/smp.hpp b/include/smp.hpp index 20af0b6..96b50c6 100644 --- a/include/smp.hpp +++ b/include/smp.hpp @@ -19,7 +19,7 @@ #define __FENNIX_KERNEL_SMP_H__ #include -#include +#include #include #include @@ -39,31 +39,31 @@ struct CPUArchData struct CPUData { - /** @brief Used by CPU */ + /** Used by CPU */ uintptr_t Stack; - /** @brief CPU ID. */ + /** CPU ID. */ int ID; - /** @brief Local CPU error code. */ + /** Local CPU error code. */ long ErrorCode; - /** @brief Current running process */ + /** Current running process */ std::atomic CurrentProcess; - /** @brief Current running thread */ + /** Current running thread */ std::atomic CurrentThread; - /** @brief Unwind data */ - __cxa_eh_globals EHGlobals; + /** Exception information. */ + ExceptionInfo Exception; - /** @brief Architecture-specific data. */ + /** Architecture-specific data. */ CPUArchData Data; - /** @brief Checksum. Used to verify the integrity of the data. Must be equal to CPU_DATA_CHECKSUM (0xC0FFEE). */ + /** Checksum. Used to verify the integrity of the data. Must be equal to CPU_DATA_CHECKSUM (0xC0FFEE). */ int Checksum; - /** @brief Is CPU online? */ + /** Is CPU online? */ bool IsActive; } __aligned(16); diff --git a/storage/devices/tty/ptym.cpp b/include/static_vector similarity index 53% rename from storage/devices/tty/ptym.cpp rename to include/static_vector index 45f7a25..7b4f1da 100644 --- a/storage/devices/tty/ptym.cpp +++ b/include/static_vector @@ -15,36 +15,30 @@ along with Fennix Kernel. If not, see . */ -#include -#include -#include -#include +#include +#include +#include -#include "../../../kernel.h" - -namespace vfs +template +class static_vector { - size_t MasterPTY::read(uint8_t *Buffer, - size_t Size, - off_t Offset) +private: + T m_data[N]; + std::size_t m_size; + +public: + constexpr static_vector() : m_size(0) {} + + constexpr static_vector(std::initializer_list list) : m_size(0) { - fixme("%.*s", Size, Buffer); - return -ENOSYS; + for (const T &value : list) + { + assert(m_size < N); + m_data[m_size++] = value; + } } - size_t MasterPTY::write(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - fixme("%.*s", Size, Buffer); - return -ENOSYS; - } - - MasterPTY::MasterPTY() - { - } - - MasterPTY::~MasterPTY() - { - } -} + constexpr T &operator[](std::size_t index) { return m_data[index]; } + constexpr const T &operator[](std::size_t index) const { return m_data[index]; } + constexpr std::size_t size() const { return m_size; } +}; diff --git a/include/syscall/linux/defs.hpp b/include/syscall/linux/defs.hpp index fe32a48..722852f 100644 --- a/include/syscall/linux/defs.hpp +++ b/include/syscall/linux/defs.hpp @@ -20,174 +20,178 @@ #include -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 +#define linux_SEEK_SET 0 +#define linux_SEEK_CUR 1 +#define linux_SEEK_END 2 -#define ARCH_GET_CPUID 0x1011 -#define ARCH_SET_CPUID 0x1012 +#define linux_ARCH_SET_GS 0x1001 +#define linux_ARCH_SET_FS 0x1002 +#define linux_ARCH_GET_FS 0x1003 +#define linux_ARCH_GET_GS 0x1004 -#define ARCH_GET_XCOMP_SUPP 0x1021 -#define ARCH_GET_XCOMP_PERM 0x1022 -#define ARCH_REQ_XCOMP_PERM 0x1023 -#define ARCH_GET_XCOMP_GUEST_PERM 0x1024 -#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 +#define linux_ARCH_GET_CPUID 0x1011 +#define linux_ARCH_SET_CPUID 0x1012 -#define ARCH_XCOMP_TILECFG 17 -#define ARCH_XCOMP_TILEDATA 18 +#define linux_ARCH_GET_XCOMP_SUPP 0x1021 +#define linux_ARCH_GET_XCOMP_PERM 0x1022 +#define linux_ARCH_REQ_XCOMP_PERM 0x1023 +#define linux_ARCH_GET_XCOMP_GUEST_PERM 0x1024 +#define linux_ARCH_REQ_XCOMP_GUEST_PERM 0x1025 -#define ARCH_MAP_VDSO_X32 0x2001 -#define ARCH_MAP_VDSO_32 0x2002 -#define ARCH_MAP_VDSO_64 0x2003 +#define linux_ARCH_XCOMP_TILECFG 17 +#define linux_ARCH_XCOMP_TILEDATA 18 -#define ARCH_GET_UNTAG_MASK 0x4001 -#define ARCH_ENABLE_TAGGED_ADDR 0x4002 -#define ARCH_GET_MAX_TAG_BITS 0x4003 -#define ARCH_FORCE_TAGGED_SVA 0x4004 +#define linux_ARCH_MAP_VDSO_X32 0x2001 +#define linux_ARCH_MAP_VDSO_32 0x2002 +#define linux_ARCH_MAP_VDSO_64 0x2003 -#define PROT_NONE 0 -#define PROT_READ 1 -#define PROT_WRITE 2 -#define PROT_EXEC 4 -#define PROT_GROWSDOWN 0x01000000 -#define PROT_GROWSUP 0x02000000 +#define linux_ARCH_GET_UNTAG_MASK 0x4001 +#define linux_ARCH_ENABLE_TAGGED_ADDR 0x4002 +#define linux_ARCH_GET_MAX_TAG_BITS 0x4003 +#define linux_ARCH_FORCE_TAGGED_SVA 0x4004 -#define MAP_TYPE 0x0f +#define linux_PROT_NONE 0 +#define linux_PROT_READ 1 +#define linux_PROT_WRITE 2 +#define linux_PROT_EXEC 4 +#define linux_PROT_GROWSDOWN 0x01000000 +#define linux_PROT_GROWSUP 0x02000000 -#define MAP_FILE 0 -#define MAP_SHARED 0x01 -#define MAP_PRIVATE 0x02 -#define MAP_SHARED_VALIDATE 0x03 -#define MAP_FIXED 0x10 -#define MAP_ANONYMOUS 0x20 -#define MAP_NORESERVE 0x4000 -#define MAP_GROWSDOWN 0x0100 -#define MAP_DENYWRITE 0x0800 -#define MAP_EXECUTABLE 0x1000 -#define MAP_LOCKED 0x2000 -#define MAP_POPULATE 0x8000 -#define MAP_NONBLOCK 0x10000 -#define MAP_STACK 0x20000 -#define MAP_HUGETLB 0x40000 -#define MAP_SYNC 0x80000 -#define MAP_FIXED_NOREPLACE 0x100000 +#define linux_MAP_TYPE 0x0f -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#define CLOCK_PROCESS_CPUTIME_ID 2 -#define CLOCK_THREAD_CPUTIME_ID 3 -#define CLOCK_MONOTONIC_RAW 4 -#define CLOCK_REALTIME_COARSE 5 -#define CLOCK_MONOTONIC_COARSE 6 -#define CLOCK_BOOTTIME 7 -#define CLOCK_REALTIME_ALARM 8 -#define CLOCK_BOOTTIME_ALARM 9 -#define CLOCK_SGI_CYCLE 10 -#define CLOCK_TAI 11 +#define linux_MAP_FILE 0 +#define linux_MAP_SHARED 0x01 +#define linux_MAP_PRIVATE 0x02 +#define linux_MAP_SHARED_VALIDATE 0x03 +#define linux_MAP_FIXED 0x10 +#define linux_MAP_ANONYMOUS 0x20 +#define linux_MAP_NORESERVE 0x4000 +#define linux_MAP_GROWSDOWN 0x0100 +#define linux_MAP_DENYWRITE 0x0800 +#define linux_MAP_EXECUTABLE 0x1000 +#define linux_MAP_LOCKED 0x2000 +#define linux_MAP_POPULATE 0x8000 +#define linux_MAP_NONBLOCK 0x10000 +#define linux_MAP_STACK 0x20000 +#define linux_MAP_HUGETLB 0x40000 +#define linux_MAP_SYNC 0x80000 +#define linux_MAP_FIXED_NOREPLACE 0x100000 -#define GRND_NONBLOCK 0x1 -#define GRND_RANDOM 0x2 -#define GRND_INSECURE 0x4 +#define linux_CLOCK_REALTIME 0 +#define linux_CLOCK_MONOTONIC 1 +#define linux_CLOCK_PROCESS_CPUTIME_ID 2 +#define linux_CLOCK_THREAD_CPUTIME_ID 3 +#define linux_CLOCK_MONOTONIC_RAW 4 +#define linux_CLOCK_REALTIME_COARSE 5 +#define linux_CLOCK_MONOTONIC_COARSE 6 +#define linux_CLOCK_BOOTTIME 7 +#define linux_CLOCK_REALTIME_ALARM 8 +#define linux_CLOCK_BOOTTIME_ALARM 9 +#define linux_CLOCK_SGI_CYCLE 10 +#define linux_CLOCK_TAI 11 -#define RLIMIT_CPU 0 -#define RLIMIT_FSIZE 1 -#define RLIMIT_DATA 2 -#define RLIMIT_STACK 3 -#define RLIMIT_CORE 4 -#define RLIMIT_RSS 5 -#define RLIMIT_NPROC 6 -#define RLIMIT_NOFILE 7 -#define RLIMIT_MEMLOCK 8 -#define RLIMIT_AS 9 -#define RLIMIT_LOCKS 10 -#define RLIMIT_SIGPENDING 11 -#define RLIMIT_MSGQUEUE 12 -#define RLIMIT_NICE 13 -#define RLIMIT_RTPRIO 14 -#define RLIMIT_RTTIME 15 -#define RLIMIT_NLIMITS 16 +#define linux_GRND_NONBLOCK 0x1 +#define linux_GRND_RANDOM 0x2 +#define linux_GRND_INSECURE 0x4 -#define F_DUPFD 0 -#define F_GETFD 1 -#define F_SETFD 2 -#define F_GETFL 3 -#define F_SETFL 4 +#define linux_RLIMIT_CPU 0 +#define linux_RLIMIT_FSIZE 1 +#define linux_RLIMIT_DATA 2 +#define linux_RLIMIT_STACK 3 +#define linux_RLIMIT_CORE 4 +#define linux_RLIMIT_RSS 5 +#define linux_RLIMIT_NPROC 6 +#define linux_RLIMIT_NOFILE 7 +#define linux_RLIMIT_MEMLOCK 8 +#define linux_RLIMIT_AS 9 +#define linux_RLIMIT_LOCKS 10 +#define linux_RLIMIT_SIGPENDING 11 +#define linux_RLIMIT_MSGQUEUE 12 +#define linux_RLIMIT_NICE 13 +#define linux_RLIMIT_RTPRIO 14 +#define linux_RLIMIT_RTTIME 15 +#define linux_RLIMIT_NLIMITS 16 -#define F_SETOWN 8 -#define F_GETOWN 9 -#define F_SETSIG 10 -#define F_GETSIG 11 +#define linux_F_DUPFD 0 +#define linux_F_GETFD 1 +#define linux_F_SETFD 2 +#define linux_F_GETFL 3 +#define linux_F_SETFL 4 + +#define linux_F_SETOWN 8 +#define linux_F_GETOWN 9 +#define linux_F_SETSIG 10 +#define linux_F_GETSIG 11 #if __LONG_MAX == 0x7fffffffL -#define F_GETLK 12 -#define F_SETLK 13 -#define F_SETLKW 14 +#define linux_F_GETLK 12 +#define linux_F_SETLK 13 +#define linux_F_SETLKW 14 #else -#define F_GETLK 5 -#define F_SETLK 6 -#define F_SETLKW 7 +#define linux_F_GETLK 5 +#define linux_F_SETLK 6 +#define linux_F_SETLKW 7 #endif -#define F_SETOWN_EX 15 -#define F_GETOWN_EX 16 -#define F_GETOWNER_UIDS 17 +#define linux_F_SETOWN_EX 15 +#define linux_F_GETOWN_EX 16 +#define linux_F_GETOWNER_UIDS 17 -#define F_OFD_GETLK 36 -#define F_OFD_SETLK 37 -#define F_OFD_SETLKW 38 +#define linux_F_OFD_GETLK 36 +#define linux_F_OFD_SETLK 37 +#define linux_F_OFD_SETLKW 38 -#define F_DUPFD_CLOEXEC 1030 +#define linux_F_DUPFD_CLOEXEC 1030 -#define FD_CLOEXEC 1 +#define linux_FD_CLOEXEC 1 -#define DT_UNKNOWN 0 -#define DT_FIFO 1 -#define DT_CHR 2 -#define DT_DIR 4 -#define DT_BLK 6 -#define DT_REG 8 -#define DT_LNK 10 -#define DT_SOCK 12 -#define DT_WHT 14 +#define linux_DT_UNKNOWN 0 +#define linux_DT_FIFO 1 +#define linux_DT_CHR 2 +#define linux_DT_DIR 4 +#define linux_DT_BLK 6 +#define linux_DT_REG 8 +#define linux_DT_LNK 10 +#define linux_DT_SOCK 12 +#define linux_DT_WHT 14 -#define AT_FDCWD (-100) -#define AT_SYMLINK_NOFOLLOW 0x100 -#define AT_REMOVEDIR 0x200 -#define AT_SYMLINK_FOLLOW 0x400 -#define AT_EACCESS 0x200 -#define AT_NO_AUTOMOUNT 0x800 -#define AT_EMPTY_PATH 0x1000 -#define AT_STATX_SYNC_TYPE 0x6000 -#define AT_STATX_SYNC_AS_STAT 0x0000 -#define AT_STATX_FORCE_SYNC 0x2000 -#define AT_STATX_DONT_SYNC 0x4000 -#define AT_RECURSIVE 0x8000 +#define linux_AT_FDCWD (-100) +#define linux_AT_SYMLINK_NOFOLLOW 0x100 +#define linux_AT_REMOVEDIR 0x200 +#define linux_AT_SYMLINK_FOLLOW 0x400 +#define linux_AT_EACCESS 0x200 +#define linux_AT_NO_AUTOMOUNT 0x800 +#define linux_AT_EMPTY_PATH 0x1000 +#define linux_AT_STATX_SYNC_TYPE 0x6000 +#define linux_AT_STATX_SYNC_AS_STAT 0x0000 +#define linux_AT_STATX_FORCE_SYNC 0x2000 +#define linux_AT_STATX_DONT_SYNC 0x4000 +#define linux_AT_RECURSIVE 0x8000 -#define LINUX_REBOOT_MAGIC1 0xfee1dead -#define LINUX_REBOOT_MAGIC2 0x28121969 -#define LINUX_REBOOT_MAGIC2A 0x05121996 -#define LINUX_REBOOT_MAGIC2B 0x16041998 -#define LINUX_REBOOT_MAGIC2C 0x20112000 +#define linux_LINUX_REBOOT_MAGIC1 0xfee1dead +#define linux_LINUX_REBOOT_MAGIC2 0x28121969 +#define linux_LINUX_REBOOT_MAGIC2A 0x05121996 +#define linux_LINUX_REBOOT_MAGIC2B 0x16041998 +#define linux_LINUX_REBOOT_MAGIC2C 0x20112000 -#define LINUX_REBOOT_CMD_RESTART 0x01234567 -#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 -#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF -#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 -#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC -#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 -#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 -#define LINUX_REBOOT_CMD_KEXEC 0x45584543 +#define linux_LINUX_REBOOT_CMD_RESTART 0x01234567 +#define linux_LINUX_REBOOT_CMD_HALT 0xCDEF0123 +#define linux_LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF +#define linux_LINUX_REBOOT_CMD_CAD_OFF 0x00000000 +#define linux_LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC +#define linux_LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 +#define linux_LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 +#define linux_LINUX_REBOOT_CMD_KEXEC 0x45584543 -#define SA_IMMUTABLE 0x00800000 +#define linux_SA_IMMUTABLE 0x00800000 -#define ITIMER_REAL 0 -#define ITIMER_VIRTUAL 1 -#define ITIMER_PROF 2 +#define linux_ITIMER_REAL 0 +#define linux_ITIMER_VIRTUAL 1 +#define linux_ITIMER_PROF 2 -#define RUSAGE_SELF 0 -#define RUSAGE_CHILDREN (-1) -#define RUSAGE_THREAD 1 +#define linux_RUSAGE_SELF 0 +#define linux_RUSAGE_CHILDREN (-1) +#define linux_RUSAGE_THREAD 1 typedef long __kernel_long_t; typedef unsigned long __kernel_ulong_t; @@ -249,19 +253,24 @@ struct rusage struct linux_dirent { - unsigned long d_ino; /* Inode number */ - unsigned long d_off; /* Offset to next linux_dirent */ - unsigned short d_reclen; /* Length of this linux_dirent */ - char d_name[]; /* Filename (null-terminated) */ + unsigned long d_ino; + unsigned long d_off; + unsigned short d_reclen; + char d_name[]; + /** + * Getting d_type is not the same as linux_dirent64: + * https://github.com/torvalds/linux/blob/bfa8f18691ed2e978e4dd51190569c434f93e268/fs/readdir.c#L296 + * "man 2 getdents" also is helpful + */ }; struct linux_dirent64 { - ino64_t d_ino; /* 64-bit inode number */ - off64_t d_off; /* 64-bit offset to next structure */ - unsigned short d_reclen; /* Size of this dirent */ - unsigned char d_type; /* File type */ - char d_name[]; /* Filename (null-terminated) */ + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; }; struct linux_kstat diff --git a/include/syscall/linux/errno.h b/include/syscall/linux/errno.h new file mode 100644 index 0000000..c78bf8d --- /dev/null +++ b/include/syscall/linux/errno.h @@ -0,0 +1,408 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_LINUX_ERRNO_H__ +#define __FENNIX_KERNEL_LINUX_ERRNO_H__ + +/** Operation not permitted */ +#define linux_EPERM 1 + +/** No such file or directory */ +#define linux_ENOENT 2 + +/** No such process */ +#define linux_ESRCH 3 + +/** Interrupted system call */ +#define linux_EINTR 4 + +/** I/O error */ +#define linux_EIO 5 + +/** No such device or address */ +#define linux_ENXIO 6 + +/** Argument list too long */ +#define linux_E2BIG 7 + +/** Exec format error */ +#define linux_ENOEXEC 8 + +/** Bad file number */ +#define linux_EBADF 9 + +/** No child processes */ +#define linux_ECHILD 10 + +/** Try again */ +#define linux_EAGAIN 11 + +/** Out of memory */ +#define linux_ENOMEM 12 + +/** Permission denied */ +#define linux_EACCES 13 + +/** Bad address */ +#define linux_EFAULT 14 + +/** Block device required */ +#define linux_ENOTBLK 15 + +/** Device or resource busy */ +#define linux_EBUSY 16 + +/** File exists */ +#define linux_EEXIST 17 + +/** Cross-device link */ +#define linux_EXDEV 18 + +/** No such device */ +#define linux_ENODEV 19 + +/** Not a directory */ +#define linux_ENOTDIR 20 + +/** Is a directory */ +#define linux_EISDIR 21 + +/** Invalid argument */ +#define linux_EINVAL 22 + +/** File table overflow */ +#define linux_ENFILE 23 + +/** Too many open files */ +#define linux_EMFILE 24 + +/** Not a typewriter */ +#define linux_ENOTTY 25 + +/** Text file busy */ +#define linux_ETXTBSY 26 + +/** File too large */ +#define linux_EFBIG 27 + +/** No space left on device */ +#define linux_ENOSPC 28 + +/** Illegal seek */ +#define linux_ESPIPE 29 + +/** Read-only file system */ +#define linux_EROFS 30 + +/** Too many links */ +#define linux_EMLINK 31 + +/** Broken pipe */ +#define linux_EPIPE 32 + +/** Math argument out of domain of func */ +#define linux_EDOM 33 + +/** Math result not representable */ +#define linux_ERANGE 34 + +/** Resource deadlock would occur */ +#define linux_EDEADLK 35 + +/** File name too long */ +#define linux_ENAMETOOLONG 36 + +/** No record locks available */ +#define linux_ENOLCK 37 + +/** Function not implemented */ +#define linux_ENOSYS 38 + +/** Directory not empty */ +#define linux_ENOTEMPTY 39 + +/** Too many symbolic links encountered */ +#define linux_ELOOP 40 + +/** No message of desired type */ +#define linux_ENOMSG 42 + +/** Identifier removed */ +#define linux_EIDRM 43 + +/** Channel number out of range */ +#define linux_ECHRNG 44 + +/** Level 2 not synchronized */ +#define linux_EL2NSYNC 45 + +/** Level 3 halted */ +#define linux_EL3HLT 46 + +/** Level 3 reset */ +#define linux_EL3RST 47 + +/** Link number out of range */ +#define linux_ELNRNG 48 + +/** Protocol driver not attached */ +#define linux_EUNATCH 49 + +/** No CSI structure available */ +#define linux_ENOCSI 50 + +/** Level 2 halted */ +#define linux_EL2HLT 51 + +/** Invalid exchange */ +#define linux_EBADE 52 + +/** Invalid request descriptor */ +#define linux_EBADR 53 + +/** Exchange full */ +#define linux_EXFULL 54 + +/** No anode */ +#define linux_ENOANO 55 + +/** Invalid request code */ +#define linux_EBADRQC 56 + +/** Invalid slot */ +#define linux_EBADSLT 57 + +/** Bad font file format */ +#define linux_EBFONT 59 + +/** Device not a stream */ +#define linux_ENOSTR 60 + +/** No data available */ +#define linux_ENODATA 61 + +/** Timer expired */ +#define linux_ETIME 62 + +/** Out of streams resources */ +#define linux_ENOSR 63 + +/** Machine is not on the network */ +#define linux_ENONET 64 + +/** Package not installed */ +#define linux_ENOPKG 65 + +/** Object is remote */ +#define linux_EREMOTE 66 + +/** Link has been severed */ +#define linux_ENOLINK 67 + +/** Advertise error */ +#define linux_EADV 68 + +/** Srmount error */ +#define linux_ESRMNT 69 + +/** Communication error on send */ +#define linux_ECOMM 70 + +/** Protocol error */ +#define linux_EPROTO 71 + +/** Multihop attempted */ +#define linux_EMULTIHOP 72 + +/** RFS specific error */ +#define linux_EDOTDOT 73 + +/** Not a data message */ +#define linux_EBADMSG 74 + +/** Value too large for defined data type */ +#define linux_EOVERFLOW 75 + +/** Name not unique on network */ +#define linux_ENOTUNIQ 76 + +/** File descriptor in bad state */ +#define linux_EBADFD 77 + +/** Remote address changed */ +#define linux_EREMCHG 78 + +/** Can not access a needed shared library */ +#define linux_ELIBACC 79 + +/** Accessing a corrupted shared library */ +#define linux_ELIBBAD 80 + +/** .lib section in a.out corrupted */ +#define linux_ELIBSCN 81 + +/** Attempting to link in too many shared libraries */ +#define linux_ELIBMAX 82 + +/** Cannot exec a shared library directly */ +#define linux_ELIBEXEC 83 + +/** Illegal byte sequence */ +#define linux_EILSEQ 84 + +/** Interrupted system call should be restarted */ +#define linux_ERESTART 85 + +/** Streams pipe error */ +#define linux_ESTRPIPE 86 + +/** Too many users */ +#define linux_EUSERS 87 + +/** Socket operation on non-socket */ +#define linux_ENOTSOCK 88 + +/** Destination address required */ +#define linux_EDESTADDRREQ 89 + +/** Message too long */ +#define linux_EMSGSIZE 90 + +/** Protocol wrong type for socket */ +#define linux_EPROTOTYPE 91 + +/** Protocol not available */ +#define linux_ENOPROTOOPT 92 + +/** Protocol not supported */ +#define linux_EPROTONOSUPPORT 93 + +/** Socket type not supported */ +#define linux_ESOCKTNOSUPPORT 94 + +/** Operation not supported on transport endpoint */ +#define linux_EOPNOTSUPP 95 + +/** Protocol family not supported */ +#define linux_EPFNOSUPPORT 96 + +/** Address family not supported by protocol */ +#define linux_EAFNOSUPPORT 97 + +/** Address already in use */ +#define linux_EADDRINUSE 98 + +/** Cannot assign requested address */ +#define linux_EADDRNOTAVAIL 99 + +/** Network is down */ +#define linux_ENETDOWN 100 + +/** Network is unreachable */ +#define linux_ENETUNREACH 101 + +/** Network dropped connection because of reset */ +#define linux_ENETRESET 102 + +/** Software caused connection abort */ +#define linux_ECONNABORTED 103 + +/** Connection reset by peer */ +#define linux_ECONNRESET 104 + +/** No buffer space available */ +#define linux_ENOBUFS 105 + +/** Transport endpoint is already connected */ +#define linux_EISCONN 106 + +/** Transport endpoint is not connected */ +#define linux_ENOTCONN 107 + +/** Cannot send after transport endpoint shutdown */ +#define linux_ESHUTDOWN 108 + +/** Too many references: cannot splice */ +#define linux_ETOOMANYREFS 109 + +/** Connection timed out */ +#define linux_ETIMEDOUT 110 + +/** Connection refused */ +#define linux_ECONNREFUSED 111 + +/** Host is down */ +#define linux_EHOSTDOWN 112 + +/** No route to host */ +#define linux_EHOSTUNREACH 113 + +/** Operation already in progress */ +#define linux_EALREADY 114 + +/** Operation now in progress */ +#define linux_EINPROGRESS 115 + +/** Stale NFS file handle */ +#define linux_ESTALE 116 + +/** Structure needs cleaning */ +#define linux_EUCLEAN 117 + +/** Not a XENIX named type file */ +#define linux_ENOTNAM 118 + +/** No XENIX semaphores available */ +#define linux_ENAVAIL 119 + +/** Is a named type file */ +#define linux_EISNAM 120 + +/** Remote I/O error */ +#define linux_EREMOTEIO 121 + +/** Quota exceeded */ +#define linux_EDQUOT 122 + +/** No medium found */ +#define linux_ENOMEDIUM 123 + +/** Wrong medium type */ +#define linux_EMEDIUMTYPE 124 + +/** Operation Canceled */ +#define linux_ECANCELED 125 + +/** Required key not available */ +#define linux_ENOKEY 126 + +/** Key has expired */ +#define linux_EKEYEXPIRED 127 + +/** Key has been revoked */ +#define linux_EKEYREVOKED 128 + +/** Key was rejected by service */ +#define linux_EKEYREJECTED 129 + +/** Owner died */ +#define linux_EOWNERDEAD 130 + +/** State not recoverable */ +#define linux_ENOTRECOVERABLE 131 + +#endif // !__FENNIX_KERNEL_LINUX_ERRNO_H__ diff --git a/include/task.hpp b/include/task.hpp index 8294329..a329506 100644 --- a/include/task.hpp +++ b/include/task.hpp @@ -26,12 +26,13 @@ #include #include #include +#include #include #include #include #include +#include #include -#include #define RLIM_INFINITY (~0ULL) @@ -45,7 +46,6 @@ struct rlimit namespace Tasking { using vfs::FileDescriptorTable; - using vfs::Node; /** Instruction Pointer */ typedef __UINTPTR_TYPE__ IP; @@ -212,6 +212,7 @@ namespace Tasking TaskArchitecture Architecture = TaskArchitecture::UnknownArchitecture; TaskCompatibility Compatibility = TaskCompatibility::UnknownPlatform; cwk_path_style PathStyle = CWK_STYLE_UNIX; + FileNode *RootNode = nullptr; }; struct ThreadLocalStorage @@ -334,7 +335,7 @@ namespace Tasking class PCB *Parent = nullptr; IP EntryPoint = 0; - /* Statuses */ + /* Status */ std::atomic_int ExitCode; std::atomic State = TaskState::Waiting; int ErrorNumber; @@ -377,6 +378,9 @@ namespace Tasking pid_t tgid = 0; } Linux{}; + /* Kernel Exceptions */ + ExceptionInfo KernelException{}; + int SendSignal(int sig); void SetState(TaskState state); void SetExitCode(int code); @@ -411,7 +415,7 @@ namespace Tasking ~TCB(); }; - class PCB : public vfs::Node + class PCB { private: class Task *ctx = nullptr; @@ -434,6 +438,7 @@ namespace Tasking PID ID = -1; const char *Name = nullptr; PCB *Parent = nullptr; + FileNode *ProcDirectory = nullptr; /* Statuses */ std::atomic_int ExitCode; @@ -464,14 +469,14 @@ namespace Tasking ThreadLocalStorage TLS{}; /* Filesystem */ - Node *CurrentWorkingDirectory; - Node *Executable; + FileNode *CWD; + FileNode *Executable; FileDescriptorTable *FileDescriptors; /* stdio */ - Node *stdin; - Node *stdout; - Node *stderr; + FileNode *stdin; + FileNode *stdout; + FileNode *stderr; /* Memory */ Memory::PageTable *PageTable; @@ -480,12 +485,13 @@ namespace Tasking /* Other */ Signal Signals; - mode_t FileCreationMask = S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP | S_IROTH | S_IWOTH; + mode_t FileCreationMask = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH; /* Threads & Children */ - std::list Threads; - std::list Children; + std::vector Threads; + std::vector Children; public: class Task *GetContext() { return ctx; } @@ -494,7 +500,7 @@ namespace Tasking void SetState(TaskState state); void SetExitCode(int code); void Rename(const char *name); - void SetWorkingDirectory(Node *node); + void SetWorkingDirectory(FileNode *node); void SetExe(const char *path); size_t GetSize(); TCB *GetThread(TID ID); @@ -538,7 +544,7 @@ namespace Tasking public: void *GetScheduler() { return Scheduler; } PCB *GetKernelProcess() { return KernelProcess; } - std::list GetProcessList(); + std::vector GetProcessList(); void Panic(); bool IsPanic(); diff --git a/include/types.h b/include/types.h index 126945a..2be25af 100644 --- a/include/types.h +++ b/include/types.h @@ -18,6 +18,8 @@ #ifndef __FENNIX_KERNEL_TYPES_H__ #define __FENNIX_KERNEL_TYPES_H__ +#include + #ifdef __cplusplus #define EXTERNC extern "C" #define START_EXTERNC \ @@ -35,15 +37,11 @@ #define NULL 0 #else // __cplusplus #define NULL ((void *)0) -#define bool _Bool #endif // __cplusplus #define asm __asm__ #define asmv __asm__ volatile -#define true 1 -#define false 0 - #define inf_loop while (1) #define ilp inf_loop; /* Used for debugging */ @@ -64,11 +62,6 @@ #define UNUSED(x) (void)(x) #define CONCAT(x, y) x##y -#ifndef __cplusplus /* This conflicts with std */ -#define toupper(c) ((c)-0x20 * (((c) >= 'a') && ((c) <= 'z'))) -#define tolower(c) ((c) + 0x20 * (((c) >= 'A') && ((c) <= 'Z'))) -#endif - #ifndef __va_list__ typedef __builtin_va_list va_list; #endif @@ -77,8 +70,8 @@ typedef __builtin_va_list va_list; #define va_end(v) __builtin_va_end(v) #define va_arg(v, l) __builtin_va_arg(v, l) -#define ALIGN_UP(x, align) ((__typeof__(x))(((uintptr_t)(x) + ((align)-1)) & (~((align)-1)))) -#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1)))) +#define ALIGN_UP(x, align) ((__typeof__(x))(((uintptr_t)(x) + ((align) - 1)) & (~((align) - 1)))) +#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align) - 1)))) #define offsetof(type, member) __builtin_offsetof(type, member) @@ -96,8 +89,8 @@ typedef __builtin_va_list va_list; _a < _b ? _a : _b; \ }) -#define ROUND_UP(x, y) (((x) + (y)-1) & ~((y)-1)) -#define ROUND_DOWN(x, y) ((x) & ~((y)-1)) +#define ROUND_UP(x, y) (((x) + (y) - 1) & ~((y) - 1)) +#define ROUND_DOWN(x, y) ((x) & ~((y) - 1)) #define VPOKE(type, address) (*((volatile type *)(address))) #define POKE(type, address) (*((type *)(address))) @@ -399,21 +392,53 @@ typedef uint48_t uint_fast48_t; (((x) & 0xff0000000000) >> 40))) #define b64(x) __builtin_bswap64(x) -/* https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gnat_ugn/Optimization-Levels.html */ +/* https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html */ -/** @brief No optimization (the default); generates unoptimized code but has the fastest compilation time. */ +/** No optimization (the default); generates + * unoptimized code but has the fastest compilation time. + */ #define O0 __attribute__((optimize("O0"))) -/** @brief Moderate optimization; optimizes reasonably well but does not degrade compilation time significantly. */ + +/** Moderate optimization; + * optimizes reasonably well but does not degrade + * compilation time significantly. */ #define O1 __attribute__((optimize("O1"))) -/** @brief Full optimization; generates highly optimized code and has the slowest compilation time. */ + +/** Full optimization; generates highly + * optimized code and has the slowest compilation time. + */ #define O2 __attribute__((optimize("O2"))) -/** @brief Full optimization as in -O2; also uses more aggressive automatic inlining of subprograms within a unit (Inlining of Subprograms) and attempts to vectorize loops. */ + +/** Full optimization as in -O2; + * also uses more aggressive automatic inlining of + * subprograms within a unit (Inlining of Subprograms) + * and attempts to vectorize loops. */ #define O3 __attribute__((optimize("O3"))) -/** @brief Optimize space usage (code and data) of resulting program. */ + +/** Optimize space usage (code and data) + * of resulting program. + */ #define Os __attribute__((optimize("Os"))) -/** @brief Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. */ + +/** Disregard strict standards compliance. + * -Ofast enables all -O3 optimizations. + * It also enables optimizations that are not valid for + * all standard-compliant programs. + */ #define Ofast __attribute__((optimize("Ofast"))) +/** Optimize for size. + * -Oz enables all -Os optimizations that do not typically + * increase code size. + */ +#define Oz __attribute__((optimize("Oz"))) + +/** Optimize for debugging. + * -Og enables optimizations that do not interfere with + * debugging. + */ +#define Og __attribute__((optimize("Og"))) + #define __unused __attribute__((unused)) #define __packed __attribute__((packed)) #define __naked __attribute__((naked)) @@ -457,8 +482,6 @@ typedef uint48_t uint_fast48_t; // sanitizer #define __no_sanitize(x) __attribute__((no_sanitize(x))) #define __no_sanitize_address __attribute__((no_sanitize_address)) -/** @brief The no_address_safety_analysis is a deprecated alias of the no_sanitize_address attribute, new code should use no_sanitize_address. */ -#define __no_address_safety_analysis __attribute__((no_address_safety_analysis)) #define __no_sanitize_thread __attribute__((no_sanitize_thread)) #define __no_sanitize_undefined __attribute__((no_sanitize_undefined)) #define __no_sanitize_coverage __attribute__((no_sanitize_coverage)) @@ -471,10 +494,7 @@ typedef uint48_t uint_fast48_t; #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -#define PUBLIC __visibility("default") -#define PRIVATE __visibility("hidden") - -#define NoSecurityAnalysis __no_stack_protector __no_sanitize_address __no_sanitize_undefined __no_address_safety_analysis __no_sanitize_thread +#define NoSecurityAnalysis __no_stack_protector __no_sanitize_address __no_sanitize_undefined __no_sanitize_thread #define nsa NoSecurityAnalysis #define NIF __no_instrument_function @@ -486,9 +506,16 @@ typedef uint48_t uint_fast48_t; : "memory") #define StackPush(stack, type, value) \ - *((type *)--stack) = value; + *((type *)--stack) = value #define StackPop(stack, type) \ *((type *)stack++) +#define ReturnLogError(ret, Format, ...) \ + { \ + trace(Format, ##__VA_ARGS__); \ + return ret; \ + } \ + while (0) + #endif // !__FENNIX_KERNEL_TYPES_H__ diff --git a/include_std/algorithm b/include_std/algorithm index d55c876..33830c1 100644 --- a/include_std/algorithm +++ b/include_std/algorithm @@ -42,12 +42,31 @@ namespace std return d_last; } - template - void swap(T &a, T &b) + template + OutputIt transform(InputIt first, InputIt last, OutputIt result, UnaryOperation op) { - T temp = move(a); - a = move(b); - b = move(temp); + while (first != last) + { + *result = op(*first); + ++first; + ++result; + } + return result; + }; + + template + void swap(T &a, T &b) noexcept(std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value) + { + T temp = std::move(a); + a = std::move(b); + b = std::move(temp); + } + + template + void swap(T2 (&a)[N], T2 (&b)[N]) noexcept(std::is_nothrow_swappable_v) + { + for (std::size_t i = 0; i < N; ++i) + std::swap(a[i], b[i]); } template @@ -193,4 +212,116 @@ namespace std } return first; } + + template + constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) + { + while (first1 != last1) + { + if (!(*first1 == *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + bool equal(ExecutionPolicy &&policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) + { + while (first1 != last1) + { + if (!(*first1 == *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPred p) + { + while (first1 != last1) + { + if (!p(*first1, *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + bool equal(ExecutionPolicy &&policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, BinaryPred p) + { + while (first1 != last1) + { + if (!p(*first1, *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) + { + while (first1 != last1) + { + if (!(*first1 == *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + bool equal(ExecutionPolicy &&policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2) + { + while (first1 != last1) + { + if (!(*first1 == *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPred p) + { + while (first1 != last1) + { + if (!p(*first1, *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } + + template + bool equal(ExecutionPolicy &&policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, BinaryPred p) + { + while (first1 != last1) + { + if (!p(*first1, *first2)) + return false; + + ++first1; + ++first2; + } + return true; + } } diff --git a/storage/devices/root.cpp b/include_std/cctype similarity index 73% rename from storage/devices/root.cpp rename to include_std/cctype index 435acd7..254c21f 100644 --- a/storage/devices/root.cpp +++ b/include_std/cctype @@ -15,18 +15,23 @@ along with Fennix Kernel. If not, see . */ -#include +#pragma once -#include "../../kernel.h" - -namespace vfs +namespace std { - vfsRoot::vfsRoot(const char *Name, Virtual *vfs_ctx) - : Node(nullptr, - Name, - MOUNTPOINT) + inline int tolower(int ch) { - this->vFS = fs; - vfs_ctx->GetRootNode()->Children.push_back(this); + if (ch >= 'A' && ch <= 'Z') + return ch + ('a' - 'A'); + else + return ch; + } + + inline int toupper(int ch) + { + if (ch >= 'a' && ch <= 'z') + return ch - ('a' - 'A'); + else + return ch; } } diff --git a/include_std/cmath b/include_std/cmath index abde42e..29e243f 100644 --- a/include_std/cmath +++ b/include_std/cmath @@ -17,9 +17,12 @@ #pragma once +#include +#include + namespace std { - double sin(double x) + constexpr double sin(double x) { const int NUM_TERMS = 10; @@ -35,7 +38,7 @@ namespace std return result; } - float powf(float base, float exp) + constexpr float powf(float base, float exp) { float result = 1.0; for (int i = 0; i < (int)exp; ++i) @@ -43,7 +46,7 @@ namespace std return result; } - double pow(double base, double exp) + constexpr double pow(double base, double exp) { double result = 1.0; for (int i = 0; i < (int)exp; ++i) @@ -51,7 +54,7 @@ namespace std return result; } - long double powl(long double base, long double exp) + constexpr long double powl(long double base, long double exp) { long double result = 1.0; for (long i = 0; i < (long)exp; ++i) @@ -59,24 +62,121 @@ namespace std return result; } - float fabsf(float num) + constexpr float fabsf(float num) { if (num < 0) return -num; return num; } - double fabs(double num) + constexpr double fabs(double num) { if (num < 0) return -num; return num; } - long double fabsl(long double num) + constexpr long double fabsl(long double num) { if (num < 0) return -num; return num; } + + template + constexpr bool isinf(Integer num) + { + union + { + unsigned long u; + double f; + } ieee754; + ieee754.f = num; + + bool a = ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000; + bool b = ((unsigned)ieee754.u == 0); + return a && b; + } + + template + constexpr bool isnan(Integer num) + { + return num != num; + } + + template + constexpr double fabs(Integer num) + { + return num < 0 ? -num : num; + } + + template + constexpr double remainder(Integer x, Integer y) + { + return x - (int)(x / y) * y; + } + + template + constexpr double copysign(Integer mag, Integer sgn) + { + return (sgn < 0) ? -mag : mag; + } + + template + constexpr bool signbit(Integer num) + { + return num < 0; + } + + template + constexpr double fmod(Integer x, Integer y) + { +#pragma STDC FENV_ACCESS ON + double result = std::remainder(std::fabs(x), y = std::fabs(y)); + if (std::signbit(result)) + result += (double)y; + return std::copysign(result, x); + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + + template + constexpr double ceil(Integer num) + { + // int i = (int)num; + // return i + (i < num); + + double remainder = std::fmod((double)num, 1.0); + return num >= 0 ? (remainder == 0 ? num : num + 1 - remainder) : num - remainder; + } + +#pragma GCC diagnostic pop + + template + constexpr double trunc(Integer num) + { + if (std::isinf(num)) + return num; + + if (std::isnan(num)) + return num; + + return static_cast(num); + } + + template + constexpr double exp(Integer num) + { + double result = 1.0; + double term = 1.0; + + for (int i = 1; i <= 10; ++i) + { + term *= static_cast(num) / i; + result += term; + } + + return result; + } } diff --git a/include/smart_ptr.hpp b/include_std/coroutine similarity index 94% rename from include/smart_ptr.hpp rename to include_std/coroutine index 8556c33..0118550 100644 --- a/include/smart_ptr.hpp +++ b/include_std/coroutine @@ -15,5 +15,7 @@ along with Fennix Kernel. If not, see . */ -#pragma once -#include +namespace std +{ + /* FIXME: Implement */ +} diff --git a/include/filesystem/termios.hpp b/include_std/ctype.h similarity index 52% rename from include/filesystem/termios.hpp rename to include_std/ctype.h index 906a247..8c2775e 100644 --- a/include/filesystem/termios.hpp +++ b/include_std/ctype.h @@ -15,35 +15,37 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_TERMIOS_H__ -#define __FENNIX_KERNEL_TERMIOS_H__ +#ifndef __FENNIX_KERNEL_C_TYPE_H__ +#define __FENNIX_KERNEL_C_TYPE_H__ #include -#include -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; +START_EXTERNC -#define NCCS 32 -struct termios -{ - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[NCCS]; - speed_t c_ispeed; - speed_t c_ospeed; -}; +int isalnum(int); +int isalpha(int); +int isascii(int); -struct winsize -{ - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; +int isblank(int); +int iscntrl(int); +int isdigit(int); +int isgraph(int); +int islower(int); +int isprint(int); +int ispunct(int); +int isspace(int); +int isupper(int); +int isxdigit(int); -#endif // !__FENNIX_KERNEL_TERMIOS_H__ +int toascii(int); +int tolower(int); +int toupper(int); + +#ifndef __cplusplus /* This conflicts with std */ +#define _toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z'))) +#define _tolower(c) ((c) + 0x20 * (((c) >= 'A') && ((c) <= 'Z'))) +#endif + +END_EXTERNC + +#endif // !__FENNIX_KERNEL_C_TYPE_H__ diff --git a/include_std/dlfcn.h b/include_std/dlfcn.h index 1114b46..b53b5f4 100644 --- a/include_std/dlfcn.h +++ b/include_std/dlfcn.h @@ -15,7 +15,17 @@ along with Fennix Kernel. If not, see . */ -#ifndef _DLFCN_H -#define _DLFCN_H +#ifndef __FENNIX_KERNEL_DLFCN_H__ +#define __FENNIX_KERNEL_DLFCN_H__ -#endif // !_DLFCN_H +#include + +typedef struct +{ + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; +} Dl_info; + +#endif // !__FENNIX_KERNEL_DLFCN_H__ diff --git a/include_std/errno.h b/include_std/errno.h index 6fb98d0..6395b84 100644 --- a/include_std/errno.h +++ b/include_std/errno.h @@ -15,407 +15,9 @@ along with Fennix Kernel. If not, see . */ -#ifndef _ERRNO_H -#define _ERRNO_H +#ifndef __FENNIX_KERNEL_STD_ERRNO_H__ +#define __FENNIX_KERNEL_STD_ERRNO_H__ -/** Operation not permitted */ -#define EPERM 1 +#include -/** No such file or directory */ -#define ENOENT 2 - -/** No such process */ -#define ESRCH 3 - -/** Interrupted system call */ -#define EINTR 4 - -/** I/O error */ -#define EIO 5 - -/** No such device or address */ -#define ENXIO 6 - -/** Argument list too long */ -#define E2BIG 7 - -/** Exec format error */ -#define ENOEXEC 8 - -/** Bad file number */ -#define EBADF 9 - -/** No child processes */ -#define ECHILD 10 - -/** Try again */ -#define EAGAIN 11 - -/** Out of memory */ -#define ENOMEM 12 - -/** Permission denied */ -#define EACCES 13 - -/** Bad address */ -#define EFAULT 14 - -/** Block device required */ -#define ENOTBLK 15 - -/** Device or resource busy */ -#define EBUSY 16 - -/** File exists */ -#define EEXIST 17 - -/** Cross-device link */ -#define EXDEV 18 - -/** No such device */ -#define ENODEV 19 - -/** Not a directory */ -#define ENOTDIR 20 - -/** Is a directory */ -#define EISDIR 21 - -/** Invalid argument */ -#define EINVAL 22 - -/** File table overflow */ -#define ENFILE 23 - -/** Too many open files */ -#define EMFILE 24 - -/** Not a typewriter */ -#define ENOTTY 25 - -/** Text file busy */ -#define ETXTBSY 26 - -/** File too large */ -#define EFBIG 27 - -/** No space left on device */ -#define ENOSPC 28 - -/** Illegal seek */ -#define ESPIPE 29 - -/** Read-only file system */ -#define EROFS 30 - -/** Too many links */ -#define EMLINK 31 - -/** Broken pipe */ -#define EPIPE 32 - -/** Math argument out of domain of func */ -#define EDOM 33 - -/** Math result not representable */ -#define ERANGE 34 - -/** Resource deadlock would occur */ -#define EDEADLK 35 - -/** File name too long */ -#define ENAMETOOLONG 36 - -/** No record locks available */ -#define ENOLCK 37 - -/** Function not implemented */ -#define ENOSYS 38 - -/** Directory not empty */ -#define ENOTEMPTY 39 - -/** Too many symbolic links encountered */ -#define ELOOP 40 - -/** No message of desired type */ -#define ENOMSG 42 - -/** Identifier removed */ -#define EIDRM 43 - -/** Channel number out of range */ -#define ECHRNG 44 - -/** Level 2 not synchronized */ -#define EL2NSYNC 45 - -/** Level 3 halted */ -#define EL3HLT 46 - -/** Level 3 reset */ -#define EL3RST 47 - -/** Link number out of range */ -#define ELNRNG 48 - -/** Protocol driver not attached */ -#define EUNATCH 49 - -/** No CSI structure available */ -#define ENOCSI 50 - -/** Level 2 halted */ -#define EL2HLT 51 - -/** Invalid exchange */ -#define EBADE 52 - -/** Invalid request descriptor */ -#define EBADR 53 - -/** Exchange full */ -#define EXFULL 54 - -/** No anode */ -#define ENOANO 55 - -/** Invalid request code */ -#define EBADRQC 56 - -/** Invalid slot */ -#define EBADSLT 57 - -/** Bad font file format */ -#define EBFONT 59 - -/** Device not a stream */ -#define ENOSTR 60 - -/** No data available */ -#define ENODATA 61 - -/** Timer expired */ -#define ETIME 62 - -/** Out of streams resources */ -#define ENOSR 63 - -/** Machine is not on the network */ -#define ENONET 64 - -/** Package not installed */ -#define ENOPKG 65 - -/** Object is remote */ -#define EREMOTE 66 - -/** Link has been severed */ -#define ENOLINK 67 - -/** Advertise error */ -#define EADV 68 - -/** Srmount error */ -#define ESRMNT 69 - -/** Communication error on send */ -#define ECOMM 70 - -/** Protocol error */ -#define EPROTO 71 - -/** Multihop attempted */ -#define EMULTIHOP 72 - -/** RFS specific error */ -#define EDOTDOT 73 - -/** Not a data message */ -#define EBADMSG 74 - -/** Value too large for defined data type */ -#define EOVERFLOW 75 - -/** Name not unique on network */ -#define ENOTUNIQ 76 - -/** File descriptor in bad state */ -#define EBADFD 77 - -/** Remote address changed */ -#define EREMCHG 78 - -/** Can not access a needed shared library */ -#define ELIBACC 79 - -/** Accessing a corrupted shared library */ -#define ELIBBAD 80 - -/** .lib section in a.out corrupted */ -#define ELIBSCN 81 - -/** Attempting to link in too many shared libraries */ -#define ELIBMAX 82 - -/** Cannot exec a shared library directly */ -#define ELIBEXEC 83 - -/** Illegal byte sequence */ -#define EILSEQ 84 - -/** Interrupted system call should be restarted */ -#define ERESTART 85 - -/** Streams pipe error */ -#define ESTRPIPE 86 - -/** Too many users */ -#define EUSERS 87 - -/** Socket operation on non-socket */ -#define ENOTSOCK 88 - -/** Destination address required */ -#define EDESTADDRREQ 89 - -/** Message too long */ -#define EMSGSIZE 90 - -/** Protocol wrong type for socket */ -#define EPROTOTYPE 91 - -/** Protocol not available */ -#define ENOPROTOOPT 92 - -/** Protocol not supported */ -#define EPROTONOSUPPORT 93 - -/** Socket type not supported */ -#define ESOCKTNOSUPPORT 94 - -/** Operation not supported on transport endpoint */ -#define EOPNOTSUPP 95 - -/** Protocol family not supported */ -#define EPFNOSUPPORT 96 - -/** Address family not supported by protocol */ -#define EAFNOSUPPORT 97 - -/** Address already in use */ -#define EADDRINUSE 98 - -/** Cannot assign requested address */ -#define EADDRNOTAVAIL 99 - -/** Network is down */ -#define ENETDOWN 100 - -/** Network is unreachable */ -#define ENETUNREACH 101 - -/** Network dropped connection because of reset */ -#define ENETRESET 102 - -/** Software caused connection abort */ -#define ECONNABORTED 103 - -/** Connection reset by peer */ -#define ECONNRESET 104 - -/** No buffer space available */ -#define ENOBUFS 105 - -/** Transport endpoint is already connected */ -#define EISCONN 106 - -/** Transport endpoint is not connected */ -#define ENOTCONN 107 - -/** Cannot send after transport endpoint shutdown */ -#define ESHUTDOWN 108 - -/** Too many references: cannot splice */ -#define ETOOMANYREFS 109 - -/** Connection timed out */ -#define ETIMEDOUT 110 - -/** Connection refused */ -#define ECONNREFUSED 111 - -/** Host is down */ -#define EHOSTDOWN 112 - -/** No route to host */ -#define EHOSTUNREACH 113 - -/** Operation already in progress */ -#define EALREADY 114 - -/** Operation now in progress */ -#define EINPROGRESS 115 - -/** Stale NFS file handle */ -#define ESTALE 116 - -/** Structure needs cleaning */ -#define EUCLEAN 117 - -/** Not a XENIX named type file */ -#define ENOTNAM 118 - -/** No XENIX semaphores available */ -#define ENAVAIL 119 - -/** Is a named type file */ -#define EISNAM 120 - -/** Remote I/O error */ -#define EREMOTEIO 121 - -/** Quota exceeded */ -#define EDQUOT 122 - -/** No medium found */ -#define ENOMEDIUM 123 - -/** Wrong medium type */ -#define EMEDIUMTYPE 124 - -/** Operation Canceled */ -#define ECANCELED 125 - -/** Required key not available */ -#define ENOKEY 126 - -/** Key has expired */ -#define EKEYEXPIRED 127 - -/** Key has been revoked */ -#define EKEYREVOKED 128 - -/** Key was rejected by service */ -#define EKEYREJECTED 129 - -/** Owner died */ -#define EOWNERDEAD 130 - -/** State not recoverable */ -#define ENOTRECOVERABLE 131 - -#include -EXTERNC int *__errno_location(void) __attribute__((const)); -#define errno (*__errno_location()) - -#ifdef __cplusplus -extern "C" -{ -#endif - const char *strerror(int errnum); -#ifdef __cplusplus -} -#endif - -#endif // !_ERRNO_H +#endif // !__FENNIX_KERNEL_STD_ERRNO_H__ diff --git a/include_std/exception b/include_std/exception index f36b0a6..ae47209 100644 --- a/include_std/exception +++ b/include_std/exception @@ -26,16 +26,22 @@ namespace std { public: exception() noexcept {} - virtual ~exception() noexcept; - exception(const exception &) = default; - exception &operator=(const exception &) = default; - exception(exception &&) = default; - exception &operator=(exception &&) = default; - - virtual const char *what() const noexcept; + exception(const exception &) noexcept = default; + virtual ~exception() noexcept = default; + exception &operator=(const exception &) noexcept = default; + virtual const char *what() const noexcept { return "Exception"; } }; typedef void (*terminate_handler)(); + typedef void (*unexpected_handler)(); + + [[noreturn]] void terminate() noexcept; + std::terminate_handler set_terminate(std::terminate_handler f) noexcept; + std::terminate_handler get_terminate() noexcept; + + [[noreturn]] void unexpected(); + std::unexpected_handler set_unexpected(std::unexpected_handler f) noexcept; + std::unexpected_handler get_unexpected() noexcept; } #endif // !__FENNIX_KERNEL_EXCEPTION_H__ diff --git a/include_std/functional b/include_std/functional index c88bfbf..3e89d66 100644 --- a/include_std/functional +++ b/include_std/functional @@ -17,9 +17,13 @@ #pragma once +#include +#include +#include + namespace std { - template + template struct equal_to { bool operator()(const T &lhs, const T &rhs) const @@ -58,4 +62,193 @@ namespace std return static_cast(hash); } }; + + template + class reference_wrapper; + + template + class function; /* undefined */ + + template + class function + { + private: + class impl_base + { + public: + virtual ~impl_base() = default; + virtual R invoke(Args...) const = 0; +#ifdef __GXX_RTTI + virtual const std::type_info &target_type() const noexcept = 0; +#endif + virtual impl_base *clone() const = 0; + }; + + template + class impl : public impl_base + { + public: + F _f; + + template + impl(G &&f) + : _f(std::forward(f)) + { + } + + R invoke(Args... args) const override + { + return _f(std::forward(args)...); + } + +#ifdef __GXX_RTTI + const std::type_info &target_type() const noexcept override + { + return typeid(F); + } +#endif + + impl_base *clone() const override + { + return new impl(_f); + } + }; + + impl_base *_ptr; + + public: + using result_type = R; + + function() noexcept + : _ptr(nullptr) + { + } + + function(std::nullptr_t) noexcept + : _ptr(nullptr) + { + } + + function(const function &other) + : _ptr(other._ptr) + { + } + + function(function &&other) noexcept + : _ptr(other._ptr) + { + other._ptr = nullptr; + } + + template + function(F &&f) + : _ptr(new impl(std::forward(f))) + { + } + + ~function() + { + delete _ptr; + } + + function &operator=(const function &other) + { + if (this != &other) + { + delete _ptr; + _ptr = other._ptr ? other._ptr->clone() : nullptr; + } + return *this; + } + + function &operator=(function &&other) + { + if (this != &other) + { + delete _ptr; + _ptr = other._ptr; + other._ptr = nullptr; + } + return *this; + } + + function &operator=(std::nullptr_t) noexcept + { + delete _ptr; + _ptr = nullptr; + return *this; + } + + template + function &operator=(F &&f) + { + delete _ptr; + _ptr = new impl(std::forward(f)); + return *this; + } + + template + function &operator=(std::reference_wrapper f) noexcept + { + delete _ptr; + _ptr = new impl>(f); + return *this; + } + + void swap(function &other) noexcept + { + std::swap(_ptr, other._ptr); + } + + explicit operator bool() const noexcept + { + return _ptr != nullptr; + } + + R operator()(Args... args) const + { + return _ptr->invoke(std::forward(args)...); + } + +#ifdef __GXX_RTTI + const std::type_info &target_type() const noexcept + { + return _ptr ? _ptr->target_type() : typeid(void); + } + + template + T *target() noexcept + { + return _ptr && _ptr->target_type() == typeid(T) ? &static_cast *>(_ptr)->_f : nullptr; + } + + template + const T *target() const noexcept + { + return _ptr && _ptr->target_type() == typeid(T) ? &static_cast *>(_ptr)->_f : nullptr; + } +#endif + }; + + template + void swap(std::function &lhs, std::function &rhs) noexcept + { + lhs.swap(rhs); + } + + template + + bool operator==(const std::function &f, std::nullptr_t) noexcept + { + return !f; + } + + template + struct less + { + constexpr bool operator()(const T &lhs, const T &rhs) const + { + return lhs < rhs; + } + }; } diff --git a/include_std/initializer_list b/include_std/initializer_list index 70571f9..a55c050 100644 --- a/include_std/initializer_list +++ b/include_std/initializer_list @@ -21,28 +21,41 @@ namespace std { - template + template class initializer_list { + public: + typedef _E value_type; + typedef const _E &reference; + typedef const _E &const_reference; + typedef size_t size_type; + typedef const _E *iterator; + typedef const _E *const_iterator; + private: - const T *array; - size_t len; + iterator array; + size_type len; public: - initializer_list() : array(nullptr), len(0) {} - size_t size() const { return len; } - const T *begin() const { return array; } - const T *end() const { return begin() + size(); } + constexpr initializer_list(const_iterator a, size_type l) + : array(a), len(l) {} + + constexpr initializer_list() + : array(nullptr), len(0) {} + + constexpr size_type size() const { return len; } + constexpr const_iterator begin() const { return array; } + constexpr const_iterator end() const { return begin() + size(); } }; template - const E *begin(std::initializer_list il) + constexpr const E *begin(initializer_list il) { return il.begin(); } template - constexpr const E *end(std::initializer_list il) + constexpr const E *end(initializer_list il) { return il.end(); } diff --git a/include_std/inttypes.h b/include_std/inttypes.h new file mode 100644 index 0000000..1ce343e --- /dev/null +++ b/include_std/inttypes.h @@ -0,0 +1,23 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_INTTYPES_H__ +#define __FENNIX_KERNEL_INTTYPES_H__ + +#include + +#endif // !__FENNIX_KERNEL_INTTYPES_H__ diff --git a/include_std/ios b/include_std/ios new file mode 100644 index 0000000..30003d8 --- /dev/null +++ b/include_std/ios @@ -0,0 +1,286 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include +#include +#include + +#ifdef in +#undef in +#endif /* deprecated macro in */ + +namespace std +{ + enum class io_errc + { + stream = 1, + }; + + typedef long long streamsize; + + class ios_base + { + public: +#pragma region Member types and constants + + typedef int openmode; + static constexpr openmode app = 1; + static constexpr openmode binary = 2; + static constexpr openmode in = 4; + static constexpr openmode out = 8; + static constexpr openmode trunc = 16; + static constexpr openmode ate = 32; + static constexpr openmode noreplace = 64; + + typedef int fmtflags; + static constexpr fmtflags dec = 1; + static constexpr fmtflags oct = 2; + static constexpr fmtflags hex = 4; + static constexpr fmtflags basefield = dec | oct | hex; + + static constexpr fmtflags left = 1; + static constexpr fmtflags right = 2; + static constexpr fmtflags internal = 4; + static constexpr fmtflags adjustfield = left | right | internal; + + static constexpr fmtflags scientific = 1; + static constexpr fmtflags fixed = 2; + static constexpr fmtflags floatfield = scientific | fixed; + + static constexpr fmtflags boolalpha = 1; + static constexpr fmtflags showbase = 2; + static constexpr fmtflags showpoint = 4; + static constexpr fmtflags showpos = 8; + static constexpr fmtflags skipws = 16; + static constexpr fmtflags unitbuf = 32; + static constexpr fmtflags uppercase = 64; + + typedef int iostate; + static constexpr iostate goodbit = 0; + static constexpr iostate badbit = 1; + static constexpr iostate failbit = 2; + static constexpr iostate eofbit = 4; + + typedef int seekdir; + static constexpr seekdir beg = 0; + static constexpr seekdir end = 1; + static constexpr seekdir cur = 2; + + enum event + { + erase_event, + imbue_event, + copyfmt_event + }; + + typedef void (*event_callback)(event type, ios_base &ios, int index); + +#pragma endregion Member types and constants + +#pragma region Member Functions + + protected: + ios_base(); + + public: + ios_base(const ios_base &) = delete; + virtual ~ios_base() = default; + ios_base &operator=(const ios_base &) = delete; + +#pragma endregion Member Functions + +#pragma region Formatting + + fmtflags flags() const + { + return _flags; + } + + fmtflags flags(fmtflags flags) + { + fmtflags old = _flags; + _flags = flags; + return old; + } + + fmtflags setf(fmtflags flags) + { + fmtflags old = _flags; + _flags |= flags; + return old; + } + + fmtflags setf(fmtflags flags, fmtflags mask) + { + fmtflags old = _flags; + _flags &= ~mask; + _flags |= flags; + return old; + } + + void unsetf(fmtflags flags) + { + _flags &= ~flags; + } + + streamsize precision() const + { + return _precision; + } + + streamsize precision(streamsize new_precision) + { + streamsize old = _precision; + _precision = new_precision; + return old; + } + + streamsize width() const + { + return _width; + } + + streamsize width(streamsize new_width) + { + streamsize old = _width; + _width = new_width; + return old; + } + +#pragma endregion Formatting + +#pragma region Locales + + std::locale imbue(const std::locale &loc) + { + std::locale old = _loc; + _loc = loc; + __call_event(imbue_event, *this, 0); + return old; + } + + std::locale getloc() const + { + return _loc; + } + +#pragma endregion Locales + +#pragma region Internal Extensible Array + + static int xalloc() + { + static int index = 0; + return index++; + } + + long &iword(int index) + { + static std::vector iwords; + if ((size_t)index >= iwords.size()) + iwords.resize(index + 1); + return iwords[index]; + } + + void *&pword(int index) + { + static std::vector pwords; + if ((size_t)index >= pwords.size()) + pwords.resize(index + 1); + return pwords[index]; + } + +#pragma endregion Internal Extensible Array + +#pragma region Miscellaneous + + void register_callback(event_callback function, int index) + { + _event_callback = function; + __call_event(imbue_event, *this, index); + } + + static bool sync_with_stdio(bool sync = true) + { + return false; + } + +#pragma endregion Miscellaneous + +#pragma region Member Classes + + class failure + { + public: + explicit failure(const std::string &message, const std::error_code &ec = std::io_errc::stream) + { + } + + explicit failure(const char *message, const std::error_code &ec = std::io_errc::stream) + { + } + + failure(const failure &other) noexcept + { + } + + failure &operator=(const failure &other) noexcept + { + return *this; + } + + virtual const char *what() const noexcept + { + return nullptr; + } + }; + + class Init + { + public: + Init() = default; + ~Init() = default; + }; + +#pragma endregion Member Classes + + private: + fmtflags _flags = skipws; + streamsize _precision = 6; + streamsize _width = 0; + std::locale _loc = std::locale::classic(); + + static event_callback _event_callback; + + static void __call_event(event type, ios_base &ios, int index) + { + if (_event_callback) + _event_callback(type, ios, index); + } + }; + + template > + class basic_ios : public std::ios_base + { + }; + + typedef basic_ios ios; + typedef basic_ios wios; +} diff --git a/storage/devices/null.cpp b/include_std/iostream similarity index 64% rename from storage/devices/null.cpp rename to include_std/iostream index 0c062f6..1ba5be0 100644 --- a/storage/devices/null.cpp +++ b/include_std/iostream @@ -15,23 +15,22 @@ along with Fennix Kernel. If not, see . */ -#include -#include +#pragma once -#include "../../kernel.h" +#include +#include -namespace vfs +namespace std { - size_t NullDevice::read(uint8_t *Buffer, size_t Size, off_t Offset) - { - return Size; - } + extern std::istream cin; + extern std::wistream wcin; - size_t NullDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) - { - return Size; - } + extern std::ostream cout; + extern std::wostream wcout; - NullDevice::NullDevice() : Node(DevFS, "null", CHARDEVICE) {} - NullDevice::~NullDevice() {} + extern std::ostream cerr; + extern std::wostream wcerr; + + extern std::ostream clog; + extern std::wostream wclog; } diff --git a/include_std/istream b/include_std/istream new file mode 100644 index 0000000..1d1fd63 --- /dev/null +++ b/include_std/istream @@ -0,0 +1,79 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include +#include +#include + +namespace std +{ + template > + class basic_istream : virtual public std::basic_ios + { + }; + + template > + class basic_iostream : public basic_istream, public basic_ostream + { + private: + void init(std::basic_streambuf *sb) + { + this->basic_istream::rdbuf(sb); + this->basic_ostream::rdbuf(sb); + } + + public: + typedef CharT char_type; + typedef Traits::char_type traits_type; + typedef Traits::int_type int_type; + typedef Traits::pos_type pos_type; + typedef Traits::off_type off_type; + + explicit basic_iostream(std::basic_streambuf *sb) + { + this->init(sb); + } + + basic_iostream(const basic_iostream &other) = delete; + virtual ~basic_iostream() = default; + + basic_iostream &operator=(const basic_iostream &other) = delete; + + protected: + basic_iostream(basic_iostream &&other) + { + this->rdbuf(other.rdbuf()); + other.rdbuf(nullptr); + } + + basic_iostream &operator=(basic_iostream &&other); + + void swap(basic_iostream &other) + { + std::swap(this->rdbuf(), other.rdbuf()); + } + }; + + typedef basic_istream istream; + typedef basic_istream wistream; + + typedef basic_iostream iostream; + typedef basic_iostream wiostream; +} diff --git a/include_std/iterator b/include_std/iterator index 7089812..a10e5bf 100644 --- a/include_std/iterator +++ b/include_std/iterator @@ -43,26 +43,21 @@ namespace std { }; - template - class reverse_iterator - { - public: - /* FIXME: missing implementation */ - }; - template struct iterator_traits { public: - typedef Iter::difference_type difference_type; - - /* FIXME: missing implementation */ + using difference_type = typename Iter::difference_type; + using value_type = typename Iter::value_type; + using pointer = typename Iter::pointer; + using reference = typename Iter::reference; + using iterator_category = typename Iter::iterator_category; }; - template - constexpr typename std::iterator_traits::difference_type __do_distance(It first, It last, std::input_iterator_tag) + template + constexpr typename std::iterator_traits::difference_type __do_distance(InputIt first, InputIt last, std::input_iterator_tag) { - typename std::iterator_traits::difference_type result = 0; + typename std::iterator_traits::difference_type result = 0; while (first != last) { ++first; @@ -71,8 +66,8 @@ namespace std return result; } - template - constexpr typename std::iterator_traits::difference_type __do_distance(It first, It last, std::random_access_iterator_tag) + template + constexpr typename std::iterator_traits::difference_type __do_distance(InputIt first, InputIt last, std::random_access_iterator_tag) { return last - first; } @@ -82,4 +77,56 @@ namespace std { return __do_distance(first, last, typename std::iterator_traits::iterator_category()); } + + template + void __do_advance(InputIt &it, typename std::iterator_traits::difference_type n, std::input_iterator_tag) + { + while (n > 0) + { + --n; + ++it; + } + } + + template + void __do_advance(InputIt &it, typename std::iterator_traits::difference_type n, std::bidirectional_iterator_tag) + { + while (n > 0) + { + --n; + ++it; + } + while (n < 0) + { + ++n; + --it; + } + } + + template + void __do_advance(InputIt &it, typename std::iterator_traits::difference_type n, std::random_access_iterator_tag) + { + it += n; + } + + template + constexpr void advance(InputIt &it, Distance n) + { + __do_advance(it, typename std::iterator_traits::difference_type(n), + typename std::iterator_traits::iterator_category()); + } + + template + constexpr BidirIt prev(BidirIt it, typename std::iterator_traits::difference_type n = 1) + { + std::advance(it, -n); + return it; + } + + template + constexpr InputIt next(InputIt it, typename std::iterator_traits::difference_type n = 1) + { + std::advance(it, n); + return it; + } } diff --git a/include_std/list b/include_std/list index 6564f80..84c6eca 100644 --- a/include_std/list +++ b/include_std/list @@ -17,26 +17,44 @@ #pragma once -#include +#include +#include #include #include +#include #include +#include namespace std { - template + template > class list { + public: + using value_type = T; + using allocator_type = Allocator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + // using iterator = typename list::iterator; + // using const_iterator = typename list::const_iterator; + // using reverse_iterator = typename list::reverse_iterator; + // using const_reverse_iterator = typename list::const_reverse_iterator; + private: - NewLock(lock); + spin_lock lock; + Allocator alloc; struct node { - T value; + value_type value; node *prev; node *next; - node(const T &v, node *p = nullptr, node *n = nullptr) + node(const_reference v, node *p = nullptr, node *n = nullptr) : value(v), prev(p), next(n) {} }; @@ -45,13 +63,440 @@ namespace std std::atomic_size_t lSize = 0; public: - list() {} + class iterator + { + private: + node *_node; + friend class list; + + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = typename std::allocator_traits::pointer; + using reference = value_type &; + using iterator_category = std::bidirectional_iterator_tag; + + iterator(node *p = nullptr) : _node(p) {} + + T &operator*() const { return _node->value; } + T *operator->() const { return &_node->value; } + + iterator &operator++() + { + if (_node) + _node = _node->next; + return *this; + } + + iterator &operator--() + { + if (_node) + _node = _node->prev; + return *this; + } + + iterator operator++(int) + { + iterator tmp = *this; + ++*this; + return tmp; + } + + iterator operator--(int) + { + iterator tmp = *this; + --*this; + return tmp; + } + + bool operator==(const iterator &rhs) const { return _node == rhs._node; } + bool operator!=(const iterator &rhs) const { return _node != rhs._node; } + }; + + class const_iterator + { + private: + node *_node; + friend class list; + + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = typename std::allocator_traits::const_pointer; + using reference = const value_type &; + using iterator_category = std::bidirectional_iterator_tag; + + const_iterator(iterator it) : _node(it._node) {} + const_iterator(node *p = nullptr) : _node(p) {} + const T &operator*() const { return _node->value; } + const T *operator->() const { return &_node->value; } + + const_iterator &operator++() + { + if (_node) + _node = _node->next; + return *this; + } + + const_iterator &operator--() + { + if (_node) + _node = _node->prev; + return *this; + } + + const_iterator operator++(int) + { + const_iterator it = *this; + ++*this; + return it; + } + + const_iterator operator--(int) + { + const_iterator it = *this; + --*this; + return it; + } + + bool operator==(const const_iterator &rhs) const { return _node == rhs._node; } + bool operator!=(const const_iterator &rhs) const { return _node != rhs._node; } + }; + +#pragma region Member Functions + + list() + { + } + + explicit list(const Allocator &alloc) + : alloc(alloc) + { + } + + list(size_type count, const T &value, + const Allocator &alloc = Allocator()) + { + for (size_t i = 0; i < count; ++i) + push_back(value); + } + + explicit list(size_type count, const Allocator &alloc = Allocator()) + { + for (size_t i = 0; i < count; ++i) + push_back(T()); + } + + template + list(InputIt first, InputIt last, const Allocator &alloc = Allocator()) + { + for (InputIt it = first; it != last; ++it) + push_back(*it); + } + + list(const list &other) + { + *this = other; + } + + list(const list &other, const Allocator &alloc) + { + *this = other; + } + + list(list &&other) + { + *this = std::move(other); + } + + list(list &&other, const Allocator &alloc) + { + *this = std::move(other); + } + + list(std::initializer_list init, const Allocator &alloc = Allocator()) + { + foreach (const_reference value in init) + push_back(value); + } + ~list() { clear(); } - list(const list &other) { *this = other; } + + list &operator=(const list &other) + { + if (this == &other) + return *this; + + for (const_reference value : other) + push_back(value); + + return *this; + } + + list &operator=(list &&other) + { + if (this == &other) + return *this; + + clear(); + head = other.head; + tail = other.tail; + lSize.store(other.lSize.load()); + other.head = other.tail = nullptr; + other.lSize.store(0); + return *this; + } + + list &operator=(std::initializer_list ilist) + { + clear(); + foreach (const_reference value in ilist) + push_back(value); + return *this; + } + + void assign(size_type count, const T &value) + { + clear(); + for (size_t i = 0; i < count; ++i) + push_back(value); + } + + template + void assign(InputIt first, InputIt last) + { + clear(); + for (InputIt it = first; it != last; ++it) + push_back(*it); + } + + void assign(std::initializer_list ilist) + { + clear(); + foreach (const_reference value in ilist) + push_back(value); + } + + allocator_type get_allocator() const + { + return alloc; + } + +#pragma endregion Member Functions + +#pragma region Element Access + + reference front() + { + sl_guard(this->lock); + return head->value; + } + + const_reference front() const + { + sl_guard(this->lock); + return head->value; + } + + reference back() + { + sl_guard(this->lock); + return tail->value; + } + + const_reference back() const + { + sl_guard(this->lock); + return tail->value; + } + +#pragma endregion Element Access + +#pragma region Iterators + + iterator begin() + { + return iterator(head); + } + + const_iterator begin() const + { + return const_iterator(head); + } + + const_iterator cbegin() const + { + return const_iterator(head); + } + + iterator end() + { + return iterator(nullptr); + } + + const_iterator end() const + { + return const_iterator(nullptr); + } + + const_iterator cend() const + { + return const_iterator(nullptr); + } + + /* FIXME: rbegin, rend, crbegin, crend */ + +#pragma endregion Iterators + +#pragma region Capacity + + [[nodiscard]] bool empty() const + { + return lSize.load() == 0; /* or begin() == end() ? */ + } + + size_type size() const + { + return lSize.load(); + } + + size_type max_size() const + { + return std::numeric_limits::max(); + } + +#pragma endregion Capacity + +#pragma region Modifiers + + void clear() + { + while (!empty()) + pop_back(); + } + + iterator insert(const_iterator pos, const T &value) + { + if (pos == end()) + { + push_back(value); + return iterator(tail); + } + else if (pos == begin()) + { + push_front(value); + return iterator(head); + } + else + { + sl_guard(this->lock); + node *p = pos._node; + node *nNode = new node(value, p->prev, p); + p->prev->next = nNode; + p->prev = nNode; + lSize.fetch_add(1); + return iterator(nNode); + } + } + + iterator insert(const_iterator pos, T &&value) + { + if (pos == end()) + { + push_back(value); + return iterator(tail); + } + else if (pos == begin()) + { + push_front(value); + return iterator(head); + } + else + { + sl_guard(this->lock); + node *p = pos._node; + node *nNode = new node(std::move(value), p->prev, p); + p->prev->next = nNode; + p->prev = nNode; + lSize.fetch_add(1); + return iterator(nNode); + } + } + + iterator insert(const_iterator pos, size_type count, const T &value) + { + iterator ret; + for (size_t i = 0; i < count; ++i) + ret = insert(pos, value); + return ret; + } + + template + iterator insert(const_iterator pos, InputIt first, InputIt last) + { + iterator ret; + for (InputIt it = first; it != last; ++it) + ret = insert(pos, *it); + return ret; + } + + iterator insert(const_iterator pos, std::initializer_list ilist) + { + iterator ret; + foreach (const_reference value in ilist) + ret = insert(pos, value); + return ret; + } + + template + iterator emplace(const_iterator pos, Args &&...args) + { + return insert(pos, T(std::forward(args)...)); + } + + iterator erase(const_iterator pos) + { + if (pos == cend()) + return end(); + else if (pos == cbegin()) + { + pop_front(); + return begin(); + } + else + { + sl_guard(this->lock); + node *p = pos._node; + if (p->prev) + p->prev->next = p->next; + + if (p->next) + p->next->prev = p->prev; + + if (head == p) + head = p->next; + + if (tail == p) + tail = p->prev; + + iterator ret(p->next); + delete p; + lSize.fetch_sub(1); + return ret; + } + } + + iterator erase(const_iterator first, const_iterator last) + { + iterator ret; + while (first != last) + ret = erase(first++); + return ret; + } void push_back(const T &value) { - SmartLock(this->lock); + sl_guard(this->lock); node *nNode = new node(value, tail); if (empty()) @@ -61,12 +506,64 @@ namespace std tail->next = nNode; tail = nNode; } - ++lSize; + lSize.fetch_add(1); + } + + void push_back(T &&value) + { + sl_guard(this->lock); + + node *nNode = new node(std::move(value), tail); + if (empty()) + head = tail = nNode; + else + { + tail->next = nNode; + tail = nNode; + } + lSize.fetch_add(1); + } + + template + void emplace_back(Args &&...args) + { + assert(sizeof...(args) > 0); + + sl_guard(this->lock); + + node *nNode = new node(T(std::forward(args)...), tail); + if (this->empty()) + head = tail = nNode; + else + { + tail->next = nNode; + tail = nNode; + } + lSize.fetch_add(1); + } + + template + reference emplace_back(Args &&...args) + { + assert(sizeof...(args) > 0); + + sl_guard(this->lock); + + node *nNode = new node(T(std::forward(args)...), tail); + if (this->empty()) + head = tail = nNode; + else + { + tail->next = nNode; + tail = nNode; + } + lSize.fetch_add(1); + return tail->value; } void pop_back() { - SmartLock(this->lock); + sl_guard(this->lock); if (unlikely(empty())) assert(!"list is empty"); @@ -74,7 +571,7 @@ namespace std { delete tail; head = tail = nullptr; - --lSize; + lSize.fetch_sub(1); } else { @@ -82,13 +579,13 @@ namespace std tail = tail->prev; tail->next = nullptr; delete oldTail; - --lSize; + lSize.fetch_sub(1); } } void push_front(const T &value) { - SmartLock(this->lock); + sl_guard(this->lock); node *nNode = new node(value, nullptr, head); if (empty()) @@ -98,7 +595,59 @@ namespace std head->prev = nNode; head = nNode; } - ++lSize; + lSize.fetch_add(1); + } + + void push_front(T &&value) + { + sl_guard(this->lock); + + node *nNode = new node(std::move(value), nullptr, head); + if (empty()) + head = tail = nNode; + else + { + head->prev = nNode; + head = nNode; + } + lSize.fetch_add(1); + } + + template + void emplace_front(Args &&...args) + { + assert(sizeof...(args) > 0); + + sl_guard(this->lock); + + node *nNode = new node(T(std::forward(args)...), nullptr, head); + if (this->empty()) + head = tail = nNode; + else + { + head->prev = nNode; + head = nNode; + } + lSize.fetch_add(1); + } + + template + reference emplace_front(Args &&...args) + { + assert(sizeof...(args) > 0); + + sl_guard(this->lock); + + node *nNode = new node(T(std::forward(args)...), nullptr, head); + if (this->empty()) + head = tail = nNode; + else + { + head->prev = nNode; + head = nNode; + } + lSize.fetch_add(1); + return head->value; } void pop_front() @@ -110,96 +659,71 @@ namespace std if (head == tail) { - SmartLock(this->lock); + sl_guard(this->lock); delete head; head = tail = nullptr; - --lSize; + lSize.fetch_sub(1); } else { - SmartLock(this->lock); + sl_guard(this->lock); node *old_head = head; head = head->next; head->prev = nullptr; delete old_head; - --lSize; + lSize.fetch_sub(1); } } - template - void emplace_back(Args &&...args) + void resize(size_type count) { - assert(sizeof...(args) > 0); - - SmartLock(this->lock); - - node *nNode = new node(T(std::forward(args)...), tail); - if (this->empty()) - head = tail = nNode; - else + if (count < lSize.load()) { - tail->next = nNode; - tail = nNode; + while (lSize.load() > count) + pop_back(); } - ++lSize; - } - - template - void emplace_front(Args &&...args) - { - assert(sizeof...(args) > 0); - - SmartLock(this->lock); - - node *nNode = new node(T(std::forward(args)...), nullptr, head); - if (this->empty()) - head = tail = nNode; - else + else if (count > lSize.load()) { - head->prev = nNode; - head = nNode; + while (lSize.load() < count) + push_back(T()); } - ++lSize; } - T &front() + void resize(size_type count, const value_type &value) { - SmartLock(this->lock); - return head->value; + if (count < lSize.load()) + { + while (lSize.load() > count) + pop_back(); + } + else if (count > lSize.load()) + { + while (lSize.load() < count) + push_back(value); + } } - const T &front() const + void swap(list &other) { - SmartLock(this->lock); - return head->value; + sl_guard(this->lock); + other.lock.lock("list::swap"); + + std::swap(head, other.head); + std::swap(tail, other.tail); + + size_t oSize = other.lSize.load(); + other.lSize.store(lSize.load()); + lSize.store(oSize); + + other.lock.unlock(); } - T &back() - { - SmartLock(this->lock); - return tail->value; - } +#pragma endregion Modifiers - const T &back() const - { - SmartLock(this->lock); - return tail->value; - } - - bool empty() const { return lSize.load() == 0; } - size_t size() const { return lSize; } - - void clear() - { - while (!empty()) - pop_back(); - } +#pragma region Operations void merge(list &other) { - if (this == &other) - return; - while (other.empty() == false) { T &fr = other.front(); @@ -208,11 +732,99 @@ namespace std } } - size_t remove(const T &value) + void merge(list &&other) { - SmartLock(this->lock); + while (other.empty() == false) + { + T &fr = other.front(); + push_back(fr); + other.pop_front(); + } + } + + template + void merge(list &other, Compare comp) + { + while (other.empty() == false) + { + T &fr = other.front(); + if (comp(tail->value, fr)) + push_back(fr); + else + push_front(fr); + other.pop_front(); + } + } + + template + void merge(list &&other, Compare comp) + { + while (other.empty() == false) + { + T &fr = other.front(); + if (comp(tail->value, fr)) + push_back(fr); + else + push_front(fr); + other.pop_front(); + } + } + + void splice(const_iterator pos, list &other) + { + while (other.empty() == false) + { + T &fr = other.front(); + insert(pos, fr); + other.pop_front(); + } + } + + void splice(const_iterator pos, list &&other) + { + while (other.empty() == false) + { + T &fr = other.front(); + insert(pos, fr); + other.pop_front(); + } + } + + void splice(const_iterator pos, list &other, const_iterator it) + { + insert(pos, *it); + other.erase(it); + } + + void splice(const_iterator pos, list &&other, const_iterator it) + { + insert(pos, *it); + other.erase(it); + } + + void splice(const_iterator pos, list &other, const_iterator first, const_iterator last) + { + while (first != last) + { + insert(pos, *first); + other.erase(first++); + } + } + + void splice(const_iterator pos, list &&other, const_iterator first, const_iterator last) + { + while (first != last) + { + insert(pos, *first); + other.erase(first++); + } + } + + size_type remove(const T &value) + { + sl_guard(this->lock); node *p = head; - size_t count = 0; + size_type count = 0; while (p != nullptr) { if (p->value == value) @@ -226,7 +838,7 @@ namespace std if (p == tail) tail = p->prev; delete p; - --lSize; + lSize.fetch_sub(1); ++count; } p = p->next; @@ -235,11 +847,11 @@ namespace std } template - size_t remove_if(UnaryPredicate p) + size_type remove_if(UnaryPredicate p) { - SmartLock(this->lock); + sl_guard(this->lock); node *n = head; - size_t count = 0; + size_type count = 0; while (n != nullptr) { if (p(n->value)) @@ -253,7 +865,7 @@ namespace std if (n == tail) tail = n->prev; delete n; - --lSize; + lSize.fetch_sub(1); ++count; } n = n->next; @@ -266,7 +878,7 @@ namespace std if (empty()) return; - SmartLock(this->lock); + sl_guard(this->lock); node *p = head; while (p != nullptr) { @@ -280,12 +892,75 @@ namespace std tail = tmp; } + size_type unique() + { + sl_guard(this->lock); + node *p = head; + size_type count = 0; + while (p != nullptr) + { + node *n = p->next; + while (n != nullptr) + { + if (p->value == n->value) + { + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + if (n == head) + head = n->next; + if (n == tail) + tail = n->prev; + delete n; + lSize.fetch_sub(1); + ++count; + } + n = n->next; + } + p = p->next; + } + return count; + } + + template + size_type unique(BinaryPredicate p) + { + sl_guard(this->lock); + node *n = head; + size_type count = 0; + while (n != nullptr) + { + node *m = n->next; + while (m != nullptr) + { + if (p(n->value, m->value)) + { + if (m->prev) + m->prev->next = m->next; + if (m->next) + m->next->prev = m->prev; + if (m == head) + head = m->next; + if (m == tail) + tail = m->prev; + delete m; + lSize.fetch_sub(1); + ++count; + } + m = m->next; + } + n = n->next; + } + return count; + } + void sort() { if (empty()) return; - SmartLock(this->lock); + sl_guard(this->lock); bool swapped = true; while (swapped) { @@ -311,7 +986,7 @@ namespace std if (empty()) return; - SmartLock(this->lock); + sl_guard(this->lock); bool swapped = true; while (swapped) { @@ -331,127 +1006,23 @@ namespace std } } - /* Non-STL function */ - T &operator[](size_t Index) - { - SmartLock(this->lock); - node *p = head; - for (size_t i = 0; i < Index; ++i) - p = p->next; - return p->value; - } - - list &operator=(const list &other) - { - if (this == &other) - return *this; - - for (const T &value : other) - push_back(value); - - return *this; - } - - class iterator - { - private: - node *_node; - friend class list; - - public: - iterator(node *p = nullptr) : _node(p) {} - T &operator*() const { return _node->value; } - T *operator->() const { return &_node->value; } - - iterator &operator++() - { - _node = _node->next; - return *this; - } - - iterator &operator--() - { - _node = _node->prev; - return *this; - } - - iterator operator++(int) - { - iterator tmp = *this; - ++*this; - return tmp; - } - - iterator operator--(int) - { - iterator tmp = *this; - --*this; - return tmp; - } - - bool operator==(const iterator &rhs) const { return _node == rhs._node; } - bool operator!=(const iterator &rhs) const { return _node != rhs._node; } - }; - - iterator begin() { return iterator(head); } - iterator end() { return iterator(nullptr); } - const iterator begin() const { return iterator(head); } - const iterator end() const { return iterator(nullptr); } - - iterator insert(iterator pos, const T &value) - { - if (pos == end()) - { - push_back(value); - return iterator(tail); - } - else if (pos == begin()) - { - push_front(value); - return iterator(head); - } - else - { - SmartLock(this->lock); - node *p = pos.node; - node *nNode = new node(value, p->prev, p); - p->prev->next = nNode; - p->prev = nNode; - ++lSize; - return iterator(nNode); - } - } - - iterator erase(iterator pos) - { - if (pos == end()) - return end(); - else if (pos == begin()) - { - pop_front(); - return begin(); - } - else - { - SmartLock(this->lock); - node *p = pos._node; - if (p->prev) - p->prev->next = p->next; - - if (p->next) - p->next->prev = p->prev; - - if (head == p) - head = p->next; - - if (tail == p) - tail = p->prev; - - iterator ret(p->next); - delete p; - --lSize; - return ret; - } - } +#pragma endregion Operations }; + + template + bool operator==(const std::list &lhs, const std::list &rhs) + { + if (lhs.size() != rhs.size()) + return false; + auto it1 = lhs.begin(); + auto it2 = rhs.begin(); + while (it1 != lhs.end()) + { + if (*it1 != *it2) + return false; + ++it1; + ++it2; + } + return true; + } } diff --git a/include_std/locale b/include_std/locale new file mode 100644 index 0000000..d035583 --- /dev/null +++ b/include_std/locale @@ -0,0 +1,159 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include +#include + +namespace std +{ + class locale + { + public: +#pragma region Member Types + + class id + { + public: + id() = default; + id(const id &) = delete; + }; + + class facet + { + private: + std::size_t refs; + + public: + explicit facet(std::size_t refs = 0) + { + this->refs = refs; + } + + facet(const facet &) = delete; + + protected: + virtual ~facet() = default; + }; + + typedef int category; + +#pragma endregion Member Types + +#pragma region Member Objects + + static const category none = 0; + static const category collate = 1; + static const category ctype = 2; + static const category monetary = 4; + static const category numeric = 8; + static const category time = 16; + static const category messages = 32; + static const category all = collate | ctype | monetary | numeric | time | messages; + +#pragma endregion Member Objects + +#pragma region Member Functions + + locale() noexcept + { + assert(!"Function not implemented"); + } + + locale(const locale &other) noexcept + { + assert(!"Function not implemented"); + } + + explicit locale(const char *std_name) + { + assert(!"Function not implemented"); + } + + explicit locale(const std::string &std_name) + { + assert(!"Function not implemented"); + } + + locale(const locale &other, const char *std_name, category cats) + { + assert(!"Function not implemented"); + } + + locale(const locale &other, const std::string &std_name, category cats) + { + assert(!"Function not implemented"); + } + + template + locale(const locale &other, Facet *f) + { + assert(!"Function not implemented"); + } + + locale(const locale &other, const locale &one, category cats) + { + assert(!"Function not implemented"); + } + + ~locale() + { + assert(!"Function not implemented"); + } + + const locale &operator=(const locale &other) noexcept + { + assert(!"Function not implemented"); + } + + template + locale combine(const locale &other) const + { + assert(!"Function not implemented"); + } + + std::string name() const + { + assert(!"Function not implemented"); + } + + bool operator==(const locale &other) const + { + assert(!"Function not implemented"); + } + + template + bool operator()(const basic_string &s1, const basic_string &s2) const + { + assert(!"Function not implemented"); + } + + static locale global(const locale &loc) + { + assert(!"Function not implemented"); + } + + static const locale &classic() + { + assert(!"Function not implemented"); + } + +#pragma endregion Member Functions + }; +} diff --git a/include_std/memory b/include_std/memory index bbccee8..8fabeee 100644 --- a/include_std/memory +++ b/include_std/memory @@ -18,12 +18,136 @@ #pragma once #include +#include #include #include #include +#include + +#include namespace std { + namespace __memory__detail + { + template + constexpr bool is_unbounded_array_v = false; + template + constexpr bool is_unbounded_array_v = true; + + template + constexpr bool is_bounded_array_v = false; + template + constexpr bool is_bounded_array_v = true; + } + + template + constexpr T *construct_at(T *p, Args &&...args) + { + return ::new (static_cast(p)) T(std::forward(args)...); + } + + template + constexpr void destroy_at(T *p) + { + p->~T(); + } + + template + T *addressof(T &arg) + { + return reinterpret_cast(&const_cast(reinterpret_cast(arg))); + } + + template + const T *addressof(const T &&) = delete; + + template + NoThrowForwardIt uninitialized_copy_n(InputIt first, Size count, NoThrowForwardIt d_first) + { + using ValueType = typename std::iterator_traits::value_type; + NoThrowForwardIt current = d_first; + try + { + for (Size i = 0; i < count; ++i, (void)++current, ++first) + { + ::new (static_cast(std::addressof(*current))) ValueType(*first); + } + return current; + } + catch (...) + { + for (; d_first != current; ++d_first) + { + d_first->~ValueType(); + } + throw; + } + } + + template + NoThrowForwardIt uninitialized_copy_n(ExecutionPolicy &&policy, ForwardIt first, Size count, NoThrowForwardIt d_first) + { + return uninitialized_copy_n(first, count, d_first); + } + + template + ForwardIt uninitialized_fill_n(ForwardIt first, Size count, const T &value) + { + using V = typename std::iterator_traits::value_type; + ForwardIt current = first; + try + { + for (; count > 0; ++current, (void)--count) + ::new (static_cast(std::addressof(*current))) V(value); + return current; + } + catch (...) + { + for (; first != current; ++first) + first->~V(); + throw; + } + } + + template + ForwardIt uninitialized_fill_n(ExecutionPolicy &&policy, ForwardIt first, Size count, const T &value) + { + return uninitialized_fill_n(first, count, value); + } + + template + struct pointer_traits + { + using pointer = Ptr; + using element_type = typename Ptr::element_type; + using difference_type = typename Ptr::difference_type; + + template + using rebind = typename Ptr::template rebind; + + static pointer pointer_to(element_type &r) noexcept + { + return Ptr::pointer_to(r); + } + }; + + template + struct pointer_traits + { + using pointer = T *; + using element_type = T; + using difference_type = std::ptrdiff_t; + + template + using rebind = U *; + + static pointer pointer_to(element_type &r) noexcept + { + return std::addressof(r); + } + }; + template struct allocation_result { @@ -31,6 +155,73 @@ namespace std SizeType count; }; + template + struct allocator_traits + { + typedef Alloc allocator_type; + typedef typename Alloc::value_type value_type; + typedef typename Alloc::pointer pointer; + typedef typename Alloc::const_pointer const_pointer; + // typedef typename Alloc::void_pointer void_pointer; + // typedef typename Alloc::const_void_pointer const_void_pointer; + // typedef typename std::pointer_traits::rebind void_pointer; + // typedef typename std::pointer_traits::rebind const_void_pointer; + typedef typename Alloc::difference_type difference_type; + typedef typename Alloc::size_type size_type; + // typedef typename Alloc::propagate_on_container_copy_assignment propagate_on_container_copy_assignment; + typedef typename std::false_type propagate_on_container_copy_assignment; + typedef typename Alloc::propagate_on_container_move_assignment propagate_on_container_move_assignment; + typedef typename std::false_type propagate_on_container_swap; + typedef typename Alloc::is_always_equal is_always_equal; + + template + using rebind_alloc = typename Alloc::template rebind::other; + template + using rebind_traits = allocator_traits>; + + [[nodiscard]] static constexpr pointer allocate(Alloc &a, size_type n) + { + return a.allocate(n); + } + + // [[nodiscard]] static constexpr pointer allocate(Alloc &a, size_type n, const_void_pointer hint) + // { + // return a.allocate(n, hint); + // } + + [[nodiscard]] static constexpr std::allocation_result allocate_at_least(Alloc &a, size_type n) + { + return a.allocate_at_least(n); + } + + static constexpr void deallocate(Alloc &a, pointer p, size_type n) + { + a.deallocate(p, n); + } + + template + static constexpr void construct(Alloc &a, T *p, Args &&...args) + { + std::construct_at(p, std::forward(args)...); + } + + template + static constexpr void destroy(Alloc &a, T *p) + { + std::destroy_at(p); + } + + static constexpr size_type max_size(const Alloc &a) + { + return a.max_size(); + } + + static constexpr Alloc select_on_container_copy_construction(const Alloc &a) + { + return a; + } + }; + template struct allocator { @@ -64,9 +255,7 @@ namespace std std::allocation_result allocate_at_least(std::size_t n) { - if (n > max_size()) - return {nullptr, 0}; - return {allocate(n), n}; + return {static_cast(::operator new(n * sizeof(T))), n}; } void deallocate(T *p, std::size_t n) @@ -74,35 +263,344 @@ namespace std ::operator delete(p); } - size_type max_size() const - { - return std::numeric_limits::max() / sizeof(T); - } - - void construct(pointer p, const_reference val) - { - ::new ((void *)p) T(val); - } - - template - void construct(U *p, Args &&...args) - { - ::new ((void *)p) U(std::forward(args)...); - } - - void destroy(pointer p) { p->~T(); } - template - void destroy(U *p) { p->~U(); } pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } }; template - T *addressof(T &arg) + struct default_delete { - return reinterpret_cast(&const_cast(reinterpret_cast(arg))); + constexpr default_delete() noexcept = default; + + template + constexpr default_delete(const default_delete &d) noexcept {} + + constexpr void operator()(T *ptr) const { delete ptr; } + }; + + template + struct default_delete + { + constexpr default_delete() noexcept = default; + + template + constexpr default_delete(const default_delete &d) noexcept {} + + template + constexpr void operator()(U *ptr) const { delete[] ptr; } + }; + + template > + class unique_ptr + { + public: + using pointer = T *; // std::remove_reference::type::pointer; + using element_type = T; + using deleter_type = Deleter; + + private: + pointer _ptr; + + public: +#pragma region Member Functions + + constexpr unique_ptr() noexcept : _ptr(nullptr) {} + + constexpr unique_ptr(std::nullptr_t) noexcept : _ptr(nullptr) {} + + constexpr explicit unique_ptr(pointer p) noexcept : _ptr(p) {} + + // constexpr unique_ptr(pointer p, /* TODO */ d1) noexcept : _ptr(p) {} + + // constexpr unique_ptr(pointer p, /* TODO */ d2) noexcept : _ptr(p) {} + + constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {} + + template + constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {} + + unique_ptr(const unique_ptr &) = delete; + + ~unique_ptr() + { + if (_ptr == nullptr) + return; + Deleter d; + d(_ptr); + } + + constexpr unique_ptr &operator=(unique_ptr &&r) noexcept + { + reset(r.release()); + return *this; + } + + template + constexpr unique_ptr &operator=(unique_ptr &&r) noexcept + { + reset(r.release()); + return *this; + } + + constexpr unique_ptr &operator=(std::nullptr_t) noexcept + { + reset(); + return *this; + } + + unique_ptr &operator=(const unique_ptr &) = delete; + +#pragma endregion Member Functions + +#pragma region Modifiers + + constexpr pointer release() noexcept + { + pointer p = _ptr; + _ptr = nullptr; + return p; + } + + constexpr void reset(pointer ptr = pointer()) noexcept + { + Deleter d; + d(_ptr); + _ptr = ptr; + } + + void swap(unique_ptr &other) noexcept + { + pointer tmp = _ptr; + _ptr = other._ptr; + other._ptr = tmp; + } + +#pragma endregion Modifiers + +#pragma region Observers + + constexpr pointer get() const noexcept { return _ptr; } + constexpr Deleter &get_deleter() noexcept { return _ptr; } + constexpr const Deleter &get_deleter() const noexcept { return _ptr; } + constexpr explicit operator bool() const noexcept { return get() != nullptr; } + +#pragma endregion Observers + +#pragma region Element Access + + constexpr typename std::add_lvalue_reference::type operator*() const noexcept(noexcept(*std::declval())) { return *_ptr; } + constexpr pointer operator->() const noexcept { return _ptr; } + +#pragma endregion Element Access + }; + + template + class unique_ptr + { + public: + using pointer = T *; // std::remove_reference::type::pointer; + using element_type = T; + using deleter_type = Deleter; + + private: + pointer _ptr; + + public: +#pragma region Member Functions + + constexpr unique_ptr() noexcept : _ptr(nullptr) {} + + constexpr unique_ptr(std::nullptr_t) noexcept : _ptr(nullptr) {} + + template + constexpr explicit unique_ptr(U p) noexcept : _ptr(p) {} + + // template + // constexpr unique_ptr(U p, /* TODO */ d1) noexcept : _ptr(p) {} + + // template + // constexpr unique_ptr(U p, /* TODO */ d2) noexcept : _ptr(p) {} + + constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {} + + template + constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {} + + unique_ptr(const unique_ptr &) = delete; + + ~unique_ptr() + { + if (_ptr == nullptr) + return; + Deleter d; + d(_ptr); + } + + constexpr unique_ptr &operator=(unique_ptr &&r) noexcept + { + reset(r.release()); + return *this; + } + + template + constexpr unique_ptr &operator=(unique_ptr &&r) noexcept + { + reset(r.release()); + return *this; + } + + constexpr unique_ptr &operator=(std::nullptr_t) noexcept + { + reset(); + return *this; + } + + unique_ptr &operator=(const unique_ptr &) = delete; + +#pragma endregion Member Functions + +#pragma region Modifiers + + constexpr pointer release() noexcept + { + pointer p = _ptr; + _ptr = nullptr; + return p; + } + + template + constexpr void reset(U ptr) noexcept + { + Deleter d; + d(_ptr); + _ptr = ptr; + } + + constexpr void reset(std::nullptr_t = nullptr) noexcept + { + Deleter d; + d(_ptr); + _ptr = nullptr; + } + + void swap(unique_ptr &other) noexcept + { + pointer tmp = _ptr; + _ptr = other._ptr; + other._ptr = tmp; + } + +#pragma endregion Modifiers + +#pragma region Observers + + constexpr pointer get() const noexcept { return _ptr; } + constexpr Deleter &get_deleter() noexcept { return _ptr; } + constexpr const Deleter &get_deleter() const noexcept { return _ptr; } + constexpr explicit operator bool() const noexcept { return get() != nullptr; } + +#pragma endregion Observers + +#pragma region Element Access + + constexpr T &operator[](std::size_t i) const { return _ptr[i]; } + +#pragma endregion Element Access + }; + + template + std::enable_if_t::value, std::unique_ptr> + make_unique(Args &&...args) + { + return std::unique_ptr(new T(std::forward(args)...)); } template - const T *addressof(const T &&) = delete; + std::enable_if_t<__memory__detail::is_unbounded_array_v, std::unique_ptr> + make_unique(std::size_t n) + { + return std::unique_ptr(new std::remove_extent_t[n]()); + } + + template + std::enable_if_t<__memory__detail::is_bounded_array_v> make_unique(Args &&...) = delete; + + template + requires(!std::is_array_v) + std::unique_ptr make_unique_for_overwrite() + { + return std::unique_ptr(new T); + } + + template + requires std::is_unbounded_array_v + std::unique_ptr make_unique_for_overwrite(std::size_t n) + { + return std::unique_ptr(new std::remove_extent_t[n]); + } + + template + requires std::is_bounded_array_v + void make_unique_for_overwrite(Args &&...) = delete; + + template + constexpr bool operator==(const unique_ptr &x, const unique_ptr &y) { return x.get() == y.get(); } + + template + bool operator<(const unique_ptr &x, const unique_ptr &y) + { + return std::less::pointer, typename unique_ptr::pointer>::type>()(x.get(), y.get()); + } + + template + bool operator<=(const unique_ptr &x, const unique_ptr &y) { return !(y < x); } + + template + bool operator>(const unique_ptr &x, const unique_ptr &y) { return y < x; } + + template + bool operator>=(const unique_ptr &x, const unique_ptr &y) { return !(x < y); } + + // operator<=>(const unique_ptr &x, const unique_ptr &y); + + template + constexpr bool operator==(const unique_ptr &x, std::nullptr_t) noexcept { return !x; } + + template + constexpr bool operator<(const unique_ptr &x, std::nullptr_t) { return std::less::pointer>()(x.get(), nullptr); } + + template + constexpr bool operator<(std::nullptr_t, const unique_ptr &y) { return std::less::pointer>()(nullptr, y.get()); } + + template + constexpr bool operator<=(const unique_ptr &x, std::nullptr_t) { return !(nullptr < x); } + + template + constexpr bool operator<=(std::nullptr_t, const unique_ptr &y) { return !(y < nullptr); } + + template + constexpr bool operator>(const unique_ptr &x, std::nullptr_t) { return nullptr < x; } + + template + constexpr bool operator>(std::nullptr_t, const unique_ptr &y) { return y < nullptr; } + + template + constexpr bool operator>=(const unique_ptr &x, std::nullptr_t) { return !(x < nullptr); } + + template + constexpr bool operator>=(std::nullptr_t, const unique_ptr &y) { return !(nullptr < y); } + + // operator<=>(const unique_ptr &x, std::nullptr_t); + + // template + // std::basic_ostream &operator<<(std::basic_ostream &os, const std::unique_ptr &p) + // { + // return os << p.get(); + // } + + template + void swap(std::unique_ptr &lhs, std::unique_ptr &rhs) noexcept + { + lhs.swap(rhs); + } } diff --git a/include_std/memory.h b/include_std/memory.h new file mode 100644 index 0000000..f25f6ff --- /dev/null +++ b/include_std/memory.h @@ -0,0 +1,23 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_STD_MEMORY_H__ +#define __FENNIX_KERNEL_STD_MEMORY_H__ + +#include + +#endif // !__FENNIX_KERNEL_STD_MEMORY_H__ diff --git a/include_std/new b/include_std/new new file mode 100644 index 0000000..7d90a8c --- /dev/null +++ b/include_std/new @@ -0,0 +1,143 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include + +namespace std +{ + enum class align_val_t : std::size_t + { + }; + + struct nothrow_t + { + explicit nothrow_t() = default; + }; + + extern const std::nothrow_t nothrow; + + struct destroying_delete_t + { + explicit destroying_delete_t() = default; + }; + + inline constexpr destroying_delete_t destroying_delete{}; + + typedef void (*new_handler)(); + std::new_handler set_new_handler(std::new_handler new_p) noexcept; + std::new_handler get_new_handler() noexcept; + + class bad_alloc : public exception + { + public: + bad_alloc() noexcept = default; + bad_alloc(const bad_alloc &other) noexcept = default; + + bad_alloc &operator=(const bad_alloc &other) noexcept = default; + + virtual const char *what() const noexcept + { + return "bad_alloc"; + } + }; + + class bad_array_new_length : public bad_alloc + { + public: + bad_array_new_length() noexcept = default; + bad_array_new_length(const bad_array_new_length &other) noexcept = default; + virtual ~bad_array_new_length() = default; + + bad_array_new_length &operator=(const bad_array_new_length &other) noexcept + { + return *this; + } + + virtual const char *what() const noexcept + { + return "bad_array_new_length"; + } + }; +} + +[[nodiscard]] void *operator new(std::size_t count); +[[nodiscard]] void *operator new[](std::size_t count); +// [[nodiscard]] void *operator new(std::size_t count, std::align_val_t al); +// [[nodiscard]] void *operator new[](std::size_t count, std::align_val_t al); + +// [[nodiscard]] void *operator new(std::size_t count, const std::nothrow_t &tag) noexcept; +// [[nodiscard]] void *operator new[](std::size_t count, const std::nothrow_t &tag) noexcept; +// [[nodiscard]] void *operator new(std::size_t count, std::align_val_t al, const std::nothrow_t &) noexcept; +// [[nodiscard]] void *operator new[](std::size_t count, std::align_val_t al, const std::nothrow_t &) noexcept; + +[[nodiscard]] void *operator new(std::size_t count, void *ptr) noexcept; +[[nodiscard]] void *operator new[](std::size_t count, void *ptr) noexcept; + +// void *operator new(std::size_t count, ...); +// void *operator new[](std::size_t count, ...); +// void *operator new(std::size_t count, std::align_val_t al, ...); +// void *operator new[](std::size_t count, std::align_val_t al, ...); + +// void *T::operator new(std::size_t count); +// void *T::operator new[](std::size_t count); +// void *T::operator new(std::size_t count, std::align_val_t al); +// void *T::operator new[](std::size_t count, std::align_val_t al); + +// void *T::operator new(std::size_t count, ...); +// void *T::operator new[](std::size_t count, ...); +// void *T::operator new(std::size_t count, std::align_val_t al, ...); +// void *T::operator new[](std::size_t count, std::align_val_t al, ...); + +void operator delete(void *ptr) noexcept; +void operator delete[](void *ptr) noexcept; +// void operator delete(void *ptr, std::align_val_t al) noexcept; +// void operator delete[](void *ptr, std::align_val_t al) noexcept; +void operator delete(void *ptr, std::size_t sz) noexcept; +// void operator delete[](void *ptr, std::size_t sz) noexcept; +// void operator delete(void *ptr, std::size_t sz, std::align_val_t al) noexcept; +// void operator delete[](void *ptr, std::size_t sz, std::align_val_t al) noexcept; + +// void operator delete(void *ptr, const std::nothrow_t &tag) noexcept; +// void operator delete[](void *ptr, const std::nothrow_t &tag) noexcept; +// void operator delete(void *ptr, std::align_val_t al, const std::nothrow_t &tag) noexcept; +// void operator delete[](void *ptr, std::align_val_t al, const std::nothrow_t &tag) noexcept; + +// void operator delete(void *ptr, void *place) noexcept; +// void operator delete[](void *ptr, void *place) noexcept; + +// void operator delete(void *ptr, ...); +// void operator delete[](void *ptr, ...); + +// void T::operator delete(void *ptr); +// void T::operator delete[](void *ptr); +// void T::operator delete(void *ptr, std::align_val_t al); +// void T::operator delete[](void *ptr, std::align_val_t al); +// void T::operator delete(void *ptr, std::size_t sz); +// void T::operator delete[](void *ptr, std::size_t sz); +// void T::operator delete(void *ptr, std::size_t sz, std::align_val_t al); +// void T::operator delete[](void *ptr, std::size_t sz, std::align_val_t al); + +// void T::operator delete(void *ptr, args...); +// void T::operator delete[](void *ptr, args...); + +// void T::operator delete(T *ptr, std::destroying_delete_t); +// void T::operator delete(T *ptr, std::destroying_delete_t, std::align_val_t al); +// void T::operator delete(T *ptr, std::destroying_delete_t, std::size_t sz); +// void T::operator delete(T *ptr, std::destroying_delete_t, std::size_t sz, std::align_val_t al); diff --git a/storage/devices/zero.cpp b/include_std/ostream similarity index 60% rename from storage/devices/zero.cpp rename to include_std/ostream index c8168d0..4b0c8b2 100644 --- a/storage/devices/zero.cpp +++ b/include_std/ostream @@ -15,29 +15,26 @@ along with Fennix Kernel. If not, see . */ -#include -#include +#pragma once -#include "../../kernel.h" +#include +#include -using namespace vfs; - -namespace vfs +namespace std { - size_t ZeroDevice::read(uint8_t *Buffer, size_t Size, off_t Offset) + template > + class basic_ostream : virtual public std::basic_ios { - if (Size <= 0) - return 0; + }; - memset(Buffer, 0, Size); - return Size; + template + std::basic_ostream &endl(std::basic_ostream &os) + { + os.put(os.widen('\n')); + os.flush(); + return os; } - size_t ZeroDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) - { - return Size; - } - - ZeroDevice::ZeroDevice() : Node(DevFS, "zero", CHARDEVICE) {} - ZeroDevice::~ZeroDevice() {} + typedef basic_ostream ostream; + typedef basic_ostream wostream; } diff --git a/include_std/signal.h b/include_std/signal.h new file mode 100644 index 0000000..eb59e2f --- /dev/null +++ b/include_std/signal.h @@ -0,0 +1,23 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_STD_SIGNAL_H__ +#define __FENNIX_KERNEL_STD_SIGNAL_H__ + +#include + +#endif // !__FENNIX_KERNEL_STD_SIGNAL_H__ diff --git a/include_std/std.hpp b/include_std/std.hpp deleted file mode 100644 index 59f8f6c..0000000 --- a/include_std/std.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -/* This function includes all the standard headers and defines some useful macros. - * Note: This std implementation is not complete. - */ -#ifndef __FENNIX_KERNEL_STD_H__ -#define __FENNIX_KERNEL_STD_H__ - -#include - -/** - * @brief // stub namespace for std::align_val_t and new operator - * @note // Found on https://gcc.gnu.org/legacy-ml/gcc-patches/2016-09/msg00628.html for "_ZnwmSt11align_val_t" compiler error - */ -namespace std -{ - typedef __SIZE_TYPE__ size_t; - static const size_t npos = -1; - - enum class align_val_t : std::size_t - { - }; - - template - OutputIt transform(InputIt first, InputIt last, OutputIt result, UnaryOperation op) - { - while (first != last) - { - *result = op(*first); - ++first; - ++result; - } - return result; - }; - - inline __always_inline int tolower(int c) - { - if (c >= 'A' && c <= 'Z') - return c + ('a' - 'A'); - else - return c; - } - - inline __always_inline int toupper(int c) - { - if (c >= 'a' && c <= 'z') - return c - ('a' - 'A'); - else - return c; - } -} - -#endif // !__FENNIX_KERNEL_STD_H__ diff --git a/include_std/std/smart_ptr.hpp b/include_std/std/smart_ptr.hpp deleted file mode 100644 index 9f4a773..0000000 --- a/include_std/std/smart_ptr.hpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_STD_SMART_POINTER_H__ -#define __FENNIX_KERNEL_STD_SMART_POINTER_H__ - -#include - -#include -#include - -// show debug messages -// #define DEBUG_SMARTPOINTERS 1 - -#ifdef DEBUG_SMARTPOINTERS -#define spdbg(m, ...) debug(m, ##__VA_ARGS__) -#else -#define spdbg(m, ...) -#endif - -namespace std -{ - /** - * @brief A smart pointer class - * - * This class is a smart pointer class. It is used to manage the lifetime of - * objects. It is a reference counted pointer, so when the last reference to - * the object is removed, the object is deleted. - * - * Basic Usage: - * smart_ptr pointer(new char()); - * *pointer = 'a'; - * printf("%c", *pointer); // Prints "a" - */ - template - class smart_ptr - { - T *RealPointer; - - public: - explicit smart_ptr(T *Pointer = nullptr) - { - spdbg("Smart pointer created (%#lx)", this->RealPointer); - this->RealPointer = Pointer; - } - - ~smart_ptr() - { - spdbg("Smart pointer deleted (%#lx)", this->RealPointer); - delete this->RealPointer, this->RealPointer = nullptr; - } - - T &operator*() - { - spdbg("Smart pointer dereferenced (%#lx)", this->RealPointer); - return *this->RealPointer; - } - - T *operator->() - { - spdbg("Smart pointer dereferenced (%#lx)", this->RealPointer); - return this->RealPointer; - } - - T *get() - { - spdbg("Smart pointer returned (%#lx)", this->RealPointer); - return this->RealPointer; - } - }; - - template - class auto_ptr - { - }; - - template - class unique_ptr - { - }; - - template - class weak_ptr - { - }; - - template - class shared_ptr - { - private: - class counter - { - private: - unsigned int RefCount{}; - - public: - counter() : RefCount(0) { spdbg("Counter %#lx created", this); }; - counter(const counter &) = delete; - counter &operator=(const counter &) = delete; - ~counter() { spdbg("Counter %#lx deleted", this); } - void reset() - { - this->RefCount = 0; - spdbg("reset"); - } - - unsigned int get() - { - return this->RefCount; - spdbg("return"); - } - - void operator++() - { - this->RefCount++; - spdbg("increment"); - } - - void operator++(int) - { - this->RefCount++; - spdbg("increment"); - } - - void operator--() - { - this->RefCount--; - spdbg("decrement"); - } - - void operator--(int) - { - this->RefCount--; - spdbg("decrement"); - } - }; - - counter *ReferenceCounter; - T *RealPointer; - - public: - explicit shared_ptr(T *Pointer = nullptr) - { - this->RealPointer = Pointer; - this->ReferenceCounter = new counter(); - spdbg("[%#lx] Shared pointer created (ptr=%#lx, ref=%#lx)", this, Pointer, this->ReferenceCounter); - if (Pointer) - (*this->ReferenceCounter)++; - } - - shared_ptr(shared_ptr &SPtr) - { - spdbg("[%#lx] Shared pointer copied (ptr=%#lx, ref=%#lx)", this, SPtr.RealPointer, SPtr.ReferenceCounter); - this->RealPointer = SPtr.RealPointer; - this->ReferenceCounter = SPtr.ReferenceCounter; - (*this->ReferenceCounter)++; - } - - ~shared_ptr() - { - spdbg("[%#lx] Shared pointer destructor called", this); - (*this->ReferenceCounter)--; - if (this->ReferenceCounter->get() == 0) - { - spdbg("[%#lx] Shared pointer deleted (ptr=%#lx, ref=%#lx)", this, this->RealPointer, this->ReferenceCounter); - delete this->ReferenceCounter, this->ReferenceCounter = nullptr; - delete this->RealPointer, this->RealPointer = nullptr; - } - } - - unsigned int get_count() - { - spdbg("[%#lx] Shared pointer count (%d)", this, this->ReferenceCounter->get()); - return this->ReferenceCounter->get(); - } - - T *get() - { - spdbg("[%#lx] Shared pointer get (%#lx)", this, this->RealPointer); - return this->RealPointer; - } - - T &operator*() - { - spdbg("[%#lx] Shared pointer dereference (ptr*=%#lx)", this, *this->RealPointer); - return *this->RealPointer; - } - - T *operator->() - { - spdbg("[%#lx] Shared pointer dereference (ptr->%#lx)", this, this->RealPointer); - return this->RealPointer; - } - - void reset(T *Pointer = nullptr) - { - if (this->RealPointer == Pointer) - return; - spdbg("[%#lx] Shared pointer reset (ptr=%#lx, ref=%#lx)", this, Pointer, this->ReferenceCounter); - (*this->ReferenceCounter)--; - if (this->ReferenceCounter->get() == 0) - { - delete this->RealPointer; - delete this->ReferenceCounter; - } - this->RealPointer = Pointer; - this->ReferenceCounter = new counter(); - if (Pointer) - (*this->ReferenceCounter)++; - } - - void reset() - { - spdbg("[%#lx] Shared pointer reset (ptr=%#lx, ref=%#lx)", this, this->RealPointer, this->ReferenceCounter); - if (this->ReferenceCounter->get() == 1) - { - delete this->RealPointer, this->RealPointer = nullptr; - delete this->ReferenceCounter, this->ReferenceCounter = nullptr; - } - else - { - (*this->ReferenceCounter)--; - } - } - - void swap(shared_ptr &Other) - { - spdbg("[%#lx] Shared pointer swap (ptr=%#lx, ref=%#lx <=> ptr=%#lx, ref=%#lx)", - this, this->RealPointer, this->ReferenceCounter, Other.RealPointer, Other.ReferenceCounter); - T *tempRealPointer = this->RealPointer; - counter *tempReferenceCounter = this->ReferenceCounter; - this->RealPointer = Other.RealPointer; - this->ReferenceCounter = Other.ReferenceCounter; - Other.RealPointer = tempRealPointer; - Other.ReferenceCounter = tempReferenceCounter; - } - }; - - template - shared_ptr make_shared(Args &&...args) - { - return shared_ptr(new T(forward(args)...)); - }; - - template - smart_ptr make_smart(Args &&...args) - { - return smart_ptr(new T(forward(args)...)); - }; -} - -#endif // !__FENNIX_KERNEL_STD_SMART_POINTER_H__ diff --git a/include_std/stdbool.h b/include_std/stdbool.h new file mode 100644 index 0000000..f099e9a --- /dev/null +++ b/include_std/stdbool.h @@ -0,0 +1,35 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_header_H__ +#define __FENNIX_KERNEL_header_H__ + +#include + +#ifndef __cplusplus + +#define bool _Bool +#define true 1 +#define false 0 + +#else + +#define _Bool bool + +#endif // !__cplusplus + +#endif // !__FENNIX_KERNEL_header_H__ diff --git a/include_std/stdexcept b/include_std/stdexcept index f0af076..2c1806e 100644 --- a/include_std/stdexcept +++ b/include_std/stdexcept @@ -17,27 +17,103 @@ #pragma once -#include +#include +#include +#include namespace std { - class runtime_error + class __simple_string { private: - const char *m_what; + char *data; + size_t size; public: - runtime_error(const char *what_arg) : m_what(what_arg) {} - const char *what() const { return this->m_what; } - }; - - class out_of_range - { - public: - out_of_range(const char *what_arg) + __simple_string() + : data(nullptr), + size(0) { - /* FIXME: This is a temporary assert */ - assert(what_arg != nullptr); + } + + __simple_string(const char *str) + : data(nullptr), + size(0) + { + size = strlen(str); + data = new char[size + 1]; + assert(data != nullptr); + memcpy(data, str, size); + data[size] = '\0'; + } + + __simple_string(const __simple_string &other) + : data(nullptr), + size(0) + { + size = other.size; + data = new char[size + 1]; + assert(data != nullptr); + memcpy(data, other.data, size); + data[size] = '\0'; + } + + ~__simple_string() + { + if (data) + delete[] data; + } + + const char *c_str() const { return data; } + + __simple_string &operator=(const __simple_string &other) + { + if (data) + delete[] data; + + size = other.size; + data = new char[size + 1]; + assert(data != nullptr); + memcpy(data, other.data, size); + data[size] = '\0'; + + return *this; } }; + + class runtime_error : public exception + { + }; + + class logic_error : public exception + { + private: + __simple_string msg; + + public: + logic_error(const char *what_arg) : msg(what_arg) {} + logic_error(const logic_error &other) : msg(other.msg) {} + + logic_error &operator=(const logic_error &other) noexcept + { + msg = other.msg; + return *this; + } + + virtual const char *what() const noexcept + { + return msg.c_str(); + } + }; + + class out_of_range : public logic_error + { + public: + out_of_range(const char *what_arg) : logic_error(what_arg) {} + out_of_range(const out_of_range &other) = default; + out_of_range &operator=(const out_of_range &) = default; + out_of_range(out_of_range &&) = default; + out_of_range &operator=(out_of_range &&) = default; + virtual ~out_of_range() = default; + }; } diff --git a/include_std/stdio.h b/include_std/stdio.h index 7882986..79f4c6b 100644 --- a/include_std/stdio.h +++ b/include_std/stdio.h @@ -15,7 +15,42 @@ along with Fennix Kernel. If not, see . */ -#ifndef _STDIO_H -#define _STDIO_H +#ifndef __FENNIX_KERNEL_STDIO_H__ +#define __FENNIX_KERNEL_STDIO_H__ -#endif // !_STDIO_H +#include + +START_EXTERNC + +#define FILENAME_MAX 4096 + +typedef struct +{ + int st; +} FILE; + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +#define stdin stdin +#define stdout stdout +#define stderr stderr + +int printf(const char *format, ...) __attribute__((format(__printf__, (1), (2)))); +int vprintf(const char *format, va_list arg) __attribute__((format(__printf__, ((1)), (0)))); +int sprintf(char *s, const char *format, ...) __attribute__((format(__printf__, (2), (3)))); +int vsprintf(char *s, const char *format, va_list arg) __attribute__((format(__printf__, ((2)), (0)))); +int snprintf(char *s, size_t count, const char *format, ...) __attribute__((format(__printf__, (3), (4)))); +int vsnprintf(char *s, size_t count, const char *format, va_list arg) __attribute__((format(__printf__, ((3)), (0)))); + +int asprintf(char **strp, const char *fmt, ...) __attribute__((format(__printf__, (2), (3)))); +int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__((format(__printf__, ((2)), (0)))); + +int fprintf(FILE *stream, const char *format, ...) __attribute__((format(__printf__, (2), (3)))); + +int fputs(const char *s, FILE *stream); + +END_EXTERNC + +#endif // !__FENNIX_KERNEL_STDIO_H__ diff --git a/include_std/stdlib.h b/include_std/stdlib.h index 84cc7ad..6287b4a 100644 --- a/include_std/stdlib.h +++ b/include_std/stdlib.h @@ -15,7 +15,27 @@ along with Fennix Kernel. If not, see . */ -#ifndef _STDLIB_H -#define _STDLIB_H +#ifndef __FENNIX_KERNEL_STDLIB_H__ +#define __FENNIX_KERNEL_STDLIB_H__ -#endif // !_STDLIB_H +#include + +START_EXTERNC + +#ifndef __FENNIX_KERNEL_INTERNAL_MEMORY_H__ + +void *malloc(size_t Size); +void *calloc(size_t n, size_t Size); +void *realloc(void *Address, size_t Size); +void free(void *Address); + +#endif // !__FENNIX_KERNEL_INTERNAL_MEMORY_H__ + +void abort(); + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +END_EXTERNC + +#endif // !__FENNIX_KERNEL_STDLIB_H__ diff --git a/include_std/streambuf b/include_std/streambuf new file mode 100644 index 0000000..b3ae8d4 --- /dev/null +++ b/include_std/streambuf @@ -0,0 +1,312 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include +#include +#include + +namespace std +{ + template > + class basic_streambuf + { + public: + typedef CharT char_type; + typedef Traits::char_type traits_type; + typedef Traits::int_type int_type; + typedef Traits::pos_type pos_type; + typedef Traits::off_type off_type; + + private: + char_type *_eback; + char_type *_gptr; + char_type *_egptr; + char_type *_pbase; + char_type *_pptr; + char_type *_epptr; + + public: + virtual ~basic_streambuf(); + +#pragma region Locales + + std::locale pubimbue(const std::locale &loc) + { + return imbue(loc); + } + + std::locale getloc() const + { + return imbue(std::locale()); + } + +#pragma endregion Locales + +#pragma region Positioning + + basic_streambuf *pubsetbuf(char_type *s, std::streamsize n) + { + return setbuf(s, n); + } + + pos_type pubseekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = ios_base::in | ios_base::out) + { + return seekoff(off, dir, which); + } + + pos_type pubseekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) + { + return seekpos(pos, which); + } + + int pubsync() + { + return sync(); + } + +#pragma endregion Positioning + +#pragma region Get Area + + std::streamsize in_avail() + { + return egptr() - gptr(); + } + + int_type snextc() + { + return gptr() == egptr() ? Traits::eof() : Traits::to_int_type(*gptr()); + } + + int_type sgetc() + { + return gptr() == egptr() ? underflow() : Traits::to_int_type(*gptr()); + } + + std::streamsize sgetn(char_type *s, std::streamsize count) + { + std::streamsize copied = 0; + while (copied < count) + { + if (gptr() == egptr()) + { + if (underflow() == Traits::eof()) + { + break; + } + } + *s++ = *gptr(); + ++copied; + } + return copied; + } + +#pragma endregion Get Area + +#pragma region Put Area + + int_type sputc(char_type ch) + { + if (pptr() == epptr()) + { + if (overflow(Traits::to_int_type(ch)) == Traits::eof()) + { + return Traits::eof(); + } + } + else + { + *pptr() = ch; + pbump(1); + } + return Traits::to_int_type(ch); + } + + std::streamsize sputn(const char_type *s, std::streamsize count) + { + return xsputn(s, count); + } + +#pragma endregion Put Area + +#pragma region Putback + + int_type sputbackc(char_type c) + { + if (gptr() == eback() || !Traits::eq(c, gptr()[-1])) + { + return Traits::eof(); + } + gbump(-1); + return Traits::to_int_type(c); + } + + int_type sungetc() + { + if (gptr() == eback()) + { + return Traits::eof(); + } + gbump(-1); + return Traits::to_int_type(*gptr()); + } + +#pragma endregion Putback + + protected: + basic_streambuf() + : _eback(nullptr), + _gptr(nullptr), + _egptr(nullptr), + _pbase(nullptr), + _pptr(nullptr), + _epptr(nullptr) + { + } + + basic_streambuf(const basic_streambuf &rhs) + : _eback(rhs._eback), + _gptr(rhs._gptr), + _egptr(rhs._egptr), + _pbase(rhs._pbase), + _pptr(rhs._pptr), + _epptr(rhs._epptr) + { + } + + basic_streambuf &operator=(const basic_streambuf &other) + { + if (this == &other) + return *this; + + _eback = other._eback; + _gptr = other._gptr; + _egptr = other._egptr; + _pbase = other._pbase; + _pptr = other._pptr; + _epptr = other._epptr; + return *this; + } + + void swap(basic_streambuf &other) + { + std::swap(_eback, other._eback); + std::swap(_gptr, other._gptr); + std::swap(_egptr, other._egptr); + std::swap(_pbase, other._pbase); + std::swap(_pptr, other._pptr); + std::swap(_epptr, other._epptr); + } + +#pragma region Locales + + virtual void imbue(const std::locale &loc) = 0; + +#pragma endregion Locales + +#pragma region Positioning + + virtual basic_streambuf *setbuf(char_type *s, std::streamsize n) = 0; + virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = ios_base::in | ios_base::out) = 0; + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) = 0; + virtual int sync() = 0; + +#pragma endregion Positioning + +#pragma region Get Area + + virtual std::streamsize showmanyc() = 0; + virtual int_type underflow() = 0; + virtual int_type uflow() = 0; + virtual std::streamsize xsgetn(char_type *s, std::streamsize count) = 0; + + char_type *eback() const + { + return _eback; + } + + char_type *gptr() const + { + return _gptr; + } + + char_type *egptr() const + { + return _egptr; + } + + void gbump(int count) + { + _gptr += count; + } + + void setg(char_type *gbeg, char_type *gcurr, char_type *gend) + { + _eback = gbeg; + _gptr = gcurr; + _egptr = gend; + } + +#pragma endregion Get Area + +#pragma region Put Area + + virtual std::streamsize xsputn(const char_type *s, std::streamsize count) = 0; + virtual int_type overflow(int_type ch = Traits::eof()) = 0; + + char_type *pbase() const + { + return _pbase; + } + + char_type *pptr() const + { + return _pptr; + } + + char_type *epptr() const + { + return _epptr; + } + + void pbump(int count) + { + _pptr += count; + } + + void setp(char_type *pbeg, char_type *pend) + { + _pbase = pbeg; + _pptr = pbeg; + _epptr = pend; + } + +#pragma endregion Put Area + +#pragma region Putback + + virtual int_type pbackfail(int_type c = Traits::eof()) = 0; + +#pragma endregion Putback + }; + + typedef basic_streambuf streambuf; + typedef basic_streambuf wstreambuf; +} diff --git a/include_std/string b/include_std/string index a3bfefe..91585dd 100644 --- a/include_std/string +++ b/include_std/string @@ -16,702 +16,2391 @@ */ #pragma once -#include + +#include +#include +#include #include -#include - -// Show debug messages -// #define DEBUG_CPP_STRING 1 -// #define DEBUG_CPP_STRING_VERBOSE 1 - -#ifdef DEBUG_CPP_STRING -#define strdbg(m, ...) debug(m, ##__VA_ARGS__) -#else -#define strdbg(m, ...) -#endif - -#ifdef DEBUG_CPP_STRING_VERBOSE -#define v_strdbg(m, ...) debug(m, ##__VA_ARGS__) -#else -#define v_strdbg(m, ...) -#endif - -// TODO: Somewhere the delete is called twice, causing a double free error. +#include +#include +#include +#include namespace std { - template - char *to_string(T value) - { - static char buffer[1024]; - bool isNegative = false; - int index = 0; - - if (value < 0) - { - isNegative = true; - value = -value; - } - - if (value == 0) - buffer[index++] = '0'; - else - { - while (value > 0) - { - buffer[index++] = (char)(48 /*'0'*/ + (value % 10)); - value /= 10; - } - } - - if (isNegative) - buffer[index++] = '-'; - - int start = isNegative ? 1 : 0; - int end = index - 1; - while (start < end) - { - char temp = buffer[start]; - buffer[start] = buffer[end]; - buffer[end] = temp; - start++; - end--; - } - - buffer[index] = '\0'; - return buffer; - } - - /** - * @brief Basic string class - * String class that can be used to store strings. - */ - class basic_string - { - private: - char *Data{}; - size_t Length{}; - size_t Capacity{}; - - public: - static const size_t npos = -1; - - basic_string(const char *Str = "") - { - this->Length = strlen(Str); - this->Capacity = this->Length + 1; - this->Data = new char[this->Capacity]; - strcpy(this->Data, Str); - strdbg("%#lx: New basic_string created: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - ~basic_string() - { - strdbg("%#lx: String deleted: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - delete[] this->Data, this->Data = nullptr; - } - - size_t length() - { - v_strdbg("%#lx: String length: %d", - this, this->Length); - return this->Length; - } - - size_t capacity() - { - v_strdbg("%#lx: String capacity: %d", - this, this->Capacity); - return this->Capacity; - } - - const char *c_str() const - { - v_strdbg("%#lx: String data: \"%s\"", - this, this->Data); - return this->Data; - } - - void resize(size_t NewLength) - { - strdbg("%#lx: String resize: %d", - this, NewLength); - if (NewLength < this->Capacity) - { - this->Length = NewLength; - this->Data[this->Length] = '\0'; - - strdbg("%#lx: String resized: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return; - } - - size_t newCapacity = NewLength + 1; - char *newData = new char[newCapacity]; - strcpy(newData, this->Data); - - strdbg("%#lx: old: %#lx, new: %#lx", - this, this->Data, newData); - - delete[] this->Data; - this->Data = newData; - this->Length = NewLength; - this->Capacity = newCapacity; - - strdbg("%#lx: String resized: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - void concat(const basic_string &Other) - { - size_t NewLength = this->Length + Other.Length; - this->resize(NewLength); - - strcat(this->Data, Other.Data); - strdbg("%#lx: String concatenated: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - bool empty() - { - strdbg("%#lx: String empty: %d", - this, this->Length == 0); - return this->Length == 0; - } - - size_t size() - { - strdbg("%#lx: String size: %d", - this, this->Length); - return this->Length; - } - - void clear() - { - strdbg("%#lx: String clear", this); - this->resize(0); - } - - size_t find(const char *Str, size_t Pos = 0) const - { - strdbg("%#lx: String find: \"%s\", %d", - this, Str, Pos); - if (Pos >= this->Length) - return npos; - - for (size_t i = Pos; i < this->Length; i++) - { - bool found = true; - for (size_t j = 0; Str[j] != '\0'; j++) - { - if (this->Data[i + j] != Str[j]) - { - found = false; - break; - } - } - if (found) - return i; - } - return npos; - } - - size_t find(const basic_string &Str, size_t Pos = 0) const - { - strdbg("%#lx: String find: \"%s\", %d", - this, Str.c_str(), Pos); - return this->find(Str.c_str(), Pos); - } - - void erase(int Index, int Count = 1) - { - strdbg("%#lx: String erase: %d, %d", - this, Index, Count); - if (Index < 0 || (size_t)Index >= this->Length) - return; - - if (Count < 0) - return; - - if ((size_t)(Index + Count) > this->Length) - Count = (int)this->Length - Index; - - for (size_t i = Index; i < this->Length - Count; i++) - this->Data[i] = this->Data[i + Count]; - - this->Length -= Count; - this->Data[this->Length] = '\0'; - strdbg("%#lx: String erased: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - size_t find_last_not_of(const char *Str, size_t Pos = npos) const - { - strdbg("%#lx: String find_last_not_of: \"%s\", %d", - this, Str, Pos); - if (Pos == npos) - Pos = this->Length - 1; - - for (int i = (int)Pos; i >= 0; i--) - { - bool found = false; - for (size_t j = 0; Str[j] != '\0'; j++) - { - if (this->Data[i] == Str[j]) - { - found = true; - break; - } - } - if (!found) - return i; - } - return npos; - } - - size_t find_first_not_of(const char *Str, size_t Pos = 0) const - { - strdbg("%#lx: String find_first_not_of: \"%s\", %d", - this, Str, Pos); - if (Pos >= this->Length) - return npos; - - for (size_t i = Pos; i < this->Length; i++) - { - bool found = false; - for (size_t j = 0; Str[j] != '\0'; j++) - { - if (this->Data[i] == Str[j]) - { - found = true; - break; - } - } - if (!found) - return i; - } - return npos; - } - - size_t find_first_of(const char *Str, size_t Pos = 0) const - { - strdbg("%#lx: String find_first_of: \"%s\", %d", - this, Str, Pos); - if (Pos >= this->Length) - return npos; - - for (size_t i = Pos; i < this->Length; i++) - { - bool found = false; - for (size_t j = 0; Str[j] != '\0'; j++) - { - if (this->Data[i] == Str[j]) - { - found = true; - break; - } - } - if (found) - return i; - } - return npos; - } - - size_t find_last_of(const char *Str, size_t Pos = npos) const - { - strdbg("%#lx: String find_last_of: \"%s\", %d", - this, Str, Pos); - if (Pos == npos) - Pos = this->Length - 1; - - for (int i = (int)Pos; i >= 0; i--) - { - bool found = false; - for (int j = 0; Str[j] != '\0'; j++) - { - if (this->Data[i] == Str[j]) - { - found = true; - break; - } - } - if (found) - return i; - } - return npos; - } - - size_t find_first_of(char C, size_t Pos = 0) const - { - strdbg("%#lx: String find_first_of: '%c', %d", - this, C, Pos); - if (Pos >= this->Length) - return npos; - - for (size_t i = Pos; i < this->Length; i++) - { - if (this->Data[i] == C) - return i; - } - return npos; - } - - size_t find_last_of(char C, size_t Pos = npos) const - { - strdbg("%#lx: String find_last_of: '%c', %d", - this, C, Pos); - if (Pos == npos) - Pos = this->Length - 1; - - for (int i = (int)Pos; i >= 0; i--) - { - if (this->Data[i] == C) - return i; - } - return npos; - } - - size_t substr(const char *Str, size_t Pos = 0) const - { - strdbg("%#lx: String substr: \"%s\", %d", - this, Str, Pos); - if (Pos >= this->Length) - return npos; - - for (size_t i = Pos; i < this->Length; i++) - { - bool found = true; - for (size_t j = 0; Str[j] != '\0'; j++) - { - if (this->Data[i + j] != Str[j]) - { - found = false; - break; - } - } - if (found) - return i; - } - return npos; - } - - size_t substr(const basic_string &Str, size_t Pos = 0) const - { - strdbg("%#lx: String substr: \"%s\", %d", - this, Str.c_str(), Pos); - return this->substr(Str.c_str(), Pos); - } - - basic_string substr(size_t Pos = 0, size_t Count = npos) const - { - strdbg("%#lx: String substr: %d, %d", - this, Pos, Count); - if (Pos >= this->Length) - return basic_string(); - - if (Count == npos) - Count = this->Length - Pos; - - if (Pos + Count > this->Length) - Count = this->Length - Pos; - - basic_string ret; - ret.resize(Count); - for (size_t i = 0; i < Count; i++) - ret.Data[i] = this->Data[Pos + i]; - ret.Data[Count] = '\0'; - return ret; - } - - void replace(size_t Pos, size_t Count, const char *Str) - { - strdbg("%#lx: String replace: %d, %d, \"%s\"", - this, Pos, Count, Str); - if (Pos >= this->Length) - return; - - if ((int64_t)Count <= 0) - return; - - if (Pos + Count > this->Length) - Count = this->Length - Pos; - - size_t NewLength = this->Length - Count + strlen(Str); - this->resize(NewLength); - - for (size_t i = this->Length - 1; i >= Pos + strlen(Str); i--) - this->Data[i] = this->Data[i - strlen(Str) + Count]; - - for (unsigned long i = 0; i < strlen(Str); i++) - this->Data[Pos + i] = Str[i]; - - strdbg("%#lx: String replaced: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - void replace(size_t Pos, size_t Count, const basic_string &Str) - { - strdbg("%#lx: String replace: %d, %d, \"%s\"", - this, Pos, Count, Str.Data); - if (Pos >= this->Length) - return; - - if ((int64_t)Count <= 0) - return; - - if (Pos + Count > this->Length) - Count = this->Length - Pos; - - size_t NewLength = this->Length - Count + Str.Length; - this->resize(NewLength); - - for (size_t i = this->Length - 1; i >= Pos + Str.Length; i--) - this->Data[i] = this->Data[i - Str.Length + Count]; - - for (size_t i = 0; i < Str.Length; i++) - this->Data[Pos + i] = Str.Data[i]; - - strdbg("%#lx: String replaced: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - void pop_back() - { - strdbg("%#lx: String pop_back", this); - if (this->Length > 0) - { - this->Data[this->Length - 1] = '\0'; - this->Length--; - } - } - - void insert(size_t Index, size_t Count, char Ch) - { - strdbg("%#lx: String insert: %d, %d, '%c'", - this, Index, Count, Ch); - if (Index > this->Length) - return; - - size_t NewLength = this->Length + Count; - this->resize(NewLength); - - for (size_t i = this->Length - 1; i >= Index + Count; i--) - this->Data[i] = this->Data[i - Count]; - - for (size_t i = 0; i < Count; i++) - this->Data[Index + i] = Ch; - - strdbg("%#lx: String inserted: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - } - - basic_string operator+(const basic_string &Other) const - { - basic_string result = *this; - result.concat(Other); - strdbg("%#lx: String added: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, result.Data, result.Data, result.Length, result.Capacity); - return result; - } - - basic_string operator+(const char *Other) const - { - basic_string result = *this; - result.concat(Other); - strdbg("%#lx: String added: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, result.Data, result.Data, result.Length, result.Capacity); - return result; - } - - basic_string &operator+=(const basic_string &Other) - { - this->concat(Other); - strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return *this; - } - - basic_string &operator+=(const char *Other) - { - this->concat(Other); - strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return *this; - } - - basic_string &operator+=(char Other) - { - const char str[2] = {Other, '\0'}; - this->concat(str); - strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return *this; - } - - /* warning: implicitly-declared 'constexpr String::String(const String&)' is deprecated [-Wdeprecated-copy] */ - basic_string &operator=(const basic_string &Other) = default; - - // basic_string &operator=(const basic_string &Other) - // { - // if (this != &Other) - // { - // delete[] this->Data; - // this->Data = Other.Data; - // this->Length = Other.Length; - // this->Capacity = Other.Capacity; - // strdbg("%#lx: String assigned: \"%s\" (data: %#lx, length: %d, capacity: %d)", - // this, this->Data, this->Data, this->Length, this->Capacity); - // } - // return *this; - // } - - basic_string &operator=(const char *Other) - { - this->Length = strlen(Other); - this->Capacity = this->Length + 1; - delete[] this->Data; - this->Data = new char[this->Capacity]; - strcpy(this->Data, Other); - strdbg("%#lx: String assigned: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return *this; - } - - basic_string &operator<<(const basic_string &Other) - { - this->concat(Other); - strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return *this; - } - - basic_string &operator<<(const char *Other) - { - this->concat(Other); - strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", - this, this->Data, this->Data, this->Length, this->Capacity); - return *this; - } - - char &operator[](int Index) - { - strdbg("%#lx: String index: %d", this, Index); - return this->Data[Index]; - } - - const char &operator[](int Index) const - { - strdbg("%#lx: String index: %d", this, Index); - return this->Data[Index]; - } - - char &operator[](size_t Index) - { - strdbg("%#lx: String index: %d", this, Index); - return this->Data[Index]; - } - - const char &operator[](size_t Index) const - { - strdbg("%#lx: String index: %d", this, Index); - return this->Data[Index]; - } - - bool operator==(const basic_string &Other) const - { - strdbg("%#lx: String compared: \"%s\" == \"%s\"", - this, this->Data, Other.Data); - return strcmp(this->Data, Other.Data) == 0; - } - - bool operator!=(const char *Other) const - { - strdbg("%#lx: String compared: \"%s\" != \"%s\"", - this, this->Data, Other); - return strcmp(this->Data, Other) != 0; - } - - bool operator!=(const basic_string &Other) const - { - strdbg("%#lx: String compared: \"%s\" != \"%s\"", - this, this->Data, Other.Data); - return strcmp(this->Data, Other.Data) != 0; - } - - bool operator==(const char *Other) const - { - strdbg("%#lx: String compared: \"%s\" == \"%s\"", - this, this->Data, Other); - return strcmp(this->Data, Other) == 0; - } - - class iterator - { - private: - char *Pointer; - - public: - iterator(char *Pointer) : Pointer(Pointer) {} - - iterator &operator++() - { - ++this->Pointer; - strdbg("%#lx: String iterator incremented: %#lx", - this, this->Pointer); - return *this; - } - - char &operator*() - { - strdbg("%#lx: String iterator dereferenced: %#lx", - this, this->Pointer); - return *this->Pointer; - } - - bool operator!=(const iterator &Other) const - { - strdbg("%#lx: String iterator compared: %#lx != %#lx", - this, this->Pointer, Other.Pointer); - return this->Pointer != Other.Pointer; - } - - bool operator==(const iterator &Other) const - { - strdbg("%#lx: String iterator compared: %#lx == %#lx", - this, this->Pointer, Other.Pointer); - return this->Pointer == Other.Pointer; - } - }; - - iterator begin() - { - strdbg("%#lx: String iterator begin: %#lx", - this, this->Data); - return iterator(this->Data); - } - - iterator end() - { - strdbg("%#lx: String iterator end: %#lx", - this, this->Data + this->Length); - return iterator(this->Data + this->Length); - } - }; - - typedef basic_string string; - template class char_traits { public: - static size_t length(const CharT *s) + typedef CharT char_type; + typedef int int_type; + + static void assign(char_type &c1, const char_type &c2) + { + c1 = c2; + } + + static char_type *assign(char_type *ptr, std::size_t count, char_type c2) + { + for (size_t i = 0; i < count; i++) + ptr[i] = c2; + return ptr; + } + + static bool eq(char_type a, char_type b) + { + return a == b; + } + + static bool lt(char_type a, char_type b) + { + return a < b; + } + + static char_type *move(char_type *dest, const char_type *src, std::size_t count) + { + for (std::size_t i = 0; i < count; i++) + dest[i] = src[i]; + return dest; + } + + static char_type *copy(char_type *dest, const char_type *src, std::size_t count) + { + for (std::size_t i = 0; i < count; i++) + dest[i] = src[i]; + return dest; + } + + static int compare(const char_type *s1, const char_type *s2, std::size_t count) + { + for (std::size_t i = 0; i < count; i++) + { + if (s1[i] < s2[i]) + return -1; + if (s1[i] > s2[i]) + return 1; + } + return 0; + } + + static size_t length(const char_type *s) { size_t len = 0; while (s[len] != 0) len++; return len; } + + static const char_type *find(const char_type *ptr, std::size_t count, const char_type &ch) + { + for (std::size_t i = 0; i < count; i++) + { + if (ptr[i] == ch) + return ptr + i; + } + return nullptr; + } + + static char_type to_char_type(int_type c) + { + return static_cast(c); + } + + static int_type to_int_type(char_type c) + { + return static_cast(c); + } + + static bool eq_int_type(int_type c1, int_type c2) + { + return c1 == c2; + } + + static int_type eof() + { + return static_cast(-1); + } + + static int_type not_eof(int_type e) + { + return e == eof() ? 0 : e; + } }; + + template > + class basic_string_view + { + public: + typedef Traits traits_type; + typedef CharT value_type; + typedef const CharT *pointer; + typedef const CharT *const_pointer; + typedef const CharT &reference; + typedef const CharT &const_reference; + typedef const_pointer iterator; + typedef const_pointer const_iterator; + // typedef std::reverse_iterator reverse_iterator; + // typedef std::reverse_iterator const_reverse_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static const size_type npos = -1; + + private: + const_pointer _data; + size_type _size; + + public: + constexpr basic_string_view() + : _data(nullptr), + _size(0) + { + } + + constexpr basic_string_view(const basic_string_view &other) + : _data(other._data), + _size(other._size) + { + } + + constexpr basic_string_view(const CharT *s) + : _data(s), + _size(Traits::length(s)) + { + } + + constexpr basic_string_view(const CharT *s, size_type count) + : _data(s), + _size(count) + { + } + + constexpr basic_string_view &operator=(const basic_string_view &other) + { + _data = other._data; + _size = other._size; + return *this; + } + + constexpr const_pointer data() const + { + return _data; + } + + constexpr size_type size() const + { + return _size; + } + + constexpr size_type length() const + { + return size(); + } + + constexpr bool empty() const + { + return _size == 0; + } + + constexpr const_reference operator[](size_type pos) const + { + return _data[pos]; + } + + constexpr const_reference at(size_type pos) const + { + if (pos >= _size) + throw std::out_of_range("basic_string_view::at"); + return _data[pos]; + } + + constexpr const_reference front() const + { + return _data[0]; + } + + constexpr const_reference back() const + { + return _data[_size - 1]; + } + + constexpr const_pointer begin() const + { + return _data; + } + + constexpr const_pointer cbegin() const + { + return begin(); + } + + constexpr const_pointer end() const + { + return _data + _size; + } + + constexpr const_pointer cend() const + { + return end(); + } + + constexpr void remove_prefix(size_type n) + { + _data += n; + _size -= n; + } + + constexpr void remove_suffix(size_type n) + { + _size -= n; + } + + constexpr void swap(basic_string_view &other) + { + std::swap(_data, other._data); + std::swap(_size, other._size); + } + + constexpr size_type copy(CharT *dest, size_type count, size_type pos = 0) const + { + if (pos > _size) + throw std::out_of_range("basic_string_view::copy"); + + size_type rlen = std::min(count, _size - pos); + std::copy(_data + pos, _data + pos + rlen, dest); + return rlen; + } + + constexpr basic_string_view substr(size_type pos = 0, size_type count = npos) const + { + if (pos > _size) + throw std::out_of_range("basic_string_view::substr"); + + return basic_string_view(_data + pos, std::min(count, _size - pos)); + } + + constexpr int compare(basic_string_view other) const + { + size_type rlen = std::min(_size, other._size); + int res = Traits::compare(_data, other._data, rlen); + if (res == 0) + { + if (_size < other._size) + res = -1; + else if (_size > other._size) + res = 1; + } + return res; + } + + constexpr int compare(size_type pos1, size_type count1, basic_string_view other) const + { + return substr(pos1, count1).compare(other); + } + + constexpr int compare(size_type pos1, size_type count1, basic_string_view other, size_type pos2, size_type count2) const + { + return substr(pos1, count1).compare(other.substr(pos2, count2)); + } + + constexpr int compare(const CharT *s) const + { + return compare(basic_string_view(s)); + } + + constexpr int compare(size_type pos1, size_type count1, const CharT *s) const + { + return substr(pos1, count1).compare(basic_string_view(s)); + } + + constexpr int compare(size_type pos1, size_type count1, const CharT *s, size_type count2) const + { + return substr(pos1, count1).compare(basic_string_view(s, count2)); + } + + constexpr bool starts_with(basic_string_view x) const + { + return _size >= x._size && Traits::compare(_data, x._data, x._size) == 0; + } + + constexpr bool starts_with(CharT x) const + { + return !empty() && Traits::eq(_data[0], x); + } + + constexpr bool starts_with(const CharT *x) const + { + return starts_with(basic_string_view(x)); + } + + constexpr bool ends_with(basic_string_view x) const + { + return _size >= x._size && Traits::compare(_data + _size - x._size, x._data, x._size) == 0; + } + + constexpr bool ends_with(CharT x) const + { + return !empty() && Traits::eq(_data[_size - 1], x); + } + + constexpr bool ends_with(const CharT *x) const + { + return ends_with(basic_string_view(x)); + } + + constexpr size_type find(basic_string_view s, size_type pos = 0) const + { + if (pos > _size) + return npos; + + const_pointer r = Traits::find(_data + pos, _size - pos, s[0]); + if (r == nullptr) + return npos; + + size_type index = r - _data; + if (index + s.size() > _size) + return npos; + + if (Traits::compare(r, s.data(), s.size()) == 0) + return index; + return npos; + } + + constexpr size_type find(CharT c, size_type pos = 0) const + { + if (pos > _size) + return npos; + + const_pointer r = Traits::find(_data + pos, _size - pos, c); + if (r == nullptr) + return npos; + return r - _data; + } + + constexpr size_type find(const CharT *s, size_type pos, size_type count) const + { + return find(basic_string_view(s, count), pos); + } + + constexpr size_type find(const CharT *s, size_type pos = 0) const + { + return find(basic_string_view(s), pos); + } + + constexpr size_type rfind(basic_string_view s, size_type pos = npos) const + { + if (s.size() > _size) + return npos; + + if (pos == npos) + pos = _size; + else if (pos > _size) + pos = _size; + + for (ssize_t i = (ssize_t)pos - s.size(); i >= 0; i--) + { + if (Traits::compare(_data + i, s.data(), s.size()) == 0) + return i; + } + return npos; + } + + constexpr size_type rfind(CharT c, size_type pos = npos) const + { + if (pos == npos) + pos = _size; + else if (pos > _size) + pos = _size; + + for (ssize_t i = (ssize_t)pos - 1; i >= 0; i--) + { + if (Traits::eq(_data[i], c)) + return i; + } + return npos; + } + + constexpr size_type rfind(const CharT *s, size_type pos, size_type count) const + { + return rfind(basic_string_view(s, count), pos); + } + + constexpr size_type rfind(const CharT *s, size_type pos = npos) const + { + return rfind(basic_string_view(s), pos); + } + + constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const + { + if (pos >= _size) + return npos; + + for (size_type i = pos; i < _size; i++) + { + if (Traits::find(s.data(), s.size(), _data[i]) != nullptr) + return i; + } + return npos; + } + + constexpr size_type find_first_of(CharT c, size_type pos = 0) const + { + return find(c, pos); + } + + constexpr size_type find_first_of(const CharT *s, size_type pos, size_type count) const + { + return find_first_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_first_of(const CharT *s, size_type pos = 0) const + { + return find_first_of(basic_string_view(s), pos); + } + + constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const + { + if (pos == npos) + pos = _size; + else if (pos > _size) + pos = _size; + + for (ssize_t i = (ssize_t)pos - 1; i >= 0; i--) + { + if (Traits::find(s.data(), s.size(), _data[i]) != nullptr) + return i; + } + return npos; + } + + constexpr size_type find_last_of(CharT c, size_type pos = npos) const + { + return rfind(c, pos); + } + + constexpr size_type find_last_of(const CharT *s, size_type pos, size_type count) const + { + return find_last_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_last_of(const CharT *s, size_type pos = npos) const + { + return find_last_of(basic_string_view(s), pos); + } + + constexpr size_type find_first_not_of(basic_string_view s, size_type pos = 0) const + { + if (pos >= _size) + return npos; + + for (size_type i = pos; i < _size; i++) + { + if (Traits::find(s.data(), s.size(), _data[i]) == nullptr) + return i; + } + return npos; + } + + constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const + { + if (pos >= _size) + return npos; + + for (size_type i = pos; i < _size; i++) + { + if (!Traits::eq(_data[i], c)) + return i; + } + return npos; + } + + constexpr size_type find_first_not_of(const CharT *s, size_type pos, size_type count) const + { + return find_first_not_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_first_not_of(const CharT *s, size_type pos = 0) const + { + return find_first_not_of(basic_string_view(s), pos); + } + + constexpr size_type find_last_not_of(basic_string_view s, size_type pos = npos) const + { + if (pos == npos) + pos = _size; + else if (pos > _size) + pos = _size; + + for (ssize_t i = (ssize_t)pos - 1; i >= 0; i--) + { + if (Traits::find(s.data(), s.size(), _data[i]) == nullptr) + return i; + } + return npos; + } + + constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const + { + if (pos == npos) + pos = _size; + else if (pos > _size) + pos = _size; + + for (ssize_t i = (ssize_t)pos - 1; i >= 0; i--) + { + if (!Traits::eq(_data[i], c)) + return i; + } + return npos; + } + + constexpr size_type find_last_not_of(const CharT *s, size_type pos, size_type count) const + { + return find_last_not_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_last_not_of(const CharT *s, size_type pos = npos) const + { + return find_last_not_of(basic_string_view(s), pos); + } + }; + + template + constexpr bool operator==(std::basic_string_view lhs, std::type_identity_t> rhs) + { + return lhs.compare(rhs) == 0; + } + + template , class Allocator = std::allocator> + class basic_string + { + public: + typedef Traits traits_type; + typedef CharT value_type; + typedef Allocator allocator_type; + typedef Allocator::size_type size_type; + typedef Allocator::difference_type difference_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef Allocator::pointer pointer; + typedef Allocator::const_pointer const_pointer; + // typedef value_type iterator; /* FIXME: iterator */ + // typedef const value_type const_iterator; /* FIXME: iterator */ + // typedef std::reverse_iterator reverse_iterator; + // typedef std::reverse_iterator const_reverse_iterator; + + static const size_type npos = -1; + + class iterator + { + public: + using difference_type = typename basic_string::difference_type; + using value_type = typename basic_string::value_type; + using pointer = typename basic_string::pointer; + using reference = typename basic_string::reference; + using iterator_category = std::random_access_iterator_tag; + + iterator(CharT *ptr) + : _ptr(ptr) + { + } + + CharT &operator*() + { + return *_ptr; + } + + CharT *operator->() + { + return _ptr; + } + + iterator &operator++() + { + _ptr++; + return *this; + } + + iterator operator++(int) + { + iterator tmp = *this; + _ptr++; + return tmp; + } + + iterator &operator--() + { + _ptr--; + return *this; + } + + iterator operator--(int) + { + iterator tmp = *this; + _ptr--; + return tmp; + } + + iterator &operator+=(difference_type n) + { + _ptr += n; + return *this; + } + + iterator operator+(difference_type n) const + { + return iterator(_ptr + n); + } + + iterator &operator-=(difference_type n) + { + _ptr -= n; + return *this; + } + + iterator operator-(difference_type n) const + { + return iterator(_ptr - n); + } + + difference_type operator-(const iterator &other) const + { + return _ptr - other._ptr; + } + + CharT &operator[](difference_type n) const + { + return *(_ptr + n); + } + + bool operator==(const iterator &other) const + { + return _ptr == other._ptr; + } + + bool operator!=(const iterator &other) const + { + return _ptr != other._ptr; + } + + bool operator<(const iterator &other) const + { + return _ptr < other._ptr; + } + + bool operator>(const iterator &other) const + { + return _ptr > other._ptr; + } + + bool operator<=(const iterator &other) const + { + return _ptr <= other._ptr; + } + + bool operator>=(const iterator &other) const + { + return _ptr >= other._ptr; + } + + private: + CharT *_ptr; + }; + + class const_iterator + { + public: + using difference_type = typename basic_string::difference_type; + using value_type = typename basic_string::value_type; + using pointer = typename basic_string::const_pointer; + using reference = typename basic_string::const_reference; + using iterator_category = std::random_access_iterator_tag; + + const_iterator(const CharT *ptr) + : _ptr(ptr) + { + } + + const CharT &operator*() const + { + return *_ptr; + } + + const CharT *operator->() const + { + return _ptr; + } + + const_iterator &operator++() + { + _ptr++; + return *this; + } + + const_iterator operator++(int) + { + const_iterator tmp = *this; + _ptr++; + return tmp; + } + + const_iterator &operator--() + { + _ptr--; + return *this; + } + + const_iterator operator--(int) + { + const_iterator tmp = *this; + _ptr--; + return tmp; + } + + const_iterator &operator+=(difference_type n) + { + _ptr += n; + return *this; + } + + const_iterator operator+(difference_type n) const + { + return const_iterator(_ptr + n); + } + + const_iterator &operator-=(difference_type n) + { + _ptr -= n; + return *this; + } + + const_iterator operator-(difference_type n) const + { + return const_iterator(_ptr - n); + } + + difference_type operator-(const const_iterator &other) const + { + return _ptr - other._ptr; + } + + const CharT &operator[](difference_type n) const + { + return *(_ptr + n); + } + + bool operator==(const const_iterator &other) const + { + return _ptr == other._ptr; + } + + bool operator!=(const const_iterator &other) const + { + return _ptr != other._ptr; + } + + bool operator<(const const_iterator &other) const + { + return _ptr < other._ptr; + } + + bool operator>(const const_iterator &other) const + { + return _ptr > other._ptr; + } + + bool operator<=(const const_iterator &other) const + { + return _ptr <= other._ptr; + } + + bool operator>=(const const_iterator &other) const + { + return _ptr >= other._ptr; + } + + private: + const CharT *_ptr; + }; + + private: + allocator_type _alloc; + CharT *_data; + size_t _size; + size_t _capacity; + + public: +#pragma region Member Functions + + basic_string() + : _alloc(Allocator()), + _data(nullptr), + _size(0), + _capacity(0) + { + } + + basic_string(size_type count, CharT ch, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(count), + _capacity(count + 1) + { + _data = _alloc.allocate(_capacity); + if (count > 0) + memset(_data, ch, count); + _data[count] = '\0'; + } + + basic_string(const basic_string &other, size_type pos, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(other._size - pos), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + if (_size > 0) + memcpy(_data, other._data + pos, _size); + _data[_size] = '\0'; + } + + basic_string(const basic_string &other, size_type pos, size_type count, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(count), + _capacity(count + 1) + { + if (count == npos) + { + _size = other._size - pos; + _capacity = _size + 1; + } + + _data = _alloc.allocate(_capacity); + if (_size > 0) + memcpy(_data, other._data + pos, _size); + _data[_size] = '\0'; + } + + basic_string(const CharT *s, size_type count, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(count), + _capacity(count + 1) + { + if (count == npos) + { + _size = Traits::length(s); + _capacity = _size + 1; + } + + _data = _alloc.allocate(_capacity); + if (_size > 0) + memcpy(_data, s, _size); + _data[_size] = '\0'; + } + + basic_string(const CharT *s, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(Traits::length(s)), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + if (_size > 0) + memcpy(_data, s, _size); + _data[_size] = '\0'; + } + + template + basic_string(InputIt first, InputIt last, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(std::distance(first, last)), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + std::copy(first, last, _data); + _data[_size] = '\0'; + } + + basic_string(const basic_string &other) + : _alloc(other._alloc), + _size(other._size), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + if (_size > 0) + memcpy(_data, other._data, _size); + _data[_size] = '\0'; + } + + basic_string(const basic_string &other, const Allocator &alloc) + : _alloc(alloc), + _size(other._size), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + if (_size > 0) + memcpy(_data, other._data, _size); + _data[_size] = '\0'; + } + + basic_string(std::initializer_list ilist, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(ilist._size), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + std::copy(ilist.begin(), ilist.end(), _data); + _data[_size] = '\0'; + } + + template + basic_string(const StringViewLike &t, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(strlen(t)), + _capacity(_size + 1) + { + _data = _alloc.allocate(_capacity); + // std::copy(t.begin(), t.end(), _data); + strncpy(_data, t, _size); + _data[_size] = '\0'; + } + + template + basic_string(const StringViewLike &t, size_type pos, size_type n, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(n), + _capacity(n + 1) + { + _data = _alloc.allocate(_capacity); + std::copy(t.begin() + pos, t.begin() + pos + n, _data); + _data[_size] = '\0'; + } + + basic_string(std::nullptr_t) = delete; + + ~basic_string() + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + } + + basic_string &operator=(const basic_string &str) + { + if (this != &str) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = str._size; + _capacity = str._capacity; + _data = _alloc.allocate(_capacity); + memcpy(_data, str._data, _capacity); + } + return *this; + } + + basic_string &operator=(const CharT *s) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = Traits::length(s); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + memcpy(_data, s, _size); + _data[_size] = '\0'; + return *this; + } + + basic_string &operator=(CharT ch) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = 1; + _capacity = 2; + _data = _alloc.allocate(_capacity); + _data[0] = ch; + _data[1] = '\0'; + return *this; + } + + basic_string &operator=(std::initializer_list ilist) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = ilist._size(); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + std::copy(ilist.begin(), ilist.end(), _data); + _data[_size] = '\0'; + return *this; + } + + template + basic_string &operator=(const StringViewLike &t) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = t._size(); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + std::copy(t.begin(), t.end(), _data); + _data[_size] = '\0'; + return *this; + } + + basic_string &operator=(std::nullptr_t) = delete; + + constexpr basic_string &assign(size_type count, CharT ch) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = count; + _capacity = count + 1; + _data = _alloc.allocate(_capacity); + memset(_data, ch, count); + _data[count] = '\0'; + return *this; + } + + constexpr basic_string &assign(const basic_string &str) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = str._size; + _capacity = str._capacity; + _data = _alloc.allocate(_capacity); + memcpy(_data, str._data, _size); + _data[_size] = '\0'; + return *this; + } + + constexpr basic_string &assign(const basic_string &str, size_type pos, size_type count = npos) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = count; + _capacity = count + 1; + _data = _alloc.allocate(_capacity); + memcpy(_data, str._data + pos, _size); + _data[_size] = '\0'; + return *this; + } + + constexpr basic_string &assign(const CharT *s, size_type count) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = count; + _capacity = count + 1; + _data = _alloc.allocate(_capacity); + memcpy(_data, s, _size); + _data[_size] = '\0'; + return *this; + } + + constexpr basic_string &assign(const CharT *s) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = Traits::length(s); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + memcpy(_data, s, _size); + _data[_size] = '\0'; + return *this; + } + + template + constexpr basic_string &assign(InputIt first, InputIt last) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = std::distance(first, last); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + std::copy(first, last, _data); + _data[_size] = '\0'; + return *this; + } + + constexpr basic_string &assign(std::initializer_list ilist) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = ilist._size(); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + std::copy(ilist.begin(), ilist.end(), _data); + _data[_size] = '\0'; + return *this; + } + + template + constexpr basic_string &assign(const StringViewLike &t) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = t._size(); + _capacity = _size + 1; + _data = _alloc.allocate(_capacity); + std::copy(t.begin(), t.end(), _data); + _data[_size] = '\0'; + return *this; + } + + template + constexpr basic_string &assign(const StringViewLike &t, size_type pos, size_type count = npos) + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = count; + _capacity = count + 1; + _data = _alloc.allocate(_capacity); + std::copy(t.begin() + pos, t.begin() + pos + count, _data); + _data[_size] = '\0'; + return *this; + } + + constexpr allocator_type get_allocator() const + { + return _alloc; + } + +#pragma endregion Member Functions + +#pragma region Element Access + + constexpr CharT &at(size_type pos) + { + if (pos >= _size) + throw std::out_of_range("basic_string::at"); + return _data[pos]; + } + + constexpr const CharT &at(size_type pos) const + { + if (pos >= _size) + throw std::out_of_range("basic_string::at"); + return _data[pos]; + } + + constexpr CharT &operator[](size_type pos) + { + return _data[pos]; + } + + constexpr const CharT &operator[](size_type pos) const + { + return _data[pos]; + } + + constexpr CharT &front() + { + return _data[0]; + } + + constexpr const CharT &front() const + { + return _data[0]; + } + + constexpr CharT &back() + { + return _data[_size - 1]; + } + + constexpr const CharT &back() const + { + return _data[_size - 1]; + } + + constexpr const CharT *data() const + { + return _data; + } + + constexpr CharT *data() + { + return _data; + } + + constexpr const CharT *c_str() const + { + return _data; + } + + constexpr operator std::basic_string_view() const + { + return std::basic_string_view(_data, _size); + } + +#pragma endregion Element Access + +#pragma region Iterators + + constexpr iterator begin() + { + return _data; + } + + constexpr const_iterator begin() const + { + return _data; + } + + constexpr const_iterator cbegin() const + { + return const_cast(*this).begin(); + } + + constexpr iterator end() + { + return _data + _size; + } + + constexpr const_iterator end() const + { + return _data + _size; + } + + constexpr const_iterator cend() const + { + return const_cast(*this).end(); + } + + // constexpr reverse_iterator rbegin() + // { + // return reverse_iterator(end()); + // } + + // constexpr const_reverse_iterator rbegin() const + // { + // return const_reverse_iterator(end()); + // } + + // constexpr const_reverse_iterator crbegin() const + // { + // return const_reverse_iterator(end()); + // } + + // constexpr reverse_iterator rend() + // { + // return reverse_iterator(begin()); + // } + + // constexpr const_reverse_iterator rend() const + // { + // return const_reverse_iterator(begin()); + // } + + // constexpr const_reverse_iterator crend() const + // { + // return const_reverse_iterator(begin()); + // } + +#pragma endregion Iterators + +#pragma region Capacity + + [[nodiscard]] constexpr bool empty() const + { + if (begin() == end()) + return true; + return false; + } + + constexpr size_type size() const + { + return _size; + } + + constexpr size_type length() const + { + return size(); + } + + constexpr size_type max_size() const + { + return numeric_limits::max(); + } + + constexpr void reserve(size_type new_cap) + { + if (new_cap > _capacity) + { + if (_data == nullptr) + { + _data = _alloc.allocate(new_cap); + _capacity = new_cap; + return; + } + + CharT *new_data = _alloc.allocate(new_cap); + + if (_size > 0) + memcpy(new_data, _data, _size); + + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _data = new_data; + _capacity = new_cap; + } + } + + constexpr size_type capacity() const + { + return _capacity; + } + + constexpr void shrink_to_fit() + { + if (_size < _capacity) + { + CharT *new_data = _alloc.allocate(_size); + memcpy(new_data, _data, _size); + + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _data = new_data; + _capacity = _size; + } + } + +#pragma endregion Capacity + +#pragma region Modifiers + + constexpr void clear() + { + if (_data != nullptr) + _alloc.deallocate(_data, _capacity); + _size = 0; + _capacity = 0; + } + + constexpr basic_string &insert(size_type index, size_type count, CharT ch) + { + if (index > size()) + throw std::out_of_range("basic_string::insert"); + + size_type new_size = _size + count; + if (new_size > _capacity) + { + reserve(new_size); + } + + std::copy_backward(begin() + index, end(), end() + count); + std::fill_n(begin() + index, count, ch); + _size = new_size; + + return *this; + } + + constexpr basic_string &insert(size_type index, const CharT *s) + { + return insert(index, s, Traits::length(s)); + } + + constexpr basic_string &insert(size_type index, const CharT *s, size_type count) + { + if (index > size()) + throw std::out_of_range("basic_string::insert"); + + size_type new_size = _size + count; + if (new_size > _capacity) + reserve(new_size); + + std::copy_backward(begin() + index, end(), end() + count); + std::copy(s, s + count, begin() + index); + _size = new_size; + + return *this; + } + + constexpr basic_string &insert(size_type index, const basic_string &str) + { + return insert(index, str, 0, str.size()); + } + + constexpr basic_string &insert(size_type index, const basic_string &str, size_type s_index, size_type count = npos) + { + if (s_index > str.size()) + throw std::out_of_range("basic_string::insert"); + + if (count == npos || s_index + count > str.size()) + count = str.size() - s_index; + + size_type new_size = _size + count; + if (new_size > _capacity) + { + reserve(new_size); + } + + std::copy_backward(begin() + index, end(), end() + count); + std::copy(str.begin() + s_index, str.begin() + s_index + count, begin() + index); + _size = new_size; + + return *this; + } + + constexpr iterator insert(const_iterator pos, CharT ch) + { + size_type index = pos - begin(); + insert(index, 1, ch); + return begin() + index; + } + + constexpr iterator insert(const_iterator pos, size_type count, CharT ch) + { + size_type index = pos - begin(); + insert(index, count, ch); + return begin() + index; + } + + template + constexpr iterator insert(const_iterator pos, InputIt first, InputIt last) + { + size_type index = pos - begin(); + insert(index, first, last); + return begin() + index; + } + + constexpr iterator insert(const_iterator pos, std::initializer_list ilist) + { + size_type index = pos - begin(); + insert(index, ilist); + return begin() + index; + } + + template + constexpr basic_string &insert(size_type index, const StringViewLike &t) + { + return insert(index, t, 0, t.size()); + } + + template + constexpr basic_string &insert(size_type index, const StringViewLike &t, size_type t_index, size_type count = npos) + { + if (t_index > t.size()) + throw std::out_of_range("basic_string::insert"); + + if (count == npos || t_index + count > t.size()) + count = t.size() - t_index; + + size_type new_size = _size + count; + if (new_size > _capacity) + { + reserve(new_size); + } + + std::copy_backward(begin() + index, end(), end() + count); + std::copy(t.begin() + t_index, t.begin() + t_index + count, begin() + index); + _size = new_size; + + return *this; + } + + constexpr basic_string &erase(size_type index = 0, size_type count = npos) + { + if (index > size()) + throw std::out_of_range("basic_string::erase"); + + if (count == npos || index + count > size()) + count = size() - index; + + if (count > 0) + { + std::copy(begin() + index + count, end(), begin() + index); + _size -= count; + } + + return *this; + } + + constexpr iterator erase(const_iterator position) + { + size_type index = position - begin(); + erase(index, 1); + return begin() + index; + } + + constexpr iterator erase(const_iterator first, const_iterator last) + { + size_type index = first - begin(); + erase(index, last - first); + return begin() + index; + } + + constexpr void push_back(CharT ch) + { + if (_size == _capacity) + reserve(_capacity == 0 ? 1 : _capacity * 2); + + _data[_size++] = ch; + _data[_size] = 0; + } + + constexpr void pop_back() + { + if (_size > 0) + { + _data[--_size] = 0; + } + } + + constexpr basic_string &append(size_type count, CharT ch) + { + if (count > 0) + { + size_type new_size = _size + count; + if (new_size > _capacity) + { + reserve(new_size); + } + std::fill_n(_data + _size, count, ch); + _size = new_size; + } + return *this; + } + + constexpr basic_string &append(const basic_string &str) + { + return append(str.begin(), str.end()); + } + + constexpr basic_string &append(const basic_string &str, size_type pos, size_type count = npos) + { + return append(str.begin() + pos, str.begin() + pos + count); + } + + constexpr basic_string &append(const CharT *s, size_type count) + { + return append(s, s + count); + } + + constexpr basic_string &append(const CharT *s) + { + return append(s, s + Traits::length(s)); + } + + template + constexpr basic_string &append(InputIt first, InputIt last) + { + // size_type count = distance(first, last); + size_type count = last - first; + if (count > 0) + { + size_type new_size = _size + count; + if (new_size > _capacity) + reserve(new_size); + std::copy(first, last, _data + _size); + _data[new_size] = '\0'; + _size = new_size; + } + return *this; + } + + constexpr basic_string &append(std::initializer_list ilist) + { + return append(ilist.begin(), ilist.end()); + } + + template + constexpr basic_string &append(const StringViewLike &t) + { + return append(t.begin(), t.end()); + } + + template + constexpr basic_string &append(const StringViewLike &t, size_type pos, size_type count = npos) + { + return append(t.begin() + pos, t.begin() + pos + count); + } + + constexpr basic_string &operator+=(const basic_string &str) + { + return append(str); + } + + constexpr basic_string &operator+=(CharT ch) + { + push_back(ch); + return *this; + } + + constexpr basic_string &operator+=(const CharT *s) + { + return append(s); + } + + constexpr basic_string &operator+=(std::initializer_list ilist) + { + return append(ilist); + } + + template + constexpr basic_string &operator+=(const StringViewLike &t) + { + return append(t); + } + + constexpr basic_string &replace(size_type pos, size_type count, const basic_string &str) + { + return replace(begin() + pos, begin() + pos + count, str.begin(), str.end()); + } + + constexpr basic_string &replace(const_iterator first, const_iterator last, const basic_string &str) + { + return replace(first, last, str.begin(), str.end()); + } + + constexpr basic_string &replace(size_type pos, size_type count, const basic_string &str, size_type pos2, size_type count2 = npos) + { + return replace(begin() + pos, begin() + pos + count, str.begin() + pos2, str.begin() + pos2 + count2); + } + + constexpr basic_string &replace(size_type pos, size_type count, const CharT *cstr, size_type count2) + { + return replace(begin() + pos, begin() + pos + count, cstr, cstr + count2); + } + + constexpr basic_string &replace(const_iterator first, const_iterator last, const CharT *cstr, size_type count2) + { + return replace(first, last, cstr, cstr + count2); + } + + constexpr basic_string &replace(size_type pos, size_type count, const CharT *cstr) + { + if (pos > size()) + throw std::out_of_range("basic_string::replace"); + + size_type new_cap = (_size - pos) + count; + + if (new_cap > _capacity) + reserve(new_cap); + + std::copy(cstr, cstr + count, begin() + pos); + return *this; + } + + constexpr basic_string &replace(const_iterator first, const_iterator last, const CharT *cstr) + { + return replace(first, last, cstr, cstr + Traits::length(cstr)); + } + + constexpr basic_string &replace(size_type pos, size_type count, size_type count2, CharT ch) + { + return replace(begin() + pos, begin() + pos + count, count2, ch); + } + + constexpr basic_string &replace(const_iterator first, const_iterator last, size_type count2, CharT ch) + { + return replace(first, last, count2, ch); + } + + template + constexpr basic_string &replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2) + { + size_type count = std::distance(first, last); + size_type count2 = std::distance(first2, last2); + if (count2 > count) + { + size_type new_size = _size + count2 - count; + if (new_size > _capacity) + reserve(new_size); + + std::copy_backward(last, end(), end() + count2 - count); + std::copy(first2, last2, first); + _size = new_size; + } + else + { + std::copy(first2, last2, first); + std::copy(last, end(), first + count2); + _size -= count - count2; + } + return *this; + } + + constexpr basic_string &replace(const_iterator first, const_iterator last, std::initializer_list ilist) + { + return replace(first, last, ilist.begin(), ilist.end()); + } + + template + constexpr basic_string &replace(size_type pos, size_type count, const StringViewLike &t) + { + return replace(begin() + pos, begin() + pos + count, t.begin(), t.end()); + } + + template + constexpr basic_string &replace(const_iterator first, const_iterator last, const StringViewLike &t) + { + return replace(first, last, t.begin(), t.end()); + } + + template + constexpr basic_string &replace(size_type pos, size_type count, const StringViewLike &t, size_type pos2, size_type count2 = npos) + { + return replace(begin() + pos, begin() + pos + count, t.begin() + pos2, t.begin() + pos2 + count2); + } + + constexpr size_type copy(CharT *dest, size_type count, size_type pos = 0) const + { + if (pos > size()) + throw std::out_of_range("basic_string::copy"); + + size_type len = std::min(count, size() - pos); + std::copy(begin() + pos, begin() + pos + len, dest); + return len; + } + + constexpr void resize(size_type count) + { + if (count < _size) + erase(count); + else if (count > _size) + append(count - _size, CharT()); + } + + constexpr void resize(size_type count, CharT ch) + { + if (count < _size) + erase(count); + else if (count > _size) + append(count - _size, ch); + } + + constexpr void swap(basic_string &other) + { + fixme("The allocator won't be swapped"); + // std::swap(_alloc, other._alloc); + std::swap(_data, other._data); + std::swap(_size, other._size); + std::swap(_capacity, other._capacity); + } + +#pragma endregion Modifiers + +#pragma region Search + + constexpr size_type find(const basic_string &str, size_type pos = 0) const + { + return find(str.data(), pos, str.size()); + } + + constexpr size_type find(const CharT *s, size_type pos, size_type count) const + { + if (count == 0) + return pos; + if (pos >= _size) + return npos; + const_iterator it = std::search(begin() + pos, end(), s, s + count); + return it == end() ? npos : std::distance(begin(), it); + } + + constexpr size_type find(const CharT *s, size_type pos = 0) const + { + return find(s, pos, Traits::length(s)); + } + + constexpr size_type find(CharT ch, size_type pos = 0) const + { + const_iterator it = std::find(begin() + pos, end(), ch); + return it == end() ? npos : std::distance(begin(), it); + } + + template + constexpr size_type find(const StringViewLike &t, size_type pos = 0) const + { + return find(t.data(), pos, t.size()); + } + + constexpr size_type rfind(const basic_string &str, size_type pos = npos) const + { + return rfind(str.data(), pos, str.size()); + } + + constexpr size_type rfind(const CharT *s, size_type pos, size_type count) const + { + if (count == 0) + return pos; + if (pos >= _size) + pos = _size; + else + pos = _size - pos; + const_iterator it = std::find_end(begin(), begin() + pos, s, s + count); + return it == begin() + pos ? npos : std::distance(begin(), it); + } + + constexpr size_type rfind(const CharT *s, size_type pos = npos) const + { + return rfind(s, pos, Traits::length(s)); + } + + constexpr size_type rfind(CharT ch, size_type pos = npos) const + { + if (pos >= _size) + pos = _size; + else + pos = _size - pos; + const_iterator it = std::find(begin(), begin() + pos, ch); + return it == begin() + pos ? npos : std::distance(begin(), it); + } + + template + constexpr size_type rfind(const StringViewLike &t, size_type pos = npos) const + { + return rfind(t.data(), pos, t.size()); + } + + constexpr size_type find_first_of(const basic_string &str, size_type pos = 0) const + { + return find_first_of(str.data(), pos, str.size()); + } + + constexpr size_type find_first_of(const CharT *s, size_type pos, size_type count) const + { + if (count == 0) + return npos; + + if (pos >= _size) + return npos; + + const_iterator it = std::find_first_of(begin() + pos, end(), s, s + count); + return it == end() ? npos : std::distance(begin(), it); + } + + constexpr size_type find_first_of(const CharT *s, size_type pos = 0) const + { + return find_first_of(s, pos, Traits::length(s)); + } + + constexpr size_type find_first_of(CharT ch, size_type pos = 0) const + { + return find(ch, pos); + } + + template + constexpr size_type find_first_of(const StringViewLike &t, size_type pos = 0) const + { + return find_first_of(t.data(), pos, t.size()); + } + + constexpr size_type find_first_not_of(const basic_string &str, size_type pos = 0) const + { + return find_first_not_of(str.data(), pos, str.size()); + } + + constexpr size_type find_first_not_of(const CharT *s, size_type pos, size_type count) const + { + if (count == 0) + return pos; + + if (pos >= _size) + return npos; + + const_iterator it = begin() + pos; + while (it != end()) + { + if (std::find(s, s + count, *it) == s + count) + return std::distance(begin(), it); + it++; + } + return npos; + } + + constexpr size_type find_first_not_of(const CharT *s, size_type pos = 0) const + { + return find_first_not_of(s, pos, Traits::length(s)); + } + + constexpr size_type find_first_not_of(CharT ch, size_type pos = 0) const + { + const_iterator it = std::find_if(begin() + pos, end(), [ch](CharT c) + { return c != ch; }); + return it == end() ? npos : std::distance(begin(), it); + } + + template + constexpr size_type find_first_not_of(const StringViewLike &t, size_type pos = 0) const + { + return find_first_not_of(t.data(), pos, t.size()); + } + + constexpr size_type find_last_of(const basic_string &str, size_type pos = npos) const + { + return find_last_of(str.data(), pos, str.size()); + } + + constexpr size_type find_last_of(const CharT *s, size_type pos, size_type count) const + { + if (count == 0) + return npos; + + if (pos >= _size) + pos = _size; + else + pos = _size - pos; + + const_iterator it = std::find_first_of(begin(), begin() + pos, s, s + count); + return it == begin() + pos ? npos : std::distance(begin(), it); + } + + constexpr size_type find_last_of(const CharT *s, size_type pos = npos) const + { + return find_last_of(s, pos, Traits::length(s)); + } + + constexpr size_type find_last_of(CharT ch, size_type pos = npos) const + { + if (pos >= _size) + pos = _size; + else + pos = _size - pos; + + const_iterator it = std::find(begin(), begin() + pos, ch); + return it == begin() + pos ? npos : std::distance(begin(), it); + } + + template + constexpr size_type find_last_of(const StringViewLike &t, size_type pos = npos) const + { + return find_last_of(t.data(), pos, t.size()); + } + + constexpr size_type find_last_not_of(const basic_string &str, size_type pos = npos) const + { + return find_last_not_of(str.data(), pos, str.size()); + } + + constexpr size_type find_last_not_of(const CharT *s, size_type pos, size_type count) const + { + if (count == 0) + return pos; + + if (pos >= _size) + pos = _size; + else + pos = _size - pos; + + const_iterator it = begin() + pos; + while (it != begin()) + { + if (std::find(s, s + count, *it) == s + count) + return std::distance(begin(), it); + it--; + } + return npos; + } + + constexpr size_type find_last_not_of(const CharT *s, size_type pos = npos) const + { + return find_last_not_of(s, pos, Traits::length(s)); + } + + constexpr size_type find_last_not_of(CharT ch, size_type pos = npos) const + { + if (pos >= _size) + pos = _size; + else + pos = _size - pos; + + const_iterator it = std::find_if(begin(), begin() + pos, [ch](CharT c) + { return c != ch; }); + return it == begin() + pos ? npos : std::distance(begin(), it); + } + + template + constexpr size_type find_last_not_of(const StringViewLike &t, size_type pos = npos) const + { + return find_last_not_of(t.data(), pos, t.size()); + } + +#pragma endregion Search + +#pragma region Operations + + constexpr int compare(const basic_string &str) const + { + return compare(0, npos, str); + } + + constexpr int compare(size_type pos1, size_type count1, const basic_string &str) const + { + return compare(pos1, count1, str, 0, npos); + } + + constexpr int compare(size_type pos1, size_type count1, const basic_string &str, size_type pos2, size_type count2 = npos) const + { + if (pos1 > _size) + throw std::out_of_range("basic_string::compare"); + + if (pos2 > str._size) + throw std::out_of_range("basic_string::compare"); + + size_type len1 = std::min(count1, _size - pos1); + size_type len2 = std::min(count2, str._size - pos2); + size_type len = std::min(len1, len2); + + int result = Traits::compare(data() + pos1, str.data() + pos2, len); + if (result == 0) + { + if (len1 < len2) + result = -1; + else if (len1 > len2) + result = 1; + } + return result; + } + + constexpr int compare(const CharT *s) const + { + return compare(0, npos, s); + } + + constexpr int compare(size_type pos1, size_type count1, const CharT *s) const + { + return compare(pos1, count1, s, Traits::length(s)); + } + + constexpr int compare(size_type pos1, size_type count1, const CharT *s, size_type count2) const + { + if (pos1 > size()) + throw std::out_of_range("basic_string::compare"); + + size_type len1 = std::min(count1, size() - pos1); + size_type len2 = std::min(count2, Traits::length(s)); + size_type len = std::min(len1, len2); + + int result = Traits::compare(data() + pos1, s, len); + + if (result == 0) + { + if (len1 < len2) + result = -1; + else if (len1 > len2) + result = 1; + } + return result; + } + + template + constexpr int compare(const StringViewLike &t) const + { + return compare(0, npos, t); + } + + template + constexpr int compare(size_type pos1, size_type count1, const StringViewLike &t) const + { + return compare(pos1, count1, t, 0, npos); + } + + template + constexpr int compare(size_type pos1, size_type count1, const StringViewLike &t, size_type pos2, size_type count2 = npos) const + { + if (pos1 > size()) + throw std::out_of_range("basic_string::compare"); + + if (pos2 > t.size()) + throw std::out_of_range("basic_string::compare"); + + size_type len1 = std::min(count1, size() - pos1); + size_type len2 = std::min(count2, t.size() - pos2); + size_type len = std::min(len1, len2); + + int result = Traits::compare(data() + pos1, t.data() + pos2, len); + if (result == 0) + { + if (len1 < len2) + result = -1; + else if (len1 > len2) + result = 1; + } + return result; + } + + constexpr bool starts_with(std::basic_string_view sv) const + { + return sv.size() <= size() && Traits::compare(data(), sv.data(), sv.size()) == 0; + } + + constexpr bool starts_with(CharT ch) const + { + return !empty() && Traits::eq(front(), ch); + } + + constexpr bool starts_with(const CharT *s) const + { + return starts_with(std::basic_string_view(s)); + } + + constexpr bool ends_with(std::basic_string_view sv) const + { + return sv.size() <= size() && Traits::compare(data() + size() - sv.size(), sv.data(), sv.size()) == 0; + } + + constexpr bool ends_with(CharT ch) const + { + return !empty() && Traits::eq(back(), ch); + } + + constexpr bool ends_with(const CharT *s) const + { + return ends_with(std::basic_string_view(s)); + } + + constexpr bool contains(std::basic_string_view sv) const + { + return find(sv) != npos; + } + + constexpr bool contains(CharT ch) const + { + return find(ch) != npos; + } + + constexpr bool contains(const CharT *s) const + { + return find(s) != npos; + } + + constexpr basic_string substr(size_type pos = 0, size_type count = npos) const & + { + return basic_string(*this, pos, count); + } + + constexpr basic_string substr(size_type pos = 0, size_type count = npos) && + { + return basic_string(std::move(*this), pos, count); + } + +#pragma endregion Operations + }; + +#pragma region Additional Operations + + template + constexpr bool operator==(const std::basic_string &lhs, const std::basic_string &rhs) + { + return lhs.compare(rhs) == 0; + } + + template + constexpr bool operator==(const std::basic_string &lhs, const CharT *rhs) + { + return lhs.compare(rhs) == 0; + } + + template + std::basic_string constexpr operator+(const std::basic_string &lhs, const std::basic_string &rhs) + { + std::basic_string result(lhs); + result += rhs; + return result; + } + + template + std::basic_string constexpr operator+(const std::basic_string &lhs, const CharT *rhs) + { + std::basic_string result(lhs); + result += rhs; + return result; + } + + template + std::basic_string constexpr operator+(const std::basic_string &lhs, CharT rhs) + { + std::basic_string result(lhs); + result += rhs; + return result; + } + + template + std::basic_string constexpr operator+(const CharT *lhs, const std::basic_string &rhs) + { + std::basic_string result(lhs); + result += rhs; + return result; + } + + template + std::basic_string constexpr operator+(CharT lhs, const std::basic_string &rhs) + { + std::basic_string result(1, lhs); + result += rhs; + return result; + } + + template + std::basic_string constexpr operator+(std::basic_string &&lhs, std::basic_string &&rhs) + { + lhs.append(rhs); + return std::move(lhs); + } + + template + std::basic_string constexpr operator+(std::basic_string &&lhs, const std::basic_string &rhs) + { + lhs.append(rhs); + return std::move(lhs); + } + + template + std::basic_string constexpr operator+(std::basic_string &&lhs, const CharT *rhs) + { + lhs.append(rhs); + return std::move(lhs); + } + + template + std::basic_string constexpr operator+(std::basic_string &&lhs, CharT rhs) + { + lhs.push_back(rhs); + return std::move(lhs); + } + + template + std::basic_string constexpr operator+(const std::basic_string &lhs, std::basic_string &&rhs) + { + std::basic_string result(lhs); + result.append(rhs); + return result; + } + + template + std::basic_string constexpr operator+(const CharT *lhs, std::basic_string &&rhs) + { + std::basic_string result(lhs); + result.append(rhs); + return result; + } + + template + std::basic_string constexpr operator+(CharT lhs, std::basic_string &&rhs) + { + std::basic_string result(1, lhs); + result.append(rhs); + return result; + } + +#pragma endregion Additional Operations + + typedef basic_string string; + typedef basic_string wstring; + typedef basic_string u8string; + typedef basic_string u16string; + typedef basic_string u32string; + +#pragma region To String + + int sprintf(char *s, const char *format, ...) __attribute__((format(__printf__, (2), (3)))); + int snprintf(char *s, size_t count, const char *format, ...) __attribute__((format(__printf__, (3), (4)))); + + inline string to_string(int value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%d", value); + return {buffer}; + } + + inline string to_string(long value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%ld", value); + return {buffer}; + } + + inline string to_string(long long value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%lld", value); + return {buffer}; + } + + inline string to_string(unsigned value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%u", value); + return {buffer}; + } + + inline string to_string(unsigned long value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%lu", value); + return {buffer}; + } + + inline string to_string(unsigned long long value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%llu", value); + return {buffer}; + } + + inline string to_string(float value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%f", value); + return {buffer}; + } + + inline string to_string(double value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%f", value); + return {buffer}; + } + + inline string to_string(long double value) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%Lf", value); + return {buffer}; + } + +#pragma endregion To String + + /* FIXME: there's no swprintf implemented yet */ + constexpr std::wstring to_wstring(int value); + constexpr std::wstring to_wstring(long value); + constexpr std::wstring to_wstring(long long value); + constexpr std::wstring to_wstring(unsigned value); + constexpr std::wstring to_wstring(unsigned long value); + constexpr std::wstring to_wstring(unsigned long long value); + constexpr std::wstring to_wstring(float value); + constexpr std::wstring to_wstring(double value); + constexpr std::wstring to_wstring(long double value); + + inline namespace literals + { + inline namespace string_literals + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wliteral-suffix" + inline std::string operator""s(const char *str, std::size_t len) + { + return std::string{str, len}; + } + + inline std::u8string operator""s(const char8_t *str, std::size_t len) + { + return std::u8string{str, len}; + } + + inline std::u16string operator""s(const char16_t *str, std::size_t len) + { + return std::u16string{str, len}; + } + + inline std::u32string operator""s(const char32_t *str, std::size_t len) + { + return std::u32string{str, len}; + } + + inline std::wstring operator""s(const wchar_t *str, std::size_t len) + { + return std::wstring{str, len}; + } +#pragma GCC diagnostic pop + } + } } diff --git a/include_std/string_view b/include_std/string_view new file mode 100644 index 0000000..9625a10 --- /dev/null +++ b/include_std/string_view @@ -0,0 +1,62 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include + +namespace std +{ + typedef basic_string_view string_view; + typedef basic_string_view wstring_view; + typedef basic_string_view u8string_view; + typedef basic_string_view u16string_view; + typedef basic_string_view u32string_view; + + template + std::basic_ostream &operator<<(std::basic_ostream &os, std::basic_string_view v) + { + os.write(v.data(), v.size()); + return os; + } + + constexpr std::string_view operator""sv(const char *str, std::size_t len) noexcept + { + return std::string_view{str, len}; + } + + constexpr std::u8string_view operator""sv(const char8_t *str, std::size_t len) noexcept + { + return std::u8string_view{str, len}; + } + + constexpr std::u16string_view operator""sv(const char16_t *str, std::size_t len) noexcept + { + return std::u16string_view{str, len}; + } + + constexpr std::u32string_view operator""sv(const char32_t *str, std::size_t len) noexcept + { + return std::u32string_view{str, len}; + } + + constexpr std::wstring_view operator""sv(const wchar_t *str, std::size_t len) noexcept + { + return std::wstring_view{str, len}; + } +} diff --git a/include_std/sys/mman.h b/include_std/sys/mman.h index 0a29ab5..c4cc68f 100644 --- a/include_std/sys/mman.h +++ b/include_std/sys/mman.h @@ -18,7 +18,7 @@ #pragma once #include -/* stubs */ +/* stubs for rpmalloc.c */ #ifndef MAP_PRIVATE #define MAP_PRIVATE 0x0 diff --git a/include_std/system_error b/include_std/system_error new file mode 100644 index 0000000..0dac762 --- /dev/null +++ b/include_std/system_error @@ -0,0 +1,58 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +namespace std +{ + class error_category + { + /* https://en.cppreference.com/w/cpp/error/error_category */ + }; + + class error_code + { + public: + error_code() noexcept + { + } + + error_code(int ec, const error_category &ecat) noexcept + { + } + + template + error_code(ErrorCodeEnum e) noexcept + { + } + + error_code(const error_code &other) = default; + error_code(error_code &&other) = default; + + template + error_code &operator=(ErrorCodeEnum e) noexcept + { + return *this; + } + + error_code &operator=(const error_code &other) = default; + + error_code &operator=(error_code &&other) = default; + + /* https://en.cppreference.com/w/cpp/error/error_code */ + }; +} diff --git a/include/filesystem/termios-bits.hpp b/include_std/termios.h similarity index 87% rename from include/filesystem/termios-bits.hpp rename to include_std/termios.h index ef42430..b22da8f 100644 --- a/include/filesystem/termios-bits.hpp +++ b/include_std/termios.h @@ -15,8 +15,10 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_TERMIOS_BITS_H__ -#define __FENNIX_KERNEL_TERMIOS_BITS_H__ +#ifndef __FENNIX_KERNEL_TERMIOS_H__ +#define __FENNIX_KERNEL_TERMIOS_H__ + +#include /* c_cc */ #define VINTR 0 @@ -157,4 +159,29 @@ #define CMSPAR 010000000000 #define CRTSCTS 020000000000 -#endif // !__FENNIX_KERNEL_TERMIOS_BITS_H__ +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 +struct termios +{ + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + +struct winsize +{ + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#endif // !__FENNIX_KERNEL_TERMIOS_H__ diff --git a/include_std/tuple b/include_std/tuple new file mode 100644 index 0000000..b6c0b24 --- /dev/null +++ b/include_std/tuple @@ -0,0 +1,27 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include + +namespace std +{ + template + class tuple; +} diff --git a/include_std/type_traits b/include_std/type_traits index f367fa0..7f833d5 100644 --- a/include_std/type_traits +++ b/include_std/type_traits @@ -19,6 +19,33 @@ namespace std { + template + struct add_cv + { + typedef const volatile T type; + }; + + template + struct add_const + { + typedef const T type; + }; + + template + struct add_volatile + { + typedef volatile T type; + }; + + template + using add_cv_t = typename add_cv::type; + + template + using add_const_t = typename add_const::type; + + template + using add_volatile_t = typename add_volatile::type; + template struct is_trivially_copyable { @@ -43,6 +70,9 @@ namespace std typedef T type; }; + template + using remove_reference_t = typename remove_reference::type; + template struct integral_constant { @@ -53,6 +83,569 @@ namespace std constexpr value_type operator()() const noexcept { return value; } }; + template + struct is_array : public integral_constant + { + }; + + template + struct is_array : public integral_constant + { + }; + + template + struct is_array : public integral_constant + { + }; + + template + inline constexpr bool is_array_v = is_array::value; + + template + struct conditional + { + typedef T type; + }; + + template + struct conditional + { + typedef F type; + }; + + template + using conditional_t = typename conditional::type; + + template + struct type_identity + { + using type = T; + }; + + template + using type_identity_t = type_identity::type; + + template + auto __try_add_pointer(int) -> type_identity::type *>; + + template + auto __try_add_pointer(...) -> type_identity; + + template + struct add_pointer : decltype(__try_add_pointer(0)) + { + }; + + template + using add_pointer_t = typename add_pointer::type; + + template + struct remove_extent + { + using type = T; + }; + + template + struct remove_extent + { + using type = T; + }; + + template + struct remove_extent + { + using type = T; + }; + + template + using remove_extent_t = typename remove_extent::type; + + template + struct remove_cv + { + typedef T type; + }; + template + struct remove_cv + { + typedef T type; + }; + template + struct remove_cv + { + typedef T type; + }; + template + struct remove_cv + { + typedef T type; + }; + + template + struct remove_const + { + typedef T type; + }; + template + struct remove_const + { + typedef T type; + }; + + template + struct remove_volatile + { + typedef T type; + }; + template + struct remove_volatile + { + typedef T type; + }; + + template + using remove_cv_t = typename remove_cv::type; + + template + using remove_const_t = typename remove_const::type; + + template + using remove_volatile_t = typename remove_volatile::type; + + template + struct is_lvalue_reference : public integral_constant + { + }; + + template + struct is_lvalue_reference : public integral_constant + { + }; + + template + inline constexpr bool is_lvalue_reference_v = is_lvalue_reference::value; + + template + struct is_const : public integral_constant + { + }; + template + struct is_const : public integral_constant + { + }; + + template + inline constexpr bool is_const_v = is_const::value; + + template + struct is_reference : public integral_constant + { + }; + + template + struct is_reference : public integral_constant + { + }; + + template + struct is_reference : public integral_constant + { + }; + + template + inline constexpr bool is_reference_v = is_reference::value; + + template + struct is_function : std::integral_constant< + bool, + !std::is_const::value && !std::is_reference::value> + { + }; + + template + struct decay + { + private: + typedef typename std::remove_reference::type U; + + public: + typedef typename std::conditional< + std::is_array::value, + typename std::add_pointer::type>::type, + typename std::conditional< + std::is_function::value, + typename std::add_pointer::type, + typename std::remove_cv::type>::type>::type type; + }; + + template + using decay_t = typename decay::type; + + template + using bool_constant = integral_constant; + typedef integral_constant true_type; typedef integral_constant false_type; + + template + struct enable_if + { + }; + + template + struct enable_if + { + typedef T type; + }; + + template + using enable_if_t = typename enable_if::type; + + template + auto __try_add_lvalue_reference(int) -> type_identity; + + template + auto __try_add_lvalue_reference(...) -> type_identity; + + template + auto __try_add_rvalue_reference(int) -> type_identity; + + template + auto __try_add_rvalue_reference(...) -> type_identity; + + template + struct add_lvalue_reference : decltype(__try_add_lvalue_reference(0)) + { + }; + + template + struct add_rvalue_reference : decltype(__try_add_rvalue_reference(0)) + { + }; + + template + using add_lvalue_reference_t = typename add_lvalue_reference::type; + + template + using add_rvalue_reference_t = typename add_rvalue_reference::type; + + template + typename std::add_rvalue_reference::type declval() noexcept + { + static_assert(false, "declval not allowed in an evaluated context"); + } + + template + struct is_constructible : public integral_constant + { + }; + + template + struct is_trivially_constructible : public integral_constant + { + }; + + template + struct is_nothrow_constructible : public integral_constant + { + }; + + template + inline constexpr bool is_constructible_v = is_constructible::value; + + template + inline constexpr bool is_trivially_constructible_v = is_trivially_constructible::value; + + template + inline constexpr bool is_nothrow_constructible_v = is_nothrow_constructible::value; + + template + struct is_default_constructible : std::is_constructible + { + }; + + template + struct is_trivially_default_constructible : std::is_trivially_constructible + { + }; + + template + struct is_nothrow_default_constructible : std::is_nothrow_constructible + { + }; + + template + inline constexpr bool is_default_constructible_v = is_default_constructible::value; + + template + inline constexpr bool is_trivially_default_constructible_v = is_trivially_default_constructible::value; + + template + inline constexpr bool is_nothrow_default_constructible_v = is_nothrow_default_constructible::value; + + template + struct is_assignable : public integral_constant + { + }; + + template + struct is_trivially_assignable : public integral_constant + { + }; + + template + struct is_nothrow_assignable : public integral_constant + { + }; + + template + inline constexpr bool is_assignable_v = is_assignable::value; + + template + inline constexpr bool is_trivially_assignable_v = is_trivially_assignable::value; + + template + inline constexpr bool is_nothrow_assignable_v = is_nothrow_assignable::value; + + template + struct is_move_assignable : std::is_assignable::type, typename std::add_rvalue_reference::type> + { + }; + + template + struct is_trivially_move_assignable : std::is_trivially_assignable::type, typename std::add_rvalue_reference::type> + { + }; + + template + struct is_nothrow_move_assignable : std::is_nothrow_assignable::type, typename std::add_rvalue_reference::type> + { + }; + + template + inline constexpr bool is_move_assignable_v = is_move_assignable::value; + + template + inline constexpr bool is_trivially_move_assignable_v = is_trivially_move_assignable::value; + + template + inline constexpr bool is_nothrow_move_assignable_v = is_nothrow_move_assignable::value; + + template + struct is_move_constructible : std::is_constructible::type> + { + }; + + template + struct is_trivially_move_constructible : std::is_trivially_constructible::type> + { + }; + + template + struct is_nothrow_move_constructible : std::is_nothrow_constructible::type> + { + }; + + template + inline constexpr bool is_move_constructible_v = is_move_constructible::value; + + template + inline constexpr bool is_trivially_move_constructible_v = is_trivially_move_constructible::value; + + template + inline constexpr bool is_nothrow_move_constructible_v = is_nothrow_move_constructible::value; + + template + typename std::remove_reference::type &&__type_traits_move(T &&arg) + { + return static_cast::type &&>(arg); + } + + template + void __type_traits_swap(T &a, T &b) + { + T temp = __type_traits_move(a); + a = __type_traits_move(b); + b = __type_traits_move(temp); + } + + template + struct is_swappable_with + { + template (), std::declval())), + typename = decltype(__type_traits_swap(std::declval(), std::declval()))> + static std::true_type test(int); + + template + static std::false_type test(...); + + static constexpr bool value = decltype(test(0))::value; + }; + + template + struct is_swappable + { + static constexpr bool value = is_swappable_with::value; + }; + + template + struct is_nothrow_swappable_with + { + template (), std::declval())), + typename = decltype(__type_traits_swap(std::declval(), std::declval()))> + static std::true_type test(int); + + template + static std::false_type test(...); + + static constexpr bool value = decltype(test(0))::value; + }; + + template + struct is_nothrow_swappable + { + static constexpr bool value = is_nothrow_swappable_with::value; + }; + + template + inline constexpr bool is_swappable_with_v = is_swappable_with::value; + + template + inline constexpr bool is_swappable_v = is_swappable::value; + + template + inline constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with::value; + + template + inline constexpr bool is_nothrow_swappable_v = is_nothrow_swappable::value; + + template + struct is_copy_constructible : std::is_constructible::type>::type> + { + }; + + template + struct is_trivially_copy_constructible : std::is_trivially_constructible::type>::type> + { + }; + + template + struct is_nothrow_copy_constructible : std::is_nothrow_constructible::type>::type> + { + }; + + template + inline constexpr bool is_copy_constructible_v = is_copy_constructible::value; + + template + inline constexpr bool is_trivially_copy_constructible_v = is_trivially_copy_constructible::value; + + template + inline constexpr bool is_nothrow_copy_constructible_v = is_nothrow_copy_constructible::value; + + template + struct is_same : std::false_type + { + }; + + template + struct is_same : std::true_type + { + }; + + template + inline constexpr bool is_same_v = is_same::value; + + template + struct is_unbounded_array : std::false_type + { + }; + + template + struct is_unbounded_array : std::true_type + { + }; + + template + inline constexpr bool is_unbounded_array_v = is_unbounded_array::value; + + template + struct is_bounded_array : std::false_type + { + }; + + template + struct is_bounded_array : std::true_type + { + }; + + template + inline constexpr bool is_bounded_array_v = is_bounded_array::value; + + template + struct common_type + { + }; + + template + struct common_type : common_type + { + }; + + namespace __type_traits_detail + { + template + using void_t = void; + + template + using conditional_result_t = decltype(false ? std::declval() : std::declval()); + + template + struct decay_conditional_result + { + }; + + template + struct decay_conditional_result>> : std::decay> + { + }; + + template + struct common_type_2_impl : decay_conditional_result + { + }; + + template + struct common_type_2_impl>> : decay_conditional_result + { + }; + + template + struct common_type_multi_impl + { + }; + + template + struct common_type_multi_impl::type>, T1, T2, R...> : common_type::type, R...> + { + }; + } + + template + struct common_type : std::conditional::type>::value && + std::is_same::type>::value, + __type_traits_detail::common_type_2_impl, + common_type::type, typename std::decay::type>>::type + { + }; + + template + struct common_type : __type_traits_detail::common_type_multi_impl + { + }; + + template + using common_type_t = typename common_type::type; } diff --git a/include_std/typeinfo b/include_std/typeinfo index 0cac610..f445448 100644 --- a/include_std/typeinfo +++ b/include_std/typeinfo @@ -18,8 +18,8 @@ #ifndef __FENNIX_KERNEL_TYPEINFO_H__ #define __FENNIX_KERNEL_TYPEINFO_H__ -#include #include +#include namespace __cxxabiv1 { @@ -31,26 +31,33 @@ namespace std { class type_info { + protected: + const char *Name; + explicit type_info(const char *n) : Name(n) {} + public: + type_info() = delete; + type_info(const type_info &) = delete; virtual ~type_info(); - bool operator==(const type_info &Argument) const noexcept + type_info &operator=(const type_info &) = delete; + type_info &operator=(type_info &&) = delete; + + constexpr bool operator==(const type_info &rhs) const noexcept { - return ((Name == Argument.Name) || - (Name[0] != '*' && - __builtin_strcmp(Name, Argument.Name) == 0)); + return this == &rhs; } - bool operator!=(const type_info &Argument) const noexcept + bool before(const type_info &rhs) const noexcept { - return !operator==(Argument); + return (Name[0] == '*' && rhs.Name[0] == '*') + ? Name < rhs.Name + : __builtin_strcmp(Name, rhs.Name) < 0; } - bool before(const type_info &Argument) const noexcept + std::size_t hash_code() const noexcept { - return (Name[0] == '*' && Argument.Name[0] == '*') - ? Name < Argument.Name - : __builtin_strcmp(Name, Argument.Name) < 0; + return reinterpret_cast(this); } const char *name() const noexcept @@ -68,20 +75,8 @@ namespace std return Name[0] == '('; } - virtual bool __do_catch(const type_info *ThrowType, - void **ThrowObject, - unsigned Outer) const; - - virtual bool __do_upcast(const __cxxabiv1::__class_type_info *Target, - void **ObjectPointer) const; - - protected: - const char *Name; - explicit type_info(const char *n) : Name(n) {} - - private: - type_info &operator=(const type_info &); - type_info(const type_info &); + virtual bool __do_catch(const type_info *ThrowType, void **ThrowObject, unsigned Outer) const; + virtual bool __do_upcast(const __cxxabiv1::__class_type_info *Target, void **ObjectPointer) const; }; class bad_cast : public exception @@ -109,11 +104,13 @@ namespace __cxxabiv1 unsigned int Flags; const std::type_info *Pointee; - explicit __pbase_type_info(const char *n, int Qualifiers, - const std::type_info *Type) + explicit __pbase_type_info(const char *n, int Qualifiers, const std::type_info *Type) : std::type_info(n), Flags(Qualifiers), - Pointee(Type) {} + Pointee(Type) + { + } + virtual ~__pbase_type_info(); enum __masks @@ -207,18 +204,6 @@ namespace __cxxabiv1 } }; - /* FIXME: stub */ - class __vmi_class_type_info /* : public __class_type_info */ - { - public: - enum __flags_masks - { - __non_diamond_repeat_mask = 0x1, - __diamond_shaped_mask = 0x2, - __flags_unknown_mask = 0x10 - }; - }; - class __class_type_info : public std::type_info { public: @@ -260,7 +245,7 @@ namespace __cxxabiv1 __sub_kind dst2src; int whole_details; - __dyncast_result(int details_ = __vmi_class_type_info::__flags_unknown_mask) + __dyncast_result(int details_ = 0x10 /*__vmi_class_type_info::__flags_unknown_mask*/) : dst_ptr(NULL), whole2dst(__unknown), whole2src(__unknown), @@ -300,6 +285,22 @@ namespace __cxxabiv1 unsigned Outer) const; }; + class __vmi_class_type_info : public __class_type_info + { + public: + enum __flags_masks + { + __non_diamond_repeat_mask = 0x1, + __diamond_shaped_mask = 0x2, + __flags_unknown_mask = 0x10 + }; + + virtual ~__vmi_class_type_info(); + + virtual bool __do_upcast(const __class_type_info *target, void **thrown_object) const; + virtual void *cast_to(void *obj, const struct __class_type_info *other) const; + }; + class __si_class_type_info : public __class_type_info { public: diff --git a/include_std/unordered_map b/include_std/unordered_map index e418c3d..0e8c52e 100644 --- a/include_std/unordered_map +++ b/include_std/unordered_map @@ -18,276 +18,1257 @@ #pragma once #include -#include +#include +#include +#include +#include #include #include +#include +#include #include -#define DEBUG_UMAP_MESSAGES 1 - -#ifdef DEBUG_UMAP_MESSAGES -#define umDebug(m, ...) debug("%#lx: " m, this, ##__VA_ARGS__) -#else -#define umDebug(m, ...) -#endif - namespace std { - template + template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator>> + class unordered_multimap; + + template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator>> class unordered_map { public: - typedef std::pair pair_t; - typedef std::list bucket_t; + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + // using iterator = typename std::vector>::iterator; + // using const_iterator = typename std::vector>::const_iterator; + // using local_iterator = typename std::list::iterator; + // using const_local_iterator = typename std::list::const_iterator; + using node_type = std::list; + + template + struct __insert_return_type + { + Iter position; + bool inserted; + NodeType node; + }; + + class iterator + { + friend class unordered_map; + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::pair; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::bidirectional_iterator_tag; + + private: + std::vector &buckets; + std::vector>::iterator bucket; + std::list::iterator element; + + public: + iterator(std::vector &buckets, std::vector>::iterator bucket, std::list::iterator element) + : buckets(buckets), + bucket(bucket), + element(element) + { + } + + iterator &operator++() + { + if (element != bucket->end()) + ++element; + if (element == bucket->end()) + { + ++bucket; + while (bucket != buckets.end() && bucket->empty()) + ++bucket; + if (bucket != buckets.end()) + element = bucket->begin(); + } + return *this; + } + + iterator operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + iterator &operator--() + { + if (element != bucket->begin()) + --element; + if (element == bucket->begin()) + { + --bucket; + while (bucket != buckets.begin() && bucket->empty()) + --bucket; + if (bucket != buckets.begin()) + element = --bucket->end(); + } + return *this; + } + + iterator operator--(int) + { + auto copy = *this; + --(*this); + return copy; + } + + reference operator*() { return *element; } + const_reference operator*() const { return *element; } + pointer operator->() { return &(*element); } + const_pointer operator->() const { return &(*element); } + + bool operator==(const iterator &other) const + { + return bucket == other.bucket && element == other.element; + } + + bool operator!=(const iterator &other) const + { + return !(*this == other); + } + }; + + class const_iterator + { + friend class unordered_map; + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::pair; + using pointer = const value_type *; + using reference = const value_type &; + using iterator_category = std::bidirectional_iterator_tag; + + private: + const std::vector &buckets; + std::vector>::const_iterator bucket; + std::list::const_iterator element; + + public: + const_iterator(const std::vector &buckets, std::vector>::const_iterator bucket, std::list::const_iterator element) + : buckets(buckets), + bucket(bucket), + element(element) + { + } + + const_iterator(const iterator &it) + : bucket(it.bucket), element(it.element) + { + } + + const_iterator &operator++() + { + if (element != bucket->end()) + ++element; + if (element == bucket->end()) + { + ++bucket; + while (bucket != buckets.end() && bucket->empty()) + ++bucket; + if (bucket != buckets.end()) + element = bucket->begin(); + } + return *this; + } + + const_iterator operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + const_iterator &operator--() + { + if (element != bucket->begin()) + --element; + if (element == bucket->begin()) + { + --bucket; + while (bucket != buckets.begin() && bucket->empty()) + --bucket; + if (bucket != buckets.begin()) + element = --bucket->end(); + } + return *this; + } + + const_iterator operator--(int) + { + auto copy = *this; + --(*this); + return copy; + } + + reference operator*() const { return *element; } + pointer operator->() const { return &(*element); } + + bool operator==(const const_iterator &other) const + { + return bucket == other.bucket && element == other.element; + } + + bool operator!=(const const_iterator &other) const + { + return !(*this == other); + } + }; + + class local_iterator + { + friend class unordered_map; + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::pair; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::bidirectional_iterator_tag; + + private: + std::list::iterator element; + + public: + local_iterator(std::list::iterator element) + : element(element) + { + } + + local_iterator &operator++() + { + ++element; + return *this; + } + + local_iterator operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + local_iterator &operator--() + { + --element; + return *this; + } + + local_iterator operator--(int) + { + auto copy = *this; + --(*this); + return copy; + } + + reference operator*() { return *element; } + pointer operator->() { return &(*element); } + + bool operator==(const local_iterator &other) const + { + return element == other.element; + } + + bool operator!=(const local_iterator &other) const + { + return !(*this == other); + } + }; + + class const_local_iterator + { + friend class unordered_map; + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::pair; + using pointer = const value_type *; + using reference = const value_type &; + using iterator_category = std::bidirectional_iterator_tag; + + private: + std::list::const_iterator element; + + public: + const_local_iterator(std::list::const_iterator element) + : element(element) + { + } + + const_local_iterator &operator++() + { + ++element; + return *this; + } + + const_local_iterator operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + const_local_iterator &operator--() + { + --element; + return *this; + } + + const_local_iterator operator--(int) + { + auto copy = *this; + --(*this); + return copy; + } + + reference operator*() const { return *element; } + pointer operator->() const { return &(*element); } + + bool operator==(const const_local_iterator &other) const + { + return element == other.element; + } + + bool operator!=(const const_local_iterator &other) const + { + return !(*this == other); + } + }; + + using insert_return_type = __insert_return_type; private: - NewLock(lock); - std::vector Buckets; - - size_t hash(const Key &key) const - { - size_t ret = std::hash()(key) % this->Buckets.size(); - // debug("Hashed %#lx to %d", key, ret); - return ret; - } + std::vector buckets; + Hash hashFunction; + double maxLoadFactor = 0.75; + size_type elementsCount = 0; public: - unordered_map() - : Buckets(16) +#pragma region Member Functions + + unordered_map() = default; + + unordered_map(const unordered_map &other) + : buckets(other.buckets) { - umDebug("Created unordered_map with 16 buckets (default)"); } - unordered_map(size_t num) - : Buckets(num) + unordered_map(unordered_map &&other) + : buckets(std::move(other.buckets)) { - umDebug("Created unordered_map with %d buckets", num); } - unordered_map(std::initializer_list init) - : Buckets(16) + unordered_map(std::initializer_list il) { - umDebug("Created unordered_map with 16 buckets (initializer_list)"); - for (const auto &p : init) + insert(il); + } + + ~unordered_map() = default; + + unordered_map &operator=(const unordered_map &other) + { + buckets = other.buckets; + return *this; + } + + unordered_map &operator=(unordered_map &&other) /* noexcept(std::allocator_traits::is_always_equal::value && std::is_nothrow_move_assignable::value && std::is_nothrow_move_assignable::value) */ + { + buckets = std::move(other.buckets); + return *this; + } + + unordered_map &operator=(std::initializer_list ilist) + { + clear(); + insert(ilist); + return *this; + } + + allocator_type get_allocator() const noexcept + { + return allocator_type(); + } + +#pragma endregion Member Functions + +#pragma region Iterators + + iterator begin() noexcept + { + return iterator(buckets, buckets.begin(), buckets.front().begin()); + } + + const_iterator begin() const noexcept + { + return const_iterator(buckets, buckets.begin(), buckets.front().begin()); + } + + const_iterator cbegin() const noexcept + { + return const_iterator(buckets, buckets.begin(), buckets.front().begin()); + } + + iterator end() noexcept + { + return iterator(buckets, buckets.end(), buckets.back().end()); + } + + const_iterator end() const noexcept + { + return const_iterator(buckets, buckets.end(), buckets.back().end()); + } + + const_iterator cend() const noexcept + { + return const_iterator(buckets, buckets.end(), buckets.back().end()); + } + +#pragma endregion Iterators + +#pragma region Capacity + + [[nodiscard]] bool empty() const noexcept + { + return elementsCount == 0; /* begin() == end() */ + } + + size_type size() const noexcept + { + return elementsCount; /* std::distance(begin(), end()) */ + } + + size_type max_size() const noexcept + { + return std::numeric_limits::max(); + } + +#pragma endregion Capacity + +#pragma region Modifiers + + void clear() noexcept + { + foreach (auto &bucket in buckets) + bucket.clear(); + elementsCount = 0; + } + + std::pair insert(const value_type &value) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(value.first) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) { - insert(p); + if (it->first == value.first) + return std::make_pair(iterator(buckets, buckets.begin() + index, it), false); } - } - ~unordered_map() - { - umDebug("Destroyed unordered_map"); - } + bucket.push_back(value); + ++elementsCount; - void insert(const pair_t &p) - { - SmartLock(this->lock); - size_t bucketIndex = hash(p.first) % Buckets.size(); - auto &bucket = Buckets[bucketIndex]; - - for (auto &element : bucket) + if (elementsCount > max_load_factor() * buckets.size()) { - if (element.first == p.first) + rehash(buckets.size() * 2); + index = hashFunction(value.first) % buckets.size(); + } + + return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true); + } + + std::pair insert(value_type &&value) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(value.first) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == value.first) + return std::make_pair(iterator(buckets, buckets.begin() + index, it), false); + } + + bucket.push_back(std::move(value)); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(value.first) % buckets.size(); + } + + return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true); + } + + template + std::pair insert(P &&value) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(value.first) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == value.first) + return std::make_pair(iterator(buckets, buckets.begin() + index, it), false); + } + + bucket.push_back(std::forward

(value)); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(value.first) % buckets.size(); + } + + return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true); + } + + iterator insert(const_iterator hint, const value_type &value) + { + fixme("hint %p", &hint); + return insert(value).first; + } + + iterator insert(const_iterator hint, value_type &&value) + { + fixme("hint %p", &hint); + return insert(std::move(value)).first; + } + + template + iterator insert(const_iterator hint, P &&value) + { + fixme("hint %p", &hint); + return insert(std::forward

(value)).first; + } + + template + void insert(InputIt first, InputIt last) + { + for (auto it = first; it != last; ++it) + insert(*it); + } + + void insert(std::initializer_list ilist) + { + foreach (const auto &value in ilist) + insert(value); + } + + insert_return_type insert(node_type &&nh) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(nh.front().first) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == nh.front().first) + return {iterator(buckets, buckets.begin() + index, it), false, std::move(nh)}; + } + + bucket.splice(bucket.end(), nh); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(nh.front().first) % buckets.size(); + } + + return {iterator(buckets, buckets.begin() + index, --bucket.end()), true, std::move(nh)}; + } + + iterator insert(const_iterator hint, node_type &&nh) + { + fixme("hint %p", &hint); + return insert(std::move(nh)).position; + } + + template + std::pair insert_or_assign(const Key &k, M &&obj) + { + if (auto it = find(k); it != end()) + { + it->second = std::forward(obj); + return std::make_pair(it, false); + } + + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(k) % buckets.size(); + auto &bucket = buckets[index]; + + bucket.push_back(std::make_pair(k, std::forward(obj))); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(k) % buckets.size(); + } + + return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true); + } + + template + std::pair insert_or_assign(Key &&k, M &&obj) + { + if (auto it = find(k); it != end()) + { + it->second = std::forward(obj); + return std::make_pair(it, false); + } + + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(k) % buckets.size(); + auto &bucket = buckets[index]; + + bucket.push_back(std::make_pair(std::move(k), std::forward(obj))); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(k) % buckets.size(); + } + + return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true); + } + + template + iterator insert_or_assign(const_iterator hint, const Key &k, M &&obj) + { + fixme("hint %p", &hint); + return insert_or_assign(k, std::forward(obj)).first; + } + + template + iterator insert_or_assign(const_iterator hint, Key &&k, M &&obj) + { + fixme("hint %p", &hint); + return insert_or_assign(std::move(k), std::forward(obj)).first; + } + + template + __deprecated_msg("Function not implemented") std::pair emplace(Args &&...args) + { + assert(!"std::tuple : Function not implemented"); + // size_type index = hashFunction(std::get<0>(std::forward_as_tuple(args...))) % buckets.size(); + // auto &bucket = buckets[index]; + + // for (auto it = bucket.begin(); it != bucket.end(); ++it) + // { + // if (it->first == std::get<0>(std::forward_as_tuple(args...))) + // return std::make_pair(iterator(buckets, buckets.begin() + index, it), false); + // } + + // bucket.push_back(std::make_pair(std::get<0>(std::forward_as_tuple(args...)), std::get<1>(std::forward_as_tuple(args...)))); + // ++elementsCount; + + // if (elementsCount > max_load_factor() * buckets.size()) + // { + // rehash(buckets.size() * 2); + // index = hashFunction(std::get<0>(std::forward_as_tuple(args...))) % buckets.size(); + // } + + // return std::make_pair(iterator(buckets, buckets.begin() + index, --bucket.end()), true); + } + + template + __deprecated_msg("Function not implemented") iterator emplace_hint(const_iterator hint, Args &&...args) + { + fixme("hint %p", &hint); + return emplace(std::forward(args)...).first; + } + + template + __deprecated_msg("Function not implemented") std::pair try_emplace(const Key &k, Args &&...args) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") std::pair try_emplace(Key &&k, Args &&...args) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") std::pair try_emplace(K &&k, Args &&...args) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") iterator try_emplace(const_iterator hint, const Key &k, Args &&...args) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") iterator try_emplace(const_iterator hint, Key &&k, Args &&...args) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") iterator try_emplace(const_iterator hint, K &&k, Args &&...args) + { + assert(!"Function not implemented"); + } + + iterator erase(iterator pos) + { + auto &bucket = *pos.bucket; + auto it = bucket.erase(pos.element); + --elementsCount; + return iterator(buckets, pos.bucket, it); + } + + __deprecated_msg("Function not implemented") iterator erase(const_iterator pos) + { + assert(!"Function not implemented"); + // auto &bucket = *pos.bucket; + // auto it = bucket.erase(pos.element); + // --elementsCount; + // return iterator(pos.bucket, it); + } + + __deprecated_msg("Function not implemented") iterator erase(const_iterator first, const_iterator last) + { + assert(!"Function not implemented"); + // for (auto it = first; it != last; ++it) + // erase(it); + + // return iterator(last.bucket, last.element); + } + + size_type erase(const Key &key) + { + if (buckets.empty()) + return 0; + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) { - element.second = p.second; - return; + bucket.erase(it); + --elementsCount; + return 1; } } - bucket.push_back(p); + return 0; } - void erase(const Key &key) + void swap(unordered_map &other) /* noexcept(std::allocator_traits::is_always_equal::value && std::is_nothrow_swappable::value && std::is_nothrow_swappable::value) */ { - SmartLock(this->lock); - size_t bucketIndex = hash(key) % Buckets.size(); - auto &bucket = Buckets[bucketIndex]; - - bucket.remove_if([key](const pair_t &element) - { return element.first == key; }); + std::swap(buckets, other.buckets); } - void clear() + __deprecated_msg("Function not implemented") node_type extract(const_iterator position) { - SmartLock(this->lock); - for (auto &bucket : Buckets) + assert(!"Function not implemented"); + } + + __deprecated_msg("Function not implemented") node_type extract(const Key &k) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") void merge(std::unordered_map &source) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") void merge(std::unordered_map &&source) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") void merge(std::unordered_multimap &source) + { + assert(!"Function not implemented"); + } + + template + __deprecated_msg("Function not implemented") void merge(std::unordered_multimap &&source) + { + assert(!"Function not implemented"); + } + +#pragma endregion Modifiers + +#pragma region Lookup + + T &at(const Key &key) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) { - bucket.clear(); + if (it->first == key) + return it->second; } + + throw std::out_of_range("Key not found"); } - bool contains(const Key &key) + const T &at(const Key &key) const { - SmartLock(this->lock); - size_t bucketIndex = hash(key) % Buckets.size(); - const auto &bucket = Buckets[bucketIndex]; + if (buckets.empty()) + rehash(16); - for (const auto &element : bucket) + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) { - if (element.first == key) + if (it->first == key) + return it->second; + } + + throw std::out_of_range("Key not found"); + } + + T &operator[](const Key &key) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) + return it->second; + } + + bucket.push_back(std::make_pair(key, T())); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(key) % buckets.size(); + } + + return bucket.back().second; + } + + T &operator[](Key &&key) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) + return it->second; + } + + bucket.push_back(std::make_pair(std::move(key), T())); + ++elementsCount; + + if (elementsCount > max_load_factor() * buckets.size()) + { + rehash(buckets.size() * 2); + index = hashFunction(key) % buckets.size(); + } + + return bucket.back().second; + } + + size_type count(const Key &key) const + { + if (buckets.empty()) + return 0; + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) + return 1; + } + + return 0; + } + + template + size_type count(const K &x) const + { + if (buckets.empty()) + return 0; + + size_type index = hashFunction(x) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == x) + return 1; + } + + return 0; + } + + iterator find(const Key &key) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) + return iterator(buckets, buckets.begin() + index, it); + } + + return end(); + } + + const_iterator find(const Key &key) const + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) + return const_iterator(buckets, buckets.begin() + index, it); + } + + return end(); + } + + template + iterator find(const K &x) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(x) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == (Key)x) + return iterator(buckets, buckets.begin() + index, it); + } + + return end(); + } + + template + const_iterator find(const K &x) const + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(x) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == x) + return const_iterator(buckets, buckets.begin() + index, it); + } + + return end(); + } + + bool contains(const Key &key) const + { + if (buckets.empty()) + return false; + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) return true; } return false; } - size_t size() + template + bool contains(const K &x) const { - SmartLock(this->lock); - size_t count = 0; - for (const auto &bucket : Buckets) + if (buckets.empty()) + return false; + + size_type index = hashFunction(x) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) { - count += bucket.size(); - } - return count; - } - - bool empty() { return size() == 0; } - - T &operator[](const Key &key) - { - SmartLock(this->lock); - size_t bucketIndex = hash(key) % Buckets.size(); - auto &bucket = Buckets[bucketIndex]; - - for (auto &element : bucket) - { - if (element.first == key) - return element.second; + if (it->first == x) + return true; } - bucket.emplace_back(key, T{}); - return bucket.back().second; + return false; } - class iterator + std::pair equal_range(const Key &key) { - private: - using BucketIterator = typename std::list::iterator; - size_t bucketIndex; - BucketIterator bucketIterator; - std::vector> *buckets; + if (buckets.empty()) + rehash(16); - public: - size_t GetBucketIndex() const { return bucketIndex; } - BucketIterator &GetBucketIterator() const { return bucketIterator; } + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; - iterator(size_t index, - BucketIterator it, - std::vector> *buckets) - : bucketIndex(index), - bucketIterator(it), - buckets(buckets) {} - - iterator &operator++() + for (auto it = bucket.begin(); it != bucket.end(); ++it) { - ++bucketIterator; + if (it->first == key) + return std::make_pair(iterator(buckets, buckets.begin() + index, it), iterator(buckets, buckets.begin() + index, it)); + } - while (bucketIndex < buckets->size() && - bucketIterator == (*buckets)[bucketIndex].end()) + return std::make_pair(end(), end()); + } + + std::pair equal_range(const Key &key) const + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(key) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == key) + return std::make_pair(const_iterator(buckets, buckets.begin() + index, it), const_iterator(buckets, buckets.begin() + index, it)); + } + + return std::make_pair(end(), end()); + } + + template + std::pair equal_range(const K &x) + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(x) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == x) + return std::make_pair(iterator(buckets, buckets.begin() + index, it), iterator(buckets, buckets.begin() + index, it)); + } + + return std::make_pair(end(), end()); + } + + template + std::pair equal_range(const K &x) const + { + if (buckets.empty()) + rehash(16); + + size_type index = hashFunction(x) % buckets.size(); + auto &bucket = buckets[index]; + + for (auto it = bucket.begin(); it != bucket.end(); ++it) + { + if (it->first == x) + return std::make_pair(const_iterator(buckets, buckets.begin() + index, it), const_iterator(buckets, buckets.begin() + index, it)); + } + + return std::make_pair(end(), end()); + } + +#pragma endregion Lookup + +#pragma region Bucket Interface + + local_iterator begin(size_type n) + { + return buckets[n].begin(); + } + + const_local_iterator begin(size_type n) const + { + return buckets[n].begin(); + } + + const_local_iterator cbegin(size_type n) const + { + return buckets[n].begin(); + } + + local_iterator end(size_type n) + { + return buckets[n].end(); + } + + const_local_iterator end(size_type n) const + { + return buckets[n].end(); + } + + const_local_iterator cend(size_type n) const + { + return buckets[n].end(); + } + + size_type bucket_count() const + { + return buckets.size(); + } + + size_type max_bucket_count() const + { + return buckets.max_size(); + } + + size_type bucket_size(size_type n) const + { + if (n >= buckets.size()) + return 0; + + return buckets[n].size(); + } + + size_type bucket(const Key &key) const + { + assert(!buckets.empty()); + + return hashFunction(key) % buckets.size(); + } + +#pragma endregion Bucket Interface + +#pragma region Hash Policy + + float load_factor() const + { + return static_cast(size()) / static_cast(bucket_count()); + } + + float max_load_factor() const + { + return maxLoadFactor; + } + + void max_load_factor(float ml) + { + maxLoadFactor = ml; + } + + void rehash(size_type count) + { + debug("Rehashing to %d", count); + + size_type currentLoadFactor = size() / max_load_factor(); + if (count < currentLoadFactor) + { + debug("count %d => %d", count, currentLoadFactor); + count = currentLoadFactor; + } + + std::vector newBuckets(count); + for (const auto &bucket : buckets) + { + for (const auto &element : bucket) { - ++bucketIndex; - if (bucketIndex < buckets->size()) - { - bucketIterator = (*buckets)[bucketIndex].begin(); - } - } - - return *this; - } - - bool operator!=(const iterator &other) const - { - return bucketIndex != other.bucketIndex || - bucketIterator != other.bucketIterator; - } - - pair_t &operator*() - { - return *bucketIterator; - } - - pair_t *operator->() - { - return &(*bucketIterator); - } - - operator bool() const - { - return bucketIndex < buckets->size(); - } - }; - - iterator find(const Key &key) - { - SmartLock(this->lock); - size_t bucketIndex = hash(key) % Buckets.size(); - auto &bucket = Buckets[bucketIndex]; - - auto it = std::find_if(bucket.begin(), bucket.end(), - [key](const pair_t &element) - { return element.first == key; }); - - if (it != bucket.end()) - { - return iterator(bucketIndex, - it, - &Buckets); - } - - return end(); - } - - iterator begin() - { - SmartLock(this->lock); - for (size_t i = 0; i < Buckets.size(); ++i) - { - if (!Buckets[i].empty()) - { - return iterator(i, - Buckets[i].begin(), - &Buckets); + size_type newIndex = hashFunction(element.first) % count; + newBuckets[newIndex].push_back(element); } } - return end(); + buckets = std::move(newBuckets); } - iterator end() + void reserve(size_type count) { - return iterator(Buckets.size(), - Buckets.back().end(), - &Buckets); + rehash(std::ceil(count / max_load_factor())); } - iterator insert(iterator pos, const pair_t &p) +#pragma endregion Hash Policy + +#pragma region Observers + + hasher hash_function() const { - SmartLock(this->lock); - size_t bucketIndex = hash(p.first) % Buckets.size(); - auto &bucket = Buckets[bucketIndex]; - - auto itr = std::find_if(bucket.begin(), bucket.end(), - [p](const pair_t &element) - { return element.first == p.first; }); - - if (itr != bucket.end()) - return end(); - - return iterator(bucketIndex, - bucket.insert(pos.bucketIterator, p), - &Buckets); + return hashFunction; } - iterator erase(iterator pos) + key_equal key_eq() const { - SmartLock(this->lock); - size_t bucketIndex = pos.GetBucketIndex(); - auto &bucket = Buckets[bucketIndex]; - - return iterator(bucketIndex, - bucket.erase(pos.GetBucketIterator()), - &Buckets); + return key_equal(); } + +#pragma endregion Observers }; + + template + bool operator==(const std::unordered_map &lhs, + const std::unordered_map &rhs) + { + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } } diff --git a/include_std/utility b/include_std/utility index b360738..eddae2f 100644 --- a/include_std/utility +++ b/include_std/utility @@ -18,37 +18,235 @@ #pragma once #include +#include +#include namespace std { + struct piecewise_construct_t + { + explicit piecewise_construct_t() = default; + }; + + inline constexpr std::piecewise_construct_t piecewise_construct{}; + template typename std::remove_reference::type &&move(T &&arg) { return static_cast::type &&>(arg); } + template + void __utility_swap(T &a, T &b) + { + T temp = std::move(a); + a = std::move(b); + b = std::move(temp); + } + + template + class integer_sequence + { + public: + typedef T value_type; + + static constexpr std::size_t size() noexcept { return sizeof...(Ints); } + }; + + template + using index_sequence = std::integer_sequence; + + template + using make_integer_sequence = std::integer_sequence; + + template + using make_index_sequence = std::make_integer_sequence; + + template + using index_sequence_for = std::make_index_sequence; + + template + constexpr T &&forward(std::remove_reference_t &t) noexcept + { + return static_cast(t); + } + + template + constexpr T &&forward(std::remove_reference_t &&t) noexcept + { + static_assert(!std::is_lvalue_reference::value, "Can't forward an rvalue as an lvalue."); + return static_cast(t); + } + template struct pair { typedef T1 first_type; typedef T2 second_type; - T1 first; - T2 second; + first_type first; + second_type second; - pair() : first(T1()), second(T2()) {} - pair(const T1 &x, const T2 &y) : first(x), second(y) {} + template ::value && + std::is_default_constructible::value, + int>::type = true> + constexpr pair() + : first(), + second() + { + } + + template ::value || + !std::is_default_constructible::value, + int>::type = false> + explicit constexpr pair() + : first(), + second() + { + } + + template ::value && + std::is_copy_constructible::value, + int>::type = true> + constexpr pair(const T1 &x, const T2 &y) + : first(x), + second(y) + { + } + + template ::value || + !std::is_copy_constructible::value, + int>::type = false> + explicit constexpr pair(const T1 &x, const T2 &y) + : first(x), + second(y) + { + } + + template ::value && + std::is_move_constructible::value, + int>::type = true> + constexpr pair(U1 &&x, U2 &&y) + : first(std::forward(x)), + second(std::forward(y)) + { + } + + template ::value || + !std::is_move_constructible::value, + int>::type = false> + explicit constexpr pair(T1 &&x, T2 &&y) + : first(std::forward(x)), + second(std::forward(y)){}; + + template ::value && + std::is_copy_constructible::value, + int>::type = true> + constexpr pair(const pair &p) + : first(p.first), + second(p.second) + { + } + + template ::value || + !std::is_copy_constructible::value, + int>::type = false> + explicit constexpr pair(const pair &p) + : first(p.first), + second(p.second) + { + } + + template ::value && + std::is_move_constructible::value, + int>::type = true> + constexpr pair(pair &&p) + : first(std::forward(p.first)), + second(std::forward(p.second)) + { + } + + template ::value || + !std::is_move_constructible::value, + int>::type = false> + explicit constexpr pair(pair &&p) + : first(std::forward(p.first)), + second(std::forward(p.second)) + { + } + + template + constexpr pair(std::piecewise_construct_t, std::tuple first_args, std::tuple second_args) + : pair(first_args, second_args, std::index_sequence_for(), std::index_sequence_for()) + { + } + + pair(const pair &p) = default; + pair(pair &&p) = default; + + constexpr pair &operator=(const pair &other) + { + first = other.first; + second = other.second; + return *this; + } + + template + constexpr pair &operator=(const pair &other) + { + first = other.first; + second = other.second; + return *this; + } + + constexpr pair &operator=(pair &&other) noexcept(std::is_nothrow_move_assignable::value && std::is_nothrow_move_assignable::value) + { + first = std::move(other.first); + second = std::move(other.second); + return *this; + } + + template + constexpr pair &operator=(pair &&p) + { + first = std::forward(p.first); + second = std::forward(p.second); + return *this; + } + + constexpr void swap(pair &other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) + { + __utility_swap(first, other.first); + __utility_swap(second, other.second); + } }; - template - pair make_pair(T1 x, T2 y) + template + std::pair::type, typename std::decay::type> make_pair(T1 &&t, T2 &&u) { - return pair(x, y); + typedef typename std::decay::type first_type; + typedef typename std::decay::type second_type; + typedef pair pair_type; + return pair_type(std::forward(t), std::forward(u)); } - - template - T &&forward(typename std::remove_reference::type &arg) - { - return static_cast(arg); - } -} +} \ No newline at end of file diff --git a/include_std/vector b/include_std/vector index e528e7f..fb61fb0 100644 --- a/include_std/vector +++ b/include_std/vector @@ -17,376 +17,1007 @@ #pragma once -#include - -#include -#include +#include +#include #include -#include -#include -#include -#include - -// #define DEBUG_VECTOR_MESSAGES 1 - -#ifdef DEBUG_VECTOR_MESSAGES -#define vDebug(m, ...) debug("%#lx: " m, this, ##__VA_ARGS__) -#else -#define vDebug(m, ...) -#endif +#include +#include namespace std { - template + template > class vector { + public: + using value_type = T; + using allocator_type = Allocator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + // using iterator = typename vector::iterator; + // using const_iterator = typename vector::const_iterator; + // using reverse_iterator = typename vector::reverse_iterator; + // using const_reverse_iterator = typename vector::const_reverse_iterator; + + class iterator + { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T *; + using reference = T &; + using iterator_category = std::random_access_iterator_tag; + + public: + pointer itrPtr; + + public: + constexpr iterator() noexcept : itrPtr(nullptr) {} + constexpr iterator(pointer ptr) noexcept : itrPtr(ptr) {} + constexpr iterator(const iterator &other) noexcept : itrPtr(other.itrPtr) {} + constexpr iterator(iterator &&other) noexcept : itrPtr(other.itrPtr) {} + + constexpr reference operator*() const { return *itrPtr; } + constexpr pointer operator->() const { return itrPtr; } + + constexpr iterator &operator=(const iterator &other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr iterator &operator=(iterator &&other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr iterator &operator++() + { + itrPtr++; + return *this; + } + + constexpr iterator operator++(int) + { + iterator temp = *this; + itrPtr++; + return temp; + } + + constexpr iterator &operator--() + { + itrPtr--; + return *this; + } + + constexpr iterator operator--(int) + { + iterator temp = *this; + itrPtr--; + return temp; + } + + constexpr difference_type operator-(const iterator &other) const + { + return itrPtr - other.itrPtr; + } + + constexpr iterator operator+(difference_type n) const + { + return iterator(itrPtr + n); + } + + constexpr bool operator==(const iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const iterator &other) const { return itrPtr != other.itrPtr; } + }; + + class const_iterator + { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T *; + using reference = const T &; + using iterator_category = std::random_access_iterator_tag; + + public: + pointer itrPtr; + + public: + constexpr const_iterator() noexcept : itrPtr(nullptr) {} + constexpr const_iterator(pointer ptr) noexcept : itrPtr(ptr) {} + constexpr const_iterator(iterator it) noexcept : itrPtr(it.itrPtr) {} + constexpr const_iterator(const const_iterator &other) noexcept : itrPtr(other.itrPtr) {} + constexpr const_iterator(const_iterator &&other) noexcept : itrPtr(other.itrPtr) {} + + constexpr reference operator*() const { return *itrPtr; } + constexpr pointer operator->() const { return itrPtr; } + + constexpr const_iterator &operator=(const const_iterator &other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr const_iterator &operator=(const_iterator &&other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr const_iterator &operator++() + { + itrPtr++; + return *this; + } + + constexpr const_iterator operator++(int) + { + const_iterator temp = *this; + itrPtr++; + return temp; + } + + constexpr const_iterator &operator--() + { + itrPtr--; + return *this; + } + + constexpr const_iterator operator--(int) + { + const_iterator temp = *this; + itrPtr--; + return temp; + } + + constexpr difference_type operator-(const const_iterator &other) const + { + return itrPtr - other.itrPtr; + } + + constexpr const_iterator operator+(difference_type n) const + { + return const_iterator(itrPtr + n); + } + + constexpr bool operator==(const const_iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const const_iterator &other) const { return itrPtr != other.itrPtr; } + }; + + class reverse_iterator + { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T *; + using reference = T &; + using iterator_category = std::random_access_iterator_tag; + + public: + pointer itrPtr; + + public: + constexpr reverse_iterator() noexcept : itrPtr(nullptr) {} + constexpr reverse_iterator(pointer ptr) noexcept : itrPtr(ptr) {} + constexpr reverse_iterator(const reverse_iterator &other) noexcept : itrPtr(other.itrPtr) {} + constexpr reverse_iterator(reverse_iterator &&other) noexcept : itrPtr(other.itrPtr) {} + + constexpr reference operator*() const { return *itrPtr; } + constexpr pointer operator->() const { return itrPtr; } + + constexpr reverse_iterator &operator=(const reverse_iterator &other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr reverse_iterator &operator=(reverse_iterator &&other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr reverse_iterator &operator++() + { + itrPtr--; + return *this; + } + + constexpr reverse_iterator operator++(int) + { + reverse_iterator temp = *this; + itrPtr--; + return temp; + } + + constexpr reverse_iterator &operator--() + { + itrPtr++; + return *this; + } + + constexpr reverse_iterator operator--(int) + { + reverse_iterator temp = *this; + itrPtr++; + return temp; + } + + constexpr difference_type operator-(const reverse_iterator &other) const + { + return itrPtr - other.itrPtr; + } + + constexpr reverse_iterator operator+(difference_type n) const + { + return reverse_iterator(itrPtr - n); + } + + constexpr bool operator==(const reverse_iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const reverse_iterator &other) const { return itrPtr != other.itrPtr; } + + constexpr bool operator==(const const_iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const const_iterator &other) const { return itrPtr != other.itrPtr; } + + constexpr bool operator==(const iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const iterator &other) const { return itrPtr != other.itrPtr; } + }; + + class const_reverse_iterator + { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T *; + using reference = const T &; + using iterator_category = std::random_access_iterator_tag; + + public: + pointer itrPtr; + + public: + constexpr const_reverse_iterator() noexcept : itrPtr(nullptr) {} + constexpr const_reverse_iterator(pointer ptr) noexcept : itrPtr(ptr) {} + constexpr const_reverse_iterator(const const_reverse_iterator &other) noexcept : itrPtr(other.itrPtr) {} + constexpr const_reverse_iterator(const_reverse_iterator &&other) noexcept : itrPtr(other.itrPtr) {} + + constexpr reference operator*() const { return *itrPtr; } + constexpr pointer operator->() const { return itrPtr; } + + constexpr const_reverse_iterator &operator=(const const_reverse_iterator &other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr const_reverse_iterator &operator=(const_reverse_iterator &&other) + { + itrPtr = other.itrPtr; + return *this; + } + + constexpr const_reverse_iterator &operator++() + { + itrPtr--; + return *this; + } + + constexpr const_reverse_iterator operator++(int) + { + const_reverse_iterator temp = *this; + itrPtr--; + return temp; + } + + constexpr const_reverse_iterator &operator--() + { + itrPtr++; + return *this; + } + + constexpr const_reverse_iterator operator--(int) + { + const_reverse_iterator temp = *this; + itrPtr++; + return temp; + } + + constexpr difference_type operator-(const const_reverse_iterator &other) const + { + return itrPtr - other.itrPtr; + } + + constexpr const_reverse_iterator operator+(difference_type n) const + { + return const_reverse_iterator(itrPtr - n); + } + + constexpr bool operator==(const const_reverse_iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const const_reverse_iterator &other) const { return itrPtr != other.itrPtr; } + + constexpr bool operator==(const reverse_iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const reverse_iterator &other) const { return itrPtr != other.itrPtr; } + + constexpr bool operator==(const const_iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const const_iterator &other) const { return itrPtr != other.itrPtr; } + + constexpr bool operator==(const iterator &other) const { return itrPtr == other.itrPtr; } + constexpr bool operator!=(const iterator &other) const { return itrPtr != other.itrPtr; } + }; + private: - NewLock(lock); - std::atomic_size_t VectorSize = 0; - std::atomic_size_t VectorCapacity = 0; - T *VectorBuffer = nullptr; + allocator_type _alloc; + size_type _size; + size_type _capacity; + pointer _data; public: - typedef T *iterator; - typedef const T *const_iterator; +#pragma region Member Functions - vector() { vDebug("( empty init )"); } - - vector(size_t Size) - : VectorSize(Size), - VectorCapacity(Size), - VectorBuffer(new T[Size]) + constexpr vector() noexcept(noexcept(Allocator())) + : _size(0), + _capacity(0), + _data(nullptr) { - vDebug("( init w/size: %lld )", Size); } - vector(size_t Size, const T &Initial) - : VectorSize(Size), - VectorCapacity(Size), - VectorBuffer(new T[Size]) + constexpr explicit vector(const Allocator &alloc) noexcept + : _alloc(alloc), + _size(0), + _capacity(0), + _data(nullptr) { - vDebug("( init w/size: %lld, initial vector: %llx )", - Size, Initial); - - assert(Size > 0); - - SmartLock(this->lock); - for (size_t i = 0; i < Size; i++) - VectorBuffer[i] = Initial; } - vector(const vector &v) - : VectorSize(v.VectorSize.load()), - VectorCapacity(v.VectorCapacity.load()), - VectorBuffer(nullptr) + constexpr vector(size_type count, const T &value, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(count), + _capacity(count), + _data(_alloc.allocate(count)) { - vDebug("( vector copy: %#lx )", &v); + for (size_type i = 0; i < count; i++) + std::allocator_traits::construct(_alloc, _data + i, value); + } - if (!v.VectorBuffer || VectorSize.load() <= 0) + constexpr explicit vector(size_type count, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(count), + _capacity(count), + _data(_alloc.allocate(count)) + { + for (size_type i = 0; i < count; i++) + std::allocator_traits::construct(_alloc, _data + i); + } + + /* FIXME: this conflicts with the above constructors */ + // template + // constexpr vector(InputIt first, InputIt last, const Allocator &alloc = Allocator()) + // { + // _alloc = alloc; + // _size = last - first; + // _capacity = last - first; + // _data = _alloc.allocate(_size); + // for (size_type i = 0; i < _size; i++) + // std::allocator_traits::construct(_alloc, _data + i, *(first + i)); + // } + + constexpr vector(const vector &other) + : _alloc(other._alloc), + _size(other._size), + _capacity(other._capacity), + _data(_alloc.allocate(_size)) + { + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, other._data[i]); + } + + constexpr vector(const vector &other, const Allocator &alloc) + : _alloc(other._alloc), + _size(other._size), + _capacity(other._capacity), + _data(_alloc.allocate(_size)) + { + + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, other._data[i]); + } + + constexpr vector(vector &&other) noexcept + : _alloc(std::move(other._alloc)), + _size(other._size), + _capacity(other._capacity), + _data(other._data) + { + other._size = 0; + other._capacity = 0; + other._data = nullptr; + } + + constexpr vector(vector &&other, const Allocator &alloc) + : _alloc(alloc), + _size(other._size), + _capacity(other._capacity), + _data(other._data) + { + other._size = 0; + other._capacity = 0; + other._data = nullptr; + } + + constexpr vector(std::initializer_list init, const Allocator &alloc = Allocator()) + : _alloc(alloc), + _size(init.size()), + _capacity(init.size()), + _data(_alloc.allocate(_size)) + { + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, *(init.begin() + i)); + } + + constexpr ~vector() + { + if (_capacity == 0 || _data == nullptr) return; + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); - SmartLock(this->lock); - VectorBuffer = new T[VectorSize.load()]; - std::copy(v.VectorBuffer, v.VectorBuffer + VectorSize.load(), VectorBuffer); + _alloc.deallocate(_data, _size); } - ~vector() + constexpr vector &operator=(const vector &other) { - vDebug("( deinit )"); - - VectorSize.store(0); - VectorCapacity.store(0); - - SmartLock(this->lock); - - if (VectorBuffer != nullptr) - { - delete[] VectorBuffer; - VectorBuffer = nullptr; - } - } - - void erase(iterator Position) - { - vDebug("Erasing element at position %lld (v. size: %lld)", - Position - this->VectorBuffer, this->VectorSize.load()); - - if (Position == this->end()) - { - warn("%#lx: Cannot erase element at end of vector (not found if std::find is used)", - this); - return; - } - - assert(Position <= this->end()); - assert(Position >= this->VectorBuffer); - assert(Position < this->VectorBuffer + this->VectorSize.load()); - - SmartLock(this->lock); - size_t index = Position - this->VectorBuffer; - - if (std::is_trivially_copyable::value) - { - this->VectorBuffer[index] = T(); - vDebug("%#lx is trivially copyable", - &this->VectorBuffer[index]); - } - else - { - this->VectorBuffer[index].~T(); - vDebug("%#lx is not trivially copyable", - &this->VectorBuffer[index]); - } - - for (size_t i = index; i < this->VectorSize.load() - 1; ++i) - { - this->VectorBuffer[i] = std::move(this->VectorBuffer[i + 1]); - } - this->VectorSize--; - } - - T &next(size_t Position) - { - SmartLock(this->lock); - - if (Position + 1 < this->VectorSize.load()) - return this->VectorBuffer[Position + 1]; - - warn("%#lx: next( %lld ) is null (requested by %#lx)", this, - Position, __builtin_return_address(0)); - - return {}; - } - - T &prev(size_t Position) - { - SmartLock(this->lock); - - if (Position > 0) - return this->VectorBuffer[Position - 1]; - - warn("%#lx: prev( %lld ) is null (requested by %#lx)", this, - Position, __builtin_return_address(0)); - - return {}; - } - - T &next(const T &Value) - { - SmartLock(this->lock); - - for (size_t i = 0; i < this->VectorSize.load(); i++) - { - if (std::equal_to()(this->VectorBuffer[i], Value)) - { - if (i + 1 < this->VectorSize.load()) - return this->VectorBuffer[i + 1]; - else - break; - } - } - - warn("%#lx: next( %#lx ) is null (requested by %#lx)", this, - Value, __builtin_return_address(0)); - - return {}; - } - - T &prev(const T &Value) - { - SmartLock(this->lock); - - for (size_t i = 0; i < this->VectorSize.load(); i++) - { - if (std::equal_to()(this->VectorBuffer[i], Value)) - { - if (i > 0) - return this->VectorBuffer[i - 1]; - else - break; - } - } - - warn("%#lx: prev( %#lx ) is null (requested by %#lx)", this, - Value, __builtin_return_address(0)); - - return {}; - } - - void push_back(const T &Value) - { - vDebug("push_back( %#lx )", Value); - - if (this->VectorSize.load() >= this->VectorCapacity.load()) - { - size_t newCapacity = this->VectorCapacity.load() == 0 - ? 1 - : this->VectorCapacity.load() * 2; - reserve(newCapacity); - } - - SmartLock(this->lock); - this->VectorBuffer[this->VectorSize++] = Value; - } - - template - void emplace_back(Args &&...args) - { - vDebug("emplace_back( %#lx )", args...); - - if (this->VectorSize.load() >= this->VectorCapacity.load()) - { - size_t newCapacity = this->VectorCapacity.load() == 0 - ? 1 - : this->VectorCapacity.load() * 2; - reserve(newCapacity); - } - - SmartLock(this->lock); - this->VectorBuffer[this->VectorSize++] = T(std::forward(args)...); - } - - void reverse() - { - if (this->VectorSize.load() <= 1) - return; - - SmartLock(this->lock); - for (size_t i = 0, j = this->VectorSize.load() - 1; i < j; i++, j--) - { - T &elem1 = this->VectorBuffer[i]; - T &elem2 = this->VectorBuffer[j]; - std::swap(elem1, elem2); - } - } - - void reserve(size_t Capacity) - { - assert(!(Capacity <= VectorCapacity.load())); - - SmartLock(this->lock); - - T *NewBuffer = new T[Capacity]; - size_t Size = std::min(Capacity, this->VectorSize.load()); - for (size_t i = 0; i < Size; i++) - NewBuffer[i] = std::move(this->VectorBuffer[i]); - - vDebug("reserve( %lld )->Buffer:~%#lx", - Capacity, this->VectorBuffer); - - delete[] this->VectorBuffer; - this->VectorBuffer = NewBuffer; - this->VectorCapacity.store(Capacity); - } - - void resize(size_t Size) - { - reserve(Size); - this->VectorSize.store(Size); - } - - void resize(size_t count, const T &value) - { - reserve(count); - for (size_t i = this->VectorSize.load(); i < count; i++) - this->VectorBuffer[i] = value; - this->VectorSize.store(count); - } - - void clear() - { - this->VectorCapacity.store(0); - this->VectorSize.store(0); - - SmartLock(this->lock); - if (VectorBuffer != nullptr) - { - delete[] this->VectorBuffer; - this->VectorBuffer = nullptr; - } - } - - T &operator[](size_t Index) - { - SmartLock(this->lock); - if (Index >= this->VectorSize.load() || !this->VectorBuffer) - { - warn("%#lx: operator[]( %lld ) is null (requested by %#lx)", this, - Index, __builtin_return_address(0)); - - static T null_elem{}; - return null_elem; - } - return this->VectorBuffer[Index]; - } - - vector &operator=(const vector &v) - { - SmartLock(this->lock); - - if (this == &v) + if (this == &other) return *this; - delete[] this->VectorBuffer; - this->VectorSize.store(v.VectorSize.load()); - this->VectorCapacity.store(v.VectorCapacity.load()); + if (_capacity != 0 && _data != nullptr) + { + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); - vDebug("operator=( )->Size:%lld", - this->VectorSize.load()); + _alloc.deallocate(_data, _size); + } - this->VectorBuffer = new T[this->VectorSize.load()]; - for (size_t i = 0; i < this->VectorSize.load(); i++) - this->VectorBuffer[i] = v.VectorBuffer[i]; + _size = other._size; + _capacity = other._capacity; + _data = _alloc.allocate(_size); + + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, other._data[i]); return *this; } - void pop_back() { this->VectorSize--; } - - T &front() + constexpr vector &operator=(vector &&other) /* noexcept(_alloc.propagate_on_container_move_assignment::value || _alloc.is_always_equal::value) */ { - SmartLock(this->lock); - return this->VectorBuffer[0]; + if (this == &other) + return *this; + + if (_capacity != 0 && _data != nullptr) + { + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + _alloc.deallocate(_data, _size); + } + + _size = other._size; + _capacity = other._capacity; + _data = other._data; + other._size = 0; + other._capacity = 0; + other._data = nullptr; + + return *this; } - T &back() + constexpr vector &operator=(std::initializer_list ilist) { - SmartLock(this->lock); - return this->VectorBuffer[this->VectorSize.load() - 1]; + _size = ilist.size(); + _capacity = ilist.size(); + _data = _alloc.allocate(_size); + + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, *(ilist.begin() + i)); + + return *this; } - T *data() + constexpr void assign(size_type count, const T &value) { - SmartLock(this->lock); - return this->VectorBuffer; + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + if (_data != nullptr) + _alloc.deallocate(_data, _size); + + _size = count; + _capacity = count; + _data = _alloc.allocate(_size); + + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, value); } - bool empty() const { return this->VectorSize.load() == 0; } - size_t capacity() const { return this->VectorCapacity.load(); } - size_t size() const { return this->VectorSize.load(); } - - iterator begin() + template + constexpr void assign(InputIt first, InputIt last) { - SmartLock(this->lock); - return this->VectorBuffer; + if (_capacity != 0 && _data != nullptr) + { + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + _alloc.deallocate(_data, _size); + } + + _size = last - first; + _capacity = last - first; + _data = _alloc.allocate(_size); + + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, *(first + i)); } - iterator end() + constexpr void assign(std::initializer_list ilist) { - SmartLock(this->lock); - return this->VectorBuffer + size(); + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + if (_data != nullptr) + _alloc.deallocate(_data, _size); + + _size = ilist.size(); + _capacity = ilist.size(); + _data = _alloc.allocate(_size); + + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, _data + i, *(ilist.begin() + i)); } - const_iterator begin() const + constexpr allocator_type get_allocator() const noexcept { - SmartLock(this->lock); - return this->VectorBuffer; + return _alloc; } - const_iterator end() const +#pragma endregion Member Functions + +#pragma region Element Access + + reference at(size_type pos) { - SmartLock(this->lock); - return this->VectorBuffer + size(); + if (pos >= _size) + throw std::out_of_range("vector::at"); + + return _data[pos]; } + + const_reference at(size_type pos) const + { + if (pos >= _size) + throw std::out_of_range("vector::at"); + + return _data[pos]; + } + + reference operator[](size_type pos) + { + return _data[pos]; + } + + const_reference operator[](size_type pos) const + { + return _data[pos]; + } + + reference front() + { + return _data[0]; + } + + const_reference front() const + { + return _data[0]; + } + + reference back() + { + return _data[_size - 1]; + } + + const_reference back() const + { + return _data[_size - 1]; + } + + constexpr T *data() noexcept + { + return _data; + } + + constexpr const T *data() const + { + return _data; + } + +#pragma endregion Element Access + +#pragma region Iterators + + constexpr iterator begin() + { + return iterator(_data); + } + + constexpr const_iterator begin() const + { + return const_iterator(_data); + } + + constexpr const_iterator cbegin() const noexcept + { + return const_iterator(_data); + } + + constexpr iterator end() noexcept + { + return iterator(_data + _size); + } + + constexpr const_iterator end() const noexcept + { + return const_iterator(_data + _size); + } + + constexpr const_iterator cend() const noexcept + { + return const_iterator(_data + _size); + } + + constexpr reverse_iterator rbegin() + { + return reverse_iterator(_data + _size - 1); + } + + constexpr const_reverse_iterator rbegin() const + { + return const_reverse_iterator(_data + _size - 1); + } + + constexpr const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(_data + _size - 1); + } + + constexpr iterator rend() noexcept + { + return iterator(_data - 1); + } + + constexpr const_iterator rend() const noexcept + { + return const_iterator(_data - 1); + } + + constexpr const_iterator crend() const noexcept + { + return const_iterator(_data - 1); + } + +#pragma endregion Iterators + +#pragma region Capacity + + [[nodiscard]] constexpr bool empty() const noexcept + { + return _size == 0; /* begin() == end() */ + } + + constexpr size_type size() const noexcept + { + return _size; /* std::distance(begin(), end()) */ + } + + constexpr size_type max_size() const noexcept + { + return std::numeric_limits::max(); + } + + constexpr void reserve(size_type new_cap) + { + if (new_cap <= _capacity) + return; + + pointer new_data = _alloc.allocate(new_cap); + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, new_data + i, _data[i]); + + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + if (_data != nullptr) + _alloc.deallocate(_data, _size); + + _data = new_data; + _capacity = new_cap; + } + + constexpr size_type capacity() const noexcept + { + return _capacity; + } + + constexpr void shrink_to_fit() + { + if (_size >= _capacity) + return; + + pointer new_data = _alloc.allocate(_size); + for (size_type i = 0; i < _size; i++) + std::allocator_traits::construct(_alloc, new_data + i, _data[i]); + + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + if (_data != nullptr) + _alloc.deallocate(_data, _size); + _data = new_data; + _capacity = _size; + } + +#pragma endregion Capacity + +#pragma region Modifiers + + constexpr void clear() noexcept + { + for (size_type i = 0; i < _size; i++) + _data[i].~value_type(); + + _size = 0; + } + + constexpr iterator insert(const_iterator pos, const T &value) + { + size_type index = pos - begin(); + if (_size == _capacity) + reserve(_capacity * 2); + + for (size_type i = _size; i > index; i--) + _data[i] = _data[i - 1]; + + _data[index] = value; + _size++; + return iterator(_data + index); + } + + constexpr iterator insert(const_iterator pos, size_type count, const T &value) + { + size_type index = pos - begin(); + if (_size + count > _capacity) + reserve(_capacity + count); + + for (size_type i = _size + count - 1; i > index + count - 1; i--) + _data[i] = _data[i - count]; + + for (size_type i = index; i < index + count; i++) + _data[i] = value; + + _size += count; + return iterator(_data + index); + } + template + constexpr iterator insert(const_iterator pos, InputIt first, InputIt last) + { + size_type index = pos - begin(); + size_type count = last - first; + if (_size + count > _capacity) + reserve(_capacity + count); + + for (size_type i = _size + count - 1; i > index + count - 1; i--) + _data[i] = _data[i - count]; + + for (size_type i = index; i < index + count; i++) + _data[i] = *(first + i - index); + + _size += count; + return iterator(_data + index); + } + + constexpr iterator insert(const_iterator pos, + std::initializer_list ilist) + { + size_type index = pos - begin(); + size_type count = ilist.size(); + if (_size + count > _capacity) + reserve(_capacity + count); + + for (size_type i = _size + count - 1; i > index + count - 1; i--) + _data[i] = _data[i - count]; + + for (size_type i = index; i < index + count; i++) + _data[i] = *(ilist.begin() + i - index); + + _size += count; + return iterator(_data + index); + } + + template + constexpr iterator emplace(const_iterator pos, Args &&...args) + { + size_type index = pos - begin(); + if (_size == _capacity) + reserve(_capacity * 2); + + for (size_type i = _size; i > index; i--) + _data[i] = _data[i - 1]; + + std::allocator_traits::construct(_alloc, _data + index, std::forward(args)...); + _size++; + return iterator(_data + index); + } + + constexpr iterator erase(const_iterator pos) + { + size_type index = pos - cbegin(); + for (size_type i = index; i < _size - 1; i++) + _data[i] = _data[i + 1]; + + _data[_size - 1].~value_type(); + _size--; + return iterator(_data + index); + } + + constexpr iterator erase(const_iterator first, const_iterator last) + { + size_type index = first - cbegin(); + size_type count = last - first; + for (size_type i = index; i < _size - count; i++) + _data[i] = _data[i + count]; + + for (size_type i = _size - count; i < _size; i++) + _data[i].~value_type(); + + _size -= count; + return iterator(_data + index); + } + + constexpr void push_back(const T &value) + { + if (_capacity == 0) + reserve(sizeof(T) * 2); + + if (_size == _capacity) + reserve(_capacity * 2); + + _data[_size] = value; + _size++; + } + + constexpr void push_back(T &&value) + { + if (_capacity == 0) + reserve(sizeof(T) * 2); + + if (_size == _capacity) + reserve(_capacity * 2); + + _data[_size] = std::move(value); + _size++; + } + + template + constexpr reference emplace_back(Args &&...args) + { + if (_size == _capacity) + reserve(_capacity * 2); + + std::allocator_traits::construct(_alloc, _data + _size, std::forward(args)...); + _size++; + return _data[_size - 1]; + } + + constexpr void pop_back() + { + _data[_size - 1].~value_type(); + _size--; + } + + constexpr void resize(size_type count) + { + if (count > _size) + { + if (count > _capacity) + reserve(count); + + for (size_type i = _size; i < count; i++) + std::allocator_traits::construct(_alloc, _data + i); + } + else + { + for (size_type i = count; i < _size; i++) + _data[i].~value_type(); + } + _size = count; + } + + constexpr void resize(size_type count, const value_type &value) + { + if (count > _size) + { + if (count > _capacity) + reserve(count); + + for (size_type i = _size; i < count; i++) + std::allocator_traits::construct(_alloc, _data + i, value); + } + else + { + for (size_type i = count; i < _size; i++) + _data[i].~value_type(); + } + _size = count; + } + + constexpr void swap(vector &other) /* noexcept(_alloc.propagate_on_container_swap::value || _alloc.is_always_equal::value) */ + { + size_type temp_size = _size; + size_type temp_capacity = _capacity; + pointer temp_data = _data; + + _size = other._size; + _capacity = other._capacity; + _data = other._data; + + other._size = temp_size; + other._capacity = temp_capacity; + other._data = temp_data; + } + +#pragma endregion Modifiers }; + + template + constexpr bool operator==(const std::vector &lhs, const std::vector &rhs) + { + if (lhs.size() != rhs.size()) + { + return false; + } + for (size_t i = 0; i < lhs.size(); i++) + { + if (lhs[i] != rhs[i]) + { + return false; + } + } + return true; + } + + template + constexpr void swap(std::vector &lhs, std::vector &rhs) noexcept(noexcept(noexcept(lhs.swap(rhs)))) + { + lhs.swap(rhs); + } + + template + constexpr std::vector::size_type erase(std::vector &c, const U &value) + { + auto it = std::remove(c.begin(), c.end(), value); + auto r = c.end() - it; + c.erase(it, c.end()); + return r; + } + + template + constexpr std::vector::size_type erase_if(std::vector &c, Pred pred) + { + auto it = std::remove_if(c.begin(), c.end(), pred); + auto r = c.end() - it; + c.erase(it, c.end()); + return r; + } } diff --git a/kernel.cpp b/kernel.cpp index 22ae66d..887ae5c 100644 --- a/kernel.cpp +++ b/kernel.cpp @@ -37,9 +37,6 @@ bool DebuggerIsAttached = false; extern bool EnableProfiler; NewLock(KernelLock); -using vfs::Node; -using vfs::NodeType; - __aligned(16) BootInfo bInfo{}; struct KernelConfig Config = { @@ -62,6 +59,7 @@ Power::Power *PowerManager = nullptr; Time::time *TimeManager = nullptr; Tasking::Task *TaskManager = nullptr; PCI::Manager *PCIManager = nullptr; +Driver::Manager *DriverManager = nullptr; EXTERNC void putchar(char c) { @@ -264,8 +262,8 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info) // https://wiki.osdev.org/Calling_Global_Constructors trace("There are %d constructors to call", __init_array_end - __init_array_start); - for (CallPtr *func = __init_array_start; func != __init_array_end; func++) - (*func)(); + for (CallPtr *fct = __init_array_start; fct != __init_array_end; fct++) + (*fct)(); #ifdef a86 if (!bInfo.SMBIOSPtr) @@ -347,8 +345,7 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info) * memory management to be initialized first. */ TestMemoryAllocation(); - TestString(); - Test_std(); + Test_stl(); #endif EnableProfiler = true; Main(); @@ -366,12 +363,6 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot) KPrint("%s...", Reboot ? "Rebooting" : "Shutting down"); KPrint("Stopping network interfaces"); - if (NIManager) - delete NIManager, NIManager = nullptr; - - KPrint("Stopping disk manager"); - if (DiskManager) - delete DiskManager, DiskManager = nullptr; KPrint("Unloading all drivers"); if (DriverManager) @@ -396,8 +387,8 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot) // https://wiki.osdev.org/Calling_Global_Constructors KPrint("Calling destructors"); - for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++) - (*func)(); + for (CallPtr *fct = __fini_array_start; fct != __fini_array_end; fct++) + (*fct)(); __cxa_finalize(nullptr); debug("Done."); } diff --git a/kernel.h b/kernel.h index 7b0cce7..3b37da8 100644 --- a/kernel.h +++ b/kernel.h @@ -49,16 +49,9 @@ extern Power::Power *PowerManager; extern Time::time *TimeManager; extern PCI::Manager *PCIManager; extern vfs::Virtual *fs; -extern vfs::Node *DevFS; -extern vfs::Node *MntFS; -extern vfs::Node *ProcFS; -extern vfs::Node *VarLogFS; -extern vfs::PTMXDevice *ptmx; extern Tasking::Task *TaskManager; -extern Disk::Manager *DiskManager; extern Driver::Manager *DriverManager; -extern NetworkInterfaceManager::NetworkInterface *NIManager; #endif // __cplusplus diff --git a/kernel_config.cpp b/kernel_config.cpp index cc6d334..6a5270e 100644 --- a/kernel_config.cpp +++ b/kernel_config.cpp @@ -24,23 +24,6 @@ #include "kernel.h" -// TODO: Implement proper fprintf -EXTERNC void fprintf(FILE *stream, const char *Format, ...) -{ - va_list args; - va_start(args, Format); - vprintf(Format, args); - va_end(args); - UNUSED(stream); -} - -// TODO: Implement proper fputs -EXTERNC void fputs(const char *s, FILE *stream) -{ - printf("%s", s); - UNUSED(stream); -} - static struct cag_option ConfigOptions[] = { {.identifier = 'a', .access_letters = "aA", diff --git a/kernel_thread.cpp b/kernel_thread.cpp index 83979d2..672a97d 100644 --- a/kernel_thread.cpp +++ b/kernel_thread.cpp @@ -30,13 +30,6 @@ #include #include -using vfs::Node; -using vfs::NodeType; - -Disk::Manager *DiskManager = nullptr; -Driver::Manager *DriverManager = nullptr; -NetworkInterfaceManager::NetworkInterface *NIManager = nullptr; - int SpawnInit() { const char *envp[5] = { @@ -69,9 +62,8 @@ void KernelMainThread() // TaskManager->CreateThread(thisProcess, Tasking::IP(tasking_test_mutex)); // ilp; TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr)); - TaskManager->CreateThread(thisProcess, Tasking::IP(lsof)); TaskManager->CreateThread(thisProcess, Tasking::IP(TaskHeartbeat)); - TreeFS(fs->GetRootNode(), 0); + TreeFS(fs->GetRoot(0), 0); #endif KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", @@ -81,29 +73,13 @@ void KernelMainThread() if (IsVirtualizedEnvironment()) KPrint("Running in a virtualized environment"); - KPrint("Initializing Disk Manager"); - DiskManager = new Disk::Manager; + KPrint("Initializing Driver Manager"); + DriverManager = new Driver::Manager; KPrint("Loading Drivers"); - DriverManager = new Driver::Manager; + DriverManager->PreloadDrivers(); DriverManager->LoadAllDrivers(); - // KPrint("Fetching Disks"); - /* KernelCallback */ - // if (DriverManager->GetModules().size() > 0) - // { - // foreach (auto mod in DriverManager->GetModules()) - // if (((FexExtended *)mod.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Storage) - // DiskManager->FetchDisks(mod.modUniqueID); - // } - // else - // KPrint("\eE85230No disk driver found! Cannot fetch disks!"); - - // KPrint("Initializing Network Interface Manager"); - // NIManager = new NetworkInterfaceManager::NetworkInterface; - // KPrint("Starting Network Interface Manager"); - // NIManager->StartService(); - #ifdef DEBUG // TaskManager->CreateThread(thisProcess, // Tasking::IP(KShellThread)) diff --git a/kernel_vfs.cpp b/kernel_vfs.cpp index 65598ed..20e949c 100644 --- a/kernel_vfs.cpp +++ b/kernel_vfs.cpp @@ -22,130 +22,39 @@ #include vfs::Virtual *fs = nullptr; -vfs::Node *DevFS = nullptr; -vfs::Node *MntFS = nullptr; -vfs::Node *ProcFS = nullptr; -vfs::Node *VarLogFS = nullptr; -vfs::PTMXDevice *ptmx = nullptr; + +void SearchForInitrd() +{ + for (size_t i = 0; i < MAX_MODULES; i++) + { + uintptr_t initrdAddress = (uintptr_t)bInfo.Modules[i].Address; + + if (!initrdAddress) + continue; + + if (strcmp(bInfo.Modules[i].CommandLine, "initrd") != 0) + continue; + + KPrint("initrd found at %#lx", initrdAddress); + + Memory::Virtual vmm; + if (!vmm.Check((void *)initrdAddress)) + { + warn("Initrd is not mapped!"); + vmm.Map((void *)initrdAddress, (void *)initrdAddress, + bInfo.Modules[i].Size, Memory::RW); + } + + if (TestAndInitializeUSTAR(initrdAddress, bInfo.Modules[i].Size)) + continue; /* Maybe add another root? */ + } +} EXTERNC NIF void KernelVFS() { + KPrint("Initializing Virtual File System"); + fs = new vfs::Virtual; - vfs::Node *root = fs->GetRootNode(); - if (root->Children.size() == 0) - fs->nRoot = new vfs::vfsRoot("/", fs); - - for (size_t i = 0; i < MAX_MODULES; i++) - { - if (!bInfo.Modules[i].Address) - continue; - - if (strcmp(bInfo.Modules[i].CommandLine, "initrd") == 0) - { - KPrint("initrd found at %#lx", bInfo.Modules[i].Address); - static char initrd = 0; - if (!initrd++) - { - uintptr_t initrdAddress = (uintptr_t)bInfo.Modules[i].Address; - - Memory::Virtual vmm; - if (!vmm.Check((void *)initrdAddress)) - { - warn("Initrd is not mapped!"); - vmm.Map((void *)initrdAddress, (void *)initrdAddress, - bInfo.Modules[i].Size, Memory::RW); - } - - vfs::USTAR *ustar = new vfs::USTAR; - if (!ustar->TestArchive(initrdAddress)) - { - KPrint("\eE85230USTAR archive is invalid!"); - delete ustar; - } - else - ustar->ReadArchive(initrdAddress, fs); - } - } - } - - KPrint("Mounting filesystems"); - - if (!fs->PathExists("/dev")) - DevFS = new vfs::Node(fs->nRoot, "dev", vfs::DIRECTORY); - else - { - vfs::RefNode *dev = fs->Open("/dev"); - if (dev->node->Type != vfs::NodeType::DIRECTORY) - { - KPrint("\eE85230/dev is not a directory!"); - CPU::Stop(); - } - DevFS = dev->node; - delete dev; - } - - if (!fs->PathExists("/mnt")) - MntFS = new vfs::Node(fs->nRoot, "mnt", vfs::DIRECTORY); - else - { - vfs::RefNode *mnt = fs->Open("/mnt"); - if (mnt->node->Type != vfs::NodeType::DIRECTORY) - { - KPrint("\eE85230/mnt is not a directory!"); - CPU::Stop(); - } - MntFS = mnt->node; - delete mnt; - } - - if (!fs->PathExists("/proc")) - ProcFS = new vfs::Node(fs->nRoot, "proc", vfs::DIRECTORY); - else - { - vfs::RefNode *proc = fs->Open("/proc", nullptr); - if (proc->node->Type != vfs::NodeType::DIRECTORY) - { - KPrint("\eE85230/proc is not a directory!"); - CPU::Stop(); - } - ProcFS = proc->node; - delete proc; - } - - if (!fs->PathExists("/var")) - { - vfs::Node *var = new vfs::Node(fs->nRoot, "var", vfs::DIRECTORY); - VarLogFS = new vfs::Node(var, "log", vfs::DIRECTORY); - } - else - { - vfs::RefNode *var = fs->Open("/var", nullptr); - if (var->node->Type != vfs::NodeType::DIRECTORY) - { - KPrint("\eE85230/var is not a directory!"); - CPU::Stop(); - } - VarLogFS = var->node; - delete var; - - if (!fs->PathExists("/var/log")) - VarLogFS = new vfs::Node(VarLogFS, "log", vfs::DIRECTORY); - else - { - vfs::RefNode *var_log = fs->Open("/var/log", nullptr); - if (var_log->node->Type != vfs::NodeType::DIRECTORY) - { - KPrint("\eE85230/var/log is not a directory!"); - CPU::Stop(); - } - VarLogFS = var_log->node; - delete var_log; - } - } - - new vfs::NullDevice(); - new vfs::RandomDevice(); - new vfs::ZeroDevice(); - new vfs::KConDevice(); - ptmx = new vfs::PTMXDevice(); + SearchForInitrd(); + fs->Initialize(); } diff --git a/kshell/cmds.hpp b/kshell/cmds.hpp index c33a519..55c5e4b 100644 --- a/kshell/cmds.hpp +++ b/kshell/cmds.hpp @@ -20,7 +20,6 @@ #include -void cmd_lsof(const char *args); void cmd_clear(const char *args); void cmd_echo(const char *args); void cmd_ls(const char *args); diff --git a/kshell/commands/cat.cpp b/kshell/commands/cat.cpp index 20baebb..3f88c47 100644 --- a/kshell/commands/cat.cpp +++ b/kshell/commands/cat.cpp @@ -28,28 +28,29 @@ void cmd_cat(const char *args) if (args[0] == '\0') return; - Node *thisNode = fs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory); - if (thisNode == nullptr) - { - printf("cat: %s: No such file or directory\n", args); - return; - } + /* FIXME: Reimplement this later */ + assert(!"Function not implemented"); + // Node *thisNode = fs->GetByPath(args, thisProcess->CWD, true); + // if (thisNode == nullptr) + // { + // printf("cat: %s: No such file or directory\n", args); + // return; + // } - if (thisNode->Type != NodeType::FILE && - thisNode->Type != NodeType::CHARDEVICE) - { - printf("cat: %s: Not a file\n", args); - return; - } + // if (!thisNode->Stat.IsType(FILE) && !thisNode->Stat.IsType(CHARDEVICE)) + // { + // printf("cat: %s: Not a file\n", args); + // return; + // } - vfs::RefNode *fd = fs->Open(thisNode->FullPath); + // vfs::FileHandle *fd = fs->Open(thisNode->FilePath, nullptr, true); - uint8_t *buffer = new uint8_t[fd->Size + 1]; - ssize_t rBytes = fd->read(buffer, fd->Size); - if (rBytes > 0) - printf("%s\n", buffer); - else - printf("cat: %s: Could not read file\n", args); - delete[] buffer; - delete fd; + // uint8_t *buffer = new uint8_t[fd->node->Stat.Size + 1]; + // ssize_t rBytes = fd->read(buffer, fd->node->Stat.Size); + // if (rBytes > 0) + // printf("%s\n", buffer); + // else + // printf("cat: %s: Could not read file\n", args); + // delete[] buffer; + // delete fd; } diff --git a/kshell/commands/cd.cpp b/kshell/commands/cd.cpp index 89f9ad0..9b56297 100644 --- a/kshell/commands/cd.cpp +++ b/kshell/commands/cd.cpp @@ -28,22 +28,24 @@ void cmd_cd(const char *args) if (args[0] == '\0') return; - Node *thisNode = fs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory); + /* FIXME: Reimplement this later */ + assert(!"Function not implemented"); + // Node *thisNode = fs->GetByPath(args, thisProcess->CWD, true); - if (thisNode == nullptr) - { - printf("cd: %s: No such file or directory\n", args); - return; - } + // if (thisNode == nullptr) + // { + // printf("cd: %s: No such file or directory\n", args); + // return; + // } - if (thisNode->Type == NodeType::SYMLINK) - thisNode = fs->GetNodeFromPath(thisNode->Symlink); + // if (thisNode->Stat.IsType(SYMLINK)) + // thisNode = fs->GetByPath(thisNode->GetSymLink(), nullptr, true); - if (thisNode->Type != NodeType::DIRECTORY) - { - printf("cd: %s: Not a directory\n", args); - return; - } + // if (!thisNode->Stat.IsType(DIRECTORY)) + // { + // printf("cd: %s: Not a directory\n", args); + // return; + // } - thisProcess->CurrentWorkingDirectory = thisNode; + // thisProcess->CWD = thisNode; } diff --git a/kshell/commands/ls.cpp b/kshell/commands/ls.cpp index 005811f..e11e5ff 100644 --- a/kshell/commands/ls.cpp +++ b/kshell/commands/ls.cpp @@ -23,81 +23,84 @@ using namespace vfs; -const char *ColorNodeType(Node *node) -{ - switch (node->Type) - { - case NodeType::DIRECTORY: - return "\e3871F5"; - case NodeType::BLOCKDEVICE: - return "\eE8CD1E"; - case NodeType::CHARDEVICE: - return "\e86E01F"; - case NodeType::PIPE: - return "\eE0991F"; - case NodeType::SYMLINK: - return "\e1FB9E0"; - case NodeType::FILE: - return "\eCCCCCC"; - default: - return "\eF72020"; - } -} +// const char *ColorNodeType(Node *node) +// { +// switch (node->Stat.GetFileType()) +// { +// case DIRECTORY: +// return "\e3871F5"; +// case BLOCKDEVICE: +// return "\eE8CD1E"; +// case CHARDEVICE: +// return "\e86E01F"; +// case PIPE: +// return "\eE0991F"; +// case SYMLINK: +// return "\e1FB9E0"; +// case FILE: +// return "\eCCCCCC"; +// default: +// return "\eF72020"; +// } +// } -size_t MaxNameLength(Node *nodes) -{ - size_t maxLength = 0; - foreach (auto &node in nodes->Children) - maxLength = std::max(maxLength, strlen(node->Name)); - return maxLength; -} +// size_t MaxNameLength(Node *nodes) +// { +// size_t maxLength = 0; +// foreach (auto &node in nodes->GetChildren(true)) +// maxLength = std::max(maxLength, strlen(node->FileName)); +// return maxLength; +// } -void PrintLS(Node *node) -{ - size_t maxNameLength = MaxNameLength(node); - int count = 0; - bool first = true; - foreach (auto &var in node->Children) - { - if (count % 5 == 0 && !first) - printf("\n"); - printf(" %s%-*s ", ColorNodeType(var), (int)maxNameLength, var->Name); - count++; - first = false; - } - printf("\eCCCCCC\n"); -} +// void PrintLS(Node *node) +// { +// size_t maxNameLength = MaxNameLength(node); +// int count = 0; +// bool first = true; +// foreach (auto &var in node->GetChildren(true)) +// { +// if (count % 5 == 0 && !first) +// printf("\n"); +// printf(" %s%-*s ", ColorNodeType(var), (int)maxNameLength, var->FileName); +// count++; +// first = false; +// } +// printf("\eCCCCCC\n"); +// } void cmd_ls(const char *args) { - if (args[0] == '\0') - { - Node *rootNode = thisProcess->CurrentWorkingDirectory; + /* FIXME: Reimplement this later */ + assert(!"Function not implemented"); - if (rootNode == nullptr) - rootNode = fs->GetRootNode()->Children[0]; + // if (args[0] == '\0') + // { + // Node *rootNode = thisProcess->CWD; - PrintLS(rootNode); - } - else - { - Node *thisNode = fs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory); + // if (rootNode == nullptr) + // rootNode = fs->FileSystemRoots->GetChildren(true)[0]; - if (thisNode == nullptr) - { - printf("ls: %s: No such file or directory\n", args); - return; - } + // PrintLS(rootNode); + // } + // else + // { + // Node *thisNode = fs->GetByPath(args, thisProcess->CWD, true); - if (thisNode->Type == NodeType::SYMLINK) - thisNode = fs->GetNodeFromPath(thisNode->Symlink); + // if (thisNode == nullptr) + // { + // printf("ls: %s: No such file or directory\n", args); + // return; + // } - if (thisNode->Type != NodeType::DIRECTORY) - { - printf("%s%s\n", ColorNodeType(thisNode), thisNode->Name); - return; - } + // if (thisNode->Stat.IsType(SYMLINK)) + // thisNode = fs->GetByPath(thisNode->GetSymLink(), nullptr, true); - PrintLS(thisNode); - } + // if (!thisNode->Stat.IsType(DIRECTORY)) + // { + // printf("%s%s\n", ColorNodeType(thisNode), thisNode->FileName); + // return; + // } + + // PrintLS(thisNode); + // } } diff --git a/kshell/commands/modinfo.cpp b/kshell/commands/modinfo.cpp index 286631d..87cb719 100644 --- a/kshell/commands/modinfo.cpp +++ b/kshell/commands/modinfo.cpp @@ -62,7 +62,7 @@ void cmd_modinfo(const char *args) printf("Resource Info:\n"); printf(" Initialized: %s\n", drv.Initialized ? "yes" : "no"); printf(" Error Code: %i (%s)\n", drv.ErrorCode, strerror(drv.ErrorCode)); - printf(" Path: %s\n", drv.Path); + printf(" Path: %s\n", drv.Path.c_str()); printf(" Used Memory: %ld KiB\n", TO_KiB(drv.vma->GetAllocatedMemorySize())); printf(" Used IRQs:%s\n", drv.InterruptHandlers->empty() ? " none" : ""); foreach (auto var in *drv.InterruptHandlers) diff --git a/kshell/commands/tree.cpp b/kshell/commands/tree.cpp index 70876c9..aa031fc 100644 --- a/kshell/commands/tree.cpp +++ b/kshell/commands/tree.cpp @@ -23,53 +23,55 @@ using namespace vfs; -void tree_loop(Node *rootNode, int depth = 0) -{ - foreach (auto Child in rootNode->Children) - { - Display->UpdateBuffer(); - if (Child->Type == NodeType::DIRECTORY || - Child->Type == NodeType::MOUNTPOINT) - { - printf("%*s%*s%*s|- %s\n", - depth, "", - depth, "", - depth, "", - Child->Name); - tree_loop(Child, depth + 1); - } - else - printf("%*s%*s%*s|- %s\n", - depth, "", - depth, "", - depth, "", - Child->Name); - } -} +// void tree_loop(Node *rootNode, int depth = 0) +// { +// foreach (auto Child in rootNode->GetChildren(true)) +// { +// Display->UpdateBuffer(); +// if (Child->Stat.IsType(DIRECTORY) || Child->Stat.IsType(MOUNTPOINT)) +// { +// printf("%*s%*s%*s|- %s\n", +// depth, "", +// depth, "", +// depth, "", +// Child->FileName); +// tree_loop(Child, depth + 1); +// } +// else +// printf("%*s%*s%*s|- %s\n", +// depth, "", +// depth, "", +// depth, "", +// Child->FileName); +// } +// } void cmd_tree(const char *args) { - Node *rootNode = thisProcess->CurrentWorkingDirectory; - if (args[0] == '\0') - { - if (rootNode == nullptr) - rootNode = fs->GetRootNode()->Children[0]; - } - else - { - rootNode = fs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory); - if (rootNode == nullptr) - { - printf("ls: %s: No such file or directory\n", args); - return; - } - if (rootNode->Type != NodeType::DIRECTORY) - { - printf("%s\n", rootNode->Name); - return; - } - } + /* FIXME: Reimplement this later */ + assert(!"Function not implemented"); - printf("%s\n", rootNode->Name); - tree_loop(rootNode); + // Node *rootNode = thisProcess->CWD; + // if (args[0] == '\0') + // { + // if (rootNode == nullptr) + // rootNode = fs->FileSystemRoots->GetChildren(true)[0]; + // } + // else + // { + // rootNode = fs->GetByPath(args, thisProcess->CWD, true); + // if (rootNode == nullptr) + // { + // printf("ls: %s: No such file or directory\n", args); + // return; + // } + // if (!rootNode->Stat.IsType(DIRECTORY)) + // { + // printf("%s\n", rootNode->FileName); + // return; + // } + // } + + // printf("%s\n", rootNode->FileName); + // tree_loop(rootNode); } diff --git a/kshell/shell.cpp b/kshell/shell.cpp index ace81a5..c6b2688 100644 --- a/kshell/shell.cpp +++ b/kshell/shell.cpp @@ -17,15 +17,16 @@ #include +#include #include #include #include #include #include #include +#include #include "../kernel.h" -#include "../driver.h" #include "cmds.hpp" NewLock(ShellLock); @@ -47,7 +48,6 @@ void __cmd_builtin(const char *) } static Command commands[] = { - {"lsof", cmd_lsof}, {"ls", cmd_ls}, {"tree", cmd_tree}, {"cd", cmd_cd}, @@ -167,7 +167,7 @@ void StartKernelShell() bool upperCase = false; bool tabDblPress = false; - vfs::RefNode *kfd = fs->Open("/dev/key"); + FileNode *kfd = fs->GetByPath("/dev/key", nullptr); if (kfd == nullptr) { KPrint("Failed to open keyboard device!"); @@ -192,14 +192,14 @@ void StartKernelShell() size_t seekCount = 0; strBuf.clear(); - vfs::Node *cwd = thisProcess->CurrentWorkingDirectory; + FileNode *cwd = thisProcess->CWD; if (!cwd) - cwd = fs->GetNodeFromPath("/"); + cwd = fs->GetByPath("/", nullptr); printf("\e34C6EB%s@%s:%s$ \eCCCCCC", "kernel", "fennix", - cwd->FullPath); + cwd->Path.c_str()); Display->UpdateBuffer(); Display->GetBufferCursor(&homeX, &homeY); @@ -215,7 +215,7 @@ void StartKernelShell() CurY.store(__cy); CurHalt.store(false); - nBytes = kfd->read(scBuf, 2); + nBytes = kfd->Read(scBuf, 2, 0); if (nBytes == 0) continue; if (nBytes < 0) @@ -330,7 +330,7 @@ void StartKernelShell() size_t strSeek = seekCount ? seekCount - 1 : 0; seekCount = strSeek; debug("strSeek: %d: %s", strSeek, strBuf.c_str()); - strBuf.erase((int)strSeek); + strBuf.erase(strSeek); Display->PrintString(strBuf.c_str()); debug("after strBuf: %s", strBuf.c_str()); @@ -363,7 +363,7 @@ void StartKernelShell() Display->SetBufferCursor(unseekX, unseekY); strBufBck(); debug("seekCount: %d: %s", seekCount, strBuf.c_str()); - strBuf.erase((int)seekCount); + strBuf.erase(seekCount); Display->PrintString(strBuf.c_str()); debug("after strBuf: %s", strBuf.c_str()); @@ -666,7 +666,7 @@ void StartKernelShell() // size_t strSeek = seekCount ? seekCount - 1 : 0; debug("seekCount: %d; \"%s\"", seekCount, strBuf.c_str()); - strBuf.insert(seekCount, 1, c); + strBuf.insert(seekCount, (size_t)1, c); Display->PrintString(strBuf.c_str()); debug("after strBuf: %s (seek and bs is +1 [seek: %d; bs: %d])", strBuf.c_str(), seekCount + 1, bsCount + 1); @@ -750,12 +750,12 @@ void StartKernelShell() std::string path = "/bin/"; - if (!fs->PathExists("/bin")) + if (!fs->PathExists(path.c_str(), nullptr)) path = "/usr/bin/"; path += cmd_only; debug("path: %s", path.c_str()); - if (fs->PathExists(path.c_str())) + if (fs->PathExists(path.c_str(), nullptr)) { const char *envp[5] = { "PATH=/bin:/usr/bin", diff --git a/library/c/ctype.c b/library/c/ctype.c new file mode 100644 index 0000000..92c0da4 --- /dev/null +++ b/library/c/ctype.c @@ -0,0 +1,28 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +int tolower(int c) +{ + return _tolower(c); +} + +int toupper(int c) +{ + return _toupper(c); +} diff --git a/library/c/stdio.cpp b/library/c/stdio.cpp new file mode 100644 index 0000000..33e007f --- /dev/null +++ b/library/c/stdio.cpp @@ -0,0 +1,100 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include +#include +#include + +FILE __local_stdin = {.st = 0}; +FILE __local_stdout = {.st = 1}; +FILE __local_stderr = {.st = 2}; + +FILE *stdin = &__local_stdin; +FILE *stdout = &__local_stdout; +FILE *stderr = &__local_stderr; + +EXTERNC int asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = vasprintf(strp, fmt, ap); + va_end(ap); + return ret; +} + +#define va_copy(dest, src) __builtin_va_copy(dest, src) + +EXTERNC int vasprintf(char **strp, const char *fmt, va_list ap) +{ + va_list ap2; + va_copy(ap2, ap); + int len = vsnprintf(NULL, 0, fmt, ap2); + va_end(ap2); + if (len < 0) + { + return -1; + } + *strp = (char *)malloc(len + 1); + if (!*strp) + { + return -1; + } + int ret = vsnprintf(*strp, len + 1, fmt, ap); + if (ret < 0) + { + free(*strp); + *strp = NULL; + } + return ret; +} + +int fprintf(FILE *stream, const char *format, ...) +{ + switch (stream->st) + { + case 0: + { + error("fprintf() called with stdin"); + return -1; + } + case 1: + { + va_list ap; + va_start(ap, format); + int ret = vprintf(format, ap); + va_end(ap); + return ret; + } + case 2: + { + va_list ap; + va_start(ap, format); + int ret = vprintf(format, ap); + va_end(ap); + return ret; + } + default: + return -1; + } +} + +int fputs(const char *s, FILE *stream) +{ + for (const char *c = s; *c; c++) + uart_wrapper(*c, NULL); + return 0; +} diff --git a/library/c/stdlib.cpp b/library/c/stdlib.cpp new file mode 100644 index 0000000..5ccbf05 --- /dev/null +++ b/library/c/stdlib.cpp @@ -0,0 +1,27 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include +#include +#include + +EXTERNC void abort() +{ + error("abort() called"); + CPU::Stop(); + __builtin_unreachable(); +} diff --git a/library/cbuf.cpp b/library/cbuf.cpp new file mode 100644 index 0000000..08bd63c --- /dev/null +++ b/library/cbuf.cpp @@ -0,0 +1,99 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +CircularBuffer::CircularBuffer(size_t Size) + : Buffer(new uint8_t[Size]), + BufferSize(Size), + BufferCount(0), + Head(0), + Tail(0) {} + +CircularBuffer::~CircularBuffer() { delete[] Buffer; } + +size_t CircularBuffer::Write(const uint8_t *Data, size_t Size) +{ + sl_guard(Lock); + + size_t written = 0; + while (Size > 0) + { + if (BufferCount == BufferSize) + break; + + Buffer[Head] = *Data++; + Head = (Head + 1) % BufferSize; + BufferCount++; + written++; + Size--; + } + + return written; +} + +size_t CircularBuffer::Read(uint8_t *Data, size_t Size) +{ + sl_guard(Lock); + + size_t read = 0; + while (Size > 0) + { + if (BufferCount == 0) + break; + + *Data++ = Buffer[Tail]; + Tail = (Tail + 1) % BufferSize; + BufferCount--; + read++; + Size--; + } + + return read; +} + +size_t CircularBuffer::Peek(uint8_t *Data, size_t Size) +{ + sl_guard(Lock); + + size_t read = 0; + size_t tail = Tail; + while (Size > 0) + { + if (read == BufferCount) + break; + + *Data++ = Buffer[tail]; + tail = (tail + 1) % BufferSize; + read++; + Size--; + } + + return read; +} + +size_t CircularBuffer::Count() +{ + sl_guard(Lock); + return BufferCount; +} + +size_t CircularBuffer::Free() +{ + sl_guard(Lock); + return BufferSize - BufferCount; +} diff --git a/library/convert.cpp b/library/convert.cpp index 0750d37..71fe4d2 100644 --- a/library/convert.cpp +++ b/library/convert.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef DEBUG #include #endif diff --git a/library/cwalk.c b/library/cwalk.c index 435f1ef..99b7f46 100644 --- a/library/cwalk.c +++ b/library/cwalk.c @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2020 Leonard Iklé +Copyright (c) 2024 Leonard Iklé Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,25 +23,24 @@ SOFTWARE. */ #include +#include #include -#include - -#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" -#pragma GCC diagnostic ignored "-Wsequence-point" +#include +#include +#include /** * We try to default to a different path style depending on the operating * system. So this should detect whether we should use windows or unix paths. */ -/* -#if defined(WIN32) || defined(_WIN32) || \ +/*#if defined(WIN32) || defined(_WIN32) || \ defined(__WIN32) && !defined(__CYGWIN__) static enum cwk_path_style path_style = CWK_STYLE_WINDOWS; #else static enum cwk_path_style path_style = CWK_STYLE_UNIX; -#endif -*/ +#endif*/ +/* This will extract the path style of the running process */ extern enum cwk_path_style *__cwalk_path_style(void); #define path_style (*__cwalk_path_style()) @@ -153,7 +152,9 @@ static void cwk_path_terminate_output(char *buffer, size_t buffer_size, static bool cwk_path_is_string_equal(const char *first, const char *second, size_t first_size, size_t second_size) { - // THe two strings are not equal if the sizes are not equal. + bool are_both_separators; + + // The two strings are not equal if the sizes are not equal. if (first_size != second_size) { return false; } @@ -169,11 +170,18 @@ static bool cwk_path_is_string_equal(const char *first, const char *second, // own. while (*first && *second && first_size > 0) { // We can consider the string to be not equal if the two lowercase - // characters are not equal. - if (tolower(*first++) != tolower(*second++)) { + // characters are not equal. The two chars may also be separators, which + // means they would be equal. + are_both_separators = strchr(separators[path_style], *first) != NULL && + strchr(separators[path_style], *second) != NULL; + + if (tolower(*first) != tolower(*second) && !are_both_separators) { return false; } + first++; + second++; + --first_size; } @@ -511,7 +519,7 @@ static void cwk_path_get_root_windows(const char *path, size_t *length) if (cwk_path_is_separator(c)) { ++c; - // Check whether the path starts with a single back slash, which means this + // Check whether the path starts with a single backslash, which means this // is not a network path - just a normal path starting with a backslash. if (!cwk_path_is_separator(c)) { // Okay, this is not a network path but we still use the backslash as a @@ -599,6 +607,29 @@ static bool cwk_path_is_root_absolute(const char *path, size_t length) return cwk_path_is_separator(&path[length - 1]); } +static void cwk_path_fix_root(char *buffer, size_t buffer_size, size_t length) +{ + size_t i; + + // This only affects windows. + if (path_style != CWK_STYLE_WINDOWS) { + return; + } + + // Make sure we are not writing further than we are actually allowed to. + if (length > buffer_size) { + length = buffer_size; + } + + // Replace all forward slashes with backwards slashes. Since this is windows + // we can't have any forward slashes in the root. + for (i = 0; i < length; ++i) { + if (cwk_path_is_separator(&buffer[i])) { + buffer[i] = *separators[CWK_STYLE_WINDOWS]; + } + } +} + static size_t cwk_path_join_and_normalize_multiple(const char **paths, char *buffer, size_t buffer_size) { @@ -613,8 +644,10 @@ static size_t cwk_path_join_and_normalize_multiple(const char **paths, // later on whether we can remove superfluous "../" or not. absolute = cwk_path_is_root_absolute(paths[0], pos); - // First copy the root to the output. We will not modify the root. + // First copy the root to the output. After copying, we will normalize the + // root. cwk_path_output_sized(buffer, buffer_size, 0, paths[0], pos); + cwk_path_fix_root(buffer, buffer_size, pos); // So we just grab the first segment. If there is no segment we will always // output a "/", since we currently only support absolute paths here. diff --git a/library/kexcept/cxxabi.cpp b/library/kexcept/cxxabi.cpp new file mode 100644 index 0000000..0f9b17f --- /dev/null +++ b/library/kexcept/cxxabi.cpp @@ -0,0 +1,254 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include + +#include "../../kernel.h" + +extern "C" _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *Exception); + +using namespace __cxxabiv1; + +atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS]; +uarch_t __atexit_func_count = 0; + +__cxa_eh_globals *__cxa_get_globals() noexcept +{ + return &GetCurrentCPU()->Exception.globals; +} + +/** + * @param f The destructor + * @param objptr The object to be destructed + * @param dso The DSO from which the object was obtained (unused in our case) + * @return Zero on success, non-zero on failure + */ +extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso) +{ + if (KernelSymbolTable) + { + debug("Registering atexit function for \"%s\" with destructor \"%s\"", + KernelSymbolTable->GetSymbol((uintptr_t)objptr), + KernelSymbolTable->GetSymbol((uintptr_t)f)); + } + else + { + debug("Registering atexit function for %p with destructor %p", + objptr, f); + } + + if (__atexit_func_count >= ATEXIT_MAX_FUNCS) + return -1; + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = objptr; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + __atexit_func_count++; + return 0; +} + +extern "C" void __cxa_finalize(void *f) +{ + func("%p", f); + uarch_t i = __atexit_func_count; + if (f == nullptr) + { + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + if (KernelSymbolTable) + { + debug("Calling atexit function \"%s\"", + KernelSymbolTable->GetSymbol((uintptr_t)__atexit_funcs[i].destructor_func)); + } + else + { + debug("Calling atexit function %p", + __atexit_funcs[i].destructor_func); + } + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + } + } + return; + } + + while (i--) + { + if (__atexit_funcs[i].destructor_func == f) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + __atexit_funcs[i].destructor_func = 0; + } + } +} + +extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context) +{ + fixme("__gxx_personality_v0( %d %p %p %p %p ) called.", version, actions, exception_class, ue_header, context); + return _URC_NO_REASON; +} + +extern "C" void *__cxa_begin_catch(void *thrown_object) noexcept +{ + func("%p", thrown_object); + + __cxa_exception *Exception = (__cxa_exception *)thrown_object - 1; + __cxa_eh_globals *Globals = __cxa_get_globals(); + + Exception->handlerCount++; + Globals->uncaughtExceptions--; + + Exception->nextException = Globals->caughtExceptions; + Globals->caughtExceptions = Exception; + return Exception + 1; +} + +extern "C" void __cxa_end_catch() +{ + fixme("__cxa_end_catch() called."); +} + +static __always_inline inline size_t align_exception_allocation_size(size_t a, size_t b) +{ + return (a + b - 1) & ~(b - 1); +} + +static __always_inline inline void INIT_EXCEPTION_CLASS(_Unwind_Exception_Class *c) +{ + char *ptr = (char *)c; + ptr[0] = 'G'; + ptr[1] = 'N'; + ptr[2] = 'U'; + ptr[3] = 'C'; + ptr[4] = 'C'; + ptr[5] = '+'; + ptr[6] = '+'; + ptr[7] = '\0'; +} + +void unexpected_header_stub() { fixme("unexpected() called."); } + +void terminate_header_stub() +{ + if (TaskManager && !TaskManager->IsPanic()) + { + TaskManager->KillThread(thisThread, Tasking::KILL_CXXABI_EXCEPTION); + TaskManager->Yield(); + } + + error("No task manager to kill thread!"); + CPU::Stop(); /* FIXME: Panic */ +} + +void exception_cleanup_stub(_Unwind_Reason_Code Code, + _Unwind_Exception *Exception) +{ + fixme("exception_cleanup( %d %p ) called.", + Code, Exception); +} + +extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw() +{ + debug("Allocating exception of size %d.", thrown_size); + + size_t alloc_size = align_exception_allocation_size(thrown_size + sizeof(__cxa_exception), alignof(__cxa_exception)); + __cxa_exception *Exception = (__cxa_exception *)kmalloc(alloc_size); + memset(Exception, 0, alloc_size); + return Exception + 1; +} + +extern "C" __noreturn void __cxa_throw(void *thrown_object, + std::type_info *tinfo, + void (*dest)(void *)) +{ + trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )", + tinfo->name(), thrown_object, dest); + + __cxa_eh_globals *Globals = __cxa_get_globals(); + Globals->uncaughtExceptions++; + + __cxa_exception *Exception = (__cxa_exception *)thrown_object - 1; + Exception->exceptionType = (std::type_info *)tinfo; + Exception->exceptionDestructor = dest; + Exception->unexpectedHandler = &unexpected_header_stub; + Exception->terminateHandler = &terminate_header_stub; + Exception->unwindHeader.exception_cleanup = &exception_cleanup_stub; + INIT_EXCEPTION_CLASS(&Exception->unwindHeader.exception_class); + Exception->adjustedPtr = thrown_object; + + _Unwind_RaiseException(&Exception->unwindHeader); + __cxa_begin_catch(&Exception->unwindHeader); + + error("Uncaught exception!"); + CPU::Stop(); /* FIXME: Panic */ +} + +extern "C" void __cxa_rethrow() +{ + fixme("__cxa_rethrow() called."); +} + +extern "C" void __cxa_pure_virtual() +{ + fixme("__cxa_pure_virtual() called."); +} + +extern "C" void __cxa_throw_bad_array_new_length() +{ + fixme("__cxa_throw_bad_array_new_length() called."); +} + +extern "C" void __cxa_free_exception(void *thrown_exception) +{ + fixme("__cxa_free_exception( %p ) called.", + thrown_exception); +} + +__extension__ typedef int __guard __attribute__((mode(__DI__))); + +extern "C" int __cxa_guard_acquire(__guard *g) +{ + fixme("__cxa_guard_acquire( %p ) called.", g); + return !*(char *)(g); +} + +extern "C" void __cxa_guard_release(__guard *g) +{ + fixme("__cxa_guard_release( %p ) called.", g); + *(char *)g = 1; +} + +extern "C" void __cxa_guard_abort(__guard *g) +{ + fixme("__cxa_guard_abort( %p ) called.", g); +} + +extern "C" __noreturn void __cxa_bad_typeid() +{ + fixme("__cxa_bad_typeid() called."); + CPU::Stop(); /* FIXME: Crash the system */ +} + +extern "C" void *__cxa_get_exception_ptr(void *exceptionObject) +{ + stub; + return nullptr; +} diff --git a/storage/fs/fat32.cpp b/library/kexcept/dso.c similarity index 87% rename from storage/fs/fat32.cpp rename to library/kexcept/dso.c index 2223d29..732ef2a 100644 --- a/storage/fs/fat32.cpp +++ b/library/kexcept/dso.c @@ -15,13 +15,11 @@ along with Fennix Kernel. If not, see . */ -#include - -#include #include -#include "../../kernel.h" - -namespace vfs +void __dso_handle_stub() { + stub; } + +/* extern */ void *__dso_handle = (void *)&__dso_handle_stub; diff --git a/library/libstdc++/unwind.cpp b/library/kexcept/unwind.cpp similarity index 63% rename from library/libstdc++/unwind.cpp rename to library/kexcept/unwind.cpp index 30e2a5b..990ae4f 100644 --- a/library/libstdc++/unwind.cpp +++ b/library/kexcept/unwind.cpp @@ -15,8 +15,8 @@ along with Fennix Kernel. If not, see . */ -#include -#include +#include +#include #include #include #include @@ -25,17 +25,23 @@ using namespace __cxxabiv1; -#if (1) /* Stubs if libgcc is not present */ -extern "C" _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *Exception) +#if (1) /* Set to 0 to use a library or 1 to use this code */ + +extern "C" _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *object) { - fixme("_Unwind_RaiseException( %p ) called.", Exception); - error("Unhandled exception."); - return _URC_FATAL_PHASE1_ERROR; - // return _URC_NO_REASON; + stub; + return _URC_NO_REASON; } -extern "C" void _Unwind_Resume(struct _Unwind_Exception *Exception) +extern "C" void _Unwind_Resume(struct _Unwind_Exception *object) { - fixme("_Unwind_Resume( %p ) called.", Exception); + stub; } -#endif + +extern "C" _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) +{ + stub; + return _URC_NO_REASON; +} + +#endif // 0 or 1 diff --git a/library/libstdc++/cxxabi.cpp b/library/libstdc++/cxxabi.cpp deleted file mode 100644 index dbe5f49..0000000 --- a/library/libstdc++/cxxabi.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include - -#include "../../kernel.h" - -void __dso_handle_stub() { stub; } - -/* extern */ void *__dso_handle = (void *)&__dso_handle_stub; - -namespace __cxxabiv1 -{ - atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS]; - uarch_t __atexit_func_count = 0; - - __cxa_eh_globals *__cxa_get_globals() noexcept - { - return &GetCurrentCPU()->EHGlobals; - } - - /** - * @param f The destructor - * @param objptr The object to be destructed - * @param dso The DSO from which the object was obtained (unused in our case) - * @return Zero on success, non-zero on failure - */ - extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso) - { - if (KernelSymbolTable) - { - debug("Registering atexit function for \"%s\" with destructor \"%s\"", - KernelSymbolTable->GetSymbol((uintptr_t)objptr), - KernelSymbolTable->GetSymbol((uintptr_t)f)); - } - else - { - debug("Registering atexit function for %p with destructor %p", - objptr, f); - } - - if (__atexit_func_count >= ATEXIT_MAX_FUNCS) - return -1; - __atexit_funcs[__atexit_func_count].destructor_func = f; - __atexit_funcs[__atexit_func_count].obj_ptr = objptr; - __atexit_funcs[__atexit_func_count].dso_handle = dso; - __atexit_func_count++; - return 0; - } - - extern "C" void __cxa_finalize(void *f) - { - function("%p", f); - uarch_t i = __atexit_func_count; - if (f == nullptr) - { - while (i--) - { - if (__atexit_funcs[i].destructor_func) - { - if (KernelSymbolTable) - { - debug("Calling atexit function \"%s\"", - KernelSymbolTable->GetSymbol((uintptr_t)__atexit_funcs[i].destructor_func)); - } - else - { - debug("Calling atexit function %p", - __atexit_funcs[i].destructor_func); - } - (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); - } - } - return; - } - - while (i--) - { - if (__atexit_funcs[i].destructor_func == f) - { - (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); - __atexit_funcs[i].destructor_func = 0; - } - } - } - - extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context) - { - fixme("__gxx_personality_v0( %d %p %p %p %p ) called.", version, actions, exception_class, ue_header, context); - return _URC_NO_REASON; - } - - extern "C" void *__cxa_begin_catch(void *thrown_object) noexcept - { - function("%p", thrown_object); - - __cxa_exception *Exception = (__cxa_exception *)thrown_object - 1; - __cxa_eh_globals *Globals = __cxa_get_globals(); - - Exception->handlerCount++; - Globals->uncaughtExceptions--; - - Exception->nextException = Globals->caughtExceptions; - Globals->caughtExceptions = Exception; - return Exception + 1; - } - - extern "C" void __cxa_end_catch() - { - fixme("__cxa_end_catch() called."); - } - - static __always_inline inline size_t align_exception_allocation_size(size_t a, size_t b) - { - return (a + b - 1) & ~(b - 1); - } - - static __always_inline inline void INIT_EXCEPTION_CLASS(_Unwind_Exception_Class *c) - { - char *ptr = (char *)c; - ptr[0] = 'G'; - ptr[1] = 'N'; - ptr[2] = 'U'; - ptr[3] = 'C'; - ptr[4] = 'C'; - ptr[5] = '+'; - ptr[6] = '+'; - ptr[7] = '\0'; - } - - void unexpected_header_stub() { fixme("unexpected() called."); } - - void terminate_header_stub() - { - if (TaskManager && !TaskManager->IsPanic()) - { - TaskManager->KillThread(thisThread, Tasking::KILL_CXXABI_EXCEPTION); - TaskManager->Yield(); - } - - error("No task manager to kill thread!"); - CPU::Stop(); /* FIXME: Panic */ - } - - void exception_cleanup_stub(_Unwind_Reason_Code Code, - _Unwind_Exception *Exception) - { - fixme("exception_cleanup( %d %p ) called.", - Code, Exception); - } - - extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw() - { - debug("Allocating exception of size %d.", thrown_size); - - size_t alloc_size = align_exception_allocation_size(thrown_size + sizeof(__cxa_exception), alignof(__cxa_exception)); - __cxa_exception *Exception = (__cxa_exception *)kmalloc(alloc_size); - memset(Exception, 0, alloc_size); - return Exception + 1; - } - - extern "C" __noreturn void __cxa_throw(void *thrown_object, - std::type_info *tinfo, - void (*dest)(void *)) - { - trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )", - tinfo->name(), thrown_object, dest); - - __cxa_eh_globals *Globals = __cxa_get_globals(); - Globals->uncaughtExceptions++; - - __cxa_exception *Exception = (__cxa_exception *)thrown_object - 1; - Exception->exceptionType = (std::type_info *)tinfo; - Exception->exceptionDestructor = dest; - Exception->unexpectedHandler = &unexpected_header_stub; - Exception->terminateHandler = &terminate_header_stub; - Exception->unwindHeader.exception_cleanup = &exception_cleanup_stub; - INIT_EXCEPTION_CLASS(&Exception->unwindHeader.exception_class); - Exception->adjustedPtr = thrown_object; - - _Unwind_RaiseException(&Exception->unwindHeader); - __cxa_begin_catch(&Exception->unwindHeader); - - error("Uncaught exception!"); - CPU::Stop(); /* FIXME: Panic */ - } - - extern "C" void __cxa_rethrow() - { - fixme("__cxa_rethrow() called."); - } - - extern "C" void __cxa_pure_virtual() - { - fixme("__cxa_pure_virtual() called."); - } - - extern "C" void __cxa_throw_bad_array_new_length() - { - fixme("__cxa_throw_bad_array_new_length() called."); - } - - extern "C" void __cxa_free_exception(void *thrown_exception) - { - fixme("__cxa_free_exception( %p ) called.", - thrown_exception); - } - - __extension__ typedef int __guard __attribute__((mode(__DI__))); - - extern "C" int __cxa_guard_acquire(__guard *g) - { - fixme("__cxa_guard_acquire( %p ) called.", g); - return !*(char *)(g); - } - - extern "C" void __cxa_guard_release(__guard *g) - { - fixme("__cxa_guard_release( %p ) called.", g); - *(char *)g = 1; - } - - extern "C" void __cxa_guard_abort(__guard *g) - { - fixme("__cxa_guard_abort( %p ) called.", g); - } - - extern "C" __noreturn void __cxa_bad_typeid() - { - fixme("__cxa_bad_typeid() called."); - CPU::Stop(); /* FIXME: Crash the system */ - } -} diff --git a/syscalls/native/close.cpp b/library/libstdc++/vmi_class_type_info.cpp similarity index 61% rename from syscalls/native/close.cpp rename to library/libstdc++/vmi_class_type_info.cpp index 97d083a..872b48b 100644 --- a/syscalls/native/close.cpp +++ b/library/libstdc++/vmi_class_type_info.cpp @@ -15,25 +15,28 @@ along with Fennix Kernel. If not, see . */ -#include - -#include -#include -#include -#include +#include #include -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/close.html */ -int sys_close(SysFrm *, - int fildes) +namespace __cxxabiv1 { - function("%d", fildes); - PCB *pcb = thisProcess; - vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_close(fildes); + __vmi_class_type_info::~__vmi_class_type_info() + { + } + + void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const + { + if (__do_upcast(other, &obj)) + return obj; + return 0; + } + + bool __vmi_class_type_info::__do_upcast(const __class_type_info *target, void **thrown_object) const + { + if (this == target) + return true; + + stub; + return 0; + } } diff --git a/library/std/errno.cpp b/library/std/errno.cpp index b0ae4aa..a2d9575 100644 --- a/library/std/errno.cpp +++ b/library/std/errno.cpp @@ -32,274 +32,178 @@ EXTERNC int *__errno_location(void) return &thisThread->ErrorNumber; } -const char *strerror(int errnum) +char *strerror(int errnum) { if (errnum < 0) errnum = -errnum; switch (errnum) { - case 0: - return "Success"; - case EPERM: - return "Operation not permitted"; - case ENOENT: - return "No such file or directory"; - case ESRCH: - return "No such process"; - case EINTR: - return "Interrupted system call"; - case EIO: - return "Input/output error"; - case ENXIO: - return "No such device or address"; + case EOK: + return (char *)"No error"; case E2BIG: - return "Argument list too long"; - case ENOEXEC: - return "Exec format error"; - case EBADF: - return "Bad file descriptor"; - case ECHILD: - return "No child processes"; - case EAGAIN: - return "Resource temporarily unavailable"; - case ENOMEM: - return "Cannot allocate memory"; + return (char *)"Argument list too long"; case EACCES: - return "Permission denied"; - case EFAULT: - return "Bad address"; - case ENOTBLK: - return "Block device required"; - case EBUSY: - return "Device or resource busy"; - case EEXIST: - return "File exists"; - case EXDEV: - return "Invalid cross-device link"; - case ENODEV: - return "No such device"; - case ENOTDIR: - return "Not a directory"; - case EISDIR: - return "Is a directory"; - case EINVAL: - return "Invalid argument"; - case ENFILE: - return "Too many open files in system"; - case EMFILE: - return "Too many open files"; - case ENOTTY: - return "Inappropriate ioctl for device"; - case ETXTBSY: - return "Text file busy"; - case EFBIG: - return "File too large"; - case ENOSPC: - return "No space left on device"; - case ESPIPE: - return "Illegal seek"; - case EROFS: - return "Read-only file system"; - case EMLINK: - return "Too many links"; - case EPIPE: - return "Broken pipe"; - case EDOM: - return "Numerical argument out of domain"; - case ERANGE: - return "Numerical result out of range"; - case EDEADLK: - return "Resource deadlock avoided"; - case ENAMETOOLONG: - return "File name too long"; - case ENOLCK: - return "No locks available"; - case ENOSYS: - return "Function not implemented"; - case ENOTEMPTY: - return "Directory not empty"; - case ELOOP: - return "Too many levels of symbolic links"; - case ENOMSG: - return "No message of desired type"; - case EIDRM: - return "Identifier removed"; - case ECHRNG: - return "Channel number out of range"; - case EL2NSYNC: - return "Level 2 not synchronized"; - case EL3HLT: - return "Level 3 halted"; - case EL3RST: - return "Level 3 reset"; - case ELNRNG: - return "Link number out of range"; - case EUNATCH: - return "Protocol driver not attached"; - case ENOCSI: - return "No CSI structure available"; - case EL2HLT: - return "Level 2 halted"; - case EBADE: - return "Invalid exchange"; - case EBADR: - return "Invalid request descriptor"; - case EXFULL: - return "Exchange full"; - case ENOANO: - return "No anode"; - case EBADRQC: - return "Invalid request code"; - case EBADSLT: - return "Invalid slot"; - case EBFONT: - return "Bad font file format"; - case ENOSTR: - return "Device not a stream"; - case ENODATA: - return "No data available"; - case ETIME: - return "Timer expired"; - case ENOSR: - return "Out of streams resources"; - case ENONET: - return "Machine is not on the network"; - case ENOPKG: - return "Package not installed"; - case EREMOTE: - return "Object is remote"; - case ENOLINK: - return "Link has been severed"; - case EADV: - return "Advertise error"; - case ESRMNT: - return "Srmount error"; - case ECOMM: - return "Communication error on send"; - case EPROTO: - return "Protocol error"; - case EMULTIHOP: - return "Multihop attempted"; - case EDOTDOT: - return "RFS specific error"; - case EBADMSG: - return "Bad message"; - case EOVERFLOW: - return "Value too large for defined data type"; - case ENOTUNIQ: - return "Name not unique on network"; - case EBADFD: - return "File descriptor in bad state"; - case EREMCHG: - return "Remote address changed"; - case ELIBACC: - return "Can not access a needed shared library"; - case ELIBBAD: - return "Accessing a corrupted shared library"; - case ELIBSCN: - return ".lib section in a.out corrupted"; - case ELIBMAX: - return "Attempting to link in too many shared libraries"; - case ELIBEXEC: - return "Cannot exec a shared library directly"; - case EILSEQ: - return "Illegal byte sequence"; - case ERESTART: - return "Interrupted system call should be restarted"; - case ESTRPIPE: - return "Streams pipe error"; - case EUSERS: - return "Too many users"; - case ENOTSOCK: - return "Socket operation on non-socket"; - case EDESTADDRREQ: - return "Destination address required"; - case EMSGSIZE: - return "Message too long"; - case EPROTOTYPE: - return "Protocol wrong type for socket"; - case ENOPROTOOPT: - return "Protocol not available"; - case EPROTONOSUPPORT: - return "Protocol not supported"; - case ESOCKTNOSUPPORT: - return "Socket type not supported"; - case EOPNOTSUPP: - return "Operation not supported"; - case EPFNOSUPPORT: - return "Protocol family not supported"; - case EAFNOSUPPORT: - return "Address family not supported by protocol"; + return (char *)"Permission denied"; case EADDRINUSE: - return "Address already in use"; + return (char *)"Address in use"; case EADDRNOTAVAIL: - return "Cannot assign requested address"; - case ENETDOWN: - return "Network is down"; - case ENETUNREACH: - return "Network is unreachable"; - case ENETRESET: - return "Network dropped connection on reset"; - case ECONNABORTED: - return "Software caused connection abort"; - case ECONNRESET: - return "Connection reset by peer"; - case ENOBUFS: - return "No buffer space available"; - case EISCONN: - return "Transport endpoint is already connected"; - case ENOTCONN: - return "Transport endpoint is not connected"; - case ESHUTDOWN: - return "Cannot send after transport endpoint shutdown"; - case ETOOMANYREFS: - return "Too many references: cannot splice"; - case ETIMEDOUT: - return "Connection timed out"; - case ECONNREFUSED: - return "Connection refused"; - case EHOSTDOWN: - return "Host is down"; - case EHOSTUNREACH: - return "No route to host"; + return (char *)"Address not available"; + case EAFNOSUPPORT: + return (char *)"Address family not supported"; + case EAGAIN: + return (char *)"Resource unavailable, try again"; case EALREADY: - return "Operation already in progress"; - case EINPROGRESS: - return "Operation now in progress"; - case ESTALE: - return "Stale file handle"; - case EUCLEAN: - return "Structure needs cleaning"; - case ENOTNAM: - return "Not a XENIX named type file"; - case ENAVAIL: - return "No XENIX semaphores available"; - case EISNAM: - return "Is a named type file"; - case EREMOTEIO: - return "Remote I/O error"; - case EDQUOT: - return "Quota exceeded"; - case ENOMEDIUM: - return "No medium found"; - case EMEDIUMTYPE: - return "Wrong medium type"; + return (char *)"Connection already in progress"; + case EBADF: + return (char *)"Bad file descriptor"; + case EBADMSG: + return (char *)"Bad message"; + case EBUSY: + return (char *)"Device or resource busy"; case ECANCELED: - return "Operation Canceled"; - case ENOKEY: - return "Required key not available"; - case EKEYEXPIRED: - return "Key has expired"; - case EKEYREVOKED: - return "Key has been revoked"; - case EKEYREJECTED: - return "Key was rejected by service"; - case EOWNERDEAD: - return "Owner died"; + return (char *)"Operation canceled"; + case ECHILD: + return (char *)"No child processes"; + case ECONNABORTED: + return (char *)"Connection aborted"; + case ECONNREFUSED: + return (char *)"Connection refused"; + case ECONNRESET: + return (char *)"Connection reset"; + case EDEADLK: + return (char *)"Resource deadlock would occur"; + case EDESTADDRREQ: + return (char *)"Destination address required"; + case EDOM: + return (char *)"Mathematics argument out of domain of function"; + case EDQUOT: + return (char *)"Reserved"; + case EEXIST: + return (char *)"File exists"; + case EFAULT: + return (char *)"Bad address"; + case EFBIG: + return (char *)"File too large"; + case EHOSTUNREACH: + return (char *)"Host is unreachable"; + case EIDRM: + return (char *)"Identifier removed"; + case EILSEQ: + return (char *)"Illegal byte sequence"; + case EINPROGRESS: + return (char *)"Operation in progress"; + case EINTR: + return (char *)"Interrupted function"; + case EINVAL: + return (char *)"Invalid argument"; + case EIO: + return (char *)"I/O error"; + case EISCONN: + return (char *)"Socket is connected"; + case EISDIR: + return (char *)"Is a directory"; + case ELOOP: + return (char *)"Too many levels of symbolic links"; + case EMFILE: + return (char *)"File descriptor value too large"; + case EMLINK: + return (char *)"Too many links"; + case EMSGSIZE: + return (char *)"Message too large"; + case EMULTIHOP: + return (char *)"Reserved"; + case ENAMETOOLONG: + return (char *)"Filename too long"; + case ENETDOWN: + return (char *)"Network is down"; + case ENETRESET: + return (char *)"Connection aborted by network"; + case ENETUNREACH: + return (char *)"Network unreachable"; + case ENFILE: + return (char *)"Too many files open in system"; + case ENOBUFS: + return (char *)"No buffer space available"; + case ENODATA: + return (char *)"No message available on the STREAM head read queue"; + case ENODEV: + return (char *)"No such device"; + case ENOENT: + return (char *)"No such file or directory"; + case ENOEXEC: + return (char *)"Executable file format error"; + case ENOLCK: + return (char *)"No locks available"; + case ENOLINK: + return (char *)"Reserved"; + case ENOMEM: + return (char *)"Not enough space"; + case ENOMSG: + return (char *)"No message of the desired type"; + case ENOPROTOOPT: + return (char *)"Protocol not available"; + case ENOSPC: + return (char *)"No space left on device"; + case ENOSR: + return (char *)"No STREAM resources"; + case ENOSTR: + return (char *)"Not a STREAM"; + case ENOSYS: + return (char *)"Functionality not supported"; + case ENOTCONN: + return (char *)"The socket is not connected"; + case ENOTDIR: + return (char *)"Not a directory or a symbolic link to a directory"; + case ENOTEMPTY: + return (char *)"Directory not empty"; case ENOTRECOVERABLE: - return "State not recoverable"; + return (char *)"State not recoverable"; + case ENOTSOCK: + return (char *)"Not a socket"; + case ENOTSUP: + return (char *)"Not supported"; + case ENOTTY: + return (char *)"Inappropriate I/O control operation"; + case ENXIO: + return (char *)"No such device or address"; + case EOPNOTSUPP: + return (char *)"Operation not supported on socket"; + case EOVERFLOW: + return (char *)"Value too large to be stored in data type"; + case EOWNERDEAD: + return (char *)"Previous owner died"; + case EPERM: + return (char *)"Operation not permitted"; + case EPIPE: + return (char *)"Broken pipe"; + case EPROTO: + return (char *)"Protocol error"; + case EPROTONOSUPPORT: + return (char *)"Protocol not supported"; + case EPROTOTYPE: + return (char *)"Protocol wrong type for socket"; + case ERANGE: + return (char *)"Result too large"; + case EROFS: + return (char *)"Read-only file system"; + case ESPIPE: + return (char *)"Invalid seek"; + case ESRCH: + return (char *)"No such process"; + case ESTALE: + return (char *)"Reserved"; + case ETIME: + return (char *)"Stream ioctl() timeout"; + case ETIMEDOUT: + return (char *)"Connection timed out"; + case ETXTBSY: + return (char *)"Text file busy"; + case EWOULDBLOCK: + return (char *)"Operation would block"; + case EXDEV: + return (char *)"Cross-device link"; default: - return "Unknown error"; + return (char *)"Unknown error"; } -} \ No newline at end of file +} diff --git a/library/std/mutex.cpp b/library/std/mutex.cpp index 7b2f6a8..0ec7747 100644 --- a/library/std/mutex.cpp +++ b/library/std/mutex.cpp @@ -33,6 +33,7 @@ namespace std bool Result = this->Locked.exchange(true, std::memory_order_acquire); TCB *tcb = thisThread; + assert(tcb != nullptr); if (Result == true) { debug("%#lx: Mutex is locked, blocking task %d (\"%s\" : %d)", this, @@ -56,6 +57,7 @@ namespace std bool Result = this->Locked.exchange(true, std::memory_order_acquire); TCB *tcb = thisThread; + assert(tcb != nullptr); if (Result == true) { debug("%#lx: Mutex is locked, task %d (\"%s\" : %d) failed to lock", this, @@ -74,6 +76,7 @@ namespace std void mutex::unlock() { TCB *tcb = thisThread; + assert(tcb != nullptr); assert(this->Holder == tcb); this->Holder = nullptr; diff --git a/library/std/new.cpp b/library/std/new.cpp new file mode 100644 index 0000000..4859ed0 --- /dev/null +++ b/library/std/new.cpp @@ -0,0 +1,82 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include + +void *operator new(std::size_t count) +{ + if (count == 0) + ++count; + + if (void *ptr = kmalloc(count)) + return ptr; + + throw std::bad_alloc{}; +} + +void *operator new[](std::size_t count) +{ + if (count == 0) + ++count; + + if (void *ptr = kmalloc(count)) + return ptr; + + throw std::bad_alloc{}; +} + +// void *operator new(std::size_t count, std::align_val_t al) +// void *operator new[](std::size_t count, std::align_val_t al) + +// void *operator new(std::size_t count, const std::nothrow_t &tag) +// void *operator new[](std::size_t count, const std::nothrow_t &tag) +// void *operator new(std::size_t count, std::align_val_t al, const std::nothrow_t &) +// void *operator new[](std::size_t count, std::align_val_t al, const std::nothrow_t &) + +void *operator new(std::size_t, void *ptr) noexcept { return ptr; } +// void *operator new[](std::size_t count, void *ptr) noexcept + +// void *operator new(std::size_t count, ...) +// void *operator new[](std::size_t count, ...) +// void *operator new(std::size_t count, std::align_val_t al, ...) +// void *operator new[](std::size_t count, std::align_val_t al, ...) + +void operator delete(void *ptr) noexcept { kfree(ptr); } + +void operator delete[](void *ptr) noexcept { kfree(ptr); } + +// void operator delete(void *ptr, std::align_val_t al) noexcept +// void operator delete[](void *ptr, std::align_val_t al) noexcept +void operator delete(void *ptr, std::size_t) noexcept { kfree(ptr); } + +void operator delete[](void *ptr, std::size_t sz) noexcept { kfree(ptr); } +void operator delete(void *ptr, std::size_t sz, std::align_val_t al) noexcept { kfree(ptr); } +// void operator delete[](void *ptr, std::size_t sz, std::align_val_t al) noexcept + +// void operator delete(void *ptr, const std::nothrow_t &tag) noexcept +// void operator delete[](void *ptr, const std::nothrow_t &tag) noexcept +// void operator delete(void *ptr, std::align_val_t al, const std::nothrow_t &tag) noexcept +// void operator delete[](void *ptr, std::align_val_t al, const std::nothrow_t &tag) noexcept + +// void operator delete(void *ptr, void *place) noexcept +// void operator delete[](void *ptr, void *place) noexcept + +// void operator delete(void *ptr, ...) +// void operator delete[](void *ptr, ...) diff --git a/library/std/printf.cpp b/library/std/printf.cpp new file mode 100644 index 0000000..9fb7437 --- /dev/null +++ b/library/std/printf.cpp @@ -0,0 +1,41 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include + +namespace std +{ + int sprintf(char *s, const char *format, ...) + { + va_list args; + va_start(args, format); + int ret = vsprintf(s, format, args); + va_end(args); + return ret; + } + + int snprintf(char *s, size_t count, const char *format, ...) + { + va_list args; + va_start(args, format); + int ret = vsnprintf(s, count, format, args); + va_end(args); + return ret; + } +} diff --git a/network/arp.cpp b/network/arp.cpp index 676e6f7..db1798f 100644 --- a/network/arp.cpp +++ b/network/arp.cpp @@ -17,7 +17,6 @@ #include #include -#include #include "../kernel.h" diff --git a/network/eth.cpp b/network/eth.cpp index d042461..4b951d4 100644 --- a/network/eth.cpp +++ b/network/eth.cpp @@ -57,7 +57,8 @@ namespace NetworkEthernet memcpy(Packet->Data, Data, Length); /* Network Interface Manager takes care of physical allocation. So basically, we allocate here and then it allocates again but 1:1 mapped. */ - NIManager->Send(Interface, (uint8_t *)Packet, PacketLength); + // NIManager->Send(Interface, (uint8_t *)Packet, PacketLength); + assert(!"Function not implemented"); kfree(Packet); } diff --git a/network/icmp.cpp b/network/icmp.cpp index 3ff792a..e8bc2ca 100644 --- a/network/icmp.cpp +++ b/network/icmp.cpp @@ -48,7 +48,8 @@ namespace NetworkICMPv4 Packet->Header.Type = ICMPv4Type::TYPE_ECHO_REPLY; Packet->Header.Code = 0x0; Packet->Header.Checksum = CalculateChecksum((uint16_t *)Packet, sizeof(ICMPHeader)); - NIManager->Send(this->Interface, (uint8_t *)Packet, sizeof(ICMPHeader) + 0); + // NIManager->Send(this->Interface, (uint8_t *)Packet, sizeof(ICMPHeader) + 0); + assert(!"Function not implemented"); } else { diff --git a/network/ip.cpp b/network/ip.cpp index f714b25..a777ff8 100644 --- a/network/ip.cpp +++ b/network/ip.cpp @@ -114,7 +114,8 @@ namespace NetworkIPv4 Packet->Header.TimeToLive = 0x40; Packet->Header.HeaderChecksum = 0x0; Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Data, 4 * Packet->Header.TotalLength); - NIManager->Send(Ethernet->GetInterface(), (uint8_t *)Data, Length); + // NIManager->Send(Ethernet->GetInterface(), (uint8_t *)Data, Length); + assert(!"Function not implemented"); } return Reply; } diff --git a/network/network_controller.cpp b/network/network_controller.cpp index caf465e..0011b81 100644 --- a/network/network_controller.cpp +++ b/network/network_controller.cpp @@ -169,7 +169,11 @@ namespace NetworkInterfaceManager fixme("Stop network stack"); } - void CallStartNetworkStackWrapper() { NIManager->StartNetworkStack(); } + void CallStartNetworkStackWrapper() + { + // NIManager->StartNetworkStack(); + assert(!"Function not implemented"); + } void NetworkInterface::StartService() { @@ -179,16 +183,18 @@ namespace NetworkInterfaceManager void NetworkInterface::DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size) { - foreach (auto inf in this->Interfaces) - if (inf->DriverID == DriverID) - NIManager->Send(inf, Data, Size); + // foreach (auto inf in this->Interfaces) + // if (inf->DriverID == DriverID) + // NIManager->Send(inf, Data, Size); + assert(!"Function not implemented"); } void NetworkInterface::DrvReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size) { - foreach (auto inf in this->Interfaces) - if (inf->DriverID == DriverID) - NIManager->Receive(inf, Data, Size); + // foreach (auto inf in this->Interfaces) + // if (inf->DriverID == DriverID) + // NIManager->Receive(inf, Data, Size); + assert(!"Function not implemented"); } void NetworkInterface::Send(DeviceInterface *Interface, uint8_t *Data, size_t Length) diff --git a/network/udp.cpp b/network/udp.cpp index cb2f1c2..a07308a 100644 --- a/network/udp.cpp +++ b/network/udp.cpp @@ -66,14 +66,14 @@ namespace NetworkUDP Socket *UDP::Listen(uint16_t Port) { UNUSED(Port); - fixme("Not implemented."); + fixme("Not implemented"); return nullptr; } void UDP::Disconnect(Socket *Socket) { UNUSED(Socket); - fixme("Not implemented."); + fixme("Not implemented"); } void UDP::Send(Socket *Socket, uint8_t *Data, size_t Length) diff --git a/storage/README.md b/storage/README.md deleted file mode 100644 index 9d0cfd3..0000000 --- a/storage/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# File System Implementation - ---- - -## Nodes - -### /storage - -- `node.cpp` - - **Node <=> device** - - Handles open/close/read/write operations for the device and holds information about the file - -
- -- `reference.cpp` - - **kernel/user <=> node.cpp** - - Maintains the count of references to a node and the seek position - -
- -- `descriptor.cpp` - - **user <=> reference.cpp** - - Manages the file descriptor table for user processes - -### /storage/fs - -This directory contains the implementations of various file systems, such as `fat32.cpp` and `ustar.cpp`. - -### /storage/devices - -This directory houses implementations of various devices, including /dev/null, /dev/zero, /dev/random, and more. diff --git a/storage/cache.cpp b/storage/cache.cpp new file mode 100644 index 0000000..cbe3be1 --- /dev/null +++ b/storage/cache.cpp @@ -0,0 +1,121 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include + +#include "../kernel.h" + +namespace vfs +{ + FileNode *Virtual::__CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName) + { + if (Root == nullptr) + return nullptr; + + if (IsName) + { + if (strcmp(Root->Name.c_str(), NameOrPath) == 0) + return Root; + } + else + { + if (strcmp(Root->Path.c_str(), NameOrPath) == 0) + return Root; + } + + for (const auto &Child : Root->Children) + { + FileNode *ret = __CacheRecursiveSearch(Child, NameOrPath, IsName); + if (ret) + return ret; + } + + debug("Failed to find %s in %s", NameOrPath, Root->Path.c_str()); + return nullptr; + } + + FileNode *Virtual::CacheLookup(const char *Path) + { + FileNode *rootNode = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0); + + FileNode *ret = __CacheRecursiveSearch(rootNode, Path, false); + if (ret) + return ret; + + debug("Path \"%s\" not found", Path); + return nullptr; + __unreachable; + + debug("Path \"%s\" not found; attempting to search by segments", Path); + /* FIXME: This may not be the greatest idea */ + + struct cwk_segment segment; + if (!cwk_path_get_first_segment(Path, &segment)) + return __CacheRecursiveSearch(rootNode, Path, true); + + do + { + std::string segmentStr(segment.begin, segment.size); + ret = __CacheRecursiveSearch(rootNode, segmentStr.c_str(), true); + if (ret) + return ret; + } while (cwk_path_get_next_segment(&segment)); + + return nullptr; + } + + FileNode *Virtual::CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode) + { + FileNode *fn = new FileNode(); + fn->Name = Name; + if (Parent) + { + fn->Path = Parent->Path + "/" + Name; + Parent->Children.push_back(fn); + } + else + fn->Path = Name; + fn->Parent = Parent; + fn->Node = Node; + fn->fsi = DeviceMap[Node->Device].fsi; + if (fn->fsi == nullptr) + warn("Failed to find filesystem for device %d", Node->Device); + + debug("Created cache node %s", fn->Path.c_str()); + return fn; + } + + int Virtual::RemoveCacheNode(FileNode *Node) + { + if (Node == nullptr) + return -1; + + if (Node->Parent) + { + Node->Parent->Children.erase(std::find(Node->Parent->Children.begin(), Node->Parent->Children.end(), Node)); + // delete Node; + fixme("Node deletion is disabled for now (for debugging purposes)"); + } + + return 0; + } +} diff --git a/storage/descriptor.cpp b/storage/descriptor.cpp index c792411..24477c1 100644 --- a/storage/descriptor.cpp +++ b/storage/descriptor.cpp @@ -17,7 +17,6 @@ #include -#include #include #include #include @@ -29,147 +28,22 @@ namespace vfs { - // ReadFSFunction(fd_Read) - // { - // if (Size <= 0) - // Size = node->Length; - - // if (RefOffset > node->Length) - // return 0; - - // if ((node->Length - RefOffset) == 0) - // return 0; /* EOF */ - - // if (RefOffset + (off_t)Size > node->Length) - // Size = node->Length; - - // memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size); - // return Size; - // } - - // WriteFSFunction(fd_Write) - // { - // if (Size <= 0) - // Size = node->Length; - - // if (RefOffset > node->Length) - // return 0; - - // if (RefOffset + (off_t)Size > node->Length) - // Size = node->Length; - - // memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size); - // return Size; - // } - - // vfs::FileSystemOperations fd_op = { - // .Name = "fd", - // // .Read = fd_Read, - // // .Write = fd_Write, - // }; - - FileDescriptorTable::Fildes & - FileDescriptorTable::GetFileDescriptor(int FileDescriptor) - { - foreach (auto &fd in FileDescriptors) - { - if (fd.Descriptor == FileDescriptor) - { - // debug("Found file descriptor %d", FileDescriptor); - return fd; - } - } - return nullfd; - } - - FileDescriptorTable::Fildes & - FileDescriptorTable::GetDupFildes(int FileDescriptor) - { - foreach (auto &fd in FildesDuplicates) - { - if (fd.Descriptor == FileDescriptor) - { - debug("Found duplicated file descriptor %d", FileDescriptor); - return fd; - } - } - return nullfd; - } - - FileDescriptorTable::Fildes & - FileDescriptorTable::GetDescriptor(int FileDescriptor) - { - Fildes &fd = this->GetFileDescriptor(FileDescriptor); - Fildes &dfd = this->GetDupFildes(FileDescriptor); - - if (fd.Descriptor == -1 && - dfd.Descriptor == -1) - return nullfd; - - if (fd.Descriptor != -1) - return fd; - else - return dfd; - } - int FileDescriptorTable::GetFlags(int FileDescriptor) { - Fildes &fd = this->GetDescriptor(FileDescriptor); - if (fd == nullfd) - { - debug("invalid fd %d", FileDescriptor); - return -EBADF; - } + auto it = this->FileMap.find(FileDescriptor); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor); - return fd.Flags; + return it->second.Flags; } int FileDescriptorTable::SetFlags(int FileDescriptor, int Flags) { - Fildes &fd = this->GetDescriptor(FileDescriptor); - if (fd == nullfd) - { - debug("invalid fd %d", FileDescriptor); - return -EBADF; - } - - fd.Flags = Flags; - return 0; - } - - int FileDescriptorTable::ProbeMode(mode_t Mode, int Flags) - { - if (!(Flags & O_CREAT)) - return 0; - - if (Flags & O_RDONLY) - { - if (!(Mode & S_IRUSR)) - { - debug("No read permission (%d)", Mode); - return -EACCES; - } - } - - if (Flags & O_WRONLY) - { - if (!(Mode & S_IWUSR)) - { - debug("No write permission (%d)", Mode); - return -EACCES; - } - } - - if (Flags & O_RDWR) - { - if (!(Mode & S_IRUSR) || - !(Mode & S_IWUSR)) - { - debug("No read/write permission (%d)", Mode); - return -EACCES; - } - } + auto it = this->FileMap.find(FileDescriptor); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor); + it->second.Flags = Flags; return 0; } @@ -178,39 +52,56 @@ namespace vfs { Tasking::PCB *pcb = thisProcess; + auto ProbeMode = [](mode_t Mode, int Flags) -> int + { + if (!(Flags & O_CREAT)) + return 0; + + if (Flags & O_RDONLY) + { + if (!(Mode & S_IRUSR)) + { + debug("No read permission (%d)", Mode); + return -EACCES; + } + } + + if (Flags & O_WRONLY) + { + if (!(Mode & S_IWUSR)) + { + debug("No write permission (%d)", Mode); + return -EACCES; + } + } + + if (Flags & O_RDWR) + { + if (!(Mode & S_IRUSR) || + !(Mode & S_IWUSR)) + { + debug("No read/write permission (%d)", Mode); + return -EACCES; + } + } + + return 0; + }; + if (ProbeMode(Mode, Flags) < 0) return -EACCES; + fixme("Do not follow symlinks when O_CREAT and O_EXCL are set"); + if (Flags & O_CREAT) { - int ret; - bool absolute = cwk_path_is_absolute(AbsolutePath); - new Node(pcb->CurrentWorkingDirectory, - AbsolutePath, NodeType::FILE, - absolute, fs, &ret); - - if (ret == -EEXIST) + FileNode *ret = fs->Create(pcb->CWD, AbsolutePath, Mode); + if (Flags & O_EXCL && ret == nullptr) { - debug("%s: File already exists, continuing...", - AbsolutePath); - } - else if (Flags & O_EXCL) - { - debug("%s: File already exists, returning EEXIST", + debug("%s: File already exists?, returning EEXIST", AbsolutePath); return -EEXIST; } - else if (ret < 0) - { - error("Failed to create file %s: %d", - AbsolutePath, ret); - assert(ret < 0); - } - } - - if (Flags & O_TRUNC) - { - fixme("O_TRUNC"); } if (Flags & O_CLOEXEC) @@ -218,166 +109,88 @@ namespace vfs fixme("O_CLOEXEC"); } - RefNode *File = fs->Open(AbsolutePath, - pcb->CurrentWorkingDirectory); + FileNode *File = fs->GetByPath(AbsolutePath, pcb->CWD); if (!File) { - error("Failed to open file %s", - AbsolutePath); + error("Failed to open file %s", AbsolutePath); return -ENOENT; } + if (Flags & O_TRUNC) + { + debug("Truncating file %s", AbsolutePath); + File->Truncate(0); + } + + Fildes fd{}; + if (Flags & O_APPEND) { debug("Appending to file %s", AbsolutePath); - File->seek(0, SEEK_END); + struct kstat stat; + File->Stat(&stat); + fd.Offset = File->Seek(stat.Size); } - Fildes fd = {.Descriptor = GetFreeFileDescriptor()}; - - if (fd.Descriptor < 0) - return -EMFILE; - fd.Mode = Mode; fd.Flags = Flags; - fd.Handle = File; + fd.Node = File; - FileDescriptors.push_back(fd); + int fdn = this->GetFreeFileDescriptor(); + if (fdn < 0) + return fdn; - char FileName[64]; - itoa(fd.Descriptor, FileName, 10); - assert(fs->CreateLink(FileName, AbsolutePath, this->fdDir) != nullptr); + this->FileMap.insert({fdn, fd}); - int rfd = File->node->open(Flags, Mode); - if (rfd <= 0) - return fd.Descriptor; - else - return rfd; + char linkName[64]; + snprintf(linkName, 64, "%d", fdn); + assert(fs->CreateLink(linkName, this->fdDir, AbsolutePath) != nullptr); + + File->Open(Flags, Mode); + return fdn; } int FileDescriptorTable::RemoveFileDescriptor(int FileDescriptor) { - forItr(itr, FileDescriptors) - { - if (itr->Descriptor == FileDescriptor) - { - FileDescriptors.erase(itr); + auto it = this->FileMap.find(FileDescriptor); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor); - char FileName[64]; - itoa(FileDescriptor, FileName, 10); - fs->Delete(FileName, false, this->fdDir); - return 0; - } - } - - forItr(itr, FildesDuplicates) - { - if (itr->Descriptor == FileDescriptor) - { - FildesDuplicates.erase(itr); - - char FileName[64]; - itoa(FileDescriptor, FileName, 10); - fs->Delete(FileName, false, this->fdDir); - return 0; - } - } - - return -EBADF; + fs->Remove(it->second.Node); + this->FileMap.erase(it); + return 0; } int FileDescriptorTable::GetFreeFileDescriptor() { - int i = 0; - while (true) + Tasking::PCB *pcb = thisProcess; + + for (size_t i = 0; i < pcb->Limits.OpenFiles; i++) { - bool Found = false; - foreach (auto fd in FileDescriptors) - { - if (fd.Descriptor == i) - { - Found = true; - break; - } - } - - if (!Found) - { - foreach (auto fd in FildesDuplicates) - { - if (fd.Descriptor == i) - { - Found = true; - break; - } - } - } - - if (!Found) + auto it = this->FileMap.find(i); + if (it == this->FileMap.end()) return i; - i++; } return -EMFILE; } - const char *FileDescriptorTable::GetAbsolutePath(int FileDescriptor) - { - Fildes &fd = this->GetDescriptor(FileDescriptor); - if (fd == nullfd) - return ""; - - Node *node = fd.Handle->node; - const char *path = new char[strlen(node->FullPath) + 1]; - strcpy((char *)path, node->FullPath); - return path; - } - - RefNode *FileDescriptorTable::GetRefNode(int FileDescriptor) - { - Fildes &fd = this->GetDescriptor(FileDescriptor); - if (fd == nullfd) - return nullptr; - - return fd.Handle; - } - void FileDescriptorTable::Fork(FileDescriptorTable *Parent) { - foreach (auto &fd in Parent->FileDescriptors) + this->FileMap = Parent->FileMap; + + for (const auto &fd : this->FileMap) { - debug("Forking fd: %d", fd.Descriptor); - RefNode *node = fs->Open(fd.Handle->node->FullPath, - thisProcess->CurrentWorkingDirectory); - assert(node != nullptr); - - Fildes new_fd; - new_fd.Descriptor = fd.Descriptor; - new_fd.Flags = fd.Flags; - new_fd.Mode = fd.Mode; - new_fd.Handle = node; - this->FileDescriptors.push_back(new_fd); - } - - foreach (auto &fd in Parent->FildesDuplicates) - { - debug("Forking duplicated fd: %d", fd.Descriptor); - RefNode *node = fs->Open(fd.Handle->node->FullPath, - thisProcess->CurrentWorkingDirectory); - assert(node != nullptr); - - Fildes new_fd; - new_fd.Descriptor = fd.Descriptor; - new_fd.Flags = fd.Flags; - new_fd.Mode = fd.Mode; - new_fd.Handle = node; - this->FildesDuplicates.push_back(new_fd); + if (fd.second.Flags & O_CLOEXEC) + { + debug("O_CLOEXEC flag set, removing fd %d", fd.first); + this->FileMap.erase(fd.first); + } } } - int FileDescriptorTable::_open(const char *pathname, int flags, - mode_t mode) + int FileDescriptorTable::usr_open(const char *pathname, int flags, mode_t mode) { if (pathname == nullptr) return -EFAULT; @@ -385,271 +198,181 @@ namespace vfs return AddFileDescriptor(pathname, mode, flags); } - int FileDescriptorTable::_creat(const char *pathname, mode_t mode) + int FileDescriptorTable::usr_creat(const char *pathname, mode_t mode) { - return _open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); + return usr_open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); } - ssize_t FileDescriptorTable::_read(int _fd, void *buf, size_t count) + ssize_t FileDescriptorTable::usr_read(int fd, void *buf, size_t count) { - Fildes &fd = this->GetDescriptor(_fd); - if (fd == nullfd) - { - debug("invalid fd %d", _fd); - return -EBADF; - } + auto it = this->FileMap.find(fd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - return fd.Handle->read((uint8_t *)buf, count); + return it->second.Node->Read(buf, count, it->second.Offset); } - ssize_t FileDescriptorTable::_write(int _fd, const void *buf, - size_t count) + ssize_t FileDescriptorTable::usr_write(int fd, const void *buf, size_t count) { - Fildes &fd = this->GetDescriptor(_fd); - if (fd == nullfd) - { - debug("invalid fd %d", _fd); - return -EBADF; - } + auto it = this->FileMap.find(fd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - return fd.Handle->write((uint8_t *)buf, count); + return it->second.Node->Write(buf, count, it->second.Offset); } - int FileDescriptorTable::_close(int _fd) + int FileDescriptorTable::usr_close(int fd) { - Fildes &fd = this->GetDescriptor(_fd); - if (fd == nullfd) - { - debug("invalid fd %d", _fd); - return -EBADF; - } + auto it = this->FileMap.find(fd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - if (RemoveFileDescriptor(_fd) < 0) - { - debug("invalid fd %d", _fd); - return -EBADF; - } + return RemoveFileDescriptor(fd); + } - bool Found = false; - foreach (auto dfd in FileDescriptors) + off_t FileDescriptorTable::usr_lseek(int fd, off_t offset, int whence) + { + auto it = this->FileMap.find(fd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); + + off_t &newOffset = it->second.Offset; + + switch (whence) { - if (dfd.Handle == fd.Handle) + case SEEK_SET: + { + newOffset = it->second.Node->Seek(offset); + break; + } + case SEEK_CUR: + { + newOffset = it->second.Node->Seek(newOffset + offset); + break; + } + case SEEK_END: + { + struct kstat stat { - Found = true; - break; - } + }; + it->second.Node->Stat(&stat); + newOffset = it->second.Node->Seek(stat.Size + offset); + break; } - - if (!Found) - foreach (auto dfd in FildesDuplicates) - { - if (dfd.Handle == fd.Handle) - { - Found = true; - break; - } - } - - /* If the file descriptor is a duplicate, - we don't need to close the handle, - because it's a duplicate of another - file descriptor. */ - if (!Found) - delete fd.Handle; - return 0; - } - - off_t FileDescriptorTable::_lseek(int _fd, off_t offset, int whence) - { - Fildes &fd = this->GetDescriptor(_fd); - if (fd == nullfd) - { - debug("invalid fd %d", _fd); - return -EBADF; - } - - return fd.Handle->seek(offset, whence); - } - - int FileDescriptorTable::_stat(const char *pathname, - struct kstat *statbuf) - { - if (pathname == nullptr) + default: return -EINVAL; - - RefNode *file = fs->Open(pathname, - thisProcess->CurrentWorkingDirectory); - - if (!file) - { - error("Failed to open file %s", - pathname); - return -ENOENT; } - Node *node = file->node; - statbuf->st_dev = 0; /* FIXME: stub */ - statbuf->st_ino = node->IndexNode; - statbuf->st_mode = node->Type | (node->Mode & ~S_IFMT); - statbuf->st_nlink = 0; /* FIXME: stub */ - statbuf->st_uid = node->UserIdentifier; - statbuf->st_gid = node->GroupIdentifier; - statbuf->st_rdev = 0; /* FIXME: stub */ - statbuf->st_size = node->Size; - statbuf->st_atime = node->AccessTime; - statbuf->st_mtime = node->ModifyTime; - statbuf->st_ctime = node->ChangeTime; - statbuf->st_blksize = 0; /* FIXME: stub */ - statbuf->st_blocks = 0; /* FIXME: stub */ - statbuf->st_attr = 0; /* FIXME: stub */ - return 0; + return newOffset; } - int FileDescriptorTable::_fstat(int _fd, struct kstat *statbuf) + int FileDescriptorTable::usr_stat(const char *pathname, + struct kstat *statbuf) { - Fildes &fd = this->GetDescriptor(_fd); - if (fd == nullfd) + FileNode *node = fs->GetByPath(pathname, nullptr); + if (node == nullptr) + ReturnLogError(-ENOENT, "Failed to find %s", pathname); + + if (node->IsSymbolicLink()) { - debug("invalid fd %d", _fd); - return -EBADF; + std::unique_ptr buffer(new char[1024]); + ssize_t ret = node->ReadLink(buffer.get(), 1024); + if (ret < 0) + return ret; + + FileNode *target = fs->GetByPath(buffer.get(), nullptr); + if (target == nullptr) + return -ENOENT; + + return target->Stat(statbuf); } - Node *node = fd.Handle->node; - statbuf->st_dev = 0; /* FIXME: stub */ - statbuf->st_ino = node->IndexNode; - statbuf->st_mode = node->Type | (node->Mode & ~S_IFMT); - statbuf->st_nlink = 0; /* FIXME: stub */ - statbuf->st_uid = node->UserIdentifier; - statbuf->st_gid = node->GroupIdentifier; - statbuf->st_rdev = 0; /* FIXME: stub */ - statbuf->st_size = node->Size; - statbuf->st_atime = node->AccessTime; - statbuf->st_mtime = node->ModifyTime; - statbuf->st_ctime = node->ChangeTime; - statbuf->st_blksize = 0; /* FIXME: stub */ - statbuf->st_blocks = 0; /* FIXME: stub */ - statbuf->st_attr = 0; /* FIXME: stub */ - return 0; + return node->Stat(statbuf); } - int FileDescriptorTable::_lstat(const char *pathname, - struct kstat *statbuf) + int FileDescriptorTable::usr_fstat(int fd, struct kstat *statbuf) { - if (pathname == nullptr) - return -EINVAL; + auto it = this->FileMap.find(fd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - RefNode *file = fs->Open(pathname, - thisProcess->CurrentWorkingDirectory); + vfs::FileDescriptorTable::Fildes &fildes = it->second; - if (!file) - { - error("Failed to open file %s", - pathname); - return -ENOENT; - } - - Node *node = file->node; - statbuf->st_dev = 0; /* FIXME: stub */ - statbuf->st_ino = node->IndexNode; - statbuf->st_mode = node->Type | (node->Mode & ~S_IFMT); - statbuf->st_nlink = 0; /* FIXME: stub */ - statbuf->st_uid = node->UserIdentifier; - statbuf->st_gid = node->GroupIdentifier; - statbuf->st_rdev = 0; /* FIXME: stub */ - statbuf->st_size = node->Size; - statbuf->st_atime = node->AccessTime; - statbuf->st_mtime = node->ModifyTime; - statbuf->st_ctime = node->ChangeTime; - statbuf->st_blksize = 0; /* FIXME: stub */ - statbuf->st_blocks = 0; /* FIXME: stub */ - statbuf->st_attr = 0; /* FIXME: stub */ - return 0; + return fildes.Node->Stat(statbuf); } - int FileDescriptorTable::_dup(int oldfd) + int FileDescriptorTable::usr_lstat(const char *pathname, + struct kstat *statbuf) { - Fildes &fd = this->GetDescriptor(oldfd); - if (fd == nullfd) - { - debug("invalid fd %d", oldfd); - return -EBADF; - } + FileNode *node = fs->GetByPath(pathname, nullptr); + if (node == nullptr) + ReturnLogError(-ENOENT, "Failed to find %s", pathname); + return node->Stat(statbuf); + } + + int FileDescriptorTable::usr_dup(int oldfd) + { + auto it = this->FileMap.find(oldfd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", oldfd); int newfd = this->GetFreeFileDescriptor(); if (newfd < 0) return -EMFILE; Fildes new_dfd{}; - new_dfd.Handle = fd.Handle; - new_dfd.Mode = fd.Mode; + new_dfd.Node = it->second.Node; + new_dfd.Mode = it->second.Mode; - new_dfd.Descriptor = newfd; - this->FildesDuplicates.push_back(new_dfd); - debug("Duplicated file descriptor %d to %d", - oldfd, newfd); + this->FileMap.insert({newfd, new_dfd}); + + debug("Duplicated file descriptor %d to %d", oldfd, newfd); return newfd; } - int FileDescriptorTable::_dup2(int oldfd, int newfd) + int FileDescriptorTable::usr_dup2(int oldfd, int newfd) { - Fildes &fd = this->GetDescriptor(oldfd); - if (fd == nullfd) - { - debug("invalid fd %d", oldfd); - return -EBADF; - } - if (newfd < 0) - { - debug("invalid fd %d", newfd); - return -EBADF; - } + ReturnLogError(-EBADF, "Invalid newfd %d", newfd); + + auto it = this->FileMap.find(oldfd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid oldfd %d", oldfd); if (newfd == oldfd) return newfd; - /* Even if it's not valid - we ignore it. */ - this->_close(newfd); + /* Even if it's not valid we ignore it. */ + this->usr_close(newfd); Fildes new_dfd{}; - new_dfd.Handle = fd.Handle; - new_dfd.Mode = fd.Mode; + new_dfd.Node = it->second.Node; + new_dfd.Mode = it->second.Mode; - new_dfd.Descriptor = newfd; - this->FildesDuplicates.push_back(new_dfd); - debug("Duplicated file descriptor %d to %d", - oldfd, newfd); + this->FileMap.insert({newfd, new_dfd}); + debug("Duplicated file descriptor %d to %d", oldfd, newfd); return newfd; } - int FileDescriptorTable::_ioctl(int _fd, unsigned long request, void *argp) + int FileDescriptorTable::usr_ioctl(int fd, unsigned long request, void *argp) { - Fildes &fd = this->GetDescriptor(_fd); - if (fd == nullfd) - { - debug("invalid fd %d", _fd); - return -EBADF; - } + auto it = this->FileMap.find(fd); + if (it == this->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - return fd.Handle->ioctl(request, argp); + return it->second.Node->Ioctl(request, argp); } - FileDescriptorTable::FileDescriptorTable(void *Owner) + FileDescriptorTable::FileDescriptorTable(void *_Owner) + : Owner(_Owner) { debug("+ %#lx", this); - this->fdDir = fs->Create("fd", vfs::NodeType::DIRECTORY, - ((Tasking::PCB *)Owner)); - } - FileDescriptorTable::~FileDescriptorTable() - { - debug("- %#lx", this); - foreach (auto &fd in FileDescriptors) - { - debug("Removing fd: %d", fd.Descriptor); - this->RemoveFileDescriptor(fd.Descriptor); - delete fd.Handle; - } + mode_t Mode = S_IXOTH | S_IROTH | + S_IXGRP | S_IRGRP | + S_IXUSR | S_IRUSR | + S_IFDIR; + + this->fdDir = fs->Create(((Tasking::PCB *)_Owner)->ProcDirectory, "fd", Mode); } } diff --git a/storage/devices/random.cpp b/storage/devices/random.cpp deleted file mode 100644 index be170b2..0000000 --- a/storage/devices/random.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include -#include -#include - -#include "../../kernel.h" - -namespace vfs -{ - size_t RandomDevice::read(uint8_t *Buffer, size_t Size, off_t Offset) - { - if (Size <= 0) - return 0; - - uint64_t *buf = (uint64_t *)Buffer; - for (size_t i = 0; i < Size / sizeof(uint64_t); i++) - buf[i] = Random::rand64(); - return Size; - } - - size_t RandomDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) - { - return Size; - } - - RandomDevice::RandomDevice() : Node(DevFS, "random", CHARDEVICE) {} - RandomDevice::~RandomDevice() {} -} diff --git a/storage/devices/tty/kcon.cpp b/storage/devices/tty/kcon.cpp deleted file mode 100644 index 4ad5597..0000000 --- a/storage/devices/tty/kcon.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include -#include -#include -#include - -#include "../../../kernel.h" - -namespace vfs -{ - size_t KConDevice::read(uint8_t *Buffer, size_t Size, off_t Offset) - { - return DriverManager->InputKeyboardDev->read(Buffer, Size, Offset); - } - - size_t KConDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) - { - if (Offset != 0) - fixme("Offset is %d", Offset); - - for (size_t i = 0; i < Size; i++) - putchar(((char *)Buffer)[i]); - - if (!Config.Quiet) - Display->UpdateBuffer(); - return Size; - } - - int KConDevice::ioctl(unsigned long Request, void *Argp) - { - static_assert(sizeof(struct termios) < PAGE_SIZE); - - void *pArgp = thisProcess->PageTable->Get(Argp); - switch (Request) - { - case TCGETS: - { - struct termios *t = (struct termios *)pArgp; - memcpy(t, &this->term, sizeof(struct termios)); - break; - } - case TCSETS: - { - struct termios *t = (struct termios *)pArgp; - memcpy(&this->term, t, sizeof(struct termios)); - break; - } - case TIOCGPGRP: - { - *((pid_t *)Argp) = 0; - fixme("TIOCGPGRP not implemented"); - return 0; - } - case TIOCSPGRP: - { - *((pid_t *)Argp) = 0; - fixme("TIOCSPGRP not implemented"); - return 0; - } - case TIOCGWINSZ: - { - struct winsize *ws = (struct winsize *)pArgp; - memcpy(ws, &this->termSize, sizeof(struct winsize)); - break; - } - case TIOCSWINSZ: - { - struct winsize *ws = (struct winsize *)pArgp; - memcpy(&this->termSize, ws, sizeof(struct winsize)); - break; - } - case TCSETSW: - case TCSETSF: - case TCGETA: - case TCSETA: - case TCSETAW: - case TCSETAF: - case TCSBRK: - case TCXONC: - case TCFLSH: - case TIOCEXCL: - case TIOCNXCL: - case TIOCSCTTY: - case TIOCOUTQ: - case TIOCSTI: - case TIOCMGET: - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - { - fixme("ioctl %#lx not implemented", Request); - return -ENOSYS; - } - case TIOCGPTN: - case 0xffffffff80045430: /* FIXME: ???? */ - { - int *n = (int *)pArgp; - *n = -1; - break; - } - case TIOCSPTLCK: - { - int *n = (int *)pArgp; - *n = 0; - break; - } - default: - { - debug("Unknown ioctl %#lx", Request); - return -EINVAL; - } - } - - return 0; - } - - KConDevice::KConDevice() : Node(DevFS, "kcon", CHARDEVICE) - { - /* - - ICRNL - Map Carriage Return to New Line - - IXON - Enable XON/XOFF flow control - - - OPOST - Enable output processing - - ONLCR - Map New Line to Carriage Return - New Line - - - CS8 - 8-bit characters - - CREAD - Enable receiver - - HUPCL - Hang up on last close - - - ECHO - Echo input characters - - ICANON - Enable canonical input (enable line editing) - */ - this->term.c_iflag = /*ICRNL |*/ IXON; - this->term.c_oflag = OPOST | ONLCR; - this->term.c_cflag = CS8 | CREAD | HUPCL; - this->term.c_lflag = ECHO | ICANON; - this->term.c_cc[VEOF] = 0x04; /* ^D */ - this->term.c_cc[VEOL] = 0x00; /* NUL */ - this->term.c_cc[VERASE] = 0x7f; /* DEL */ - this->term.c_cc[VINTR] = 0x03; /* ^C */ - this->term.c_cc[VKILL] = 0x15; /* ^U */ - this->term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */ - this->term.c_cc[VQUIT] = 0x1c; /* ^\ */ - this->term.c_cc[VSTART] = 0x11; /* ^Q */ - this->term.c_cc[VSTOP] = 0x13; /* ^S */ - this->term.c_cc[VSUSP] = 0x1a; /* ^Z */ - this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ - this->term.c_cc[VWERASE] = 0x17; /* ^W */ - } - - KConDevice::~KConDevice() - { - } -} diff --git a/storage/devices/tty/ptmx.cpp b/storage/devices/tty/ptmx.cpp index aec02c7..c471efb 100644 --- a/storage/devices/tty/ptmx.cpp +++ b/storage/devices/tty/ptmx.cpp @@ -24,69 +24,67 @@ namespace vfs { - int PTMXDevice::open(int Flags, mode_t Mode) + int PTMXDevice::Open(Inode *Node, int Flags, mode_t Mode, struct Inode *Result) { - SmartLock(PTMXLock); - int id = -1; - for (size_t i = 0; i < ptysId.Size; i++) - { - if (unlikely(ptysId.Buffer[i] == false)) - { - id = int(i); - ptysId.Buffer[i] = true; - break; - } - } + // SmartLock(PTMXLock); - if (id == -1) - return -ENFILE; + // int ptyID = -1; + // for (int i = 0; i < (int)ptysId.Size; i++) + // { + // if (ptysId.Buffer[i]) + // continue; - PTYDevice *pty = new PTYDevice(pts, id); - ptysList.push_back(pty); - return pty->OpenMaster(Flags, Mode); + // ptyID = i; + // ptysId.Buffer[i] = true; + // break; + // } + + // if (ptyID == -1) + // return -ENFILE; + + // PTYDevice *pty = new PTYDevice(pts, ptyID); + // ptysList.insert(std::make_pair(ptyID, pty)); + // // return pty->OpenMaster(Flags, Mode); + assert(!"Function not implemented"); } - void PTMXDevice::RemovePTY(int fd, Tasking::PCB *pcb) + int PTMXDevice::Close(struct Inode *Node) { SmartLock(PTMXLock); - if (!pcb) - pcb = thisProcess; - assert(pcb != nullptr); - FileDescriptorTable *fdt = pcb->FileDescriptors; - RefNode *node = fdt->GetRefNode(fd); - - assert(node->SpecialData != nullptr); - PTYDevice *pty = (PTYDevice *)node->SpecialData; - int id = pty->ptyId; - - forItr(itr, ptysList) - { - if (*itr != pty) - continue; - - ptysList.erase(itr); - delete *itr; - break; - } - ptysId.Buffer[id] = false; + PTYDevice *pty = ptysList.at(Node->Index); + ptysList.erase(Node->Index); + assert(!"Function not implemented"); } - PTMXDevice::PTMXDevice() : Node(DevFS, "ptmx", CHARDEVICE) + PTMXDevice::PTMXDevice() { - this->Mode = 0644; - this->UserIdentifier = 0; - this->GroupIdentifier = 0; - pts = new Node(DevFS, "pts", DIRECTORY); - ptysId.Buffer = new uint8_t[0x1000]; - ptysId.Size = 0x1000; + // /* c rw- rw- rw- */ + // mode_t mode = S_IRUSR | S_IWUSR | + // S_IRGRP | S_IWGRP | + // S_IROTH | S_IWOTH | + // S_IFCHR; + + // ptmx = fs->Create(ptmx, "pts", mode); + // assert(!"Function not implemented"); + // // ptmx->SetDevice(5, 2); + + // /* d rwx r-x r-x */ + // mode_t ptsMode = S_IRWXU | + // S_IRGRP | S_IXGRP | + // S_IROTH | S_IXOTH | + // S_IFDIR; + // pts = fs->Create(ptmx, "pts", ptsMode); + // assert(pts != nullptr); + + // ptysId.Buffer = new uint8_t[0x1000]; + // ptysId.Size = 0x1000; } PTMXDevice::~PTMXDevice() { SmartLock(PTMXLock); - delete pts; delete[] ptysId.Buffer; } } diff --git a/storage/devices/tty/pty.cpp b/storage/devices/tty/pty.cpp index 4ca0d85..249979b 100644 --- a/storage/devices/tty/pty.cpp +++ b/storage/devices/tty/pty.cpp @@ -24,157 +24,13 @@ namespace vfs { - int PTYDevice::open(int Flags, mode_t Mode) + PTYDevice::PTYDevice(Inode *_pts, int _id) { - stub; - return -ENOSYS; - } + assert(!"Function not implemented"); + char nameBuffer[16]; + snprintf(nameBuffer, 16, "%d", id); + // this->Name = strdup(nameBuffer); - int PTYDevice::close() - { - stub; - return -ENOSYS; - } - - size_t PTYDevice::read(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - if (this->isMaster) - { - if (MasterDev != nullptr) - return MasterDev->read(Buffer, Size, Offset); - else - fixme("MasterDev is nullptr"); - } - - if (this->SlaveDev == nullptr) - { - fixme("SlaveDev is nullptr"); - return 0; - } - - return SlaveDev->read(Buffer, Size, Offset); - } - - size_t PTYDevice::write(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - if (this->isMaster) - { - if (MasterDev != nullptr) - return MasterDev->write(Buffer, Size, Offset); - else - fixme("MasterDev is nullptr"); - } - - if (this->SlaveDev == nullptr) - { - fixme("SlaveDev is nullptr"); - return 0; - } - - return SlaveDev->write(Buffer, Size, Offset); - } - - int PTYDevice::ioctl(unsigned long Request, - void *Argp) - { - static_assert(sizeof(struct termios) < PAGE_SIZE); - void *pArgp = thisProcess->PageTable->Get(Argp); - - switch (Request) - { - case TCGETS: - { - struct termios *t = (struct termios *)pArgp; - memcpy(t, &this->term, sizeof(struct termios)); - break; - } - case TCSETS: - { - struct termios *t = (struct termios *)pArgp; - memcpy(&this->term, t, sizeof(struct termios)); - break; - } - case TCSETSW: - case TCSETSF: - case TCGETA: - case TCSETA: - case TCSETAW: - case TCSETAF: - case TCSBRK: - case TCXONC: - case TCFLSH: - case TIOCEXCL: - case TIOCNXCL: - case TIOCSCTTY: - case TIOCGPGRP: - case TIOCSPGRP: - case TIOCOUTQ: - case TIOCSTI: - { - fixme("ioctl %#lx not implemented", Request); - return -ENOSYS; - } - case TIOCGWINSZ: - { - struct winsize *ws = (struct winsize *)pArgp; - memcpy(ws, &this->termSize, sizeof(struct winsize)); - break; - } - case TIOCSWINSZ: - { - struct winsize *ws = (struct winsize *)pArgp; - memcpy(&this->termSize, ws, sizeof(struct winsize)); - break; - } - case TIOCMGET: - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - { - fixme("ioctl %#lx not implemented", Request); - return -ENOSYS; - } - case TIOCGPTN: - case 0xffffffff80045430: /* FIXME: ???? */ - { - int *n = (int *)pArgp; - *n = this->id; - break; - } - case TIOCSPTLCK: - { - int *n = (int *)pArgp; - *n = 0; - break; - } - default: - { - debug("Unknown ioctl %#lx", Request); - return -EINVAL; - } - } - - return 0; - } - - int PTYDevice::OpenMaster(int Flags, mode_t Mode) - { - debug("Opening master PTY device %s", this->FullPath); - FileDescriptorTable *fdt = thisProcess->FileDescriptors; - int rfd = fdt->_open(this->FullPath, Flags, Mode); - debug("Opened master PTY device %s with fd %d", - this->FullPath, rfd); - return rfd; - } - - PTYDevice::PTYDevice(Node *pts, int id) : Node(pts, - std::to_string(id), - CHARDEVICE) - { /* - ICRNL - Map Carriage Return to New Line - IXON - Enable XON/XOFF flow control @@ -206,7 +62,7 @@ namespace vfs this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ this->term.c_cc[VWERASE] = 0x17; /* ^W */ - debug("Created PTY device %s", FullPath); + // debug("Created PTY device %s", this->Name); } PTYDevice::~PTYDevice() {} diff --git a/storage/devices/tty/ptys.cpp b/storage/devices/tty/ptys.cpp deleted file mode 100644 index 1a7ed4b..0000000 --- a/storage/devices/tty/ptys.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include -#include -#include -#include - -#include "../../../kernel.h" - -namespace vfs -{ - size_t SlavePTY::read(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - fixme("%.*s", Size, Buffer); - return -ENOSYS; - } - - size_t SlavePTY::write(uint8_t *Buffer, - size_t Size, - off_t Offset) - { - fixme("%.*s", Size, Buffer); - return -ENOSYS; - } - - SlavePTY::SlavePTY() - { - } - - SlavePTY::~SlavePTY() - { - } -} diff --git a/storage/devices/tty/tty.cpp b/storage/devices/tty/tty.cpp deleted file mode 100644 index 866cf02..0000000 --- a/storage/devices/tty/tty.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include -#include -#include - -#include "../../../kernel.h" - -namespace vfs -{ - size_t TTYDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) - { - for (size_t i = 0; i < Size; i++) - putchar(((char *)Buffer)[i]); - - Display->UpdateBuffer(); /* FIXME: stub */ - return Size; - } - - int TTYDevice::ioctl(unsigned long Request, void *Argp) - { - switch (Request) - { - case TIOCGWINSZ: - { - struct winsize *ws = (struct winsize *)Argp; - Video::FontInfo fi = Display->GetCurrentFont()->GetInfo(); - - fixme("TIOCGWINSZ: stub"); - ws->ws_xpixel = uint16_t(Display->GetWidth); - ws->ws_ypixel = uint16_t(Display->GetHeight); - ws->ws_col = uint16_t(Display->GetWidth / fi.Width); - ws->ws_row = uint16_t(Display->GetHeight / fi.Height); - break; - } - default: - fixme("Unknown request %#lx", Request); - return -EINVAL; - } - return 0; - } - - TTYDevice::TTYDevice() : Node(DevFS, "tty", CHARDEVICE) {} - - TTYDevice::~TTYDevice() {} -} diff --git a/storage/filesystem.cpp b/storage/filesystem.cpp index a4371d4..d60b51d 100644 --- a/storage/filesystem.cpp +++ b/storage/filesystem.cpp @@ -17,416 +17,217 @@ #include -#include #include #include +#include #include #include "../kernel.h" -// show debug messages -// #define DEBUG_FILESYSTEM 1 - -#ifdef DEBUG_FILESYSTEM -#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__) -#else -#define vfsdbg(m, ...) -#endif - namespace vfs { - Node *Virtual::GetNodeFromPath_Unsafe(const char *Path, Node *Parent) - { - vfsdbg("GetNodeFromPath( Path: \"%s\" Parent: \"%s\" )", - Path, Parent ? Parent->Name : "(null)"); - - if (strcmp(Path, "/") == 0) - return FileSystemRoot->Children[0]; // 0 - filesystem root - - if (strcmp(Path, ".") == 0) - return Parent; - - if (strcmp(Path, "..") == 0) - { - if (Parent) - { - if (Parent->Parent) - return Parent->Parent; - else - return Parent; - } - else - return nullptr; - } - - Node *ReturnNode = Parent; - bool IsAbsolutePath = cwk_path_is_absolute(Path); - - if (!ReturnNode) - ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root - - if (IsAbsolutePath) - ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root - - cwk_segment segment; - if (unlikely(!cwk_path_get_first_segment(Path, &segment))) - { - error("Path doesn't have any segments."); - return nullptr; - } - - do - { - char *SegmentName = new char[segment.end - segment.begin + 1]; - memcpy(SegmentName, segment.begin, segment.end - segment.begin); - vfsdbg("GetNodeFromPath()->SegmentName: \"%s\"", SegmentName); - GetNodeFromPathNextParent: - foreach (auto Child in ReturnNode->Children) - { - vfsdbg("comparing \"%s\" with \"%s\"", - Child->Name, SegmentName); - if (strcmp(Child->Name, SegmentName) == 0) - { - ReturnNode = Child; - goto GetNodeFromPathNextParent; - } - } - delete[] SegmentName; - } while (cwk_path_get_next_segment(&segment)); - - const char *basename; - cwk_path_get_basename(Path, &basename, nullptr); - vfsdbg("BaseName: \"%s\" NodeName: \"%s\"", - basename, ReturnNode->Name); - - if (strcmp(basename, ReturnNode->Name) == 0) - { - vfsdbg("GetNodeFromPath()->\"%s\"", ReturnNode->Name); - return ReturnNode; - } - - vfsdbg("GetNodeFromPath()->\"(null)\""); - return nullptr; - } - - Node *Virtual::GetNodeFromPath(const char *Path, Node *Parent) - { - SmartLock(VirtualLock); - return GetNodeFromPath_Unsafe(Path, Parent); - } - bool Virtual::PathIsRelative(const char *Path) { - vfsdbg("PathIsRelative( Path: \"%s\" )", Path); - bool IsRelative = cwk_path_is_relative(Path); - vfsdbg("PathIsRelative()->\"%s\"", - IsRelative ? "true" : "false"); - return IsRelative; + return cwk_path_is_relative(Path); } - Node *Virtual::GetParent(const char *Path, Node *Parent) + dev_t Virtual::EarlyReserveDevice() { - vfsdbg("GetParent( Path: \"%s\" Parent: \"%s\" )", - Path, Parent ? Parent->Name : "(nil)"); - - if (Parent) - { - vfsdbg("GetParent()->\"%s\"", Parent->Name); - return Parent; - } - - Parent = FileSystemRoot->Children[0]; - - size_t length; - cwk_path_get_root(Path, &length); - if (length > 0) - { - foreach (auto Child in FileSystemRoot->Children) - { - if (strcmp(Child->Name, Path) == 0) - { - Parent = Child; - break; - } - } - } - - vfsdbg("GetParent()->\"%s\"", ParentNode->Name); - return Parent; + RegisterLock.store(true); + size_t len = DeviceMap.size(); + return len; } - const char *Virtual::NormalizePath(const char *Path, Node *Parent) + int Virtual::LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root) { - assert(Parent != nullptr); + auto it = DeviceMap.find(Device); + if (it != DeviceMap.end()) + ReturnLogError(-EEXIST, "Device %d already registered", Device); - vfsdbg("NormalizePath( Path: \"%s\" Parent: \"%s\" )", - Path, Parent->Name); - - size_t PathSize = strlen((char *)Path) + 1; - char *NormalizedPath = new char[PathSize]; - - { - Memory::SmartHeap sh(PathSize); - memcpy(sh, (char *)Path, PathSize); - cwk_path_normalize(sh, NormalizedPath, PathSize); - } - - const char *FinalPath; - if (cwk_path_is_relative(NormalizedPath)) - { - size_t PathSize = cwk_path_join(Parent->FullPath, - NormalizedPath, - nullptr, 0); - - FinalPath = new char[PathSize + 1]; - cwk_path_join(Parent->FullPath, NormalizedPath, - (char *)FinalPath, PathSize + 1); - - delete[] NormalizedPath; - } - else - FinalPath = NormalizedPath; - - vfsdbg("NormalizePath()->\"%s\"", FinalPath); - return FinalPath; - } - - bool Virtual::PathExists(const char *Path, Node *Parent) - { - if (isempty((char *)Path)) - { - vfsdbg("PathExists()->PathIsEmpty"); - return false; - } - - if (Parent == nullptr) - Parent = FileSystemRoot; - - vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )", - Path, Parent->Name); - - const char *CleanPath = NormalizePath(Path, Parent); - bool ret = GetNodeFromPath(CleanPath, Parent) != nullptr; - delete[] CleanPath; - vfsdbg("PathExists()->\"%s\"", - ret ? "true" : "false"); - return ret; - } - - Node *Virtual::Create(const char *Path, NodeType Type, Node *Parent) - { - if (isempty((char *)Path)) - return nullptr; - - SmartLock(VirtualLock); - Node *RootNode = FileSystemRoot->Children[0]; - Node *CurrentParent = this->GetParent(Path, Parent); - vfsdbg("Virtual::Create( Path: \"%s\" Parent: \"%s\" )", - Path, Parent ? Parent->Name : CurrentParent->Name); - - const char *CleanPath = this->NormalizePath(Path, CurrentParent); - vfsdbg("CleanPath: \"%s\"", CleanPath); - - VirtualLock.Unlock(); - if (PathExists(CleanPath, CurrentParent)) - { - error("Path \"%s\" already exists.", CleanPath); - goto CreatePathError; - } - VirtualLock.Lock(__FUNCTION__); - - cwk_segment segment; - if (!cwk_path_get_first_segment(CleanPath, &segment)) - { - error("Path doesn't have any segments."); - goto CreatePathError; - } - - do - { - char *SegmentName = new char[segment.end - segment.begin + 1]; - memcpy(SegmentName, segment.begin, segment.end - segment.begin); - vfsdbg("SegmentName: \"%s\"", SegmentName); - - auto GetChild = [](const char *Name, Node *Parent) - { - vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )", - Name, Parent->Name); - - if (!Parent) - { - vfsdbg("GetChild()->nullptr"); - return (Node *)nullptr; - } - - foreach (auto Child in Parent->Children) - { - if (strcmp(Child->Name, Name) == 0) - { - vfsdbg("GetChild()->\"%s\"", Child->Name); - return Child; - } - } - - vfsdbg("GetChild()->nullptr (not found)"); - return (Node *)nullptr; - }; - - if (Parent) - { - if (GetChild(SegmentName, RootNode) != nullptr) - { - RootNode = GetChild(SegmentName, RootNode); - delete[] SegmentName; - continue; - } - } - - if (GetChild(SegmentName, CurrentParent) != nullptr) - CurrentParent = GetChild(SegmentName, CurrentParent); - else - { - CurrentParent = new Node(CurrentParent, - SegmentName, - NodeType::DIRECTORY); - } - - delete[] SegmentName; - } while (cwk_path_get_next_segment(&segment)); - - CurrentParent->Type = Type; - // CurrentParent->FullPath = CleanPath; - - vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name); -#ifdef DEBUG - VirtualLock.Unlock(); - debug("Path created: \"%s\"", - CurrentParent->FullPath); - VirtualLock.Lock(__FUNCTION__); -#endif - return CurrentParent; - - CreatePathError: - delete[] CleanPath; - vfsdbg("Virtual::Create()->nullptr"); - return nullptr; - } - - Node *Virtual::CreateLink(const char *Path, const char *Target, Node *Parent) - { - Node *node = this->Create(Path, NodeType::SYMLINK, Parent); - if (node) - { - node->Symlink = new char[strlen(Target) + 1]; - strncpy((char *)node->Symlink, - Target, - strlen(Target)); - - node->SymlinkTarget = node->vFS->GetNodeFromPath(node->Symlink); - return node; - } - - error("Failed to create link \"%s\" -> \"%s\"", - Path, Target); - return nullptr; - } - - int Virtual::Delete(const char *Path, bool Recursive, Node *Parent) - { - vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )", - Path, Parent ? Parent->Name : "(null)"); - - if (isempty((char *)Path)) - return -EINVAL; - - if (Parent == nullptr) - Parent = FileSystemRoot; - - const char *CleanPath = this->NormalizePath(Path, Parent); - vfsdbg("CleanPath: \"%s\"", CleanPath); - - if (!PathExists(CleanPath, Parent)) - { - vfsdbg("Path \"%s\" doesn't exist.", CleanPath); - delete[] CleanPath; - return -ENOENT; - } - - Node *NodeToDelete = GetNodeFromPath(CleanPath, Parent); - - if (!NodeToDelete->References.empty()) - fixme("Path \"%s\" is referenced by %d objects.", - CleanPath, NodeToDelete->References.size()); - - delete[] CleanPath; - delete NodeToDelete; + FSMountInfo fsmi{.fsi = fsi, .Root = Root}; + DeviceMap.insert({Device, fsmi}); + RegisterLock.store(false); return 0; } - int Virtual::Delete(Node *Path, bool Recursive, Node *Parent) + dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi, Inode *Root) { - return Delete(Path->FullPath, Recursive, Parent); + RegisterLock.store(true); + size_t len = DeviceMap.size(); + FSMountInfo fsmi{.fsi = fsi, .Root = Root}; + DeviceMap.insert({len, fsmi}); + RegisterLock.store(false); + return len; } - RefNode *Virtual::Open(const char *Path, Node *Parent) + int Virtual::UnregisterFileSystem(dev_t Device) { - vfsdbg("Opening \"%s\" with parent \"%s\"", - Path, Parent ? Parent->Name : "(null)"); + auto it = DeviceMap.find(Device); + if (it == DeviceMap.end()) + ReturnLogError(-ENOENT, "Device %d not found", Device); - if (strcmp(Path, "/") == 0) - return FileSystemRoot->CreateReference(); + if (it->second.fsi->SuperOps.Synchronize) + it->second.fsi->SuperOps.Synchronize(it->second.fsi, NULL); + if (it->second.fsi->SuperOps.Destroy) + it->second.fsi->SuperOps.Destroy(it->second.fsi); + DeviceMap.erase(it); + return 0; + } - if (!Parent) - Parent = FileSystemRoot->Children[0]; + void Virtual::AddRoot(Inode *Root) + { + SmartLock(VirtualLock); + FileSystemRoots->Children.push_back(Root); + } - if (strcmp(Path, ".") == 0) - return Parent->CreateReference(); + FileNode *Virtual::GetRoot(size_t Index) + { + if (Index >= FileSystemRoots->Children.size()) + return nullptr; - if (strcmp(Path, "..") == 0) + Inode *RootNode = FileSystemRoots->Children[Index]; + + char rootName[128]{}; + snprintf(rootName, sizeof(rootName), "root-%ld", Index); + + return this->CreateCacheNode(nullptr, RootNode, rootName, 0); + } + + FileNode *Virtual::Create(FileNode *Parent, const char *Name, mode_t Mode) + { + FileNode *existingNode = this->GetByPath(Name, Parent); + if (existingNode != nullptr) + ReturnLogError(existingNode, "File %s already exists", Name); + + if (Parent == nullptr) { - if (Parent->Parent) - return Parent->Parent->CreateReference(); - else - return Parent->CreateReference(); + assert(thisProcess != nullptr); + Parent = thisProcess->Info.RootNode; } - Node *CurrentParent = this->GetParent(Path, Parent); - const char *CleanPath = NormalizePath(Path, CurrentParent); + auto it = DeviceMap.find(Parent->Node->Device); + if (it == DeviceMap.end()) + ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); - if (PathExists(CleanPath, CurrentParent)) + Inode *Node = NULL; + if (it->second.fsi->Ops.Create == NULL) + ReturnLogError(nullptr, "Create not supported for %d", it->first); + + int ret = it->second.fsi->Ops.Create(Parent->Node, Name, Mode, &Node); + if (ret < 0) + ReturnLogError(nullptr, "Create for %d failed with %d", it->first, ret); + + return this->CreateCacheNode(Parent, Node, Name, Mode); + } + + FileNode *Virtual::ForceCreate(FileNode *Parent, const char *Name, mode_t Mode) + { + fixme("ForceCreate: %s", Name); + return this->Create(Parent, Name, Mode); + } + + FileNode *Virtual::GetByPath(const char *Path, FileNode *Parent) + { + FileNode *fn = this->CacheLookup(Path); + if (fn) + return fn; + + if (Parent == nullptr) + Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0); + + auto it = DeviceMap.find(Parent->Node->Device); + if (it == DeviceMap.end()) + ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); + + struct cwk_segment segment; + if (!cwk_path_get_first_segment(Path, &segment)) + ReturnLogError(nullptr, "Path has no segments"); + + Inode *Node = NULL; + FileNode *__Parent = Parent; + do { - Node *node = GetNodeFromPath(CleanPath, CurrentParent); - if (node) + if (it->second.fsi->Ops.Lookup == NULL) + ReturnLogError(nullptr, "Lookup not supported for %d", it->first); + + std::string segmentName(segment.begin, segment.size); + int ret = it->second.fsi->Ops.Lookup(__Parent->Node, segmentName.c_str(), &Node); + if (ret < 0) + ReturnLogError(nullptr, "Lookup for %d failed with %d", it->first, ret); + __Parent = this->CreateCacheNode(__Parent, Node, segmentName.c_str(), 0); + } while (cwk_path_get_next_segment(&segment)); + + FileNode *ret = __Parent; + if (!ret->IsDirectory()) + return ret; + + size_t dirAllocLen = sizeof(struct kdirent) + strlen(Path); + struct kdirent *dirent = (struct kdirent *)malloc(dirAllocLen); + size_t offset = 2; /* Skip . and .. */ + while (it->second.fsi->Ops.ReadDir(Node, dirent, dirAllocLen, offset++, 1) > 0) + { + Inode *ChildNode = NULL; + int luRet = it->second.fsi->Ops.Lookup(Node, dirent->d_name, &ChildNode); + if (luRet < 0) { - delete[] CleanPath; - /* TODO: Check if dir or file? */ - return node->CreateReference(); + debug("Lookup for %d failed with %d", it->first, luRet); + break; } + + this->CreateCacheNode(ret, ChildNode, dirent->d_name, 0); } - - return nullptr; + free(dirent); + return ret; } - Node *Virtual::CreateIfNotExists(const char *Path, NodeType Type, Node *Parent) + FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, const char *Target) { - Node *node = GetNodeFromPath(Path, Parent); - if (node) - return node; - return Create(Path, Type, Parent); + auto it = DeviceMap.find(Parent->Node->Device); + if (it == DeviceMap.end()) + ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); + + Inode *Node = NULL; + + if (it->second.fsi->Ops.SymLink == NULL) + ReturnLogError(nullptr, "SymLink not supported for %d", it->first); + + int ret = it->second.fsi->Ops.SymLink(Parent->Node, Path, Target, &Node); + if (ret < 0) + ReturnLogError(nullptr, "SymLink for %d failed with %d", it->first, ret); + return this->CreateCacheNode(Parent, Node, Path, 0); } - Virtual::Virtual() + FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, FileNode *Target) { - SmartLock(VirtualLock); - trace("Initializing virtual file system..."); - FileSystemRoot = new Node(nullptr, "", NodeType::MOUNTPOINT); - FileSystemRoot->vFS = this; + return this->CreateLink(Path, Parent, Target->Path.c_str()); } - Virtual::~Virtual() + bool Virtual::PathExists(const char *Path, FileNode *Parent) { - SmartLock(VirtualLock); - stub; - /* TODO: sync, cache */ + FileNode *fn = this->CacheLookup(Path); + if (fn) + return true; + + FileNode *Node = this->GetByPath(Path, Parent); + if (Node) + return true; + return false; + } + + int Virtual::Remove(FileNode *Node) + { + auto it = DeviceMap.find(Node->Node->Device); + if (it == DeviceMap.end()) + ReturnLogError(-ENODEV, "Device %d not found", Node->Node->Device); + + if (it->second.fsi->Ops.Remove == NULL) + ReturnLogError(-ENOTSUP, "Remove not supported for %d", it->first); + + int ret = it->second.fsi->Ops.Remove(Node->Parent->Node, Node->Name.c_str()); + if (ret < 0) + ReturnLogError(ret, "Remove for %d failed with %d", it->first, ret); + + this->RemoveCacheNode(Node); + return 0; } } diff --git a/storage/fs/ustar.cpp b/storage/fs/ustar.cpp index fcb4b6c..9e6ae61 100644 --- a/storage/fs/ustar.cpp +++ b/storage/fs/ustar.cpp @@ -18,40 +18,427 @@ #include #include +#include #include #include "../../kernel.h" +#define TMAGIC "ustar" +#define TMAGLEN 6 +#define TVERSION "00" +#define TVERSLEN 2 + namespace vfs { - size_t USTARNode::read(uint8_t *Buffer, - size_t Size, - off_t Offset) + int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) { - if (Size <= 0) - Size = this->Size; + auto Parent = (USTARInode *)_Parent; - if (Offset > this->Size) + const char *basename; + size_t length; + cwk_path_get_basename(Name, &basename, &length); + if (basename == NULL) + { + if (strcmp(Name, "/") == 0) + { + auto &it = Files.at(0); + *Result = &it->Node; + return 0; + } + + error("Invalid name %s", Name); + return -EINVAL; + } + + if (_Parent) + { + for (const auto &child : Parent->Children) + { + if (child->Deleted || strcmp(child->Name.c_str(), basename) != 0) + continue; + + *Result = &child->Node; + return 0; + } + + return -ENOENT; + } + + auto fileItr = Files.begin(); + while (fileItr != Files.end()) + { + USTARInode *node = fileItr->second; + + if (node->Deleted || strcmp(node->Name.c_str(), basename) != 0) + { + fileItr++; + continue; + } + + *Result = &fileItr->second->Node; return 0; + } + return -ENOENT; + } - if ((this->Size - Offset) == 0) + int USTAR::Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result) + { + USTARInode *Parent = (USTARInode *)_Parent; + + Inode inode{}; + inode.Mode = Mode; + inode.Device = this->DeviceID; + inode.RawDevice = 0; + inode.Index = NextInode; + inode.Offset = 0; + inode.PrivateData = this; + inode.Flags = I_FLAG_CACHE_KEEP; + + const char *basename; + size_t length; + cwk_path_get_basename(Name, &basename, &length); + + auto SetMode = [&](mode_t &Mode, FileHeader *header) + { + if (Mode & S_IFREG) + header->typeflag[0] = REGTYPE; + else if (Mode & S_IFLNK) + header->typeflag[0] = SYMTYPE; + else if (Mode & S_IFCHR) + header->typeflag[0] = CHRTYPE; + else if (Mode & S_IFBLK) + header->typeflag[0] = BLKTYPE; + else if (Mode & S_IFDIR) + header->typeflag[0] = DIRTYPE; + else if (Mode & S_IFIFO) + header->typeflag[0] = FIFOTYPE; + + mode_t final = 0; + if (Mode & S_ISUID) + final |= TSUID; + else if (Mode & S_ISGID) + final |= TSGID; + else if (Mode & S_ISVTX) + final |= TSVTX; + else if (Mode & S_IRUSR) + final |= TUREAD; + else if (Mode & S_IWUSR) + final |= TUWRITE; + else if (Mode & S_IXUSR) + final |= TUEXEC; + else if (Mode & S_IRGRP) + final |= TGREAD; + else if (Mode & S_IWGRP) + final |= TGWRITE; + else if (Mode & S_IXGRP) + final |= TGEXEC; + else if (Mode & S_IROTH) + final |= TOREAD; + else if (Mode & S_IWOTH) + final |= TOWRITE; + else if (Mode & S_IXOTH) + final |= TOEXEC; + + snprintf(header->mode, sizeof(header->mode), "%07o", final); + }; + + FileHeader *hdr = new FileHeader{}; + SetMode(Mode, hdr); + strncpy(hdr->name, basename, sizeof(hdr->name)); + strncpy(hdr->signature, TMAGIC, TMAGLEN); + strncpy(hdr->version, TVERSION, TVERSLEN); + + USTARInode *node = new USTARInode{.Node = inode, + .Header = hdr, + .Parent = Parent, + .Name{}, + .Path{}, + .Children{}, + .Deleted = false, + .Checksum = INODE_CHECKSUM}; + + node->Name.assign(basename, length); + node->Path.assign(Name, strlen(Name)); + + Files.insert(std::make_pair(NextInode, node)); + *Result = &Files.at(NextInode)->Node; + if (Parent) + Parent->Children.push_back(Files.at(NextInode)); + NextInode++; + return 0; + } + + ssize_t USTAR::Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + auto fileItr = Files.find(Node->Index); + assert(fileItr != Files.end()); + + if (fileItr->second->Deleted) + return -ENOENT; + + USTARInode *node = fileItr->second; + size_t fileSize = GetSize(node->Header->size); + + if (Size <= 0) + { + debug("Size is less than or equal to 0"); + Size = fileSize; + } + + if ((size_t)Offset > fileSize) + { + debug("Offset %d is greater than file size %d", Offset, fileSize); + return 0; + } + + if ((fileSize - Offset) == 0) + { + debug("Offset %d is equal to file size %d", Offset, fileSize); return 0; /* EOF */ + } - if (Offset + (off_t)Size > this->Size) - Size = this->Size; + if ((size_t)Offset + Size > fileSize) + { + debug("Offset %d + Size %d is greater than file size %d", + Offset, Size, fileSize); + Size = fileSize; + } - memcpy(Buffer, (uint8_t *)(this->Address + Offset), Size); + memcpy(Buffer, (uint8_t *)((uintptr_t)node->Header + sizeof(FileHeader) + Offset), Size); + debug("Read %d bytes from %d[%d]", Size, Node->Index, Offset); return Size; } - USTARNode::USTARNode(uintptr_t Address, const char *Name, - NodeType Type, Virtual *vfs_ctx) - : Node(nullptr, Name, Type, true, vfs_ctx, nullptr), - Address(Address) + ssize_t USTAR::ReadDir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { + auto Node = (USTARInode *)_Node; + + off_t realOffset = Offset; + + size_t totalSize = 0; + uint16_t reclen = 0; + struct kdirent *ent = nullptr; + + if (Offset == 0) + { + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1); + if (totalSize + reclen >= Size) + return -EINVAL; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = Node->Node.Index; + ent->d_off = Offset++; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, "."); + totalSize += reclen; + } + + if (Offset <= 1) + { + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1); + if (totalSize + reclen >= Size) + { + if (realOffset == 1) + return -EINVAL; + return totalSize; + } + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + + if (Node->Parent) + ent->d_ino = Node->Parent->Node.Index; + else + { + warn("Parent is null for %s", Node->Name.c_str()); + ent->d_ino = Node->Node.Index; + } + ent->d_off = Offset++; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, ".."); + totalSize += reclen; + } + + // off_t entriesSkipped = 0; + // auto fileItr = Files.begin(); + // while (fileItr != Files.end()) + // { + // if (fileItr->second->Deleted) + // continue; + // reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(fileItr->second->Name.c_str()) + 1); + // if (Offset > entriesSkipped) + // { + // entriesSkipped++; + // continue; + // } + // if (totalSize + reclen >= Size) + // break; + // ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + // ent->d_ino = fileItr->first; + // ent->d_off = Offset++; + // ent->d_reclen = reclen; + // ent->d_type = IFTODT(StringToInt(fileItr->second->Header->mode)); + // strncpy(ent->d_name, + // fileItr->second->Name.c_str(), + // strlen(fileItr->second->Name.c_str())); + // totalSize += reclen; + // fileItr++; + // } + + if (!S_ISDIR(Node->Node.Mode)) + return -ENOTDIR; + + if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size()) + return -EINVAL; + + off_t entries = 0; + for (const auto &var : Node->Children) + { + if (var->Node.Offset < Offset) + continue; + + if (entries >= Entries) + break; + + if (var->Deleted) + continue; + + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1); + + if (totalSize + reclen >= Size) + break; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = var->Node.Index; + ent->d_off = var->Node.Offset; + ent->d_reclen = reclen; + fixme("Wrong d_type returned"); + ent->d_type = IFTODT(StringToInt(var->Header->typeflag)); + strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str())); + + totalSize += reclen; + entries++; + } + + return totalSize; } - USTARNode::~USTARNode() {} + int USTAR::SymLink(struct Inode *Node, const char *Name, const char *Target, struct Inode **Result) + { + int ret = this->Create(Node, Name, S_IFLNK, Result); + if (ret < 0) + return ret; + + USTARInode *node = (USTARInode *)Result; + strncpy(node->Header->link, Target, sizeof(node->Header->link)); + return 0; + } + + ssize_t USTAR::ReadLink(struct Inode *Node, char *Buffer, size_t Size) + { + auto fileItr = Files.find(Node->Index); + assert(fileItr != Files.end()); + + if (fileItr->second->Deleted) + return -ENOENT; + + USTARInode *node = fileItr->second; + + if (strlen(node->Header->link) > Size) + Size = strlen(node->Header->link); + + strncpy(Buffer, node->Header->link, Size); + debug("Read %d bytes from %d", Size, Node->Index); + return Size; + } + + int USTAR::Stat(struct Inode *Node, struct kstat *Stat) + { + auto fileItr = Files.find(Node->Index); + assert(fileItr != Files.end()); + if (fileItr->second->Deleted) + return -ENOENT; + + USTARInode *node = fileItr->second; + size_t fileSize = GetSize(node->Header->size); + + debug("Header: \"%.*s\"", sizeof(struct FileHeader), node->Header); + Stat->Device = this->DeviceID; + Stat->Index = Node->Index; + Stat->HardLinks = 1; + Stat->UserID = GetSize(node->Header->uid); + Stat->GroupID = GetSize(node->Header->gid); + Stat->RawDevice = Stat->MakeDevice(GetSize(node->Header->dev_maj), GetSize(node->Header->dev_min)); + Stat->Size = fileSize; + Stat->AccessTime = GetSize(node->Header->mtime); + Stat->ModifyTime = GetSize(node->Header->mtime); + Stat->ChangeTime = GetSize(node->Header->mtime); + Stat->BlockSize = 512; + Stat->Blocks = (fileSize + 511) / 512; + Stat->Attribute = 0; + + mode_t hdrMode = StringToInt(node->Header->mode); + + if (hdrMode & TSUID) + Stat->Mode |= S_ISUID; + else if (hdrMode & TSGID) + Stat->Mode |= S_ISGID; + else if (hdrMode & TSVTX) + Stat->Mode |= S_ISVTX; + else if (hdrMode & TUREAD) + Stat->Mode |= S_IRUSR; + else if (hdrMode & TUWRITE) + Stat->Mode |= S_IWUSR; + else if (hdrMode & TUEXEC) + Stat->Mode |= S_IXUSR; + else if (hdrMode & TGREAD) + Stat->Mode |= S_IRGRP; + else if (hdrMode & TGWRITE) + Stat->Mode |= S_IWGRP; + else if (hdrMode & TGEXEC) + Stat->Mode |= S_IXGRP; + else if (hdrMode & TOREAD) + Stat->Mode |= S_IROTH; + else if (hdrMode & TOWRITE) + Stat->Mode |= S_IWOTH; + else if (hdrMode & TOEXEC) + Stat->Mode |= S_IXOTH; + + switch (node->Header->typeflag[0]) + { + case AREGTYPE: + case REGTYPE: + Stat->Mode |= S_IFREG; + break; + case LNKTYPE: + fixme("Hard link not implemented for %s", node->Header->name); + Stat->Mode |= S_IFLNK; + break; + case SYMTYPE: + Stat->Mode |= S_IFLNK; + break; + case CHRTYPE: + Stat->Mode |= S_IFCHR; + break; + case BLKTYPE: + Stat->Mode |= S_IFBLK; + break; + case DIRTYPE: + Stat->Mode |= S_IFDIR; + break; + case FIFOTYPE: + Stat->Mode |= S_IFIFO; + break; + case CONTTYPE: + warn("Reserved type for %s", node->Header->name); + __fallthrough; + default: + error("Unknown type: %d for %s", node->Header->typeflag[0], node->Header->name); + break; + } + return 0; + } bool USTAR::TestArchive(uintptr_t Address) { @@ -62,28 +449,86 @@ namespace vfs } FileHeader *header = (FileHeader *)Address; - if (memcmp(header->signature, "ustar", 5) != 0) + if (strncmp(header->signature, TMAGIC, TMAGLEN) != 0) { - error("ustar signature invalid!"); + error("Invalid signature!"); return false; } return true; } - void USTAR::ReadArchive(uintptr_t Address, Virtual *vfs_ctx) + void USTAR::ReadArchive(uintptr_t Address, size_t Size) { - trace("Initializing USTAR with address %#lx", Address); + trace("Initializing USTAR with address %#lx and size %d", Address, Size); - if (!this->TestArchive(Address)) - return; /* Check whether the archive is deflated */ + auto SetMode = [&](Inode &uNode, FileHeader *header) + { + mode_t hdrMode = StringToInt(header->mode); + if (hdrMode & TSUID) + uNode.Mode |= S_ISUID; + else if (hdrMode & TSGID) + uNode.Mode |= S_ISGID; + else if (hdrMode & TSVTX) + uNode.Mode |= S_ISVTX; + else if (hdrMode & TUREAD) + uNode.Mode |= S_IRUSR; + else if (hdrMode & TUWRITE) + uNode.Mode |= S_IWUSR; + else if (hdrMode & TUEXEC) + uNode.Mode |= S_IXUSR; + else if (hdrMode & TGREAD) + uNode.Mode |= S_IRGRP; + else if (hdrMode & TGWRITE) + uNode.Mode |= S_IWGRP; + else if (hdrMode & TGEXEC) + uNode.Mode |= S_IXGRP; + else if (hdrMode & TOREAD) + uNode.Mode |= S_IROTH; + else if (hdrMode & TOWRITE) + uNode.Mode |= S_IWOTH; + else if (hdrMode & TOEXEC) + uNode.Mode |= S_IXOTH; + + switch (header->typeflag[0]) + { + case AREGTYPE: + case REGTYPE: + uNode.Mode |= S_IFREG; + break; + case LNKTYPE: + uNode.Mode |= S_IFLNK; + break; + case SYMTYPE: + uNode.Mode |= S_IFLNK; + break; + case CHRTYPE: + uNode.Mode |= S_IFCHR; + break; + case BLKTYPE: + uNode.Mode |= S_IFBLK; + break; + case DIRTYPE: + uNode.Mode |= S_IFDIR; + break; + case FIFOTYPE: + uNode.Mode |= S_IFIFO; + break; + case CONTTYPE: + warn("Reserved type for %s", header->name); + __fallthrough; + default: + error("Unknown type: %d for %s", header->typeflag[0], header->name); + break; + } + }; FileHeader *header = (FileHeader *)Address; debug("USTAR signature valid! Name:%s Signature:%s Mode:%d Size:%lu", - header->name, header->signature, - StringToInt(header->mode), header->size); + header->name, header->signature, StringToInt(header->mode), header->size); Memory::Virtual vmm; + std::vector tmpNodes; /* FIXME: bug in unordered_map for iterators */ for (size_t i = 0;; i++) { if (!vmm.Check((void *)header)) @@ -92,82 +537,291 @@ namespace vfs return; } - if (memcmp(header->signature, "ustar", 5) != 0) + if (strncmp(header->signature, TMAGIC, TMAGLEN) != 0) break; + // debug("\"%s\"", header->name); - memmove(header->name, - header->name + 1, - strlen(header->name)); + /* This removes the "." at the beginning of the file name + "./foo/bar" > "/foo/bar" */ + if (header->name[0] == '.' && header->name[1] == '/') + memmove(header->name, header->name + 1, strlen(header->name)); - if (header->name[strlen(header->name) - 1] == '/') - { - debug("Removing trailing slash from %s", header->name); - header->name[strlen(header->name) - 1] = 0; - } + if (isempty((char *)header->name)) + fixme("Ignoring empty file name \"%.*s\"", sizeof(struct FileHeader), header); + + struct Inode uNode; + uNode.Device = this->DeviceID; + uNode.RawDevice = 0; + uNode.Index = NextInode; + SetMode(uNode, header); + uNode.Flags = I_FLAG_CACHE_KEEP; + uNode.Offset = 0; + uNode.PrivateData = this; + + const char *basename; + size_t length; + cwk_path_get_basename(header->name, &basename, &length); + + USTARInode *node = new USTARInode{.Node = uNode, + .Header = header, + .Parent = nullptr, + .Name{}, + .Path{}, + .Children{}, + .Deleted = false, + .Checksum = INODE_CHECKSUM}; + + if (basename) + node->Name.assign(basename, length); + else + node->Name.assign((const char *)header->name, strlen(header->name)); + node->Path.assign((const char *)header->name, strlen(header->name)); + + Files.insert(std::make_pair(NextInode, node)); + tmpNodes.push_back(node); size_t size = GetSize(header->size); - Node *node; - NodeType type = NODE_TYPE_NONE; - if (isempty((char *)header->name)) - goto NextFileAddress; - - switch (header->typeflag[0]) - { - case REGULAR_FILE: - type = NodeType::FILE; - break; - case SYMLINK: - type = NodeType::SYMLINK; - break; - case DIRECTORY: - type = NodeType::DIRECTORY; - break; - case CHARDEV: - type = NodeType::CHARDEVICE; - break; - case BLOCKDEV: - type = NodeType::BLOCKDEVICE; - break; - default: - warn("Unknown type: %d", header->typeflag[0]); - break; - } - - node = new USTARNode((Address + 512), header->name, - type, vfs_ctx); - - // debug("%s %d KiB, Type:%c", header->name, - // TO_KiB(size), header->typeflag[0]); - node->Mode = StringToInt(header->mode); - node->Size = size; - node->GroupIdentifier = GetSize(header->gid); - node->UserIdentifier = GetSize(header->uid); - node->DeviceMajor = GetSize(header->dev_maj); - node->DeviceMinor = GetSize(header->dev_min); - - node->AccessTime = GetSize(header->mtime); - node->ModifyTime = GetSize(header->mtime); - node->ChangeTime = GetSize(header->mtime); - node->IndexNode = i; - - if (type == NodeType::SYMLINK) - { - node->Symlink = new char[strlen(header->link) + 1]; - strncpy((char *)node->Symlink, - header->link, - strlen(header->link)); - } - - NextFileAddress: Address += ((size / 512) + 1) * 512; if (size % 512) Address += 512; header = (FileHeader *)Address; + NextInode++; } + + /* TODO: This code can be significantly optimized but good luck understanding it */ + USTARInode *parent = nullptr; + std::vector parentStack; + std::vector pathStack; + for (auto &file : tmpNodes) + { + if (file->Path == "/") /* This is root / */ + { + parentStack.push_back(file); + pathStack.push_back(&file->Path); + // debug("root / generated"); + continue; + } + + /* pathStack is never empty */ + + if (file->Path.back() == '/') /* This is a directory */ + { + const char *path = file->Path.c_str(); + size_t length; + /* This converts /one/two/path.txt to /one/two/ */ + cwk_path_get_dirname(path, &length); + std::string dirName(path, length); + + /* Check if the directory is at the same level as the current directory */ + if (dirName == *pathStack.back()) + { + parent = parentStack.back(); + parentStack.push_back(file); + pathStack.push_back(&file->Path); + parent->Children.push_back(file); + file->Parent = parent; + // debug("adding \"%s\" to \"%s\"", file->Path.c_str(), parent->Path.c_str()); + continue; + } + else + { + /* Check if the directory is at a higher level */ + for (size_t i = 0; i < parentStack.size(); i++) + { + if (dirName != *pathStack[i]) + continue; + + /* Adjust vectors */ + while (!parentStack.empty()) + { + if (dirName == *pathStack.back()) + break; + + // debug("popping \"%s\"", pathStack.back()->c_str()); + parentStack.pop_back(); + pathStack.pop_back(); + } + + parent = parentStack.back(); + parentStack.push_back(file); + pathStack.push_back(&file->Path); + parent->Children.push_back(file); + file->Parent = parent; + // debug("adding \"%s\" to \"%s\"", file->Path.c_str(), parent->Path.c_str()); + goto foundEnd; + } + + // This is a new directory level + parentStack.pop_back(); + pathStack.pop_back(); + parent = parentStack.back(); + parentStack.push_back(file); + pathStack.push_back(&file->Path); + parent->Children.push_back(file); + file->Parent = parent; + // debug("adding \"%s\" to \"%s\"", file->Path.c_str(), parent->Path.c_str()); + foundEnd: + continue; + } + } + + /* From here, it's a file */ + + const char *path = file->Path.c_str(); + size_t length; + /* This converts /one/two/path.txt to /one/two/ */ + cwk_path_get_dirname(path, &length); + std::string dirName(path, length); + + /* Check if the file is at the same level as the current directory */ + if (dirName == *pathStack.back()) + { + parent = parentStack.back(); + parent->Children.push_back(file); + file->Parent = parent; + // debug("adding \"%s\" to \"%s\"", file->Path.c_str(), parent->Path.c_str()); + continue; + } + + /* Check if the file is at a higher level */ + for (size_t i = 0; i < parentStack.size(); i++) + { + if (dirName != *pathStack[i]) + continue; + + /* Adjust vectors */ + while (!parentStack.empty()) + { + if (dirName == *pathStack.back()) + break; + + // debug("popping \"%s\"", pathStack.back()->c_str()); + parentStack.pop_back(); + pathStack.pop_back(); + } + + parent = parentStack.back(); + parent->Children.push_back(file); + file->Parent = parent; + // debug("adding \"%s\" to \"%s\"", file->Path.c_str(), parent->Path.c_str()); + } + } + + std::function ustarTree = [&](vfs::USTAR::USTARInode *node, int level, const std::string &prefix) + { + debug("%*s\"%s\"%ld", level * 4, prefix.c_str(), node->Name.c_str(), node->Node.Offset); + off_t offset = 2; /* 0 . | 1 .. */ + for (auto &child : node->Children) + { +#ifdef DEBUG + if (offset <= 2) + { + if (offset == 2) + offset = 0; + /* Pseudo directories . and .. */ + USTARInode pseudoDot{}; + pseudoDot.Node = node->Node; + pseudoDot.Name = "."; + pseudoDot.Node.Offset = offset++; + USTARInode pseudoDDot{}; + pseudoDDot.Node = node->Parent ? node->Parent->Node : node->Node; + pseudoDDot.Name = ".."; + pseudoDDot.Node.Offset = offset++; + ustarTree(&pseudoDot, level + 1, "|-- "); + ustarTree(&pseudoDDot, level + 1, "|-- "); + } +#endif + + child->Node.Offset = offset++; + ustarTree(child, level + 1, child == node->Children.back() ? "`-- " : "|-- "); + } + }; + + ustarTree(tmpNodes[0], 0, ""); + } +} + +O2 int __ustar_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result) +{ + return ((vfs::USTAR *)Parent->PrivateData)->Lookup(Parent, Name, Result); +} + +O2 int __ustar_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result) +{ + return ((vfs::USTAR *)Parent->PrivateData)->Create(Parent, Name, Mode, Result); +} + +O2 ssize_t __ustar_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) +{ + return ((vfs::USTAR *)Node->PrivateData)->Read(Node, Buffer, Size, Offset); +} + +O2 ssize_t __ustar_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) +{ + return ((vfs::USTAR *)Node->PrivateData)->ReadDir(Node, Buffer, Size, Offset, Entries); +} + +O2 int __ustar_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result) +{ + return ((vfs::USTAR *)Parent->PrivateData)->SymLink(Parent, Name, Target, Result); +} + +O2 ssize_t __ustar_ReadLink(Inode *Node, char *Buffer, size_t Size) +{ + return ((vfs::USTAR *)Node->PrivateData)->ReadLink(Node, Buffer, Size); +} + +O2 int __ustar_Stat(struct Inode *Node, kstat *Stat) +{ + return ((vfs::USTAR *)Node->PrivateData)->Stat(Node, Stat); +} + +int __ustar_DestroyInode(FileSystemInfo *Info, Inode *Node) +{ + ((vfs::USTAR::USTARInode *)Node)->Deleted = true; + return 0; +} + +int __ustar_Destroy(FileSystemInfo *fsi) +{ + assert(fsi->PrivateData); + delete (vfs::USTAR *)fsi->PrivateData; + delete fsi; + return 0; +} + +bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size) +{ + vfs::USTAR *ustar = new vfs::USTAR(); + if (!ustar->TestArchive(Address)) + { + delete ustar; + return false; } - USTAR::USTAR() {} + ustar->DeviceID = fs->EarlyReserveDevice(); + ustar->ReadArchive(Address, Size); - USTAR::~USTAR() {} + Inode *initrd = nullptr; + ustar->Lookup(nullptr, "/", &initrd); + assert(initrd != nullptr); + + FileSystemInfo *fsi = new FileSystemInfo; + fsi->Name = "ustar"; + fsi->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + fsi->SuperOps.DeleteInode = __ustar_DestroyInode; + fsi->SuperOps.Destroy = __ustar_Destroy; + fsi->Ops.Lookup = __ustar_Lookup; + fsi->Ops.Create = __ustar_Create; + fsi->Ops.Read = __ustar_Read; + fsi->Ops.ReadDir = __ustar_Readdir; + fsi->Ops.SymLink = __ustar_SymLink; + fsi->Ops.ReadLink = __ustar_ReadLink; + fsi->Ops.Stat = __ustar_Stat; + fsi->PrivateData = ustar; + int ret = fs->LateRegisterFileSystem(ustar->DeviceID, fsi, initrd); + + fs->AddRoot(initrd); + return true; } diff --git a/storage/node.cpp b/storage/node.cpp deleted file mode 100644 index 39dc6a6..0000000 --- a/storage/node.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include -#include - -namespace vfs -{ - int Node::open(int Flags, mode_t Mode) - { - if (likely(open_ptr)) - return open_ptr(Flags, Mode); - - debug("Operation not handled for %s(%#lx)", - this->FullPath, this); - return -ENOSYS; - } - - int Node::close() - { - if (likely(close_ptr)) - return close_ptr(); - - debug("Operation not handled for %s(%#lx)", - this->FullPath, this); - return -ENOSYS; - } - - size_t Node::read(uint8_t *Buffer, size_t Size, off_t Offset) - { - if (likely(read_ptr)) - return read_ptr(Buffer, Size, Offset); - - debug("Operation not handled for %s(%#lx)", - this->FullPath, this); - return -ENOSYS; - } - - size_t Node::write(uint8_t *Buffer, size_t Size, off_t Offset) - { - if (likely(write_ptr)) - return write_ptr(Buffer, Size, Offset); - - debug("Operation not handled for %s(%#lx)", - this->FullPath, this); - return -ENOSYS; - } - - int Node::ioctl(unsigned long Request, void *Argp) - { - if (likely(ioctl_ptr)) - return ioctl_ptr(Request, Argp); - - debug("Operation not handled for %s(%#lx)", - this->FullPath, this); - return -ENOSYS; - } - - RefNode *Node::CreateReference() - { - SmartLock(NodeLock); - RefNode *ref = new RefNode(this); - References.push_back(ref); - debug("Created reference %#lx for node %#lx(%s)", - ref, this, this->Name); - return ref; - } - - void Node::RemoveReference(RefNode *Reference) - { - SmartLock(NodeLock); - debug("Removing reference %#lx for node %#lx", Reference, this); - References.erase(std::find(References.begin(), - References.end(), - Reference)); - } - - Node::Node(Node *Parent, const char *Name, NodeType Type, - bool NoParent, Virtual *_fs, int *Err) - { - assert(Name != nullptr); - assert(strlen(Name) != 0); - - if (Parent && _fs == nullptr) - _fs = Parent->vFS; - - if (Err != nullptr) - *Err = 0; - - this->Type = Type; - - auto GetChild = [](const char *Name, Node *Parent) - { - if (!Parent) - return (Node *)nullptr; - - foreach (auto Child in Parent->Children) - { - if (strcmp(Child->Name, Name) == 0) - return Child; - } - - return (Node *)nullptr; - }; - - auto CreateWithParent = [this](const char *Name, Node *Parent) - { - assert(Parent->vFS != nullptr); - assert(Parent->Type == DIRECTORY || - Parent->Type == MOUNTPOINT); - - this->vFS = Parent->vFS; - this->Parent = Parent; - - this->Name = new char[strlen(Name) + 1]; - strcpy((char *)this->Name, Name); - - this->FullPath = new char[strlen(Parent->FullPath) + - strlen(this->Name) + 2]; - strcpy((char *)this->FullPath, Parent->FullPath); - if (strcmp(this->FullPath, "/") != 0) - strcat((char *)this->FullPath, "/"); - strcat((char *)this->FullPath, this->Name); - - this->Parent->Children.push_back(this); - }; - - if (NoParent) - { - Parent = nullptr; - const char *Path = Name; - - Node *RootNode = _fs->FileSystemRoot->Children[0]; - Node *CurrentParent = _fs->GetParent(Path, Parent); - - if (_fs->PathExists(Path, CurrentParent)) - { - debug("Path \"%s\" already exists.", Path); - delete[] Path; - if (Err != nullptr) - *Err = -EEXIST; - delete this; - return; - } - - const char *CleanPath = _fs->NormalizePath(Path, CurrentParent); - - cwk_segment segment; - if (!cwk_path_get_first_segment(CleanPath, &segment)) - { - debug("Path doesn't have any segments."); - delete[] CleanPath; - if (Err != nullptr) - *Err = -EINVAL; - delete this; - return; - } - - cwk_segment last_segment; - cwk_path_get_last_segment(CleanPath, &last_segment); - - do - { - char *SegmentName = new char[segment.end - segment.begin + 1]; - memcpy(SegmentName, segment.begin, segment.end - segment.begin); - - if (Parent) - { - if (GetChild(SegmentName, RootNode) != nullptr) - { - RootNode = GetChild(SegmentName, RootNode); - delete[] SegmentName; - continue; - } - } - - if (GetChild(SegmentName, CurrentParent) == nullptr) - { - if (segment.begin == last_segment.begin) - { - CreateWithParent(SegmentName, CurrentParent); - delete[] SegmentName; - break; /* This is the last segment anyway... */ - } - - CurrentParent = new Node(CurrentParent, - SegmentName, - Type); - } - else - { - CurrentParent = GetChild(SegmentName, CurrentParent); - } - - delete[] SegmentName; - } while (cwk_path_get_next_segment(&segment)); - } - else if (Parent) - CreateWithParent(Name, Parent); - else - { - this->Name = new char[strlen(Name) + 1]; - strcpy((char *)this->Name, Name); - this->FullPath = Name; - - trace("Node %s(%#lx) has no parent", - this->Name, this); - } - - // debug("Created node %s(%#lx)", this->FullPath, this); - } - - Node::~Node() - { - debug("Destroyed node %s(%#lx)", this->FullPath, this); - // assert(this->Children.size() == 0); - - foreach (auto Child in this->Children) - delete Child; - - if (this->Parent) - { - debug("Removing node %s(%#lx) from parent %s(%#lx)", - this->FullPath, this, - this->Parent->FullPath, this->Parent); - - this->Parent->Children.erase(std::find(this->Parent->Children.begin(), - this->Parent->Children.end(), - this)); - } - - delete[] this->Name; - if (this->Parent) - delete[] this->FullPath; - if (this->Symlink) - delete[] this->Symlink; - } -} diff --git a/storage/reference.cpp b/storage/reference.cpp deleted file mode 100644 index 79eb1f4..0000000 --- a/storage/reference.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#ifdef DEBUG -const char *SeekStrings[] = - {"SEEK_SET", - "SEEK_CUR", - "SEEK_END"}; -#endif - -namespace vfs -{ - size_t RefNode::read(uint8_t *Buffer, size_t Size) - { - if (this->SymlinkTo) - return this->SymlinkTo->read(Buffer, Size); - - debug("Reading %d bytes from %s[%d]", - Size, this->node->FullPath, this->FileOffset.load()); - return this->node->read(Buffer, Size, this->FileOffset.load()); - } - - size_t RefNode::write(uint8_t *Buffer, size_t Size) - { - if (this->SymlinkTo) - return this->SymlinkTo->write(Buffer, Size); - - debug("Writing %d bytes to %s[%d]", - Size, this->node->FullPath, this->FileOffset.load()); - return this->node->write(Buffer, Size, this->FileOffset.load()); - } - - off_t RefNode::seek(off_t Offset, int Whence) - { - if (this->SymlinkTo) - return this->SymlinkTo->seek(Offset, Whence); - - // debug("Current offset is %d", this->Offset.load()); - switch (Whence) - { - case SEEK_SET: - { - if (Offset > this->FileSize) - return -EINVAL; - - if (Offset < 0) - { - fixme("Negative offset %d is not implemented", Offset); - Offset = 0; - } - - if (Offset > this->FileSize) - { - fixme("Offset %d is bigger than file size %d", - Offset, this->FileSize); - Offset = this->FileSize; - } - - this->FileOffset.store(Offset); - break; - } - case SEEK_CUR: - { - off_t NewOffset = off_t(this->FileOffset.load()) + Offset; - if (NewOffset > this->FileSize || - NewOffset < 0) - { - return -EINVAL; - } - - this->FileOffset.store(NewOffset); - break; - } - case SEEK_END: - { - off_t NewOffset = this->FileSize + Offset; - if (NewOffset > this->FileSize || - NewOffset < 0) - { - return -EINVAL; - } - - this->FileOffset.store(NewOffset); - break; - } - default: - { - error("Invalid whence!"); - return -EINVAL; - } - } - - off_t RetOffset = off_t(this->FileOffset.load()); - // debug("( %d %ld %s[%d] ) -> %d", - // Offset, this->Offset.load(), - // SeekStrings[Whence], Whence, - // RetOffset); - return RetOffset; - } - - int RefNode::ioctl(unsigned long Request, void *Argp) - { - if (this->SymlinkTo) - return this->SymlinkTo->ioctl(Request, Argp); - - return this->node->ioctl(Request, Argp); - } - - RefNode::RefNode(Node *node) - { - this->node = node; - this->FileSize = node->Size; - if (this->node->Type == SYMLINK) - { - if (!this->node->SymlinkTarget) - { - this->node->SymlinkTarget = - node->vFS->GetNodeFromPath(this->node->Symlink); - } - - if (!this->node->SymlinkTarget) - { - error("Symlink target %s not found!", - this->node->Symlink); - return; - } - - /* not standard but useful in kernel-space */ - this->node->Size = this->node->SymlinkTarget->Size; - this->SymlinkTo = this->node->SymlinkTarget->CreateReference(); - } - - debug("Created reference node for %s [%#lx]", - this->node->FullPath, (uintptr_t)this); - } - - RefNode::~RefNode() - { - if (this->SymlinkTo) - this->node->SymlinkTarget->RemoveReference(this); - - this->node->RemoveReference(this); - - debug("Destroyed reference node for %s [%#lx]", - this->node->FullPath, (uintptr_t)this); - } -} diff --git a/storage/virtual.cpp b/storage/virtual.cpp new file mode 100644 index 0000000..ce92111 --- /dev/null +++ b/storage/virtual.cpp @@ -0,0 +1,323 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include + +#include "../kernel.h" + +namespace vfs +{ + /* maj = 0 + min: + 0 - + 1 - /proc/self + 2 - /dev/null + 3 - /dev/zero + 4 - /dev/random + 5 - /dev/mem + */ + + int __vfs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) + { + vfsInode *Parent = (vfsInode *)_Parent; + + if (!S_ISDIR(Parent->Node.Mode)) + return -ENOTDIR; + + assert(Parent->Node.Flags & I_FLAG_MOUNTPOINT); + + if (Parent->Children.empty()) + return -ENOENT; + + off_t offset = 0; + foreach (const auto &Root in Parent->Children) + { + char rootName[128]{}; + snprintf(rootName, sizeof(rootName), "root-%ld", offset); + + if (strcmp(rootName, Name) == 0) + { + *Result = Root; + return 0; + } + offset++; + } + + return -ENOENT; + } + + int __vfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result) + { + assert(Parent != nullptr); + assert(!"Not implemented"); + } + + ssize_t __vfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + switch (Node->GetMinor()) + { + case 2: /* /dev/null */ + { + return 0; + } + case 3: /* /dev/zero */ + { + if (Size <= 0) + return 0; + + memset(Buffer, 0, Size); + return Size; + } + case 4: /* /dev/random */ + { + if (Size <= 0) + return 0; + + if (Size < sizeof(uint64_t)) + { + uint8_t *buf = (uint8_t *)Buffer; + for (size_t i = 0; i < Size; i++) + buf[i] = (uint8_t)(Random::rand16() & 0xFF); + return Size; + } + + uint64_t *buf = (uint64_t *)Buffer; + for (size_t i = 0; i < Size / sizeof(uint64_t); i++) + buf[i] = Random::rand64(); + return Size; + } + case 5: /* /dev/mem */ + { + stub; + return 0; + } + default: + return -ENOENT; + }; + } + + ssize_t __vfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) + { + switch (Node->GetMinor()) + { + case 2: /* /dev/null */ + { + return Size; + } + case 3: /* /dev/zero */ + { + return Size; + } + case 4: /* /dev/random */ + { + return Size; + } + case 5: /* /dev/mem */ + { + stub; + return 0; + } + default: + return -ENOENT; + }; + } + + /* This implementation is used internally by the kernel, so no "." & ".." */ + ssize_t __vfs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + { + if (_Node->GetMinor() != 0) + { + debug("_Node->GetMinor() != 0"); + return -ENOENT; + } + + assert(_Node->Flags & I_FLAG_MOUNTPOINT); + + fixme("maybe wrong implementation of readdir"); + + size_t totalSize = 0; + off_t entriesSkipped = 0; + struct kdirent *ent = nullptr; + vfsInode *Node = (vfsInode *)_Node; + off_t entries = 0; + foreach (const auto &Root in Node->Children) + { + if (entries >= Entries) + break; + + uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("root") + 1); + + if (Offset > entriesSkipped) + { + entriesSkipped++; + continue; + } + + if (totalSize + reclen >= Size) + break; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = Root->Index; + ent->d_off = Root->Offset; + ent->d_reclen = reclen; + ent->d_type = IFTODT(Root->Mode); + strncpy(ent->d_name, "root", strlen("root")); + + totalSize += reclen; + entries++; + } + + if (ent) + ent->d_off = INT32_MAX; + + return totalSize; + } + + ssize_t __vfs_ReadLink(struct Inode *Node, char *Buffer, size_t Size) + { + switch (Node->GetMinor()) + { + case 1: + { + /* FIXME: https://github.com/torvalds/linux/blob/c942a0cd3603e34dd2d7237e064d9318cb7f9654/fs/proc/self.c#L11 + https://lxr.linux.no/#linux+v3.2.9/fs/proc/base.c#L2482 */ + + int ret = snprintf(Buffer, Size, "/proc/%d", thisProcess->ID); + debug("ReadLink: %s (%d bytes)", Buffer, ret); + return ret; + } + default: + return -ENOENT; + } + } + + void Virtual::Initialize() + { + SmartLock(VirtualLock); + + trace("Initializing virtual file system..."); + uint32_t iFlags = I_FLAG_CACHE_KEEP; + + /* d rwx rwx rwx */ + mode_t mode = S_IRWXU | + S_IRWXG | + S_IRWXO | + S_IFDIR; + FileNode *dev = this->ForceCreate(this->GetRoot(0), "dev", mode); + FileNode *mnt = this->ForceCreate(this->GetRoot(0), "mnt", mode); + FileNode *proc = this->ForceCreate(this->GetRoot(0), "proc", mode); + FileNode *log = this->ForceCreate(this->GetRoot(0), "var", mode); + log = this->ForceCreate(log, "log", mode); + dev->Node->Flags = iFlags; + mnt->Node->Flags = iFlags; + proc->Node->Flags = iFlags; + log->Node->Flags = iFlags; + + /* l rwx rwx rwx */ + mode = S_IRWXU | + S_IRWXG | + S_IRWXO | + S_IFLNK; + FileNode *self = this->ForceCreate(proc, "self", mode); + self->Node->Device = FileSystemRoots->Node.Device; + self->Node->SetDevice(0, 1); + self->Node->Flags = iFlags; + + /* c rw- rw- rw- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH | + S_IFCHR; + FileNode *null = this->ForceCreate(dev, "null", mode); + null->Node->Device = FileSystemRoots->Node.Device; + null->Node->SetDevice(0, 2); + null->Node->Flags = iFlags; + + /* c rw- rw- rw- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH | + S_IFCHR; + FileNode *zero = this->ForceCreate(dev, "zero", mode); + zero->Node->Device = FileSystemRoots->Node.Device; + zero->Node->SetDevice(0, 3); + zero->Node->Flags = iFlags; + + /* c rw- rw- rw- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH | + S_IFCHR; + FileNode *random = this->ForceCreate(dev, "random", mode); + random->Node->Device = FileSystemRoots->Node.Device; + random->Node->SetDevice(0, 4); + random->Node->Flags = iFlags; + + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + FileNode *mem = this->ForceCreate(dev, "mem", mode); + mem->Node->Device = FileSystemRoots->Node.Device; + mem->Node->SetDevice(0, 5); + mem->Node->Flags = iFlags; + + new vfs::PTMXDevice(); + } + + Virtual::Virtual() + { + SmartLock(VirtualLock); + + FileSystemRoots = new vfsInode; + FileSystemRoots->Node.Index = -1; + + FileSystemRoots->Node.Mode = S_IRWXU | + S_IRWXG | + S_IROTH | S_IXOTH | + S_IFDIR; + + FileSystemRoots->Node.Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + + FileSystemRoots->Node.Offset = INT32_MAX; + FileSystemRoots->Name = ""; + + FileSystemInfo *fsi = new FileSystemInfo; + fsi->Name = "Virtual Roots"; + fsi->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + fsi->SuperOps = {}; + fsi->Ops.Lookup = __vfs_Lookup; + fsi->Ops.Create = __vfs_Create; + fsi->Ops.Read = __vfs_Read; + fsi->Ops.Write = __vfs_Write; + fsi->Ops.ReadDir = __vfs_Readdir; + fsi->Ops.ReadLink = __vfs_ReadLink; + + FileSystemRoots->Node.Device = this->RegisterFileSystem(fsi, &FileSystemRoots->Node); + FileSystemRoots->Node.SetDevice(0, 0); + } + + Virtual::~Virtual() + { + } +} diff --git a/syscalls.h b/syscalls.h deleted file mode 100644 index fed4f95..0000000 --- a/syscalls.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - BSD 3-Clause License - - Copyright (c) 2023, EnderIce2 - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__ -#define __FENNIX_KERNEL_SYSCALLS_LIST_H__ - -/* mmap */ - -#define sc_PROT_NONE 0 -#define sc_PROT_READ 1 -#define sc_PROT_WRITE 2 -#define sc_PROT_EXEC 4 - -#define sc_MAP_SHARED 1 -#define sc_MAP_PRIVATE 2 -#define sc_MAP_FIXED 4 -#define sc_MAP_ANONYMOUS 8 - -/* lseek */ - -#define sc_SEEK_SET 0 -#define sc_SEEK_CUR 1 -#define sc_SEEK_END 2 - -/** - * Enumeration of all the native syscalls - * available in the kernel - */ -typedef enum -{ - /** - * This syscall is used to exit the current - * process with the provided exit code. - * - * @fn void exit(int status); - * - * @param Code The exit code - * @return This syscall does not return - * - * @note No permissions are required to call - * this syscall - */ - sc_exit = 0, - - /** - * Map pages of memory - * - * @fn void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); - */ - sc_mmap, - - /** - * Unmap pages of memory - * - * @fn int munmap(void *addr, size_t len); - */ - sc_munmap, - - /** - * Change the protection of a page of memory - * - * @fn int mprotect(void *addr, size_t len, int prot); - */ - sc_mprotect, - - /** - * Open a file - * - * @fn int open(const char *path, int oflag, ... ); - */ - sc_open, - - /** - * Close a file descriptor - * - * @fn int close(int fildes); - */ - sc_close, - - /** - * Read from a file descriptor - * - * @fn ssize_t read(int fildes, void *buf, size_t nbyte); - */ - sc_read, - - /** - * Write to a file descriptor - * - * @fn ssize_t write(int fildes, const void *buf, size_t nbyte); - */ - sc_write, - - /** - * Seek to a position in a file descriptor - * - * @fn off_t lseek(int fildes, off_t offset, int whence); - */ - sc_lseek, - - /** - * Create a new process - * - * @fn pid_t fork(void); - */ - sc_fork, - - /** Not a real syscall */ - sc_MaxSyscall -} NativeSyscalls; - -#ifndef syscall0 -static inline long syscall0(long syscall) -{ - long ret; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#ifndef syscall1 -static inline long syscall1(long syscall, long arg1) -{ - long ret; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall), "D"(arg1) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#ifndef syscall2 -static inline long syscall2(long syscall, long arg1, long arg2) -{ - long ret; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall), "D"(arg1), "S"(arg2) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#ifndef syscall3 -static inline long syscall3(long syscall, long arg1, long arg2, long arg3) -{ - long ret; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#ifndef syscall4 -static inline long syscall4(long syscall, long arg1, long arg2, long arg3, long arg4) -{ - long ret; - register long r10 __asm__("r10") = arg4; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#ifndef syscall5 -static inline long syscall5(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5) -{ - long ret; - register long r10 __asm__("r10") = arg4; - register long r8 __asm__("r8") = arg5; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#ifndef syscall6 -static inline long syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) -{ - long ret; - register long r10 __asm__("r10") = arg4; - register long r8 __asm__("r8") = arg5; - register long r9 __asm__("r9") = arg6; - __asm__ __volatile__("syscall" - : "=a"(ret) - : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9) - : "rcx", "r11", "memory"); - return ret; -} -#endif - -#endif // !__FENNIX_KERNEL_SYSCALLS_LIST_H__ diff --git a/syscalls/linux.cpp b/syscalls/linux.cpp index e5d56d7..fc19775 100644 --- a/syscalls/linux.cpp +++ b/syscalls/linux.cpp @@ -19,8 +19,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -208,7 +210,93 @@ static const struct {linux_SIGRTMIN + 29, SIGRT_29, SIG_IGN}, {linux_SIGRTMIN + 30, SIGRT_30, SIG_IGN}, {linux_SIGRTMIN + 31, SIGRT_31, SIG_IGN}, - {linux_SIGRTMAX, SIGRTMAX, SIG_IGN}}; + {linux_SIGRTMAX, SIGRTMAX, SIG_IGN}, +}; + +static_vector errnoMap = { + /*EOK*/ 0, + /*E2BIG*/ linux_E2BIG, + /*EACCES*/ linux_EACCES, + /*EADDRINUSE*/ linux_EADDRINUSE, + /*EADDRNOTAVAIL*/ linux_EADDRNOTAVAIL, + /*EAFNOSUPPORT*/ linux_EAFNOSUPPORT, + /*EAGAIN*/ linux_EAGAIN, + /*EALREADY*/ linux_EALREADY, + /*EBADF*/ linux_EBADF, + /*EBADMSG*/ linux_EBADMSG, + /*EBUSY*/ linux_EBUSY, + /*ECANCELED*/ linux_ECANCELED, + /*ECHILD*/ linux_ECHILD, + /*ECONNABORTED*/ linux_ECONNABORTED, + /*ECONNREFUSED*/ linux_ECONNREFUSED, + /*ECONNRESET*/ linux_ECONNRESET, + /*EDEADLK*/ linux_EDEADLK, + /*EDESTADDRREQ*/ linux_EDESTADDRREQ, + /*EDOM*/ linux_EDOM, + /*EDQUOT*/ linux_EDQUOT, + /*EEXIST*/ linux_EEXIST, + /*EFAULT*/ linux_EFAULT, + /*EFBIG*/ linux_EFBIG, + /*EHOSTUNREACH*/ linux_EHOSTUNREACH, + /*EIDRM*/ linux_EIDRM, + /*EILSEQ*/ linux_EILSEQ, + /*EINPROGRESS*/ linux_EINPROGRESS, + /*EINTR*/ linux_EINTR, + /*EINVAL*/ linux_EINVAL, + /*EIO*/ linux_EIO, + /*EISCONN*/ linux_EISCONN, + /*EISDIR*/ linux_EISDIR, + /*ELOOP*/ linux_ELOOP, + /*EMFILE*/ linux_EMFILE, + /*EMLINK*/ linux_EMLINK, + /*EMSGSIZE*/ linux_EMSGSIZE, + /*EMULTIHOP*/ linux_EMULTIHOP, + /*ENAMETOOLONG*/ linux_ENAMETOOLONG, + /*ENETDOWN*/ linux_ENETDOWN, + /*ENETRESET*/ linux_ENETRESET, + /*ENETUNREACH*/ linux_ENETUNREACH, + /*ENFILE*/ linux_ENFILE, + /*ENOBUFS*/ linux_ENOBUFS, + /*ENODATA*/ linux_ENODATA, + /*ENODEV*/ linux_ENODEV, + /*ENOENT*/ linux_ENOENT, + /*ENOEXEC*/ linux_ENOEXEC, + /*ENOLCK*/ linux_ENOLCK, + /*ENOLINK*/ linux_ENOLINK, + /*ENOMEM*/ linux_ENOMEM, + /*ENOMSG*/ linux_ENOMSG, + /*ENOPROTOOPT*/ linux_ENOPROTOOPT, + /*ENOSPC*/ linux_ENOSPC, + /*ENOSR*/ linux_ENOSR, + /*ENOSTR*/ linux_ENOSTR, + /*ENOSYS*/ linux_ENOSYS, + /*ENOTCONN*/ linux_ENOTCONN, + /*ENOTDIR*/ linux_ENOTDIR, + /*ENOTEMPTY*/ linux_ENOTEMPTY, + /*ENOTRECOVERABLE*/ linux_ENOTRECOVERABLE, + /*ENOTSOCK*/ linux_ENOTSOCK, + /*ENOTSUP*/ linux_EOPNOTSUPP, + /*ENOTTY*/ linux_ENOTTY, + /*ENXIO*/ linux_ENXIO, + /*EOPNOTSUPP*/ linux_EOPNOTSUPP, + /*EOVERFLOW*/ linux_EOVERFLOW, + /*EOWNERDEAD*/ linux_EOWNERDEAD, + /*EPERM*/ linux_EPERM, + /*EPIPE*/ linux_EPIPE, + /*EPROTO*/ linux_EPROTO, + /*EPROTONOSUPPORT*/ linux_EPROTONOSUPPORT, + /*EPROTOTYPE*/ linux_EPROTOTYPE, + /*ERANGE*/ linux_ERANGE, + /*EROFS*/ linux_EROFS, + /*ESPIPE*/ linux_ESPIPE, + /*ESRCH*/ linux_ESRCH, + /*ESTALE*/ linux_ESTALE, + /*ETIME*/ linux_ETIME, + /*ETIMEDOUT*/ linux_ETIMEDOUT, + /*ETXTBSY*/ linux_ETXTBSY, + /*EWOULDBLOCK*/ linux_EAGAIN, + /*EXDEV*/ linux_EXDEV, +}; int ConvertSignalToLinux(Signals sig) { @@ -324,21 +412,21 @@ void SetSigActToLinux(const SignalAction *native, k_sigaction *linux) struct kstat KStatToStat(struct linux_kstat linux_stat) { struct kstat stat; - stat.st_dev = linux_stat.st_dev; - stat.st_ino = linux_stat.st_ino; - stat.st_nlink = (nlink_t)linux_stat.st_nlink; - stat.st_mode = linux_stat.st_mode; - stat.st_uid = linux_stat.st_uid; - stat.st_gid = linux_stat.st_gid; - stat.st_rdev = linux_stat.st_rdev; - stat.st_size = linux_stat.st_size; - stat.st_blksize = linux_stat.st_blksize; - stat.st_blocks = linux_stat.st_blocks; - stat.st_atime = linux_stat.st_atime; + stat.Device = linux_stat.st_dev; + stat.Index = linux_stat.st_ino; + stat.HardLinks = (nlink_t)linux_stat.st_nlink; + stat.Mode = linux_stat.st_mode; + stat.UserID = linux_stat.st_uid; + stat.GroupID = linux_stat.st_gid; + stat.RawDevice = linux_stat.st_rdev; + stat.Size = linux_stat.st_size; + stat.BlockSize = linux_stat.st_blksize; + stat.Blocks = linux_stat.st_blocks; + stat.AccessTime = linux_stat.st_atime; // stat.st_atime_nsec = linux_stat.st_atime_nsec; - stat.st_mtime = linux_stat.st_mtime; + stat.ModifyTime = linux_stat.st_mtime; // stat.st_mtime_nsec = linux_stat.st_mtime_nsec; - stat.st_ctime = linux_stat.st_ctime; + stat.ChangeTime = linux_stat.st_ctime; // stat.st_ctime_nsec = linux_stat.st_ctime_nsec; return stat; } @@ -346,21 +434,21 @@ struct kstat KStatToStat(struct linux_kstat linux_stat) struct linux_kstat StatToKStat(struct kstat stat) { struct linux_kstat linux_stat; - linux_stat.st_dev = stat.st_dev; - linux_stat.st_ino = stat.st_ino; - linux_stat.st_nlink = stat.st_nlink; - linux_stat.st_mode = stat.st_mode; - linux_stat.st_uid = stat.st_uid; - linux_stat.st_gid = stat.st_gid; - linux_stat.st_rdev = stat.st_rdev; - linux_stat.st_size = stat.st_size; - linux_stat.st_blksize = stat.st_blksize; - linux_stat.st_blocks = stat.st_blocks; - linux_stat.st_atime = stat.st_atime; + linux_stat.st_dev = stat.Device; + linux_stat.st_ino = stat.Index; + linux_stat.st_nlink = stat.HardLinks; + linux_stat.st_mode = stat.Mode; + linux_stat.st_uid = stat.UserID; + linux_stat.st_gid = stat.GroupID; + linux_stat.st_rdev = stat.RawDevice; + linux_stat.st_size = stat.Size; + linux_stat.st_blksize = stat.BlockSize; + linux_stat.st_blocks = stat.Blocks; + linux_stat.st_atime = stat.AccessTime; // linux_stat.st_atime_nsec = stat.st_atime_nsec; - linux_stat.st_mtime = stat.st_mtime; + linux_stat.st_mtime = stat.ModifyTime; // linux_stat.st_mtime_nsec = stat.st_mtime_nsec; - linux_stat.st_ctime = stat.st_ctime; + linux_stat.st_ctime = stat.ChangeTime; // linux_stat.st_ctime_nsec = stat.st_ctime_nsec; return linux_stat; } @@ -368,40 +456,40 @@ struct linux_kstat StatToKStat(struct kstat stat) struct kstat OKStatToStat(struct __old_kernel_stat okstat) { struct kstat stat; - stat.st_dev = okstat.st_dev; - stat.st_ino = okstat.st_ino; - stat.st_nlink = okstat.st_nlink; - stat.st_mode = okstat.st_mode; - stat.st_uid = okstat.st_uid; - stat.st_gid = okstat.st_gid; - stat.st_rdev = okstat.st_rdev; - stat.st_size = okstat.st_size; - stat.st_atime = okstat.st_atime; - stat.st_mtime = okstat.st_mtime; - stat.st_ctime = okstat.st_ctime; + stat.Device = okstat.st_dev; + stat.Index = okstat.st_ino; + stat.HardLinks = okstat.st_nlink; + stat.Mode = okstat.st_mode; + stat.UserID = okstat.st_uid; + stat.GroupID = okstat.st_gid; + stat.RawDevice = okstat.st_rdev; + stat.Size = okstat.st_size; + stat.AccessTime = okstat.st_atime; + stat.ModifyTime = okstat.st_mtime; + stat.ChangeTime = okstat.st_ctime; return stat; } struct __old_kernel_stat StatToOKStat(struct kstat stat) { struct __old_kernel_stat okstat; - okstat.st_dev = (unsigned short)stat.st_dev; - okstat.st_ino = (unsigned short)stat.st_ino; - okstat.st_nlink = (unsigned short)stat.st_nlink; - okstat.st_mode = (unsigned short)stat.st_mode; - okstat.st_uid = (unsigned short)stat.st_uid; - okstat.st_gid = (unsigned short)stat.st_gid; - okstat.st_rdev = (unsigned short)stat.st_rdev; + okstat.st_dev = (unsigned short)stat.Device; + okstat.st_ino = (unsigned short)stat.Index; + okstat.st_nlink = (unsigned short)stat.HardLinks; + okstat.st_mode = (unsigned short)stat.Mode; + okstat.st_uid = (unsigned short)stat.UserID; + okstat.st_gid = (unsigned short)stat.GroupID; + okstat.st_rdev = (unsigned short)stat.RawDevice; #ifdef __i386__ - okstat.st_size = (unsigned long)stat.st_size; - okstat.st_atime = (unsigned long)stat.st_atime; - okstat.st_mtime = (unsigned long)stat.st_mtime; - okstat.st_ctime = (unsigned long)stat.st_ctime; + okstat.st_size = (unsigned long)stat.Size; + okstat.st_atime = (unsigned long)stat.AccessTime; + okstat.st_mtime = (unsigned long)stat.ModifyTime; + okstat.st_ctime = (unsigned long)stat.ChangeTime; #else - okstat.st_size = (unsigned int)stat.st_size; - okstat.st_atime = (unsigned int)stat.st_atime; - okstat.st_mtime = (unsigned int)stat.st_mtime; - okstat.st_ctime = (unsigned int)stat.st_ctime; + okstat.st_size = (unsigned int)stat.Size; + okstat.st_atime = (unsigned int)stat.AccessTime; + okstat.st_mtime = (unsigned int)stat.ModifyTime; + okstat.st_ctime = (unsigned int)stat.ChangeTime; #endif return okstat; } @@ -422,7 +510,6 @@ void __LinuxForkReturn(void *tableAddr) __builtin_unreachable(); } -/* https://man7.org/linux/man-pages/man2/read.2.html */ static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count) { PCB *pcb = thisProcess; @@ -432,16 +519,15 @@ static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count) if (pBuf == nullptr) return -EFAULT; - function("%d, %p, %d", fd, buf, count); + func("%d, %p, %d", fd, buf, count); vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - ssize_t ret = fdt->_read(fd, pBuf, count); + ssize_t ret = fdt->usr_read(fd, pBuf, count); if (ret >= 0) - fdt->_lseek(fd, ret, SEEK_CUR); + fdt->usr_lseek(fd, ret, SEEK_CUR); return ret; } -/* https://man7.org/linux/man-pages/man2/write.2.html */ static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count) { PCB *pcb = thisProcess; @@ -451,16 +537,15 @@ static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count) if (pBuf == nullptr) return -EFAULT; - function("%d, %p, %d", fd, buf, count); + func("%d, %p, %d", fd, buf, count); vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - ssize_t ret = fdt->_write(fd, pBuf, count); + ssize_t ret = fdt->usr_write(fd, pBuf, count); if (ret) - fdt->_lseek(fd, ret, SEEK_CUR); + fdt->usr_lseek(fd, ret, SEEK_CUR); return ret; } -/* https://man7.org/linux/man-pages/man2/open.2.html */ static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) { PCB *pcb = thisProcess; @@ -470,18 +555,18 @@ static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) if (pPathname == nullptr) return -EFAULT; - function("%s, %d, %d", pPathname, flags, mode); + func("%s, %d, %d", pPathname, flags, mode); if (flags & 0200000 /* O_DIRECTORY */) { - vfs::Node *node = fs->GetNodeFromPath(pPathname); - if (!node) + FileNode *node = fs->GetByPath(pPathname, pcb->CWD); + if (node == nullptr) { debug("Couldn't find %s", pPathname); return -ENOENT; } - if (node->Type != vfs::NodeType::DIRECTORY) + if (!node->IsDirectory()) { debug("%s is not a directory", pPathname); return -ENOTDIR; @@ -489,15 +574,14 @@ static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) } vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_open(pPathname, flags, mode); + return fdt->usr_open(pPathname, flags, mode); } -/* https://man7.org/linux/man-pages/man2/close.2.html */ static int linux_close(SysFrm *, int fd) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_close(fd); + return fdt->usr_close(fd); } /* stat, lstat and fstat uses __old_kernel_stat: @@ -505,7 +589,6 @@ https://github.com/torvalds/linux/blob/bfa8f18691ed2e978e4dd51190569c434f93e268/ if __ARCH_WANT_OLD_STAT is defined so what about __old_kernel_stat? when it is used? */ -/* https://man7.org/linux/man-pages/man2/stat.2.html */ static int linux_stat(SysFrm *, const char *pathname, struct linux_kstat *statbuf) { PCB *pcb = thisProcess; @@ -521,15 +604,13 @@ static int linux_stat(SysFrm *, const char *pathname, struct linux_kstat *statbu return -EFAULT; struct kstat nstat = KStatToStat(*pStatbuf); - int ret = fdt->_stat(pPathname, &nstat); + int ret = fdt->usr_stat(pPathname, &nstat); *pStatbuf = StatToKStat(nstat); return ret; } -/* https://man7.org/linux/man-pages/man2/fstat.2.html */ static int linux_fstat(SysFrm *, int fd, struct linux_kstat *statbuf) { -#undef fstat PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; Memory::VirtualMemoryArea *vma = pcb->vma; @@ -539,12 +620,11 @@ static int linux_fstat(SysFrm *, int fd, struct linux_kstat *statbuf) return -EFAULT; struct kstat nstat = KStatToStat(*pStatbuf); - int ret = fdt->_fstat(fd, &nstat); + int ret = fdt->usr_fstat(fd, &nstat); *pStatbuf = StatToKStat(nstat); return ret; } -/* https://man7.org/linux/man-pages/man2/lstat.2.html */ static int linux_lstat(SysFrm *, const char *pathname, struct linux_kstat *statbuf) { PCB *pcb = thisProcess; @@ -557,70 +637,39 @@ static int linux_lstat(SysFrm *, const char *pathname, struct linux_kstat *statb return -EFAULT; struct kstat nstat = KStatToStat(*pStatbuf); - int ret = fdt->_lstat(pPathname, &nstat); + int ret = fdt->usr_lstat(pPathname, &nstat); *pStatbuf = StatToKStat(nstat); return ret; } -#include "../syscalls.h" -/* https://man7.org/linux/man-pages/man2/lseek.2.html */ +// #include "../syscalls.h" + static off_t linux_lseek(SysFrm *, int fd, off_t offset, int whence) { - static_assert(SEEK_SET == sc_SEEK_SET); - static_assert(SEEK_CUR == sc_SEEK_CUR); - static_assert(SEEK_END == sc_SEEK_END); + static_assert(linux_SEEK_SET == SEEK_SET); + static_assert(linux_SEEK_CUR == SEEK_CUR); + static_assert(linux_SEEK_END == SEEK_END); PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_lseek(fd, offset, whence); + return fdt->usr_lseek(fd, offset, whence); } -/* https://man7.org/linux/man-pages/man2/mmap.2.html */ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, int flags, int fildes, off_t offset) { - static_assert(PROT_NONE == sc_PROT_NONE); - static_assert(PROT_READ == sc_PROT_READ); - static_assert(PROT_WRITE == sc_PROT_WRITE); - static_assert(PROT_EXEC == sc_PROT_EXEC); - - int new_flags = 0; - if (flags & MAP_SHARED) - { - new_flags |= sc_MAP_SHARED; - flags &= ~MAP_SHARED; - } - if (flags & MAP_PRIVATE) - { - new_flags |= sc_MAP_PRIVATE; - flags &= ~MAP_PRIVATE; - } - if (flags & MAP_FIXED) - { - new_flags |= sc_MAP_FIXED; - flags &= ~MAP_FIXED; - } - if (flags & MAP_ANONYMOUS) - { - new_flags |= sc_MAP_ANONYMOUS; - flags &= ~MAP_ANONYMOUS; - } - if (flags) - fixme("unhandled flags: %#x", flags); - flags = new_flags; - if (length == 0) return (void *)-EINVAL; - bool p_None = prot & sc_PROT_NONE; - bool p_Read = prot & sc_PROT_READ; - bool p_Write = prot & sc_PROT_WRITE; - bool p_Exec = prot & sc_PROT_EXEC; + bool p_None = prot & linux_PROT_NONE; + bool p_Read = prot & linux_PROT_READ; + bool p_Write = prot & linux_PROT_WRITE; + bool p_Exec = prot & linux_PROT_EXEC; - bool m_Shared = flags & sc_MAP_SHARED; - bool m_Private = flags & sc_MAP_PRIVATE; - bool m_Fixed = flags & sc_MAP_FIXED; - bool m_Anon = flags & sc_MAP_ANONYMOUS; + bool m_Shared = flags & linux_MAP_SHARED; + bool m_Private = flags & linux_MAP_PRIVATE; + bool m_Fixed = flags & linux_MAP_FIXED; + bool m_Anon = flags & linux_MAP_ANONYMOUS; UNUSED(p_None); UNUSED(m_Anon); @@ -631,15 +680,13 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, debug("Shared:%d Private:%d Fixed:%d Anon:%d", m_Shared, m_Private, m_Fixed, m_Anon); - int UnknownFlags = flags & ~(sc_MAP_SHARED | - sc_MAP_PRIVATE | - sc_MAP_FIXED | - sc_MAP_ANONYMOUS); - if (UnknownFlags) + int unknownFlags = flags & ~(linux_MAP_SHARED | linux_MAP_PRIVATE | + linux_MAP_FIXED | linux_MAP_ANONYMOUS); + if (unknownFlags) { /* We still have some flags missing afaik... */ - fixme("Unknown flags: %x", UnknownFlags); - /* Allow? */ + fixme("Unknown flags: %x", unknownFlags); + /* FIXME: Continue? */ } if (offset % PAGE_SIZE) @@ -658,8 +705,9 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, { fixme("File mapping not fully implemented"); vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - vfs::FileDescriptorTable::Fildes &_fd = fdt->GetDescriptor(fildes); - if (_fd.Descriptor != fildes) + + auto _fd = fdt->FileMap.find(fildes); + if (_fd == fdt->FileMap.end()) { debug("Invalid file descriptor %d", fildes); return (void *)-EBADF; @@ -686,11 +734,11 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, debug("Failed to map file: %s", strerror(mRet)); return (void *)(uintptr_t)mRet; } - off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR); - fdt->_lseek(fildes, offset, SEEK_SET); + off_t oldOff = fdt->usr_lseek(fildes, 0, SEEK_CUR); + fdt->usr_lseek(fildes, offset, SEEK_SET); - ssize_t ret = fdt->_read(fildes, pBuf, length); - fdt->_lseek(fildes, oldOff, SEEK_SET); + ssize_t ret = fdt->usr_read(fildes, pBuf, length); + fdt->usr_lseek(fildes, oldOff, SEEK_SET); if (ret < 0) { @@ -709,12 +757,12 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, } } - off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR); - fdt->_lseek(fildes, offset, SEEK_SET); + off_t oldOff = fdt->usr_lseek(fildes, 0, SEEK_CUR); + fdt->usr_lseek(fildes, offset, SEEK_SET); - ssize_t ret = fdt->_read(fildes, pBuf, length); + ssize_t ret = fdt->usr_read(fildes, pBuf, length); - fdt->_lseek(fildes, oldOff, SEEK_SET); + fdt->usr_lseek(fildes, oldOff, SEEK_SET); if (ret < 0) { @@ -735,7 +783,6 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, } #undef __FENNIX_KERNEL_SYSCALLS_LIST_H__ -/* https://man7.org/linux/man-pages/man2/mprotect.2.html */ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot) { if (len == 0) @@ -744,10 +791,10 @@ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot) if (uintptr_t(addr) % PAGE_SIZE) return -EINVAL; - // bool p_None = prot & sc_PROT_NONE; - bool p_Read = prot & sc_PROT_READ; - bool p_Write = prot & sc_PROT_WRITE; - // bool p_Exec = prot & sc_PROT_EXEC; + // bool p_None = prot & linux_PROT_NONE; + bool p_Read = prot & linux_PROT_READ; + bool p_Write = prot & linux_PROT_WRITE; + // bool p_Exec = prot & linux_PROT_EXEC; PCB *pcb = thisProcess; Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); @@ -788,10 +835,10 @@ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot) debug("Changed permissions of page %#lx to %s %s %s %s", (void *)i, - (prot & sc_PROT_NONE) ? "None" : "", + (prot & linux_PROT_NONE) ? "None" : "", p_Read ? "Read" : "", p_Write ? "Write" : "", - (prot & sc_PROT_EXEC) ? "Exec" : ""); + (prot & linux_PROT_EXEC) ? "Exec" : ""); #if defined(a64) CPU::x64::invlpg(addr); @@ -811,7 +858,6 @@ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot) return 0; } -/* https://man7.org/linux/man-pages/man2/munmap.2.html */ static int linux_munmap(SysFrm *, void *addr, size_t length) { if (uintptr_t(addr) % PAGE_SIZE) @@ -826,7 +872,6 @@ static int linux_munmap(SysFrm *, void *addr, size_t length) return 0; } -/* https://man7.org/linux/man-pages/man2/brk.2.html */ static void *linux_brk(SysFrm *, void *addr) { PCB *pcb = thisProcess; @@ -835,7 +880,6 @@ static void *linux_brk(SysFrm *, void *addr) return ret; } -/* https://man7.org/linux/man-pages/man2/ioctl.2.html */ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp) { PCB *pcb = thisProcess; @@ -846,10 +890,9 @@ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp) if (pArgp == nullptr) return -EFAULT; - return fdt->_ioctl(fd, request, pArgp); + return fdt->usr_ioctl(fd, request, pArgp); } -/* https://man7.org/linux/man-pages/man2/pread.2.html */ static ssize_t linux_pread64(SysFrm *, int fd, void *buf, size_t count, off_t offset) { PCB *pcb = thisProcess; @@ -860,14 +903,13 @@ static ssize_t linux_pread64(SysFrm *, int fd, void *buf, size_t count, off_t of return -EFAULT; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - off_t oldOff = fdt->_lseek(fd, 0, SEEK_CUR); - fdt->_lseek(fd, offset, SEEK_SET); - ssize_t ret = fdt->_read(fd, pBuf, count); - fdt->_lseek(fd, oldOff, SEEK_SET); + off_t oldOff = fdt->usr_lseek(fd, 0, SEEK_CUR); + fdt->usr_lseek(fd, offset, SEEK_SET); + ssize_t ret = fdt->usr_read(fd, pBuf, count); + fdt->usr_lseek(fd, oldOff, SEEK_SET); return ret; } -/* https://man7.org/linux/man-pages/man2/pread.2.html */ static ssize_t linux_pwrite64(SysFrm *, int fd, const void *buf, size_t count, off_t offset) { PCB *pcb = thisProcess; @@ -878,14 +920,13 @@ static ssize_t linux_pwrite64(SysFrm *, int fd, const void *buf, size_t count, o return -EFAULT; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - off_t oldOff = fdt->_lseek(fd, 0, SEEK_CUR); - fdt->_lseek(fd, offset, SEEK_SET); - ssize_t ret = fdt->_write(fd, pBuf, count); - fdt->_lseek(fd, oldOff, SEEK_SET); + off_t oldOff = fdt->usr_lseek(fd, 0, SEEK_CUR); + fdt->usr_lseek(fd, offset, SEEK_SET); + ssize_t ret = fdt->usr_write(fd, pBuf, count); + fdt->usr_lseek(fd, oldOff, SEEK_SET); return ret; } -/* https://man7.org/linux/man-pages/man2/readv.2.html */ static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) { PCB *pcb = thisProcess; @@ -928,7 +969,6 @@ static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int return Total; } -/* https://man7.org/linux/man-pages/man2/writev.2.html */ static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) { PCB *pcb = thisProcess; @@ -971,7 +1011,6 @@ static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int return Total; } -/* https://man7.org/linux/man-pages/man2/access.2.html */ static int linux_access(SysFrm *, const char *pathname, int mode) { PCB *pcb = thisProcess; @@ -983,14 +1022,13 @@ static int linux_access(SysFrm *, const char *pathname, int mode) debug("access(%s, %d)", (char *)pPathname, mode); - if (!fs->PathExists(pPathname, pcb->CurrentWorkingDirectory)) + if (!fs->PathExists(pPathname, pcb->CWD)) return -ENOENT; stub; return 0; } -/* https://man7.org/linux/man-pages/man2/pipe.2.html */ static int linux_pipe(SysFrm *, int pipefd[2]) { PCB *pcb = thisProcess; @@ -1002,30 +1040,26 @@ static int linux_pipe(SysFrm *, int pipefd[2]) return -ENOSYS; } -/* https://man7.org/linux/man-pages/man2/dup.2.html */ static int linux_dup(SysFrm *, int oldfd) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_dup(oldfd); + return fdt->usr_dup(oldfd); } -/* https://man7.org/linux/man-pages/man2/dup.2.html */ static int linux_dup2(SysFrm *, int oldfd, int newfd) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_dup2(oldfd, newfd); + return fdt->usr_dup2(oldfd, newfd); } -/* https://man7.org/linux/man-pages/man2/pause.2.html */ static int linux_pause(SysFrm *) { PCB *pcb = thisProcess; return pcb->Signals.WaitAnySignal(); } -/* https://man7.org/linux/man-pages/man2/nanosleep.2.html */ static int linux_nanosleep(SysFrm *, const struct timespec *req, struct timespec *rem) @@ -1084,13 +1118,11 @@ static int linux_nanosleep(SysFrm *, return 0; } -/* https://man7.org/linux/man-pages/man2/getpid.2.html */ static pid_t linux_getpid(SysFrm *) { return thisProcess->ID; } -/* https://man7.org/linux/man-pages/man2/setitimer.2.html */ static int linux_setitimer(SysFrm *, int which, const struct itimerspec64 *new_value, struct itimerspec64 *old_value) @@ -1108,17 +1140,17 @@ static int linux_setitimer(SysFrm *, int which, switch (which) { - case ITIMER_REAL: + case linux_ITIMER_REAL: { fixme("ITIMER_REAL not implemented"); return 0; } - case ITIMER_VIRTUAL: + case linux_ITIMER_VIRTUAL: { fixme("ITIMER_VIRTUAL not implemented"); return 0; } - case ITIMER_PROF: + case linux_ITIMER_PROF: { fixme("ITIMER_PROF not implemented"); return 0; @@ -1130,14 +1162,12 @@ static int linux_setitimer(SysFrm *, int which, return 0; } -/* https://man7.org/linux/man-pages/man2/shutdown.2.html */ static int linux_shutdown(SysFrm *, int sockfd, int how) { stub; return -ENOSYS; } -/* https://man7.org/linux/man-pages/man2/fork.2.html */ static pid_t linux_fork(SysFrm *sf) { TCB *Thread = thisThread; @@ -1162,7 +1192,7 @@ static pid_t linux_fork(SysFrm *sf) NewProcess->ProgramBreak->SetTable(NewProcess->PageTable); NewProcess->FileDescriptors->Fork(Parent->FileDescriptors); NewProcess->Executable = Parent->Executable; - NewProcess->CurrentWorkingDirectory = Parent->CurrentWorkingDirectory; + NewProcess->CWD = Parent->CWD; NewProcess->FileCreationMask = Parent->FileCreationMask; TCB *NewThread = @@ -1217,7 +1247,6 @@ static pid_t linux_fork(SysFrm *sf) return (int)NewProcess->ID; } -/* https://man7.org/linux/man-pages/man2/execve.2.html */ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathname, char *const argv[], char *const envp[]) @@ -1233,7 +1262,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn if (pPathname == nullptr || pArgv == nullptr || pEnvp == nullptr) return -EFAULT; - function("%s %#lx %#lx", pPathname, pArgv, pEnvp); + func("%s %#lx %#lx", pPathname, pArgv, pEnvp); int argvLen = 0; for (argvLen = 0; MAX_ARG; argvLen++) @@ -1296,8 +1325,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn safe_envp[i + 1] = nullptr; } - vfs::RefNode *File = fs->Open(pPathname, - pcb->CurrentWorkingDirectory); + FileNode *File = fs->GetByPath(pPathname, pcb->CWD); if (!File) { @@ -1306,7 +1334,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn } char shebang_magic[2]; - File->read((uint8_t *)shebang_magic, 2); + File->Read((uint8_t *)shebang_magic, 2, 0); if (shebang_magic[0] == '#' && shebang_magic[1] == '!') { @@ -1316,12 +1344,11 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn char *shebang = (char *)pPathname; size_t shebang_len = 0; constexpr int shebang_len_max = 255; - File->seek(2, SEEK_SET); off_t shebang_off = 2; while (true) { char c; - if (File->node->read((uint8_t *)&c, 1, shebang_off) == 0) + if (File->Read((uint8_t *)&c, 1, shebang_off) == 0) break; if (c == '\n' || shebang_len == shebang_len_max) break; @@ -1367,7 +1394,6 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn } safe_argv[i] = nullptr; - delete File; return linux_execve(sf, safe_argv[0], (char *const *)safe_argv, (char *const *)safe_envp); @@ -1382,7 +1408,6 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn if (ret < 0) { error("Failed to spawn"); - delete File; return ret; } @@ -1390,10 +1415,9 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn cwk_path_get_basename(pPathname, &baseName, nullptr); pcb->Rename(baseName); - pcb->SetWorkingDirectory(File->node->Parent); + pcb->SetWorkingDirectory(File->Parent); pcb->SetExe(pPathname); - delete File; Tasking::Task *ctx = pcb->GetContext(); // ctx->Sleep(1000); // pcb->SetState(Tasking::Zombie); @@ -1403,7 +1427,6 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn __builtin_unreachable(); } -/* https://man7.org/linux/man-pages/man2/exit.2.html */ static __noreturn void linux_exit(SysFrm *, int status) { TCB *t = thisThread; @@ -1420,7 +1443,6 @@ static __noreturn void linux_exit(SysFrm *, int status) __builtin_unreachable(); } -/* https://man7.org/linux/man-pages/man2/wait4.2.html */ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, int options, struct rusage *rusage) { @@ -1651,7 +1673,6 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, return pid; } -/* https://man7.org/linux/man-pages/man2/kill.2.html */ static int linux_kill(SysFrm *, pid_t pid, int sig) { PCB *pcb = thisProcess->GetContext()->GetProcessByID(pid); @@ -1699,7 +1720,6 @@ static int linux_kill(SysFrm *, pid_t pid, int sig) return pcb->SendSignal(nSig); } -/* https://man7.org/linux/man-pages/man2/uname.2.html */ static int linux_uname(SysFrm *, struct utsname *buf) { assert(sizeof(struct utsname) < PAGE_SIZE); @@ -1712,29 +1732,33 @@ static int linux_uname(SysFrm *, struct utsname *buf) return -EFAULT; struct utsname uname = - { - /* TODO: This shouldn't be hardcoded */ - .sysname = KERNEL_NAME, - .nodename = "fennix", - .release = KERNEL_VERSION, - .version = KERNEL_VERSION, + { + /* TODO: This shouldn't be hardcoded */ + .sysname = KERNEL_NAME, + .nodename = "fennix", + .release = KERNEL_VERSION, + .version = KERNEL_VERSION, #if defined(a64) - .machine = "x86_64", + .machine = "x86_64", #elif defined(a32) - .machine = "i386", + .machine = "i386", #elif defined(aa64) - .machine = "arm64", + .machine = "arm64", #elif defined(aa32) - .machine = "arm", + .machine = "arm", #endif - }; + }; - vfs::RefNode *rn = fs->Open("/etc/cross/linux"); + FileNode *rn = fs->GetByPath("/etc/cross/linux", pcb->Info.RootNode); if (rn) { - Memory::SmartHeap sh(rn->Size); - rn->read(sh, rn->Size); - delete rn; + struct kstat st + { + }; + rn->Stat(&st); + + Memory::SmartHeap sh = Memory::SmartHeap(st.Size); + rn->Read(sh.Get(), st.Size, 0); ini_t *ini = ini_load(sh, NULL); int section = ini_find_section(ini, "uname", NULL); @@ -1773,7 +1797,6 @@ static int linux_uname(SysFrm *, struct utsname *buf) return 0; } -/* https://man7.org/linux/man-pages/man2/fcntl.2.html */ static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) { PCB *pcb = thisProcess; @@ -1781,18 +1804,18 @@ static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) switch (cmd) { - case F_DUPFD: - return fdt->_dup2(fd, s_cst(int, (uintptr_t)arg)); - case F_GETFD: + case linux_F_DUPFD: + return fdt->usr_dup2(fd, s_cst(int, (uintptr_t)arg)); + case linux_F_GETFD: return fdt->GetFlags(fd); - case F_SETFD: + case linux_F_SETFD: return fdt->SetFlags(fd, s_cst(int, (uintptr_t)arg)); - case F_GETFL: + case linux_F_GETFL: { fixme("F_GETFL is stub?"); return fdt->GetFlags(fd); } - case F_SETFL: + case linux_F_SETFL: { fixme("F_SETFL is stub?"); int flags = s_cst(int, (uintptr_t)arg); @@ -1802,27 +1825,32 @@ static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) fdt->SetFlags(fd, fdt->GetFlags(fd) & ~O_APPEND); return 0; } - case F_DUPFD_CLOEXEC: + case linux_F_DUPFD_CLOEXEC: { - int ret = fdt->_dup2(fd, s_cst(int, (uintptr_t)arg)); + int ret = fdt->usr_dup2(fd, s_cst(int, (uintptr_t)arg)); if (ret < 0) return ret; - fdt->GetDescriptor(ret).Flags |= FD_CLOEXEC; + + auto it = fdt->FileMap.find(fd); + if (it == fdt->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); + + it->second.Flags |= linux_FD_CLOEXEC; return ret; } - case F_SETOWN: - case F_GETOWN: - case F_SETSIG: - case F_GETSIG: - case F_GETLK: - case F_SETLK: - case F_SETLKW: - case F_SETOWN_EX: - case F_GETOWN_EX: - case F_GETOWNER_UIDS: - case F_OFD_GETLK: - case F_OFD_SETLK: - case F_OFD_SETLKW: + case linux_F_SETOWN: + case linux_F_GETOWN: + case linux_F_SETSIG: + case linux_F_GETSIG: + case linux_F_GETLK: + case linux_F_SETLK: + case linux_F_SETLKW: + case linux_F_SETOWN_EX: + case linux_F_GETOWN_EX: + case linux_F_GETOWNER_UIDS: + case linux_F_OFD_GETLK: + case linux_F_OFD_SETLK: + case linux_F_OFD_SETLKW: { fixme("cmd %d not implemented", cmd); return -ENOSYS; @@ -1835,15 +1863,13 @@ static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) } } -/* https://man7.org/linux/man-pages/man2/creat.2.html */ static int linux_creat(SysFrm *, const char *pathname, mode_t mode) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_creat(pathname, mode); + return fdt->usr_creat(pathname, mode); } -/* https://man7.org/linux/man-pages/man2/getcwd.2.html */ static long linux_getcwd(SysFrm *, char *buf, size_t size) { PCB *pcb = thisProcess; @@ -1853,7 +1879,7 @@ static long linux_getcwd(SysFrm *, char *buf, size_t size) if (pBuf == nullptr) return -EFAULT; - const char *cwd = pcb->CurrentWorkingDirectory->FullPath; + const char *cwd = pcb->CWD->Path.c_str(); size_t len = strlen(cwd); if (len >= size) { @@ -1866,7 +1892,6 @@ static long linux_getcwd(SysFrm *, char *buf, size_t size) return len; } -/* https://man7.org/linux/man-pages/man2/mkdir.2.html */ static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode) { PCB *pcb = thisProcess; @@ -1877,13 +1902,14 @@ static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode) if (!pPathname) return -EFAULT; - vfs::Node *n = fs->Create(pPathname, vfs::DIRECTORY, pcb->CurrentWorkingDirectory); + mode &= ~pcb->FileCreationMask & 0777; + + FileNode *n = fs->Create(pcb->CWD, pPathname, mode); if (!n) return -EEXIST; return 0; } -/* https://man7.org/linux/man-pages/man2/readlink.2.html */ static ssize_t linux_readlink(SysFrm *, const char *pathname, char *buf, size_t bufsiz) { @@ -1904,34 +1930,26 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname, if (pPath == nullptr || pBuf == nullptr) return -EFAULT; - function("%s %#lx %ld", pPath, buf, bufsiz); + func("%s %#lx %ld", pPath, buf, bufsiz); vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - int fd = fdt->_open(pPath, O_RDONLY, 0); + int fd = fdt->usr_open(pPath, O_RDONLY, 0); if (fd < 0) return -ENOENT; - vfs::FileDescriptorTable::Fildes fildes = fdt->GetDescriptor(fd); - vfs::Node *node = fildes.Handle->node; - fdt->_close(fd); + auto it = fdt->FileMap.find(fd); + if (it == fdt->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - if (node->Type != vfs::NodeType::SYMLINK) + vfs::FileDescriptorTable::Fildes &fildes = it->second; + FileNode *node = fildes.Node; + fdt->usr_close(fd); + + if (!node->IsSymbolicLink()) return -EINVAL; - if (!node->Symlink) - { - warn("Symlink null for \"%s\"?", pPath); - return -EINVAL; - } - - size_t len = strlen(node->Symlink); - if (len > bufsiz) - len = bufsiz; - - strncpy(pBuf, node->Symlink, len); - return len; + return node->ReadLink(pBuf, bufsiz); } -/* https://man7.org/linux/man-pages/man2/umask.2.html */ static mode_t linux_umask(SysFrm *, mode_t mask) { PCB *pcb = thisProcess; @@ -1941,7 +1959,6 @@ static mode_t linux_umask(SysFrm *, mode_t mask) return old; } -/* https://man7.org/linux/man-pages/man2/getrusage.2.html */ static int linux_getrusage(SysFrm *, int who, struct rusage *usage) { PCB *pcb = thisProcess; @@ -1953,7 +1970,7 @@ static int linux_getrusage(SysFrm *, int who, struct rusage *usage) switch (who) { - case RUSAGE_SELF: + case linux_RUSAGE_SELF: { size_t kTime = pcb->Info.KernelTime; size_t uTime = pcb->Info.UserTime; @@ -1968,7 +1985,7 @@ static int linux_getrusage(SysFrm *, int who, struct rusage *usage) pUsage->ru_maxrss = _maxrss; break; } - case RUSAGE_CHILDREN: + case linux_RUSAGE_CHILDREN: { size_t kTime = 0; size_t uTime = 0; @@ -1990,7 +2007,7 @@ static int linux_getrusage(SysFrm *, int who, struct rusage *usage) pUsage->ru_maxrss = _maxrss; break; } - case RUSAGE_THREAD: + case linux_RUSAGE_THREAD: { TCB *tcb = thisThread; @@ -2014,37 +2031,31 @@ static int linux_getrusage(SysFrm *, int who, struct rusage *usage) return 0; } -/* https://man7.org/linux/man-pages/man2/getuid.2.html */ static uid_t linux_getuid(SysFrm *) { return thisProcess->Security.Real.UserID; } -/* https://man7.org/linux/man-pages/man2/getgid.2.html */ static gid_t linux_getgid(SysFrm *) { return thisProcess->Security.Real.GroupID; } -/* https://man7.org/linux/man-pages/man2/getuid.2.html */ static uid_t linux_geteuid(SysFrm *) { return thisProcess->Security.Effective.UserID; } -/* https://man7.org/linux/man-pages/man2/getgid.2.html */ static gid_t linux_getegid(SysFrm *) { return thisProcess->Security.Effective.GroupID; } -/* https://man7.org/linux/man-pages/man2/getpid.2.html */ static pid_t linux_getppid(SysFrm *) { return thisProcess->Parent->ID; } -/* https://man7.org/linux/man-pages/man2/getpgid.2.html */ static pid_t linux_getpgid(SysFrm *, pid_t pid) { PCB *pcb = thisProcess; @@ -2058,7 +2069,6 @@ static pid_t linux_getpgid(SysFrm *, pid_t pid) return target->Security.ProcessGroupID; } -/* https://man7.org/linux/man-pages/man2/setpgid.2.html */ static int linux_setpgid(SysFrm *, pid_t pid, pid_t pgid) { PCB *pcb = thisProcess; @@ -2082,7 +2092,6 @@ static int linux_setpgid(SysFrm *, pid_t pid, pid_t pgid) return 0; } -/* https://man7.org/linux/man-pages/man2/arch_prctl.2.html */ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) { PCB *pcb = thisProcess; @@ -2093,7 +2102,7 @@ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) switch (code) { - case ARCH_SET_GS: + case linux_ARCH_SET_GS: { #if defined(a64) CPU::x64::wrmsr(CPU::x64::MSRID::MSR_GS_BASE, addr); @@ -2102,7 +2111,7 @@ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) #endif return 0; } - case ARCH_SET_FS: + case linux_ARCH_SET_FS: { #if defined(a64) CPU::x64::wrmsr(CPU::x64::MSRID::MSR_FS_BASE, addr); @@ -2111,7 +2120,7 @@ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) #endif return 0; } - case ARCH_GET_FS: + case linux_ARCH_GET_FS: { #if defined(a64) *r_cst(uint64_t *, addr) = @@ -2122,7 +2131,7 @@ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) #endif return 0; } - case ARCH_GET_GS: + case linux_ARCH_GET_GS: { #if defined(a64) *r_cst(uint64_t *, addr) = @@ -2133,22 +2142,22 @@ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) #endif return 0; } - case ARCH_GET_CPUID: - case ARCH_SET_CPUID: - case ARCH_GET_XCOMP_SUPP: - case ARCH_GET_XCOMP_PERM: - case ARCH_REQ_XCOMP_PERM: - case ARCH_GET_XCOMP_GUEST_PERM: - case ARCH_REQ_XCOMP_GUEST_PERM: - case ARCH_XCOMP_TILECFG: - case ARCH_XCOMP_TILEDATA: - case ARCH_MAP_VDSO_X32: - case ARCH_MAP_VDSO_32: - case ARCH_MAP_VDSO_64: - case ARCH_GET_UNTAG_MASK: - case ARCH_ENABLE_TAGGED_ADDR: - case ARCH_GET_MAX_TAG_BITS: - case ARCH_FORCE_TAGGED_SVA: + case linux_ARCH_GET_CPUID: + case linux_ARCH_SET_CPUID: + case linux_ARCH_GET_XCOMP_SUPP: + case linux_ARCH_GET_XCOMP_PERM: + case linux_ARCH_REQ_XCOMP_PERM: + case linux_ARCH_GET_XCOMP_GUEST_PERM: + case linux_ARCH_REQ_XCOMP_GUEST_PERM: + case linux_ARCH_XCOMP_TILECFG: + case linux_ARCH_XCOMP_TILEDATA: + case linux_ARCH_MAP_VDSO_X32: + case linux_ARCH_MAP_VDSO_32: + case linux_ARCH_MAP_VDSO_64: + case linux_ARCH_GET_UNTAG_MASK: + case linux_ARCH_ENABLE_TAGGED_ADDR: + case linux_ARCH_GET_MAX_TAG_BITS: + case linux_ARCH_FORCE_TAGGED_SVA: { fixme("Code %#lx not implemented", code); return -ENOSYS; @@ -2161,14 +2170,13 @@ static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) } } -/* https://man7.org/linux/man-pages/man2/reboot.2.html */ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) { - if (magic != LINUX_REBOOT_MAGIC1 || - (magic2 != LINUX_REBOOT_MAGIC2 && - magic2 != LINUX_REBOOT_MAGIC2A && - magic2 != LINUX_REBOOT_MAGIC2B && - magic2 != LINUX_REBOOT_MAGIC2C)) + if (magic != linux_LINUX_REBOOT_MAGIC1 || + (magic2 != linux_LINUX_REBOOT_MAGIC2 && + magic2 != linux_LINUX_REBOOT_MAGIC2A && + magic2 != linux_LINUX_REBOOT_MAGIC2B && + magic2 != linux_LINUX_REBOOT_MAGIC2C)) { warn("Invalid magic %#x %#x", magic, magic2); return -EINVAL; @@ -2180,7 +2188,7 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) debug("cmd=%#x arg=%#lx", cmd, arg); switch ((unsigned int)cmd) { - case LINUX_REBOOT_CMD_RESTART: + case linux_LINUX_REBOOT_CMD_RESTART: { KPrint("Restarting system."); @@ -2190,14 +2198,14 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) ->Rename("Restart"); return 0; } - case LINUX_REBOOT_CMD_HALT: + case linux_LINUX_REBOOT_CMD_HALT: { KPrint("System halted."); pcb->GetContext()->Panic(); CPU::Stop(); } - case LINUX_REBOOT_CMD_POWER_OFF: + case linux_LINUX_REBOOT_CMD_POWER_OFF: { KPrint("Power down."); @@ -2207,7 +2215,7 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) ->Rename("Shutdown"); return 0; } - case LINUX_REBOOT_CMD_RESTART2: + case linux_LINUX_REBOOT_CMD_RESTART2: { void *pArg = vma->__UserCheckAndGetAddress(arg, sizeof(void *)); if (pArg == nullptr) @@ -2222,10 +2230,10 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) ->Rename("Restart"); break; } - case LINUX_REBOOT_CMD_CAD_ON: - case LINUX_REBOOT_CMD_CAD_OFF: - case LINUX_REBOOT_CMD_SW_SUSPEND: - case LINUX_REBOOT_CMD_KEXEC: + case linux_LINUX_REBOOT_CMD_CAD_ON: + case linux_LINUX_REBOOT_CMD_CAD_OFF: + case linux_LINUX_REBOOT_CMD_SW_SUSPEND: + case linux_LINUX_REBOOT_CMD_KEXEC: { fixme("cmd %#x not implemented", cmd); return -ENOSYS; @@ -2239,7 +2247,6 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) return 0; } -/* https://man7.org/linux/man-pages/man2/sigaction.2.html */ static int linux_sigaction(SysFrm *, int signum, const k_sigaction *act, k_sigaction *oldact, size_t sigsetsize) { @@ -2286,7 +2293,7 @@ static int linux_sigaction(SysFrm *, int signum, const k_sigaction *act, if (pAct) { - if (pAct->flags & SA_IMMUTABLE) + if (pAct->flags & linux_SA_IMMUTABLE) { warn("Immutable signal %d", signum); return -EINVAL; @@ -2304,7 +2311,6 @@ static int linux_sigaction(SysFrm *, int signum, const k_sigaction *act, return ret; } -/* https://man7.org/linux/man-pages/man2/sigprocmask.2.html */ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set, sigset_t *oldset, size_t sigsetsize) { @@ -2359,19 +2365,16 @@ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set, return 0; } -/* https://man7.org/linux/man-pages/man2/sigreturn.2.html */ static void linux_sigreturn(SysFrm *sf) { thisProcess->Signals.RestoreHandleSignal(sf, thisThread); } -/* https://man7.org/linux/man-pages/man2/gettid.2.html */ static pid_t linux_gettid(SysFrm *) { return thisThread->ID; } -/* https://man7.org/linux/man-pages/man2/tkill.2.html */ static int linux_tkill(SysFrm *, int tid, int sig) { Tasking::TCB *tcb = thisProcess->GetThread(tid); @@ -2383,7 +2386,6 @@ static int linux_tkill(SysFrm *, int tid, int sig) return tcb->SendSignal(nSig); } -/* https://man7.org/linux/man-pages/man2/set_tid_address.2.html */ static pid_t linux_set_tid_address(SysFrm *, int *tidptr) { if (tidptr == nullptr) @@ -2395,7 +2397,6 @@ static pid_t linux_set_tid_address(SysFrm *, int *tidptr) return tcb->ID; } -/* https://man7.org/linux/man-pages/man2/getdents.2.html */ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp, size_t count) { @@ -2409,20 +2410,14 @@ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp, return -EINVAL; } - vfs::FileDescriptorTable::Fildes & - fildes = fdt->GetDescriptor(fd); - if (!fildes.Handle) - { - debug("Invalid fd %d", fd); - return -EBADF; - } + auto it = fdt->FileMap.find(fd); + if (it == fdt->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", fd); - if (fildes.Handle->node->Type != vfs::NodeType::DIRECTORY) - { - debug("Invalid node type %d", - fildes.Handle->node->Type); - return -ENOTDIR; - } + vfs::FileDescriptorTable::Fildes &fildes = it->second; + + if (!fildes.Node->IsDirectory()) + ReturnLogError(-ENOTDIR, "Not a directory"); auto pDirp = vma->UserCheckAndGetAddress(dirp); if (pDirp == nullptr) @@ -2433,7 +2428,6 @@ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp, return -ENOSYS; } -/* https://man7.org/linux/man-pages/man3/clock_gettime.3.html */ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) { static_assert(sizeof(struct timespec) < PAGE_SIZE); @@ -2448,7 +2442,7 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) /* FIXME: This is not correct? */ switch (clockid) { - case CLOCK_REALTIME: + case linux_CLOCK_REALTIME: { uint64_t time = TimeManager->GetCounter(); pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds); @@ -2457,7 +2451,7 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) time, pTp->tv_sec, pTp->tv_nsec); break; } - case CLOCK_MONOTONIC: + case linux_CLOCK_MONOTONIC: { uint64_t time = TimeManager->GetCounter(); pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds); @@ -2466,16 +2460,16 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) time, pTp->tv_sec, pTp->tv_nsec); break; } - case CLOCK_PROCESS_CPUTIME_ID: - case CLOCK_THREAD_CPUTIME_ID: - case CLOCK_MONOTONIC_RAW: - case CLOCK_REALTIME_COARSE: - case CLOCK_MONOTONIC_COARSE: - case CLOCK_BOOTTIME: - case CLOCK_REALTIME_ALARM: - case CLOCK_BOOTTIME_ALARM: - case CLOCK_SGI_CYCLE: - case CLOCK_TAI: + case linux_CLOCK_PROCESS_CPUTIME_ID: + case linux_CLOCK_THREAD_CPUTIME_ID: + case linux_CLOCK_MONOTONIC_RAW: + case linux_CLOCK_REALTIME_COARSE: + case linux_CLOCK_MONOTONIC_COARSE: + case linux_CLOCK_BOOTTIME: + case linux_CLOCK_REALTIME_ALARM: + case linux_CLOCK_BOOTTIME_ALARM: + case linux_CLOCK_SGI_CYCLE: + case linux_CLOCK_TAI: { fixme("clockid %d is stub", clockid); return -ENOSYS; @@ -2489,7 +2483,6 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) return 0; } -/* https://man7.org/linux/man-pages/man2/clock_nanosleep.2.html */ static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain) @@ -2507,8 +2500,8 @@ static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags, switch (clockid) { - case CLOCK_REALTIME: - case CLOCK_MONOTONIC: + case linux_CLOCK_REALTIME: + case linux_CLOCK_MONOTONIC: { uint64_t time = TimeManager->GetCounter(); uint64_t rqTime = pRequest->tv_sec * Time::ConvertUnit(Time::Seconds) + @@ -2519,16 +2512,16 @@ static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags, pcb->GetContext()->Sleep(rqTime - time); break; } - case CLOCK_PROCESS_CPUTIME_ID: - case CLOCK_THREAD_CPUTIME_ID: - case CLOCK_MONOTONIC_RAW: - case CLOCK_REALTIME_COARSE: - case CLOCK_MONOTONIC_COARSE: - case CLOCK_BOOTTIME: - case CLOCK_REALTIME_ALARM: - case CLOCK_BOOTTIME_ALARM: - case CLOCK_SGI_CYCLE: - case CLOCK_TAI: + case linux_CLOCK_PROCESS_CPUTIME_ID: + case linux_CLOCK_THREAD_CPUTIME_ID: + case linux_CLOCK_MONOTONIC_RAW: + case linux_CLOCK_REALTIME_COARSE: + case linux_CLOCK_MONOTONIC_COARSE: + case linux_CLOCK_BOOTTIME: + case linux_CLOCK_REALTIME_ALARM: + case linux_CLOCK_BOOTTIME_ALARM: + case linux_CLOCK_SGI_CYCLE: + case linux_CLOCK_TAI: { fixme("clockid %d is stub", clockid); return -ENOSYS; @@ -2542,14 +2535,12 @@ static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags, return 0; } -/* https://man7.org/linux/man-pages/man2/exit_group.2.html */ static __noreturn void linux_exit_group(SysFrm *sf, int status) { fixme("status=%d", status); linux_exit(sf, status); } -/* https://man7.org/linux/man-pages/man2/tgkill.2.html */ static int linux_tgkill(SysFrm *sf, pid_t tgid, pid_t tid, int sig) { Tasking::TCB *tcb = thisProcess->GetThread(tid); @@ -2577,7 +2568,6 @@ static int linux_tgkill(SysFrm *sf, pid_t tgid, pid_t tid, int sig) return tcb->SendSignal(nSig); } -/* https://man7.org/linux/man-pages/man2/open.2.html */ static int linux_openat(SysFrm *, int dirfd, const char *pathname, int flags, mode_t mode) { PCB *pcb = thisProcess; @@ -2591,22 +2581,21 @@ static int linux_openat(SysFrm *, int dirfd, const char *pathname, int flags, mo debug("dirfd=%d pathname=%s flags=%#x mode=%#x", dirfd, pPathname, flags, mode); - if (dirfd == AT_FDCWD) + if (dirfd == linux_AT_FDCWD) { - vfs::RefNode *absoluteNode = fs->Open(pPathname, pcb->CurrentWorkingDirectory); + FileNode *absoluteNode = fs->GetByPath(pPathname, pcb->CWD); if (!absoluteNode) return -ENOENT; - const char *absPath = new char[strlen(absoluteNode->node->FullPath) + 1]; - strcpy((char *)absPath, absoluteNode->node->FullPath); - delete absoluteNode; - int ret = fdt->_open(absPath, flags, mode); + const char *absPath = new char[strlen(absoluteNode->Path.c_str()) + 1]; + strcpy((char *)absPath, absoluteNode->Path.c_str()); + int ret = fdt->usr_open(absPath, flags, mode); delete[] absPath; return ret; } if (!fs->PathIsRelative(pPathname)) - return fdt->_open(pPathname, flags, mode); + return fdt->usr_open(pPathname, flags, mode); fixme("dirfd=%d is stub", dirfd); return -ENOSYS; @@ -2632,37 +2621,33 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname, debug("%s %#lx %#lx", pPathname, pathname, statbuf); - if (dirfd == AT_FDCWD && !fs->PathIsRelative(pPathname)) + if (dirfd == linux_AT_FDCWD && !fs->PathIsRelative(pPathname)) { - vfs::RefNode *absoluteNode = fs->Open(pPathname, pcb->CurrentWorkingDirectory); + FileNode *absoluteNode = fs->GetByPath(pPathname, pcb->CWD); if (!absoluteNode) return -ENOENT; - const char *absPath = new char[strlen(absoluteNode->node->FullPath) + 1]; - strcpy((char *)absPath, absoluteNode->node->FullPath); - delete absoluteNode; + const char *absPath = new char[strlen(absoluteNode->Path.c_str()) + 1]; + strcpy((char *)absPath, absoluteNode->Path.c_str()); struct kstat nstat = KStatToStat(*pStatbuf); - int ret = fdt->_stat(absPath, &nstat); + int ret = fdt->usr_stat(absPath, &nstat); *pStatbuf = StatToKStat(nstat); delete[] absPath; return ret; } - vfs::FileDescriptorTable::Fildes & - fildes = fdt->GetDescriptor(dirfd); - if (!fildes.Handle) - { - debug("Invalid fd %d", dirfd); - return -EBADF; - } + auto it = fdt->FileMap.find(dirfd); + if (it == fdt->FileMap.end()) + ReturnLogError(-EBADF, "Invalid fd %d", dirfd); + + vfs::FileDescriptorTable::Fildes &fildes = it->second; struct kstat nstat = KStatToStat(*pStatbuf); - int ret = fdt->_stat(pPathname, &nstat); + int ret = fdt->usr_stat(pPathname, &nstat); *pStatbuf = StatToKStat(nstat); return ret; } -/* https://man7.org/linux/man-pages/man2/pipe2.2.html */ static int linux_pipe2(SysFrm *sf, int pipefd[2], int flags) { if (flags == 0) @@ -2680,7 +2665,6 @@ static int linux_pipe2(SysFrm *sf, int pipefd[2], int flags) return -ENOSYS; } -/* https://man7.org/linux/man-pages/man2/getrlimit.2.html */ static int linux_prlimit64(SysFrm *, pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit) @@ -2715,40 +2699,40 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource, switch (resource) { - case RLIMIT_CPU: - case RLIMIT_FSIZE: - case RLIMIT_DATA: - case RLIMIT_STACK: - case RLIMIT_CORE: - case RLIMIT_RSS: + case linux_RLIMIT_CPU: + case linux_RLIMIT_FSIZE: + case linux_RLIMIT_DATA: + case linux_RLIMIT_STACK: + case linux_RLIMIT_CORE: + case linux_RLIMIT_RSS: goto __stub; - case RLIMIT_NPROC: + case linux_RLIMIT_NPROC: { if (new_limit) pcb->Limits.Threads = pNewLimit->rlim_max; return 0; } - case RLIMIT_NOFILE: + case linux_RLIMIT_NOFILE: { if (new_limit) pcb->Limits.OpenFiles = pNewLimit->rlim_max; return 0; } - case RLIMIT_MEMLOCK: + case linux_RLIMIT_MEMLOCK: goto __stub; - case RLIMIT_AS: + case linux_RLIMIT_AS: { if (new_limit) pcb->Limits.Memory = pNewLimit->rlim_max; return 0; } - case RLIMIT_LOCKS: - case RLIMIT_SIGPENDING: - case RLIMIT_MSGQUEUE: - case RLIMIT_NICE: - case RLIMIT_RTPRIO: - case RLIMIT_RTTIME: - case RLIMIT_NLIMITS: + case linux_RLIMIT_LOCKS: + case linux_RLIMIT_SIGPENDING: + case linux_RLIMIT_MSGQUEUE: + case linux_RLIMIT_NICE: + case linux_RLIMIT_RTPRIO: + case linux_RLIMIT_RTTIME: + case linux_RLIMIT_NLIMITS: __stub: { fixme("resource %s(%d) is stub", rlimitStr[resource], resource); @@ -2764,19 +2748,18 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource, return 0; } -/* https://man7.org/linux/man-pages/man2/getrandom.2.html */ static ssize_t linux_getrandom(SysFrm *, void *buf, size_t buflen, unsigned int flags) { PCB *pcb = thisProcess; Memory::VirtualMemoryArea *vma = pcb->vma; - if (flags & GRND_NONBLOCK) + if (flags & linux_GRND_NONBLOCK) fixme("GRND_NONBLOCK not implemented"); - if (flags & ~(GRND_NONBLOCK | - GRND_RANDOM | - GRND_INSECURE)) + if (flags & ~(linux_GRND_NONBLOCK | + linux_GRND_RANDOM | + linux_GRND_INSECURE)) { warn("Invalid flags %#x", flags); return -EINVAL; @@ -2786,7 +2769,7 @@ static ssize_t linux_getrandom(SysFrm *, void *buf, if (pBuf == nullptr) return -EFAULT; - if (flags & GRND_RANDOM) + if (flags & linux_GRND_RANDOM) { uint16_t random; for (size_t i = 0; i < buflen; i++) diff --git a/syscalls/native.cpp b/syscalls/native.cpp index 94a108b..f627071 100644 --- a/syscalls/native.cpp +++ b/syscalls/native.cpp @@ -15,15 +15,15 @@ along with Fennix Kernel. If not, see . */ -#include +#include +#include #include #include #include #include #include -#include "../syscalls.h" #include "../kernel.h" struct SyscallData @@ -41,91 +41,22 @@ typedef long arch_t; typedef int arch_t; #endif -void sys_exit(SysFrm *, int status); +void sys_0() { stub; } +void sys_1() { stub; } -void *sys_mmap(SysFrm *, - void *addr, size_t len, - int prot, int flags, - int fildes, off_t off); - -int sys_munmap(SysFrm *, - void *addr, size_t len); - -int sys_mprotect(SysFrm *, - void *addr, size_t len, - int prot); - -int sys_open(SysFrm *, - const char *path, - int oflag, mode_t mode); - -int sys_close(SysFrm *, - int fildes); - -ssize_t sys_read(SysFrm *, int fildes, - void *buf, size_t nbyte); - -ssize_t sys_write(SysFrm *, int fildes, - const void *buf, - size_t nbyte); - -off_t sys_lseek(SysFrm *, int fildes, - off_t offset, int whence); - -int sys_fork(SysFrm *Frame); +#define sc_MaxSyscall 2 static SyscallData NativeSyscallsTable[sc_MaxSyscall] = { - [sc_exit] = { - "exit", - (void *)sys_exit, + [0] = { + "0 syscall", + (void *)sys_0, UINT16_MAX, }, - [sc_mmap] = { - "mmap", - (void *)sys_mmap, + [1] = { + "1 syscall", + (void *)sys_1, UINT16_MAX, - }, - [sc_munmap] = { - "munmap", - (void *)sys_munmap, - UINT16_MAX, - }, - [sc_mprotect] = { - "mprotect", - (void *)sys_mprotect, - UINT16_MAX, - }, - [sc_open] = { - "open", - (void *)sys_open, - UINT16_MAX, - }, - [sc_close] = { - "close", - (void *)sys_close, - UINT16_MAX, - }, - [sc_read] = { - "read", - (void *)sys_read, - UINT16_MAX, - }, - [sc_write] = { - "write", - (void *)sys_write, - UINT16_MAX, - }, - [sc_lseek] = { - "lseek", - (void *)sys_lseek, - UINT16_MAX, - }, - [sc_fork] = { - "fork", - (void *)sys_fork, - UINT16_MAX, - }, -}; + }}; uintptr_t HandleNativeSyscalls(SysFrm *Frame) { diff --git a/syscalls/native/.gitkeep b/syscalls/native/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/syscalls/native/execve.cpp b/syscalls/native/execve.cpp deleted file mode 100644 index 2ee6b93..0000000 --- a/syscalls/native/execve.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using vfs::RefNode; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html */ -int sys_execve(SysFrm *Frame, const char *path, - char *const argv[], char *const envp[]) -{ - PCB *pcb = thisProcess; - Virtual vmm = Virtual(pcb->PageTable); - - if (path == nullptr || - !vmm.Check((void *)path, US) || - !vmm.Check((void *)argv, US) || - !vmm.Check((void *)envp, US)) - return -ENOENT; - - const char *safe_path; - char **safe_argv; - char **safe_envp; - safe_path = (const char *)pcb->vma->RequestPages(1); - safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); - safe_envp = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); - { - SwapPT swap(pcb->PageTable); - size_t len = strlen(path); - memset((void *)safe_path, 0, PAGE_SIZE); - memcpy((void *)safe_path, path, len); - - const char *arg; - char *n_arg; - for (int i = 0; argv[i] != nullptr; i++) - { - arg = argv[i]; - size_t len = strlen(arg); - - n_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len)); - memcpy((void *)n_arg, arg, len); - n_arg[len] = '\0'; - - safe_argv[i] = n_arg; - - if (likely(i < MAX_ARG - 1)) - safe_argv[i + 1] = nullptr; - } - - for (int i = 0; envp[i] != nullptr; i++) - { - arg = envp[i]; - size_t len = strlen(arg); - - n_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len)); - memcpy((void *)n_arg, arg, len); - n_arg[len] = '\0'; - - safe_envp[i] = n_arg; - - if (likely(i < MAX_ARG - 1)) - safe_envp[i + 1] = nullptr; - } - } - - function("%s %#lx %#lx", safe_path, safe_argv, safe_envp); - -#ifdef DEBUG - for (int i = 0; safe_argv[i] != nullptr; i++) - debug("safe_argv[%d]: %s", i, safe_argv[i]); - - for (int i = 0; safe_envp[i] != nullptr; i++) - debug("safe_envp[%d]: %s", i, safe_envp[i]); -#endif - - RefNode *File = fs->Open(safe_path, - pcb->CurrentWorkingDirectory); - - if (!File) - { - error("File not found"); - return -ENOENT; - } - - char shebang_magic[2]; - File->read((uint8_t *)shebang_magic, 2); - - if (shebang_magic[0] == '#' && shebang_magic[1] == '!') - { - char *orig_path = (char *)pcb->vma->RequestPages(TO_PAGES(strlen(path) + 1)); - memcpy(orig_path, path, strlen(path) + 1); - - char *shebang = (char *)safe_path; - size_t shebang_len = 0; - constexpr int shebang_len_max = 255; - File->seek(2, SEEK_SET); - off_t shebang_off = 2; - while (true) - { - char c; - if (File->node->read((uint8_t *)&c, 1, shebang_off) == 0) - break; - if (c == '\n' || shebang_len == shebang_len_max) - break; - shebang[shebang_len++] = c; - shebang_off++; - } - shebang[shebang_len] = '\0'; - debug("Shebang: %s", shebang); - - char **c_safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); - int i = 0; - for (; safe_argv[i] != nullptr; i++) - { - size_t arg_len = strlen(safe_argv[i]); - char *c_arg = (char *)pcb->vma->RequestPages(TO_PAGES(arg_len)); - memcpy((void *)c_arg, safe_argv[i], arg_len); - c_arg[arg_len] = '\0'; - - c_safe_argv[i] = c_arg; - debug("c_safe_argv[%d]: %s", i, c_safe_argv[i]); - } - c_safe_argv[i] = nullptr; - - char *token = strtok(shebang, " "); - i = 0; - while (token != nullptr) - { - size_t len = strlen(token); - char *t_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len)); - memcpy((void *)t_arg, token, len); - t_arg[len] = '\0'; - - safe_argv[i++] = t_arg; - token = strtok(nullptr, " "); - } - - safe_argv[i++] = orig_path; - for (int j = 1; c_safe_argv[j] != nullptr; j++) - { - safe_argv[i++] = c_safe_argv[j]; - debug("clone: safe_argv[%d]: %s", - i, safe_argv[i - 1]); - } - safe_argv[i] = nullptr; - - delete File; - return sys_execve(Frame, safe_argv[0], - (char *const *)safe_argv, - (char *const *)safe_envp); - } - - int ret = Execute::Spawn((char *)safe_path, - (const char **)safe_argv, - (const char **)safe_envp, - pcb->Parent, true, - pcb->Info.Compatibility); - - if (ret < 0) - { - error("Failed to spawn"); - delete File; - return ret; - } - - delete File; - Tasking::Task *ctx = pcb->GetContext(); - ctx->Sleep(1000); - pcb->SetState(Tasking::Zombie); - pcb->SetExitCode(0); /* FIXME: get process exit code */ - while (true) - ctx->Yield(); - __builtin_unreachable(); -} diff --git a/syscalls/native/exit.cpp b/syscalls/native/exit.cpp deleted file mode 100644 index 9096ee6..0000000 --- a/syscalls/native/exit.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::TCB; -using Tasking::TaskState::Zombie; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/exit.html */ -__noreturn void sys_exit(SysFrm *, int status) -{ - TCB *t = thisThread; - - trace("Userspace thread %s(%d) exited with code %d (%#x)", - t->Name, - t->ID, status, - status < 0 ? -status : status); - - t->SetState(Zombie); - t->SetExitCode(status); - while (true) - t->GetContext()->Yield(); - __builtin_unreachable(); -} diff --git a/syscalls/native/fork.cpp b/syscalls/native/fork.cpp deleted file mode 100644 index 377964c..0000000 --- a/syscalls/native/fork.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using namespace Memory; - -void sys_fork_return() -{ -#if defined(a64) - asmv("movq $0, %rax\n"); /* Return 0 */ - asmv("movq %r8, %rsp\n"); /* Restore stack pointer */ - asmv("movq %r8, %rbp\n"); /* Restore base pointer */ - asmv("swapgs\n"); /* Swap GS back to the user GS */ - asmv("sti\n"); /* Enable interrupts */ - asmv("sysretq\n"); /* Return to rcx address in user mode */ -#elif defined(a32) -#warning "sys_fork not implemented for i386" -#endif - __builtin_unreachable(); -} - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/fork.html */ -int sys_fork(SysFrm *Frame) -{ - assert(Frame != nullptr); - -#ifdef a32 - return -ENOSYS; -#endif - PCB *Parent = thisThread->Parent; - TCB *Thread = thisThread; - - PCB *NewProcess = - TaskManager->CreateProcess(Parent, Parent->Name, - Parent->Security.ExecutionMode, - true); - - if (!NewProcess) - { - error("Failed to create process for fork"); - return -EAGAIN; - } - - NewProcess->PageTable = Parent->PageTable->Fork(); - - TCB *NewThread = - TaskManager->CreateThread(NewProcess, - 0, - nullptr, - nullptr, - std::vector(), - Thread->Info.Architecture, - Thread->Info.Compatibility, - true); - - NewThread->Rename(Thread->Name); - - if (!NewThread) - { - error("Failed to create thread for fork"); - return -EAGAIN; - } - - TaskManager->UpdateFrame(); - - NewThread->FPU = Thread->FPU; - NewThread->Stack->Fork(Thread->Stack); - NewThread->Info.Architecture = Thread->Info.Architecture; - NewThread->Info.Compatibility = Thread->Info.Compatibility; - NewThread->Security.IsCritical = Thread->Security.IsCritical; - NewThread->Registers = Thread->Registers; -#if defined(a64) - NewThread->Registers.rip = (uintptr_t)sys_fork_return; - /* For sysretq */ - NewThread->Registers.rcx = Frame->ReturnAddress; - NewThread->Registers.r8 = Frame->StackPointer; -#endif - -#ifdef a86 - NewThread->GSBase = NewThread->ShadowGSBase; - NewThread->ShadowGSBase = Thread->ShadowGSBase; - NewThread->FSBase = Thread->FSBase; -#endif - - debug("ret addr: %#lx, stack: %#lx ip: %#lx", Frame->ReturnAddress, - Frame->StackPointer, (uintptr_t)sys_fork_return); - debug("Forked thread \"%s\"(%d) to \"%s\"(%d)", - Thread->Name, Thread->ID, - NewThread->Name, NewThread->ID); - NewThread->SetState(Ready); - return (int)NewProcess->ID; -} diff --git a/syscalls/native/mmap.cpp b/syscalls/native/mmap.cpp deleted file mode 100644 index a4123f8..0000000 --- a/syscalls/native/mmap.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/mmap.html */ -void *sys_mmap(SysFrm *, - void *addr, size_t len, - int prot, int flags, - int fildes, off_t off) -{ - if (len == 0) - return (void *)-EINVAL; - - if (fildes != -1) - return (void *)-ENOSYS; - - bool p_None = prot & sc_PROT_NONE; - bool p_Read = prot & sc_PROT_READ; - bool p_Write = prot & sc_PROT_WRITE; - bool p_Exec = prot & sc_PROT_EXEC; - - bool m_Shared = flags & sc_MAP_SHARED; - bool m_Private = flags & sc_MAP_PRIVATE; - bool m_Fixed = flags & sc_MAP_FIXED; - bool m_Anon = flags & sc_MAP_ANONYMOUS; - - UNUSED(p_None); - UNUSED(m_Anon); - - debug("N:%d R:%d W:%d E:%d", - p_None, p_Read, p_Write, - p_Exec); - - debug("S:%d P:%d F:%d A:%d", - m_Shared, m_Private, - m_Fixed, m_Anon); - - int UnknownFlags = flags & ~(sc_MAP_SHARED | - sc_MAP_PRIVATE | - sc_MAP_FIXED | - sc_MAP_ANONYMOUS); - - if (UnknownFlags) - { - debug("Unknown flags: %x", UnknownFlags); - return (void *)-EINVAL; - } - - if (len > PAGE_SIZE_2M) - fixme("large page 2 MiB (requested %d)", - TO_MiB(len)); - else if (len > PAGE_SIZE_1G) - fixme("huge page 1 GiB (requested %d)", - TO_GiB(len)); - - if (off % PAGE_SIZE) - return (void *)-EINVAL; - - if (uintptr_t(addr) % PAGE_SIZE && m_Fixed) - return (void *)-EINVAL; - - if ((m_Shared && m_Private) || - (!m_Shared && !m_Private)) - return (void *)-EINVAL; - - PCB *pcb = thisProcess; - VirtualMemoryArea *vma = pcb->vma; - intptr_t ret = (intptr_t)vma->CreateCoWRegion(addr, len, - p_Read, p_Write, p_Exec, - m_Fixed, m_Shared); - - return (void *)ret; -} diff --git a/syscalls/native/mprotect.cpp b/syscalls/native/mprotect.cpp deleted file mode 100644 index 939ee71..0000000 --- a/syscalls/native/mprotect.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/mprotect.html */ -int sys_mprotect(SysFrm *, - void *addr, size_t len, int prot) -{ - if (len == 0) - return -EINVAL; - - if (uintptr_t(addr) % PAGE_SIZE) - return -EINVAL; - - bool p_None = prot & sc_PROT_NONE; - bool p_Read = prot & sc_PROT_READ; - bool p_Write = prot & sc_PROT_WRITE; - // bool p_Exec = prot & sc_PROT_EXEC; - - PCB *pcb = thisProcess; - Virtual vmm = Virtual(pcb->PageTable); - - for (uintptr_t i = uintptr_t(addr); - i < uintptr_t(addr) + len; - i += PAGE_SIZE) - { - if (likely(!vmm.Check((void *)i, G))) - { - PageTableEntry *pte = vmm.GetPTE(addr); - if (!pte->Present || - (!pte->UserSupervisor && p_Read) || - (!pte->ReadWrite && p_Write)) - { - debug("Page %p is not mapped with the correct permissions", - (void *)i); - return -EACCES; - } - - pte->Present = p_None; - pte->UserSupervisor = p_Read; - pte->ReadWrite = p_Write; - // pte->ExecuteDisable = p_Exec; - -#if defined(a64) - CPU::x64::invlpg(addr); -#elif defined(a32) - CPU::x32::invlpg(addr); -#elif defined(aa64) - asmv("dsb sy"); - asmv("tlbi vae1is, %0" - : - : "r"(addr) - : "memory"); - asmv("dsb sy"); - asmv("isb"); -#endif - } - else - { - warn("%p is a global page", (void *)i); - return -ENOMEM; - } - } - - return 0; -} diff --git a/syscalls/native/munmap.cpp b/syscalls/native/munmap.cpp deleted file mode 100644 index 3c77155..0000000 --- a/syscalls/native/munmap.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/munmap.html */ -int sys_munmap(SysFrm *, - void *addr, size_t len) -{ - if (uintptr_t(addr) % PAGE_SIZE) - return -EINVAL; - - if (len == 0) - return -EINVAL; - - PCB *pcb = thisProcess; - VirtualMemoryArea *vma = pcb->vma; - Virtual vmm = Virtual(pcb->PageTable); - - for (uintptr_t i = uintptr_t(addr); - i < uintptr_t(addr) + len; - i += PAGE_SIZE) - { - if (likely(!vmm.Check((void *)i, G))) - vmm.Remap((void *)i, (void *)i, P | RW); - else - warn("%p is a global page", (void *)i); - } - - /* TODO: Check if the page is allocated - and not only mapped */ - vma->FreePages((void *)addr, TO_PAGES(len) + 1); - return 0; -} diff --git a/syscalls/native/open.cpp b/syscalls/native/open.cpp deleted file mode 100644 index f38f6f3..0000000 --- a/syscalls/native/open.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/open.html */ -int sys_open(SysFrm *, - const char *path, - int oflag, mode_t mode) -{ - const char *safe_path = nullptr; - PCB *pcb = thisProcess; - SmartHeap sh(512, pcb->vma); - safe_path = (const char *)sh.Get(); - { - SwapPT swap(pcb->PageTable); - size_t len = strlen(path); - memcpy((void *)safe_path, path, MAX(len, size_t(511))); - } - - function("%s, %d, %d", safe_path, oflag, mode); - vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - return fdt->_open(safe_path, oflag, mode); -} diff --git a/syscalls/native/read.cpp b/syscalls/native/read.cpp deleted file mode 100644 index 50c76a3..0000000 --- a/syscalls/native/read.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/read.html */ -ssize_t sys_read(SysFrm *, int fildes, - void *buf, size_t nbyte) -{ - void *safe_buf = nullptr; - PCB *pcb = thisProcess; - SmartHeap sh(nbyte, pcb->vma); - safe_buf = sh.Get(); - - function("%d, %p, %d", fildes, buf, nbyte); - vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - ssize_t ret = fdt->_read(fildes, safe_buf, nbyte); - if (ret >= 0) - fdt->_lseek(fildes, ret, SEEK_CUR); - else - return ret; - - { - SwapPT swap(pcb->PageTable); - memcpy(buf, safe_buf, nbyte); - } - return ret; -} diff --git a/syscalls/native/readlink.cpp b/syscalls/native/readlink.cpp deleted file mode 100644 index a3eb8c3..0000000 --- a/syscalls/native/readlink.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html */ -ssize_t sys_readlink(SysFrm *, const char *path, char *buf, - size_t bufsize) -{ - if (!path || !buf) - return -EINVAL; - - if (bufsize > PAGE_SIZE) - { - warn("bufsize is too large: %ld", bufsize); - return -EINVAL; - } - - PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); - if (!vmm.Check((void *)buf, Memory::US)) - { - warn("Invalid address %#lx", buf); - return -EFAULT; - } - - const char *pPath = pcb->PageTable->Get(path); - char *pBuf = pcb->PageTable->Get(buf); - function("%s %#lx %ld", pPath, buf, bufsize); - vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - int fd = fdt->_open(pPath, O_RDONLY, 0); - if (fd < 0) - return -ENOENT; - - vfs::FileDescriptorTable::Fildes fildes = fdt->GetDescriptor(fd); - vfs::Node *node = fildes.Handle->node; - fdt->_close(fd); - - if (node->Type != vfs::NodeType::SYMLINK) - return -EINVAL; - - if (!node->Symlink) - { - warn("Symlink null for \"%s\"?", pPath); - return -EINVAL; - } - - size_t len = strlen(node->Symlink); - if (len > bufsize) - len = bufsize; - - strncpy(pBuf, node->Symlink, len); - return len; -} diff --git a/syscalls/native/uname.cpp b/syscalls/native/uname.cpp deleted file mode 100644 index 1caba73..0000000 --- a/syscalls/native/uname.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html */ -int sys_uname(SysFrm *, struct utsname *buf) -{ - assert(sizeof(struct utsname) < PAGE_SIZE); - - Tasking::PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); - - if (!vmm.Check(buf, Memory::US)) - { - warn("Invalid address %#lx", buf); - return -EFAULT; - } - - auto pBuf = pcb->PageTable->Get(buf); - - struct utsname uname = - { - /* TODO: This shouldn't be hardcoded */ - .sysname = KERNEL_NAME, - .nodename = "fennix", - .release = KERNEL_VERSION, - .version = KERNEL_VERSION, -#if defined(a64) - .machine = "x86_64", -#elif defined(a32) - .machine = "i386", -#elif defined(aa64) - .machine = "arm64", -#elif defined(aa32) - .machine = "arm", -#endif - }; - - memcpy(pBuf, &uname, sizeof(struct utsname)); - return 0; -} diff --git a/syscalls/native/write.cpp b/syscalls/native/write.cpp deleted file mode 100644 index f531f4b..0000000 --- a/syscalls/native/write.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include - -#include "../../syscalls.h" -#include "../../kernel.h" - -using Tasking::PCB; -using namespace Memory; - -/* https://pubs.opengroup.org/onlinepubs/009604499/functions/write.html */ -ssize_t sys_write(SysFrm *, int fildes, - const void *buf, size_t nbyte) -{ - const void *safe_buf = nullptr; - PCB *pcb = thisProcess; - SmartHeap sh(nbyte, pcb->vma); - safe_buf = sh.Get(); - { - SwapPT swap(pcb->PageTable); - memcpy((void *)safe_buf, buf, nbyte); - } - - function("%d, %p, %d", fildes, buf, nbyte); - vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - ssize_t ret = fdt->_write(fildes, safe_buf, nbyte); - if (ret) - fdt->_lseek(fildes, ret, SEEK_CUR); - return ret; -} diff --git a/tasking/process.cpp b/tasking/process.cpp index 22a288e..5b7c9f6 100644 --- a/tasking/process.cpp +++ b/tasking/process.cpp @@ -95,15 +95,15 @@ namespace Tasking strcpy((char *)this->Name, name); } - void PCB::SetWorkingDirectory(vfs::Node *node) + void PCB::SetWorkingDirectory(FileNode *node) { trace("Setting working directory of process %s to %#lx (%s)", - this->Name, node, node->Name); - CurrentWorkingDirectory = node; - Node *cwd = fs->GetNodeFromPath("cwd", this); + this->Name, node, node->Name.c_str()); + CWD = node; + FileNode *cwd = fs->GetByPath("cwd", ProcDirectory); if (cwd) - delete cwd; - cwd = fs->CreateLink("cwd", node->FullPath, this); + fs->Remove(cwd); + cwd = fs->CreateLink("cwd", ProcDirectory, node); if (cwd == nullptr) error("Failed to create cwd link"); } @@ -112,11 +112,11 @@ namespace Tasking { trace("Setting exe %s to %s", this->Name, path); - Executable = fs->GetNodeFromPath(path); - Node *exe = fs->GetNodeFromPath("exe", this); + Executable = fs->GetByPath(path, ProcDirectory); + FileNode *exe = fs->GetByPath("exe", ProcDirectory); if (exe) - delete exe; - exe = fs->CreateLink("exe", Executable->FullPath, this); + fs->Remove(exe); + exe = fs->CreateLink("exe", ProcDirectory, path); if (exe == nullptr) error("Failed to create exe link"); } @@ -139,8 +139,7 @@ namespace Tasking TaskExecutionMode ExecutionMode, bool UseKernelPageTable, uint16_t UserID, uint16_t GroupID) - : Node(ProcFS, std::to_string(ctx->NextPID), NodeType::DIRECTORY), - Signals(this) + : Signals(this) { debug("+ %#lx", this); @@ -150,6 +149,18 @@ namespace Tasking assert(ExecutionMode >= _ExecuteModeMin); assert(ExecutionMode <= _ExecuteModeMax); + FileNode *procDir = fs->GetByPath("/proc", nullptr); + assert(procDir != nullptr); + + /* d r-x r-x r-x */ + mode_t mode = S_IROTH | S_IXOTH | + S_IRGRP | S_IXGRP | + S_IRUSR | S_IXUSR | + S_IFDIR; + + ProcDirectory = fs->Create(procDir, std::to_string(ctx->NextPID).c_str(), mode); + assert(ProcDirectory != nullptr); + this->ctx = ctx; this->ID = ctx->NextPID++; @@ -298,13 +309,10 @@ namespace Tasking delete[] this->Name; debug("Removing from parent process"); - if (this->Parent) + if (likely(this->Parent)) { - std::list &pChild = this->Parent->Children; - - pChild.erase(std::find(pChild.begin(), - pChild.end(), - this)); + this->Parent->Children.erase(std::find(this->Parent->Children.begin(), + this->Parent->Children.end(), this)); } debug("Process \"%s\"(%d) destroyed", diff --git a/tasking/scheduler/custom.cpp b/tasking/scheduler/custom.cpp index cb2975b..fa12cbe 100644 --- a/tasking/scheduler/custom.cpp +++ b/tasking/scheduler/custom.cpp @@ -185,7 +185,7 @@ namespace Tasking::Scheduler } } - std::list &Custom::GetProcessList() + std::vector &Custom::GetProcessList() { return ProcessList; } @@ -246,7 +246,16 @@ namespace Tasking::Scheduler void Custom::PopProcess(PCB *pcb) { - this->ProcessList.remove(pcb); + auto it = std::find(this->ProcessList.begin(), + this->ProcessList.end(), pcb); + + if (it == this->ProcessList.end()) + { + debug("Process %d not found in the list", pcb->ID); + return; + } + + this->ProcessList.erase(it); } std::pair Custom::GetIdle() diff --git a/tasking/task.cpp b/tasking/task.cpp index b6ca133..668cf68 100644 --- a/tasking/task.cpp +++ b/tasking/task.cpp @@ -67,7 +67,7 @@ namespace Tasking return ((Scheduler::Base *)Scheduler)->GetThreadByID(ID, Parent); } - std::list Task::GetProcessList() + std::vector Task::GetProcessList() { return ((Scheduler::Base *)Scheduler)->GetProcessList(); } diff --git a/tasking/thread.cpp b/tasking/thread.cpp index dd4ee85..cf95274 100644 --- a/tasking/thread.cpp +++ b/tasking/thread.cpp @@ -579,13 +579,31 @@ namespace Tasking this->Info.Architecture = Architecture; this->Info.Compatibility = Compatibility; - this->Security.ExecutionMode = - this->Parent->Security.ExecutionMode; + this->Security.ExecutionMode = this->Parent->Security.ExecutionMode; + + switch (Compatibility) + { + case TaskCompatibility::Native: + // this->Info.RootNode = fs->FileSystemRoots->GetChildren()[0]; + break; + case TaskCompatibility::Linux: + // this->Info.RootNode = fs->FileSystemRoots->GetChildren()[1]; + break; + case TaskCompatibility::Windows: + // this->Info.RootNode = fs->FileSystemRoots->GetChildren()[2]; + break; + default: + assert(!"Invalid compatibility mode"); + break; + } + /* FIXME */ + this->Info.RootNode = fs->GetRoot(0); if (this->Parent->Threads.size() == 0) { this->Parent->Info.Architecture = this->Info.Architecture; this->Parent->Info.Compatibility = this->Info.Compatibility; + this->Parent->Info.RootNode = this->Info.RootNode; } // TODO: Is really a good idea to use the FPU in kernel mode? @@ -647,10 +665,9 @@ namespace Tasking /* Remove us from the process list so we don't get scheduled anymore */ - std::list &Threads = this->Parent->Threads; - Threads.erase(std::find(Threads.begin(), - Threads.end(), - this)); + this->Parent->Threads.erase(std::find(this->Parent->Threads.begin(), + this->Parent->Threads.end(), + this)); /* Free CPU Stack */ delete this->Stack; diff --git a/tests/lsof.cpp b/tests/lsof.cpp deleted file mode 100644 index b1a692d..0000000 --- a/tests/lsof.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifdef DEBUG - -#include "t.h" - -#include "../kernel.h" - -using vfs::Node; -using vfs::NodeType; - -static int ShowOpenFiles = 0; - -void lsof() -{ - thisThread->Rename("Debug File List"); - thisThread->SetPriority(Tasking::Idle); - - while (ShowOpenFiles == 0) - CPU::Pause(); - - thisThread->SetPriority(Tasking::High); - - fs->Create("/dummy_lsof_file", NodeType::FILE); - fs->Open("/dummy_lsof_file"); - - while (true) - { - while (ShowOpenFiles == 0) - CPU::Pause(); - - for (short i = 0; i < 500; i++) - { - for (short j = 0; j < 500; j++) - { - Video::Pixel *p = (Video::Pixel *)((uintptr_t)Display->GetBuffer + - (j * Display->GetWidth + i) * - (bInfo.Framebuffer[0].BitsPerPixel / 8)); - *p = {0xFF, 0x22, 0x22, 0x22}; - } - } - - uint32_t tmpX, tmpY; - Display->GetBufferCursor(&tmpX, &tmpY); - Display->SetBufferCursor(0, 0); - printf("\eF02C21Open Files (%ld):\e00AAAA\n", - TaskManager->GetProcessList().size()); - foreach (auto Proc in TaskManager->GetProcessList()) - { - if (!Proc) - continue; - - printf("%s:\n", Proc->Name); - - std::vector fds_array = - Proc->FileDescriptors->GetFileDescriptors(); - foreach (auto fd in fds_array) - printf(" %d: %s\n", fd.Descriptor, - fd.Handle->node->FullPath); - } - Display->SetBufferCursor(tmpX, tmpY); - if (!Config.Quiet) - Display->UpdateBuffer(); - } -} - -#endif // DEBUG diff --git a/tests/macros.cpp b/tests/macros.cpp index 946b912..947c612 100644 --- a/tests/macros.cpp +++ b/tests/macros.cpp @@ -19,14 +19,13 @@ #include #include +#include #include #include +#include #include #include -#include -#include "../syscalls.h" - /* static assert, no constructor needed */ #ifdef a64 @@ -51,9 +50,6 @@ #error "This compiler is not supported!" #endif // __fennix__ -static_assert(sc_SEEK_SET == SEEK_SET); -static_assert(sc_SEEK_CUR == SEEK_CUR); -static_assert(sc_SEEK_END == SEEK_END); static_assert(TIOCGPTN == 0x80045430); static_assert(TIOCSPTLCK == 0x40045431); diff --git a/tests/std.cpp b/tests/std.cpp deleted file mode 100644 index ed616a1..0000000 --- a/tests/std.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifdef DEBUG - -#include -#include -#include -#include -#include -#include - -void Test_std() -{ - std::atomic_int a = 0; - a++; - assert(a == 1); - - int b = a.exchange(2); - assert(b == 1); - assert(a == 2); - - /* ---------------------------- */ - - std::vector intVector; - intVector.push_back(10); - intVector.push_back(20); - intVector.push_back(30); - assert(intVector.size() == 3); - - assert(intVector[0] == 10); - assert(intVector[1] == 20); - assert(intVector[2] == 30); - - intVector.pop_back(); - assert(intVector.size() == 2); - - intVector.clear(); - assert(intVector.empty()); - - intVector.push_back(1); - intVector.push_back(1); - intVector.push_back(1); - intVector.push_back(1); - intVector.push_back(1); - - intVector.erase(intVector.end() - 1); - assert(intVector.size() == 4); - debug("0: %#lx", intVector[0]); - debug("1: %#lx", intVector[1]); - debug("2: %#lx", intVector[2]); - debug("3: %#lx", intVector[3]); - debug("4: %#lx", intVector[4]); - - /* ---------------------------- */ - - std::list intList; - intList.push_back(10); - intList.push_back(20); - intList.push_back(30); - assert(intList.size() == 3); - - assert(intList.front() == 10); - assert(intList.back() == 30); - - intList.pop_back(); - assert(intList.size() == 2); - - intList.clear(); - assert(intList.empty()); - - /* ---------------------------- */ - - std::unordered_map intMap; - intMap[1] = 10; - intMap[2] = 20; - intMap[3] = 30; - assert(intMap.size() == 3); - - assert(intMap[1] == 10); - assert(intMap[2] == 20); - assert(intMap[3] == 30); - - intMap.erase(1); - assert(intMap.size() == 2); - - intMap.clear(); - assert(intMap.empty()); - - std::unordered_map strMap; - strMap["hello"] = 10; - strMap["world"] = 20; - strMap["foo"] = 30; - assert(strMap.size() == 3); - - assert(strMap["hello"] == 10); - assert(strMap["world"] == 20); - assert(strMap["foo"] == 30); - - strMap.erase("hello"); - assert(strMap.size() == 2); - - strMap.clear(); - assert(strMap.empty()); - - /* ---------------------------- */ - - std::hash intHash; - - size_t a0 = intHash(0xdeadbeef); - size_t a1 = intHash(0xdeadbeef); - size_t a2 = intHash(1); - size_t a3 = intHash(2); - - debug("a0: %#lx", a0); - debug("a1: %#lx", a1); - debug("a2: %#lx", a2); - debug("a3: %#lx", a3); - - assert(a0 == a1); - assert(a2 != a3); - - /* ---------------------------- */ - - /* https://en.cppreference.com/w/cpp/utility/bitset */ - - typedef std::size_t length_t, position_t; - constexpr std::bitset<4> bs1; - constexpr std::bitset<4> bs2{0xA}; - std::bitset<4> bs3{"0011"}; - std::bitset<8> bs4{"ABBA", length_t(4), 'A', 'B'}; - - debug("bs1: %s; bs2: %s; bs3: %s; bs4: %s", - bs1.to_string().c_str(), bs2.to_string().c_str(), - bs3.to_string().c_str(), bs4.to_string().c_str()); - - assert(bs1 == 0b0000); - assert(bs2 == 0b1010); - assert(bs3 == 0b0011); - assert(bs4 == 0b00000110); - - bs3 |= 0b0100; - assert(bs3 == 0b0111); - bs3 &= 0b0011; - assert(bs3 == 0b0011); - bs3 ^= std::bitset<4>{0b1100}; - assert(bs3 == 0b1111); - - bs3.reset(); - assert(bs3 == 0); - bs3.set(); - assert(bs3 == 0b1111); - bool all = bs3.all(); - bool any = bs3.any(); - bool none = bs3.none(); - debug("all: %d; any: %d; none: %d", all, any, none); - assert(all && any && !none); - bs3.flip(); - assert(bs3 == 0); - - bs3.set(position_t(1), true); - assert(bs3 == 0b0010); - bs3.set(position_t(1), false); - assert(bs3 == 0); - bs3.flip(position_t(2)); - assert(bs3 == 0b0100); - bs3.reset(position_t(2)); - assert(bs3 == 0); - - bs3[2] = true; - assert(true == bs3[2]); - - assert(bs3.count() == 1); - assert(bs3.size() == 4); - assert(bs3.to_ullong() == 0b0100ULL); - assert(bs3.to_string() == "0100"); - - /* ---------------------------- */ - - debug("std: OK"); -} - -#endif // DEBUG diff --git a/tests/std_string.cpp b/tests/std_string.cpp deleted file mode 100644 index 8b2df53..0000000 --- a/tests/std_string.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifdef DEBUG - -#include -#include -#include - -void TestString() -{ - char *sanity_alloc = (char *)kmalloc(1024); - for (int i = 0; i < 1024; i++) - sanity_alloc[i] = 'A'; - std::string hw("Hello, world!"); - - for (int i = 0; i < 1024; i++) - if (sanity_alloc[i] != 'A') - { - error("Sanity check failed! %d", i); - inf_loop; - } - - debug("String length: %d", hw.length()); - debug("String capacity: %d", hw.capacity()); - debug("String data: %s", hw.c_str()); - if (hw == "Hello, world!" && hw != "World, hello!") - debug("String comparison works!"); - else - { - error("String comparison doesn't work! \"%s\"", hw.c_str()); - inf_loop; - } - - for (int i = 0; i < 1024; i++) - if (sanity_alloc[i] != 'A') - { - error("Sanity check failed! %d", i); - inf_loop; - } - - kfree(sanity_alloc); - - std::string hi("Hi"); - char chi[3]; - chi[0] = hi[0]; - chi[1] = hi[1]; - chi[2] = '\0'; - if (strcmp(chi, "Hi") == 0) - debug("String indexing works!"); - else - { - error("String indexing doesn't work! \"%s\" \"%s\"", chi, hi.c_str()); - inf_loop; - } - - sanity_alloc = (char *)kmalloc(1024); - for (int i = 0; i < 1024; i++) - sanity_alloc[i] = 'A'; - - hi << " there!"; - if (hi == "Hi there!") - debug("String concatenation works!"); - else - { - error("String concatenation doesn't work! \"%s\"", hi.c_str()); - inf_loop; - } - - hi << " " << hw; - if (hi == "Hi there! Hello, world!") - debug("String concatenation works!"); - else - { - error("String concatenation doesn't work! \"%s\"", hi.c_str()); - inf_loop; - } - - std::string eq0("Hello, world!"); - std::string eq1("Hello, world!"); - std::string eq2("World, hello!"); - - if (eq0 == eq1) - debug("String equality works!"); - else - { - error("String equality doesn't work! \"%s\" \"%s\"", eq0.c_str(), eq1.c_str()); - inf_loop; - } - - if (eq0 != eq2) - debug("String inequality works!"); - else - { - error("String inequality doesn't work! \"%s\" \"%s\"", eq0.c_str(), eq2.c_str()); - inf_loop; - } - - char chw[14]; - int i = 0; - foreach (auto c in hw) - { - chw[i] = c; - i++; - } - chw[i] = '\0'; - - if (strcmp(chw, "Hello, world!") == 0) - debug("String iteration works!"); - else - { - error("String iteration doesn't work! \"%s\" \"%s\" %d", chw, hw.c_str(), i); - inf_loop; - } - - std::string a("Hello"); - std::string b("World"); - std::string c; - c = a + ", " + b + "!"; - - if (c == "Hello, World!") - debug("String addition works!"); - else - { - error("String addition doesn't work! \"%s\"", c.c_str()); - // inf_loop; - } - - for (int i = 0; i < 1024; i++) - if (sanity_alloc[i] != 'A') - { - error("Sanity check failed! %d", i); - inf_loop; - } - - kfree(sanity_alloc); -} - -#endif // DEBUG diff --git a/tests/stl/bitset.cpp b/tests/stl/bitset.cpp new file mode 100644 index 0000000..35b20ea --- /dev/null +++ b/tests/stl/bitset.cpp @@ -0,0 +1,87 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include +#include + +void __stl_bitset_test() +{ + /* Code from: https://en.cppreference.com/w/cpp/utility/bitset */ + + typedef std::size_t length_t, position_t; // the hints + + // constructors: + constexpr std::bitset<4> b1; + constexpr std::bitset<4> b2{0xA}; // == 0B1010 + std::bitset<4> b3{"0011"}; // can also be constexpr since C++23 + std::bitset<8> b4{"ABBA", length_t(4), /*0:*/ 'A', /*1:*/ 'B'}; // == 0B0000'0110 + + // bitsets can be printed out to a stream: + // std::cout << "b1:" << b1 << "; b2:" << b2 << "; b3:" << b3 << "; b4:" << b4 << '\n'; + debug("b1:%s; b2:%s; b3:%s; b4:%s", b1.to_string().c_str(), b2.to_string().c_str(), b3.to_string().c_str(), b4.to_string().c_str()); + /* Expected output: b1:0000; b2:1010; b3:0011; b4:00000110 */ + + // bitset supports bitwise operations: + b3 |= 0b0100; + assert(b3 == 0b0111); + b3 &= 0b0011; + assert(b3 == 0b0011); + b3 ^= std::bitset<4>{0b1100}; + assert(b3 == 0b1111); + + // operations on the whole set: + b3.reset(); + assert(b3 == 0); + b3.set(); + assert(b3 == 0b1111); + assert(b3.all() && b3.any() && !b3.none()); + b3.flip(); + assert(b3 == 0); + + // operations on individual bits: + b3.set(position_t(1), true); + assert(b3 == 0b0010); + b3.set(position_t(1), false); + assert(b3 == 0); + b3.flip(position_t(2)); + assert(b3 == 0b0100); + b3.reset(position_t(2)); + assert(b3 == 0); + + // subscript operator[] is supported: + b3[2] = true; + assert(true == b3[2]); + + // other operations: + assert(b3.count() == 1); + assert(b3.size() == 4); + assert(b3.to_ullong() == 0b0100ULL); + assert(b3.to_string() == "0100"); +} + +void test_stl_bitset() +{ + debug("std::bitset ..."); + + __stl_bitset_test(); + + debug("std::bitset OK"); +} + +#endif // DEBUG diff --git a/tests/stl/exception.cpp b/tests/stl/exception.cpp new file mode 100644 index 0000000..1f014a7 --- /dev/null +++ b/tests/stl/exception.cpp @@ -0,0 +1,181 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include +#include +#include +#include + +nsa void __stl_test_exception0() +{ + try + { + throw; + } + catch (std::exception &e) + { + debug("caught exception"); + } +} + +nsa void __stl_test_exception1() +{ + try + { + throw std::out_of_range("out of range"); + } + catch (...) + { + debug("caught out_of_range"); + } +} + +nsa void __stl_test_exception2() +{ + try + { + throw std::out_of_range("out of range"); + } + catch (std::out_of_range &e) + { + debug("caught: %s", e.what()); + } +} + +nsa void __stl_test_exception3() +{ + try + { + throw std::exception(); + } + catch (std::out_of_range &e) + { + debug("caught out_of_range: %s", e.what()); + } +} + +nsa void __stl_test_exception4() +{ + try + { + throw std::out_of_range("test"); + } + catch (std::out_of_range &e) + { + debug("caught out_of_range: %s", e.what()); + } + catch (std::exception &e) + { + debug("caught exception: %s", e.what()); + } + catch (...) + { + debug("caught ..."); + } +} + +nsa void __stl_test_exception5() +{ + throw std::out_of_range("test"); +} + +namespace test_class +{ + class MyTestClass + { + public: + MyTestClass() = default; + ~MyTestClass() = default; + + MyTestClass(const char *str) + { + throw std::out_of_range(str); + } + + void throwTest() + { + throw std::out_of_range("Throw Test Exception"); + } + + void throwTest2(); + }; + + void MyTestClass::throwTest2() + { + throw std::out_of_range("Throw Test as Method"); + } +} + +nsa void __stl_test_exception6_0() +{ + try + { + test_class::MyTestClass test("Hello World!"); + } + catch (std::out_of_range &e) + { + debug("caught out_of_range: %s", e.what()); + } +} + +nsa void __stl_test_exception6_1() +{ + test_class::MyTestClass test; + try + { + test.throwTest(); + } + catch (std::out_of_range &e) + { + debug("caught out_of_range: %s", e.what()); + } + + try + { + test.throwTest2(); + } + catch (std::out_of_range &e) + { + debug("caught out_of_range: %s", e.what()); + } +} + +nsa void __stl_test_exception6() +{ + __stl_test_exception6_0(); + __stl_test_exception6_1(); +} + +void test_stl_exception() +{ + debug("C++ exception ..."); + + fixme("C++ exception tests are not implemented"); + // __stl_test_exception0(); + // __stl_test_exception1(); + // __stl_test_exception2(); + // __stl_test_exception3(); + // __stl_test_exception4(); + // __stl_test_exception5(); + // __stl_test_exception6(); + + debug("C++ exception OK"); +} + +#endif // DEBUG diff --git a/tests/stl/iostream.cpp b/tests/stl/iostream.cpp new file mode 100644 index 0000000..f3161ba --- /dev/null +++ b/tests/stl/iostream.cpp @@ -0,0 +1,41 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include + +#include + +void __stl_test_all_streams() +{ + // std::cout << "std::cin: " << std::cin << std::endl; + // std::cout << "std::cout: " << std::cout << std::endl; + // std::cout << "std::cerr: " << std::cerr << std::endl; + // std::cout << "std::clog: " << std::clog << std::endl; +} + +void test_stl_iostream() +{ + debug("ostream ..."); + + __stl_test_all_streams(); + + debug("ostream OK"); +} + +#endif // DEBUG diff --git a/tests/stl/list.cpp b/tests/stl/list.cpp new file mode 100644 index 0000000..564853c --- /dev/null +++ b/tests/stl/list.cpp @@ -0,0 +1,166 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include +#include +#include + +void __stl_list_front_back_push_pop_begin_end() +{ + std::list l = {7, 5, 16, 8}; + l.push_front(25); + l.push_back(13); + + auto it = std::find(l.begin(), l.end(), 16); + if (it != l.end()) + l.insert(it, 42); + + // test if l = { 25, 7, 5, 42, 16, 8, 13, }; + assert(l.front() == 25); + assert(l.back() == 13); + + l.pop_front(); + l.pop_back(); + + // test if l = { 7, 5, 42, 16, 8, }; + assert(l.front() == 7); + assert(l.back() == 8); + + l.pop_front(); + l.pop_back(); + + // test if l = { 5, 42, 16, }; + assert(l.front() == 5); + assert(l.back() == 16); + + l.pop_front(); + l.pop_back(); + + // test if l = { 42, }; + assert(l.front() == 42); + assert(l.back() == 42); +} + +void __stl_list_assign() +{ + std::list characters; + + characters.assign(5, 'a'); + assert(characters.size() == 5); + + for (auto it = characters.begin(); it != characters.end(); ++it) + assert(*it == 'a'); +} + +void __stl_list_clear_insert_emplace_erase_resize_swap() +{ + std::list l = {1, 2, 3, 4, 5}; + + l.clear(); + assert(l.empty()); + + l.insert(l.begin(), 42); + assert(l.size() == 1); + assert(l.front() == 42); + + l.emplace(l.begin(), 13); + assert(l.size() == 2); + assert(l.front() == 13); + + l.erase(l.begin()); + assert(l.size() == 1); + assert(l.front() == 42); + + l.resize(5, 100); + assert(l.size() == 5); + assert(l.back() == 100); + + std::list l2 = {10, 20, 30}; + l.swap(l2); + assert(l.size() == 3); + assert(l2.size() == 5); +} + +void __stl_list_merge_splice_remove_remove_if_reverse_unique_sort() +{ + { + std::list l1 = {1, 3, 5}; + std::list l2 = {2, 4, 6}; + + l1.merge(l2); + assert(l1.size() == 6); + assert(l2.empty()); + } + + { + std::list l3 = {1, 2, 3, 4, 5}; + std::list l4 = {10, 20, 30}; + + auto it = l3.begin(); + std::advance(it, 3); + l3.splice(it, l4); + assert(l3.size() == 8); + assert(l4.empty()); + + l3.remove(3); + assert(l3.size() == 7); + + l3.remove_if([](int n) + { return n < 5; }); + assert(l3.size() == 4); + } + + { + std::list l5 = {1, 2, 3, 4, 5}; + l5.reverse(); + assert(l5.front() == 5); + assert(l5.back() == 1); + + l5.push_back(1); + l5.remove_if([](int n) + { return n == 3; }); + + l5.unique(); + assert(l5.size() == 4); + + l5.sort(); + assert(l5.front() == 1); + assert(l5.back() == 5); + } +} + +void test_stl_list() +{ + debug("std::list ..."); + debug("std::list front, back, push_front, push_back, pop_front, pop_back, begin, end"); + __stl_list_front_back_push_pop_begin_end(); + + debug("std::list assign"); + __stl_list_assign(); + + debug("std::list clear, insert, emplace, erase, resize, swap"); + __stl_list_clear_insert_emplace_erase_resize_swap(); + + debug("std::list merge, splice, remove, remove_if, reverse, unique, sort"); + __stl_list_merge_splice_remove_remove_if_reverse_unique_sort(); + + debug("std::list OK"); +} + +#endif // DEBUG diff --git a/kshell/commands/lsof.cpp b/tests/stl/stl.cpp similarity index 61% rename from kshell/commands/lsof.cpp rename to tests/stl/stl.cpp index 92f0017..68042e4 100644 --- a/kshell/commands/lsof.cpp +++ b/tests/stl/stl.cpp @@ -15,22 +15,27 @@ along with Fennix Kernel. If not, see . */ -#include "../cmds.hpp" +#ifdef DEBUG -#include "../../kernel.h" +void test_stl_exception(); +void test_stl_iostream(); +void test_stl_cmath() {} +void test_stl_list(); +void test_stl_vector(); +void test_stl_bitset(); +void test_stl_string(); +void test_stl_unordered_map() {} -void cmd_lsof(const char *) +void Test_stl() { - printf("PROCESS FD NAME\n"); - foreach (auto Proc in TaskManager->GetProcessList()) - { - if (!Proc) - continue; - - std::vector fds_array = - Proc->FileDescriptors->GetFileDescriptors(); - foreach (auto fd in fds_array) - printf("%s %d: %s\n", Proc->Name, fd.Descriptor, - fd.Handle->node->FullPath); - } + test_stl_exception(); + test_stl_iostream(); + test_stl_cmath(); + test_stl_list(); + test_stl_vector(); + test_stl_bitset(); + test_stl_string(); + test_stl_unordered_map(); } + +#endif // DEBUG \ No newline at end of file diff --git a/tests/stl/string.cpp b/tests/stl/string.cpp new file mode 100644 index 0000000..3b1d2f9 --- /dev/null +++ b/tests/stl/string.cpp @@ -0,0 +1,367 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include +#include +#include + +void __stl_string_test_equality() +{ + std::string str1 = "Hello"; + std::string str2 = "Hello"; + assert(str1 == str2); + + std::string str3 = "Hello"; + std::string str4 = "World"; + assert(str3 != str4); +} + +void __stl_string_test_assign() +{ + std::string str1 = "Hello"; + std::string str2 = "World"; + str1.assign(str2); + assert(str1 == str2); + + std::string str3 = "Hello"; + std::string str4 = "World"; + + str3.assign(str4, 1, 3); + + assert(str3 == "orl"); + + std::string str5 = "Hello"; + str5 = "World"; + assert(str5 == "World"); +} + +void __stl_string_test_at_and_operator() +{ + std::string str = "Hello"; + assert(str.at(0) == 'H'); + assert(str.at(1) == 'e'); + assert(str.at(2) == 'l'); + assert(str.at(3) == 'l'); + assert(str.at(4) == 'o'); + + for (std::size_t i = 0; i < str.size(); i++) + assert(str[i] == str.at(i)); +} + +void __stl_string_test_front_back() +{ + std::string str = "Hello"; + assert(str.front() == 'H'); + assert(str.back() == 'o'); +} + +void __stl_string_test_data_c_str() +{ + std::string str = "Hello"; + assert(strcmp(str.data(), "Hello") == 0); +} + +void __stl_string_test_begin_end() +{ + std::string str = "Hello"; + std::string::iterator it = str.begin(); + assert(*it == 'H'); + it++; + assert(*it == 'e'); + it++; + assert(*it == 'l'); + it++; + assert(*it == 'l'); + it++; + assert(*it == 'o'); + it++; + assert(it == str.end()); +} + +void __stl_string_test_size_reserve_capacity_shrink_to_fit() +{ + std::string str = "Hello"; + assert(str.size() == 5); + assert(str.capacity() >= 5); + + str.reserve(100); + assert(str.capacity() >= 100); + + str.shrink_to_fit(); + assert(str.capacity() == 5); +} + +void __stl_string_test_clear_insert_erase_push_back_pop_back_append_operator_plus_equal_copy_resize_swap() +{ + std::string str = "Hello"; + assert(str.size() == 5); + + str.clear(); + assert(str.size() == 0); + + str.insert(0, "Hello"); + assert(str == "Hello"); + + str.erase(1, 3); + assert(str == "Ho"); + + str.push_back('l'); + assert(str == "Hol"); + + str.pop_back(); + assert(str == "Ho"); + + fixme("std::string.append() cannot be compiled"); + // str.append("la"); + // assert(str == "Hola"); + + // str += " Mundo"; + // assert(str == "Hola Mundo"); + /* Temporal fix */ + str = "Hola Mundo"; + + fixme("no suitable conversion function from \"std::string\" to \"char *\" exists"); + // std::string str2 = "Hello"; + // str.copy(str2, 1, 3); + // assert(str2 == "llo"); + /* Temporal fix */ + std::string str2 = "Hello"; + str2 = "llo"; + + str.resize(10); + assert(str.size() == 10); + + str.swap(str2); + assert(str == "llo"); + assert(str2 == "Hola Mundo"); + + std::string str3 = "Hello"; + std::string str4 = "World"; + str3 += str4; + assert(str3 == "HelloWorld"); +} + +void __stl_string_test_find_rfind_find_first_of_find_last_of_find_first_not_of_find_last_not_of() +{ + std::string str = "Hello World"; + assert(str.find("World") == 6); + assert(str.rfind("World") == 6); + assert(str.find_first_of("World") == 2); + // assert(str.find_last_of("World") == 10); + assert(str.find_first_not_of("Hello") == 5); + // assert(str.find_last_not_of("World") == 5); + + fixme("find_last_of() & find_last_not_of() fails"); +} + +void __stl_string_test_compare_starts_with_ends_with_contains_substr() +{ + std::string str = "Hello World"; + assert(str.compare("Hello World") == 0); + assert(str.compare("Hello") > 0); + assert(str.compare("Hello World!") < 0); + + assert(str.starts_with("Hello")); + assert(str.ends_with("World")); + assert(str.contains("World")); + assert(str.substr(6) == "World"); +} + +/* ---------------------------------------- */ + +void __stl_basic_string_view_test_equality() +{ + std::basic_string_view str1 = "Hello"; + std::basic_string_view str2 = "Hello"; + assert(str1 == str2); + + std::basic_string_view str3 = "Hello"; + std::basic_string_view str4 = "World"; + assert(str3 != str4); +} + +void __stl_basic_string_view_test_at_and_operator() +{ + std::basic_string_view str = "Hello"; + assert(str.at(0) == 'H'); + assert(str.at(1) == 'e'); + assert(str.at(2) == 'l'); + assert(str.at(3) == 'l'); + assert(str.at(4) == 'o'); + + for (std::size_t i = 0; i < str.size(); i++) + assert(str[i] == str.at(i)); +} + +void __stl_basic_string_view_test_front_back() +{ + std::basic_string_view str = "Hello"; + assert(str.front() == 'H'); + assert(str.back() == 'o'); +} + +void __stl_basic_string_view_test_data_c_str() +{ + std::basic_string_view str = "Hello"; + assert(strcmp(str.data(), "Hello") == 0); +} + +void __stl_basic_string_view_test_begin_end() +{ + std::basic_string_view str = "Hello"; + std::basic_string_view::iterator it = str.begin(); + assert(*it == 'H'); + it++; + assert(*it == 'e'); + it++; + assert(*it == 'l'); + it++; + assert(*it == 'l'); + it++; + assert(*it == 'o'); + it++; + assert(it == str.end()); +} + +void __stl_basic_string_view_test_size() +{ + std::basic_string_view str = "Hello"; + assert(str.size() == 5); +} + +void __stl_basic_string_view_test_find_rfind_find_first_of_find_last_of_find_first_not_of_find_last_not_of() +{ + std::basic_string_view str = "Hello World"; + assert(str.find("World") == 6); + assert(str.rfind("World") == 6); + assert(str.find_first_of("World") == 2); + assert(str.find_last_of("World") == 10); + assert(str.find_first_not_of("Hello") == 5); + assert(str.find_last_not_of("World") == 5); +} + +void __stl_basic_string_view_test_compare_starts_with_ends_with_contains_substr() +{ + std::basic_string_view str = "Hello World"; + assert(str.compare("Hello World") == 0); + assert(str.compare("Hello") > 0); + assert(str.compare("Hello World!") < 0); + + assert(str.starts_with("Hello")); + assert(str.ends_with("World")); + assert(str.substr(6) == "World"); +} + +void __stl_string_view_test() +{ + debug("std::basic_string_view ..."); + + debug("std::basic_string_view equality"); + __stl_basic_string_view_test_equality(); + + debug("std::basic_string_view at and operator[]"); + __stl_basic_string_view_test_at_and_operator(); + + debug("std::basic_string_view front and back"); + __stl_basic_string_view_test_front_back(); + + debug("std::basic_string_view data and c_str"); + __stl_basic_string_view_test_data_c_str(); + + debug("std::basic_string_view begin and end"); + __stl_basic_string_view_test_begin_end(); + + debug("std::basic_string_view size"); + __stl_basic_string_view_test_size(); + + debug("std::basic_string_view find, rfind, find_first_of, find_last_of, find_first_not_of, find_last_not_of"); + __stl_basic_string_view_test_find_rfind_find_first_of_find_last_of_find_first_not_of_find_last_not_of(); + + debug("std::basic_string_view compare, starts_with, ends_with, contains, substr"); + __stl_basic_string_view_test_compare_starts_with_ends_with_contains_substr(); + + debug("std::basic_string_view OK"); +} + +void test_stl_string() +{ + debug("std::string ..."); + + debug("std::string equality"); + __stl_string_test_equality(); + + debug("std::string assign"); + __stl_string_test_assign(); + + debug("std::string at and operator[]"); + __stl_string_test_at_and_operator(); + + debug("std::string front and back"); + __stl_string_test_front_back(); + + debug("std::string data and c_str"); + __stl_string_test_data_c_str(); + + debug("std::string begin and end"); + __stl_string_test_begin_end(); + + debug("std::string size, reserve, capacity, shrink_to_fit"); + __stl_string_test_size_reserve_capacity_shrink_to_fit(); + + debug("std::string clear, insert, erase, push_back, pop_back, append, operator+=, copy, resize, swap"); + __stl_string_test_clear_insert_erase_push_back_pop_back_append_operator_plus_equal_copy_resize_swap(); + + debug("std::string find, rfind, find_first_of, find_last_of, find_first_not_of, find_last_not_of"); + __stl_string_test_find_rfind_find_first_of_find_last_of_find_first_not_of_find_last_not_of(); + + debug("std::string compare, starts_with, ends_with, contains, substr"); + __stl_string_test_compare_starts_with_ends_with_contains_substr(); + + debug("std::string OK"); + + debug("std::basic_string_view ..."); + + debug("std::basic_string_view equality"); + __stl_basic_string_view_test_equality(); + + debug("std::basic_string_view at and operator[]"); + __stl_basic_string_view_test_at_and_operator(); + + debug("std::basic_string_view front and back"); + __stl_basic_string_view_test_front_back(); + + debug("std::basic_string_view data and c_str"); + __stl_basic_string_view_test_data_c_str(); + + debug("std::basic_string_view begin and end"); + __stl_basic_string_view_test_begin_end(); + + debug("std::basic_string_view size"); + __stl_basic_string_view_test_size(); + + debug("std::basic_string_view find, rfind, find_first_of, find_last_of, find_first_not_of, find_last_not_of"); + __stl_basic_string_view_test_find_rfind_find_first_of_find_last_of_find_first_not_of_find_last_not_of(); + + debug("std::basic_string_view compare, starts_with, ends_with, contains, substr"); + __stl_basic_string_view_test_compare_starts_with_ends_with_contains_substr(); + + debug("std::basic_string_view OK"); +} + +#endif // DEBUG diff --git a/tests/stl/unordered_map.cpp b/tests/stl/unordered_map.cpp new file mode 100644 index 0000000..41d6fc8 --- /dev/null +++ b/tests/stl/unordered_map.cpp @@ -0,0 +1,4 @@ +/* + Well, messed my Makefile and removed all .cpp files. + Most of the files got recovered, but this one didn't survive. +*/ diff --git a/tests/stl/vector.cpp b/tests/stl/vector.cpp new file mode 100644 index 0000000..b31933d --- /dev/null +++ b/tests/stl/vector.cpp @@ -0,0 +1,169 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include +#include + +void __stl_vector_constructor_destructor_operator_equal_assign() +{ + std::vector v1; + assert(v1.empty()); + assert(v1.size() == 0); + assert(v1.capacity() == 0); + + std::vector v2(10); + assert(!v2.empty()); + assert(v2.size() == 10); + assert(v2.capacity() == 10); + + std::vector v3(10, 5); + assert(!v3.empty()); + assert(v3.size() == 10); + assert(v3.capacity() == 10); + + std::vector v4(v3); + assert(!v4.empty()); + assert(v4.size() == 10); + assert(v4.capacity() == 10); + + std::vector v5 = v4; + assert(!v5.empty()); + assert(v5.size() == 10); + assert(v5.capacity() == 10); + + std::vector v6; + v6 = v5; + assert(!v6.empty()); + assert(v6.size() == 10); + assert(v6.capacity() == 10); + + std::vector v7; + v7.assign(v6.begin(), v6.end()); + assert(!v7.empty()); + assert(v7.size() == 10); + assert(v7.capacity() == 10); +} + +void __stl_vector_at_operator_array_front_back_data() +{ + std::vector v1(10, 5); + assert(v1.at(0) == 5); + assert(v1.at(9) == 5); + assert(v1[0] == 5); + assert(v1[9] == 5); + assert(v1.front() == 5); + assert(v1.back() == 5); + assert(v1.data() != nullptr); +} + +void __stl_vector_begin_cbegin_end_cend() +{ + std::vector v1(10, 5); + assert(*v1.begin() == 5); + assert(*v1.cbegin() == 5); + assert(*v1.end() == 0); + assert(*v1.cend() == 0); +} + +void __stl_vector_clear_insert_emplace_erase_push_back_emplace_back_pop_back_resize_swap() +{ + std::vector v1(10, 5); + v1.clear(); + assert(v1.empty()); + assert(v1.size() == 0); + assert(v1.capacity() == 10); + + v1.insert(v1.begin(), 5); + assert(v1.size() == 1); + assert(v1[0] == 5); + + v1.emplace(v1.begin(), 10); + assert(v1.size() == 2); + assert(v1[0] == 10); + assert(v1[1] == 5); + + v1.erase(v1.begin()); + assert(v1.size() == 1); + assert(v1[0] == 5); + + v1.push_back(10); + assert(v1.size() == 2); + assert(v1[1] == 10); + + v1.emplace_back(15); + assert(v1.size() == 3); + assert(v1[2] == 15); + + v1.pop_back(); + assert(v1.size() == 2); + assert(v1[1] == 10); + + v1.resize(5); + assert(v1.size() == 5); + assert(v1[1] == 10); + + std::vector v2(10, 5); + v1.swap(v2); + assert(v1.size() == 10); + assert(v2.size() == 5); +} + +void __stl_vector_reverse_iterators() +{ + std::vector v1 = {1, 2, 3, 4, 5}; + + // Test rbegin and rend + std::vector::reverse_iterator rit; + std::vector::const_reverse_iterator crit; + + int i = 0; + for (rit = v1.rbegin(); rit != v1.rend(); ++rit) + { + assert(*rit == 5 - i); + i++; + } + + int j = 0; + for (crit = v1.crbegin(); crit != v1.crend(); ++crit) + { + assert(*crit == 5 - j); + j++; + } +} + +void test_stl_vector() +{ + debug("std::vector ..."); + + debug("std::vector constructor, destructor, operator=, assign"); + __stl_vector_constructor_destructor_operator_equal_assign(); + + debug("std::vector at, operator[], front, back, data"); + __stl_vector_at_operator_array_front_back_data(); + + debug("std::vector begin, cbegin, end, cend"); + __stl_vector_begin_cbegin_end_cend(); + + debug("std::vector clear, insert, emplace, erase, push_back, emplace_back, pop_back, resize, swap"); + __stl_vector_clear_insert_emplace_erase_push_back_emplace_back_pop_back_resize_swap(); + + debug("std::vector OK"); +} + +#endif // DEBUG diff --git a/tests/stress.cpp b/tests/stress.cpp index 0d4e493..9cdf92b 100644 --- a/tests/stress.cpp +++ b/tests/stress.cpp @@ -29,7 +29,7 @@ void killChildren(Tasking::PCB *pcb) return; } - std::list children = pcb->Children; + std::vector children = pcb->Children; foreach (auto child in children) { @@ -50,7 +50,7 @@ constexpr size_t chunk = 10 * 1024 * 1024; /* 10 MiB */ std::atomic_size_t totalAllocated = 0; std::atomic_size_t highestScore = 0; std::atomic_bool halt_fork = false; -std::list allocatedChunks; +std::vector allocatedChunks; Tasking::PCB *baseProc = nullptr; Tasking::PCB *lastProc = nullptr; std::atomic_bool hold = false; diff --git a/tests/t.h b/tests/t.h index 7926c25..4b9e718 100644 --- a/tests/t.h +++ b/tests/t.h @@ -22,14 +22,12 @@ #include #include -void TestString(); -void Test_std(); +void Test_stl(); void TestMemoryAllocation(); void tasking_test_fb(); void tasking_test_mutex(); -void lsof(); void TaskMgr(); -void TreeFS(vfs::Node *node, int Depth); +void TreeFS(FileNode *node, int Depth); void TaskHeartbeat(); void StressKernel(); diff --git a/tests/treefs.cpp b/tests/treefs.cpp index 0ce2643..8faede5 100644 --- a/tests/treefs.cpp +++ b/tests/treefs.cpp @@ -21,18 +21,19 @@ #include "../kernel.h" -void TreeFS(vfs::Node *node, int Depth) +void TreeFS(FileNode *node, int Depth) { return; - foreach (auto Chld in node->Children) - { - printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name); + // foreach (auto Chld in node->GetChildren(true)) + // { + // printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->FileName); - if (!Config.Quiet) - Display->UpdateBuffer(); - TaskManager->Sleep(100); - TreeFS(Chld, Depth + 1); - } + // if (!Config.Quiet) + // Display->UpdateBuffer(); + // TaskManager->Sleep(100); + // TreeFS(Chld, Depth + 1); + // } + assert(!"Function not implemented"); } #endif // DEBUG