summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--GNUmakefile2
-rw-r--r--kernel/GNUmakefile2
-rw-r--r--kernel/src/drivers/disk.cpp74
-rw-r--r--kernel/src/drivers/disk.hpp7
-rw-r--r--kernel/src/drivers/ext2.cpp679
-rw-r--r--kernel/src/drivers/ext2.hpp74
-rw-r--r--kernel/src/drivers/gpt.hpp28
-rw-r--r--kernel/src/generic/vfs.cpp134
-rw-r--r--kernel/src/generic/vfs.hpp173
-rw-r--r--kernel/src/klibc/string.cpp106
-rw-r--r--kernel/src/klibc/string.hpp6
-rw-r--r--kernel/src/utils/math.hpp3
-rw-r--r--limine.conf2
14 files changed, 1256 insertions, 37 deletions
diff --git a/.gitignore b/.gitignore
index 4452fe7..0e9345e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@
*.iso
*.hdd
disk.img
-disk_gpt.img \ No newline at end of file
+disk_gpt.img
+*.img \ No newline at end of file
diff --git a/GNUmakefile b/GNUmakefile
index e777f1f..276807d 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -5,7 +5,7 @@
ARCH := x86_64
# Default user QEMU flags. These are appended to the QEMU command calls.
-QEMUFLAGS := -m 256M -d int -no-reboot -serial stdio
+QEMUFLAGS := -m 256M -d int -serial stdio
override IMAGE_NAME := orange-$(ARCH)
diff --git a/kernel/GNUmakefile b/kernel/GNUmakefile
index 538a975..055b8c2 100644
--- a/kernel/GNUmakefile
+++ b/kernel/GNUmakefile
@@ -46,7 +46,7 @@ ifeq ($(TOOLCHAIN),llvm)
endif
# User controllable C flags.
-CFLAGS := -g -O3 -pipe -Werror -Wall
+CFLAGS := -g -O3 -ffast-math -pipe -Werror -Wall -fomit-frame-pointer -funroll-loops -fno-exceptions -mllvm -force-vector-width=64 -mllvm -inline-threshold=1000
# User controllable C++ flags. We default to same as C flags.
CXXFLAGS := $(CFLAGS)
diff --git a/kernel/src/drivers/disk.cpp b/kernel/src/drivers/disk.cpp
index 78477dd..36742f2 100644
--- a/kernel/src/drivers/disk.cpp
+++ b/kernel/src/drivers/disk.cpp
@@ -8,6 +8,13 @@
#include <drivers/gpt.hpp>
#include <drivers/ext2.hpp>
+std::uint8_t linux_fs_signature[16] = {
+ 0xAF, 0x3D, 0xC6, 0x0F,
+ 0x83, 0x84,
+ 0x72, 0x47,
+ 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4
+};
+
const char* disk_type_to_str(partition_style disk_type) {
switch(disk_type) {
case partition_style::err:
@@ -66,13 +73,34 @@ const char* mbr_to_str(std::uint8_t type) {
return "unknown";
}
+bool disk_try_linux(disk* new_disk) {
+ bytes_to_block_res b = bytes_to_blocks(1024, 1024, new_disk->lba_size);
+
+ char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ new_disk->read(new_disk->arg, buffer, b.lba, b.size_in_blocks);
+ ext2_superblock *sb = (ext2_superblock*)((std::uint64_t)buffer + b.offset);
+
+ if (sb->s_magic == EXT2_MAGIC) {
+#ifdef MBR_ORANGE_TRACE
+ klibc::printf("Disk: Detected ext2\r\n");
+#endif
+ drivers::ext2::init(new_disk, 0);
+ pmm::freelist::free((std::uint64_t)buffer - etc::hhdm());
+ return true;
+ } else {
+ pmm::freelist::free((std::uint64_t)buffer - etc::hhdm());
+ return false;
+ }
+ return false;
+}
+
void disk_do_mbr_linux(disk* new_disk, std::uint64_t start_lba) {
bytes_to_block_res b = bytes_to_blocks(1024, 1024, new_disk->lba_size);
char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
new_disk->read(new_disk->arg, buffer, start_lba + b.lba, b.size_in_blocks);
- ext2_superblock *sb = (ext2_superblock*)buffer;
+ ext2_superblock *sb = (ext2_superblock*)((std::uint64_t)buffer + b.offset);
if (sb->s_magic == EXT2_MAGIC) {
#ifdef MBR_ORANGE_TRACE
@@ -103,6 +131,43 @@ void disk_do_mbr(disk* new_disk) {
pmm::freelist::free((std::uint64_t)buffer - etc::hhdm());
}
+void print_gpt_guid(uint8_t *g) {
+
+ klibc::printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\r\n",
+ g[3], g[2], g[1], g[0],
+ g[5], g[4],
+ g[7], g[6],
+ g[8], g[9],
+ g[10], g[11], g[12],
+ g[13], g[14], g[15]);
+}
+
+void disk_do_gpt(disk* new_disk) {
+ char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ new_disk->read(new_disk->arg, (char*)buffer, 1, 1);
+ gpt_lba1 lba1 = {};
+ klibc::memcpy(&lba1, buffer, sizeof(gpt_lba1));
+ new_disk->read(new_disk->arg, (char*)buffer, lba1.partition_lba, 1);
+
+ gpt_partition_entry* part_table = (gpt_partition_entry*)buffer;
+ for(std::size_t i = 0;i < lba1.count_partitions; i++) {
+ gpt_partition_entry entry = part_table[i];
+ if(klibc::memcmp(entry.guid, (uint8_t[16]){0}, 16) == 0) continue;
+#ifdef MBR_ORANGE_TRACE
+ klibc::printf("gpt: detected fs with start_lba %lli with type ",entry.start_lba);
+ print_gpt_guid(entry.guid);
+#endif
+ if(klibc::memcmp(entry.guid, linux_fs_signature, 16) == 0) {
+#ifdef MBR_ORANGE_TRACE
+ klibc::printf("gpt: detected linux fs\r\n");
+#endif
+ disk_do_mbr_linux(new_disk, entry.start_lba);
+ }
+ }
+
+ pmm::freelist::free((std::uint64_t)buffer - etc::hhdm());
+}
+
void drivers::init_disk(disk* new_disk) {
if(disk_selftest(new_disk) == false)
return;
@@ -115,8 +180,13 @@ void drivers::init_disk(disk* new_disk) {
case partition_style::mbr:
disk_do_mbr(new_disk);
break;
+ case partition_style::gpt:
+ disk_do_gpt(new_disk);
+ break;
default:
- assert(0,"unsupported disk\r\n");
+ bool status = disk_try_linux(new_disk);
+ if(status == false)
+ assert(0,"unsupported disk\r\n");
break;
}
} \ No newline at end of file
diff --git a/kernel/src/drivers/disk.hpp b/kernel/src/drivers/disk.hpp
index d1ac4b5..1186952 100644
--- a/kernel/src/drivers/disk.hpp
+++ b/kernel/src/drivers/disk.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <klibc/stdio.hpp>
+#include <utils/align.hpp>
enum class partition_style : std::uint8_t {
err = 0,
@@ -20,12 +21,14 @@ struct disk {
struct bytes_to_block_res {
std::uint64_t lba;
std::uint64_t size_in_blocks;
+ std::uint64_t offset;
};
inline static bytes_to_block_res bytes_to_blocks(std::uint64_t start, std::uint64_t size, std::uint64_t lba_size) {
bytes_to_block_res result;
- result.lba = start / lba_size;
- result.size_in_blocks = (size / lba_size) == 0 ? 1 : (size / lba_size);
+ result.lba = ALIGNDOWN(start,lba_size) / lba_size;
+ result.size_in_blocks = (ALIGNUP(size,lba_size) / lba_size) == 0 ? 1 : (ALIGNUP(size,lba_size) / lba_size);
+ result.offset = start - ALIGNDOWN(start, lba_size);
return result;
}
diff --git a/kernel/src/drivers/ext2.cpp b/kernel/src/drivers/ext2.cpp
index f153e7a..34fdf32 100644
--- a/kernel/src/drivers/ext2.cpp
+++ b/kernel/src/drivers/ext2.cpp
@@ -5,43 +5,684 @@
#include <generic/hhdm.hpp>
#include <utils/assert.hpp>
#include <klibc/stdio.hpp>
+#include <utils/math.hpp>
+#include <klibc/string.hpp>
+#include <utils/errno.hpp>
#include <cstdint>
-ext2_inode ext2_get_inode(ext2_partition* partition, std::uint64_t inode_num) {
+inline static std::uint64_t inode_to_block_group(ext2_superblock* sb, std::uint64_t inode) {
+ return (inode - 1) / sb->s_inodes_per_group;
+}
- char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+inline static std::uint64_t inode_size(ext2_superblock* sb) {
+ return sb->revision >= 1 ? sb->inode_size : 128;
+}
- ext2_superblock* sb = partition->sb;
- std::uint32_t group = (inode_num - 1) / sb->s_inodes_per_group;
- std::uint32_t index = (inode_num - 1) % sb->s_inodes_per_group;
+inline static std::uint64_t inode_to_index(ext2_superblock* sb, std::uint64_t inode) {
+ return div_remain(inode - 1, sb->s_inodes_per_group);
+}
- std::uint32_t bgdt_block = (sb->s_log_block_size == 0) ? 2 : 1;
+inline static std::uint64_t inode_to_block(ext2_superblock* sb, std::uint64_t inode) {
+ std::uint64_t index = inode_to_index(sb, inode);
+ return (index * inode_size(sb)) / (1024 << sb->s_log_block_size);
+}
+
+inline static std::uint64_t ext2_blocks_count(ext2_superblock* sb) {
+ if(sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) {
+ return sb->s_blocks_count | ((std::uint64_t)sb->s_blocks_count_hi << 32);
+ } else
+ return sb->s_blocks_count;
+ return 0;
+}
+
+
+inline static bool ext2_test_bit(std::uint8_t* bitmap, std::uint32_t bit) {
+ return bitmap[bit / 8] & (1 << (bit % 8));
+}
+
+inline static void ext2_set_bit(std::uint8_t* bitmap, std::uint32_t bit) {
+ bitmap[bit / 8] |= (1 << (bit % 8));
+}
+
+inline static void ext2_clear_bit(std::uint8_t* bitmap, std::uint32_t bit) {
+ bitmap[bit / 8] &= ~(1 << (bit % 8));
+}
+
+ext2_inode ext2_get_inode(ext2_partition* partition, std::uint64_t inode_num, std::int32_t* status = nullptr) {
+ ext2_superblock* sb = partition->sb;
std::uint32_t block_size = 1024 << sb->s_log_block_size;
+
+ std::uint64_t group = inode_to_block_group(sb, inode_num);
+
+ char* bgdt = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ bytes_to_block_res res;
+
+ ext2_group_desc* gd = (ext2_group_desc*)((std::uint64_t)partition->cached_group + group * sizeof(ext2_group_desc));
+ uint32_t inode_table_block = gd->bg_inode_table;
+
+ uint32_t inode_byte_offset = inode_to_index(sb, inode_num) * inode_size(sb);
+
+ uint32_t final_inode_block = gd->bg_inode_table + (inode_byte_offset / block_size);
+ uint32_t final_offset_in_block = div_remain(inode_byte_offset, block_size);
+
+ res = bytes_to_blocks(final_inode_block * block_size, block_size, partition->target_disk->lba_size);
+ partition->target_disk->read(partition->target_disk->arg, bgdt, res.lba + partition->lba_start, res.size_in_blocks);
+
+ ext2_inode actual_inode = {};
+ klibc::memcpy(&actual_inode, bgdt + res.offset + final_offset_in_block, sizeof(ext2_inode));
+
+#ifdef EXT2_ORANGE_TRACE
+ klibc::printf("ext2: inode_size %lli inode_to_block_group %lli inode_to_block %lli index %lli inode %lli inode per group %lli bgdt start %lli block size %lli block offset %lli block internal offset %lli inode_table_block %lli byte offset %lli inode block %lli offset inode in block %lli\r\n",inode_size(sb), inode_to_block_group(partition->sb,inode_num),inode_to_block(sb, inode_num), inode_to_index(sb, inode_num), inode_num, sb->s_inodes_per_group,bgdt_start_block, block_size, 0, 0, inode_table_block, inode_byte_offset, final_inode_block, final_offset_in_block);
+#else
+ (void)inode_to_block;
+ (void)inode_table_block;
+#endif
+
+ pmm::freelist::free((std::uint64_t)bgdt - etc::hhdm());
+
+ if(status != nullptr)
+ *status = 0;
+
+ return actual_inode;
+}
+
+uint32_t read_indirect_ptr(ext2_partition* partition, std::uint64_t table_block, std::uint64_t index) {
+ if (table_block == 0) return 0;
+ std::uint32_t* buffer = (std::uint32_t*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ std::uint64_t saved_index = 0;
+ std::uint64_t block_size = 1024 << partition->sb->s_log_block_size;
+ bytes_to_block_res b = bytes_to_blocks(table_block * block_size, block_size / 4, partition->target_disk->lba_size);
+ partition->target_disk->read(partition->target_disk->arg, (char*)buffer, b.lba + partition->lba_start, b.size_in_blocks);
+ std::uint32_t* table = (std::uint32_t*)((std::uint64_t)buffer + b.offset);
+ saved_index = table[index];
+ pmm::freelist::free((std::uint64_t)buffer - etc::hhdm());
+ return saved_index;
+}
+
+std::uint64_t get_extent_address(uint16_t hi, uint32_t lo) {
+ return (static_cast<uint64_t>(hi) << 32) | lo;
+}
+
+void ext2_read_block(ext2_partition* partition, std::uint64_t block, char* buffer) {
+ bytes_to_block_res b = bytes_to_blocks(block * (1024 << partition->sb->s_log_block_size), 1024 << partition->sb->s_log_block_size, partition->target_disk->lba_size);
+ assert(b.offset == 0, "uhhhhh r :(");
+ partition->target_disk->read(partition->target_disk->arg, buffer, b.lba + partition->lba_start, b.size_in_blocks);
+}
+
+void ext2_memcpy_block(ext2_partition* part, std::uint64_t block, void* buffer, std::size_t c) {
+ ext2_read_block(part, block, part->temp_buffer2);
+ klibc::memcpy(buffer, part->temp_buffer2, c);
+}
+
+void ext2_write_block(ext2_partition* partition, std::uint64_t block, char* buffer) {
+ bytes_to_block_res b = bytes_to_blocks(block * (1024 << partition->sb->s_log_block_size), 1024 << partition->sb->s_log_block_size, partition->target_disk->lba_size);
+ assert(b.offset == 0, "uhhhhh w :(");
+ partition->target_disk->write(partition->target_disk->arg, buffer + b.offset, b.lba + partition->lba_start, b.size_in_blocks);
+}
+
+std::uint64_t ext4_get_phys_block_extents(ext2_partition* part, ext4_extent_header* header, std::uint32_t logical_block) {
+
+ assert(header->eh_magic == 0xF30A, "uhh :((");
+ if (header->eh_magic != 0xF30A) return 0;
+
+ if (header->eh_depth > 0) {
+ ext4_extent_idx* idx = (ext4_extent_idx*)((std::uint8_t*)header + sizeof(ext4_extent_header));
+ int target_idx = -1;
+
+ for (int i = 0; i < header->eh_entries; i++) {
+ if (logical_block >= idx[i].ei_block) {
+ target_idx = i;
+ } else {
+ break;
+ }
+ }
+
+ if (target_idx == -1) return 0;
+
+ std::uint64_t next_node_phys = get_extent_address(idx[target_idx].ei_leaf_hi, idx[target_idx].ei_leaf_lo);
+
+ std::uint32_t block_size = 1024 << part->sb->s_log_block_size;
+ char* local_buf = new char[block_size];
+ ext2_memcpy_block(part, next_node_phys, local_buf, block_size);
+
+ std::uint64_t res = ext4_get_phys_block_extents(part, (ext4_extent_header*)local_buf, logical_block);
+ delete[] local_buf;
+ return res;
+ } else {
+ ext4_extent* ext = (ext4_extent*)((std::uint8_t*)header + sizeof(ext4_extent_header));
+
+ for (int i = 0; i < header->eh_entries; i++) {
+ std::uint32_t start_lblock = ext[i].ee_block;
+ std::uint32_t len = ext[i].ee_len;
+ if (len > 32768) len -= 32768;
+
+ if (logical_block >= start_lblock && logical_block < start_lblock + len) {
+ std::uint64_t phys_start = get_extent_address(ext[i].ee_start_hi, ext[i].ee_start_lo);
+ return phys_start + (logical_block - start_lblock);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+std::uint64_t get_phys_block(ext2_partition* partition, ext2_inode *node, std::uint32_t logical_block) {
+
+ if(partition->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) {
+ return ext4_get_phys_block_extents(partition, (ext4_extent_header*)node->i_block, logical_block);
+ }
+
+ std::uint32_t block_size = 1024 << partition->sb->s_log_block_size;
+ std::uint64_t ptrs_per_block = block_size / 4;
+
+ if (logical_block < 12) {
+ return node->i_block[logical_block];
+ }
+ logical_block -= 12;
+
+ if (logical_block < ptrs_per_block) {
+ return read_indirect_ptr(partition, node->i_block[12], logical_block);
+ }
+ logical_block -= ptrs_per_block;
+
+ std::uint64_t doubly_limit = ptrs_per_block * ptrs_per_block;
+ if (logical_block < doubly_limit) {
+ std::uint64_t a = logical_block / ptrs_per_block;
+ std::uint64_t b = logical_block % ptrs_per_block;
+
+ std::uint64_t first_level_ptr = read_indirect_ptr(partition, node->i_block[13], a);
+ return read_indirect_ptr(partition, first_level_ptr, b);
+ }
+ logical_block -= doubly_limit;
+
+ std::uint64_t triply_limit = ptrs_per_block * ptrs_per_block * ptrs_per_block;
+ if (logical_block < triply_limit) {
+ std::uint64_t a = logical_block / (ptrs_per_block * ptrs_per_block);
+ std::uint64_t remaining = logical_block % (ptrs_per_block * ptrs_per_block);
+ std::uint64_t b = remaining / ptrs_per_block;
+ std::uint64_t c = remaining % ptrs_per_block;
+
+ std::uint64_t L1_ptr = read_indirect_ptr(partition, node->i_block[14], a);
+ std::uint64_t L2_ptr = read_indirect_ptr(partition, L1_ptr, b);
+ return read_indirect_ptr(partition, L2_ptr, c);
+ }
- bytes_to_block_res result = bytes_to_blocks(block_size * bgdt_block, block_size, partition->target_disk->lba_size);
- partition->target_disk->read(partition->target_disk->arg, buffer, result.lba, result.size_in_blocks);
+ return 0;
+}
+
+
+std::uint64_t ext2_find_child(ext2_partition* part, ext2_inode* dir_inode, const char* name) {
+ std::uint32_t block_size = 1024 << part->sb->s_log_block_size;
+ char* block_buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
- struct ext2_group_desc *gd = (struct ext2_group_desc *)((std::uint64_t)buffer + group);
+ std::uint64_t num_blocks = dir_inode->i_size / block_size;
+ for (std::uint64_t i = 0; i < num_blocks; i++) {
+ std::uint64_t phys_block = get_phys_block(part, dir_inode, i);
+ if (phys_block == 0) continue;
- uint32_t inode_size = 128;
- uint32_t byte_offset = index * inode_size;
- uint32_t block_in_table = gd->bg_inode_table + (byte_offset / block_size);
- uint32_t internal_offset = byte_offset % block_size;
+ ext2_read_block(part, phys_block, block_buffer);
- result = bytes_to_blocks(block_size * block_in_table, block_size, partition->target_disk->lba_size);
+ ext2_dir_entry* entry = (ext2_dir_entry*)block_buffer;
+ std::uint64_t offset = 0;
- char* inode_buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
- partition->target_disk->read(partition->target_disk->arg, inode_buffer, result.lba, result.size_in_blocks);
+ while (offset < block_size && entry->inode != 0) {
+ if (klibc::strlen(name) == entry->name_len &&
+ klibc::memcmp(name, entry->name, entry->name_len) == 0) {
+
+ std::uint64_t found_inode = entry->inode;
+ pmm::freelist::free((std::uint64_t)block_buffer - etc::hhdm());
+ return found_inode;
+ }
- pmm::freelist::free((std::uint64_t)buffer - etc::hhdm());
- return *(struct ext2_inode*)((std::uint64_t)inode_buffer + internal_offset);
+ offset += entry->rec_len;
+ entry = (ext2_dir_entry*)(block_buffer + offset);
+ }
+ }
+
+ pmm::freelist::free((std::uint64_t)block_buffer - etc::hhdm());
+ return 0;
+}
+
+std::int32_t ext2_lookup(ext2_partition* part, const char* path, ext2_inode* out, std::uint64_t* inode_out) {
+ uint32_t current_inode_num = 2;
+ ext2_inode current_inode = ext2_get_inode(part, 2);
+
+ char path_copy[1024];
+ klibc::memcpy(path_copy, path, klibc::strlen(path));
+
+ char* saveptr;
+ char* token = klibc::strtok(&saveptr, path_copy, "/");
+
+#ifdef EXT2_ORANGE_TRACE
+ klibc::printf("ext2: trying to lookup %s\r\n",path);
+#endif
+
+ while (token != nullptr) {
+ if ((current_inode.i_mode & 0xF000) != 0x4000) {
+ return -ENOTDIR;
+ }
+
+ current_inode_num = ext2_find_child(part, &current_inode, token);
+ if (current_inode_num == 0) {
+ return -ENOENT;
+ }
+
+ current_inode = ext2_get_inode(part, current_inode_num);
+ token = klibc::strtok(&saveptr, nullptr, "/");
+ }
+
+
+#ifdef EXT2_ORANGE_TRACE
+ klibc::printf("ext2: return inode %lli (%s)\r\n", current_inode_num, path);
+#endif
+
+ *inode_out = current_inode_num;
+ *out = current_inode;
+ return 0;
+}
+
+std::int64_t ext2_alloc_blocks(ext2_partition* part, uint32_t count, uint64_t* out) {
+ uint64_t blocks_per_group = part->sb->s_blocks_per_group;
+ uint64_t total_groups = (ext2_blocks_count(part->sb) + blocks_per_group - 1) / blocks_per_group;
+
+ uint8_t* bitmap = (uint8_t*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ uint64_t allocated_so_far = 0;
+
+ for (uint32_t g = 0; g < total_groups; g++) {
+ ext2_group_desc* gd = &((ext2_group_desc*)part->cached_group)[g];
+ if (gd->bg_free_blocks_count < count) continue;
+
+ ext2_read_block(part, gd->bg_block_bitmap, (char*)bitmap);
+
+ for (uint32_t i = 0; i <= blocks_per_group - count; i++) {
+ bool found = true;
+ for (uint32_t j = 0; j < count; j++) {
+ if (ext2_test_bit(bitmap, i + j)) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found) {
+ for (uint32_t j = 0; j < count; j++) {
+ ext2_set_bit(bitmap, i + j);
+ out[j] = (uint64_t)g * blocks_per_group + i + j + part->sb->s_first_data_block;
+ }
+ ext2_write_block(part, gd->bg_block_bitmap, (char*)bitmap);
+ gd->bg_free_blocks_count -= count;
+ pmm::freelist::free((uint64_t)bitmap - etc::hhdm());
+ return 0;
+ }
+ }
+ }
+
+ for (uint32_t g = 0; g < total_groups && allocated_so_far < count; g++) {
+ ext2_group_desc* gd = &((ext2_group_desc*)part->cached_group)[g];
+ if (gd->bg_free_blocks_count == 0) continue;
+
+ ext2_read_block(part, gd->bg_block_bitmap, (char*)bitmap);
+ bool changed = false;
+
+ for (uint32_t i = 0; i < blocks_per_group && allocated_so_far < count; i++) {
+ if (!ext2_test_bit(bitmap, i)) {
+ ext2_set_bit(bitmap, i);
+ out[allocated_so_far++] = (uint64_t)g * blocks_per_group + i + part->sb->s_first_data_block;
+ gd->bg_free_blocks_count--;
+ changed = true;
+ }
+ }
+ if (changed) ext2_write_block(part, gd->bg_block_bitmap, (char*)bitmap);
+ }
+
+ pmm::freelist::free((uint64_t)bitmap - etc::hhdm());
+ return (allocated_so_far == count) ? 0 : -ENOSPC;
+}
+
+void ext2_free_blocks(ext2_partition* part, uint32_t count, uint64_t* blocks) {
+ uint32_t blocks_per_group = part->sb->s_blocks_per_group;
+ uint8_t* bitmap = (uint8_t*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ for (uint32_t i = 0; i < count; i++) {
+ uint64_t abs_block = blocks[i] - part->sb->s_first_data_block;
+ uint32_t group = abs_block / blocks_per_group;
+ uint32_t index = abs_block % blocks_per_group;
+
+ ext2_group_desc* gd = &((ext2_group_desc*)part->cached_group)[group];
+
+ ext2_read_block(part, gd->bg_block_bitmap, (char*)bitmap);
+ if (ext2_test_bit(bitmap, index)) {
+ ext2_clear_bit(bitmap, index);
+ gd->bg_free_blocks_count++;
+ ext2_write_block(part, gd->bg_block_bitmap, (char*)bitmap);
+ }
+ }
+ pmm::freelist::free((uint64_t)bitmap - etc::hhdm());
+}
+
+signed long ext2_read(file_descriptor* file, void* buffer, signed long count) {
+ if (count <= 0) return 0;
+
+ file->vnode.fs->lock.lock();
+
+ std::int32_t status = 0;
+ ext2_partition* part = (ext2_partition*)(file->vnode.fs->fs_specific.partition);
+ ext2_inode inode = ext2_get_inode(part, file->fs_specific.ino, &status);
+
+ if (status != 0) {
+ file->vnode.fs->lock.unlock();
+ return status;
+ }
+
+ if (file->offset >= inode.i_size) {
+ file->vnode.fs->lock.unlock();
+ return 0;
+ }
+
+ if (file->offset + count > inode.i_size) {
+ count = inode.i_size - file->offset;
+ }
+
+ std::uint32_t block_size = 1024 << part->sb->s_log_block_size;
+ char* temp_block = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ signed long total_read = 0;
+ char* out_ptr = (char*)buffer;
+
+ while (total_read < count) {
+ std::uint64_t logical_block = (file->offset + total_read) / block_size;
+ std::uint64_t block_offset = (file->offset + total_read) % block_size;
+
+ std::uint64_t phys_block = get_phys_block(part, &inode, logical_block);
+
+ if (phys_block == 0) {
+ klibc::memset(temp_block, 0, block_size);
+ } else {
+ ext2_read_block(part, phys_block, temp_block);
+ }
+
+ std::uint32_t to_copy = block_size - block_offset;
+ if (to_copy > (std::uint32_t)(count - total_read)) {
+ to_copy = count - total_read;
+ }
+
+ klibc::memcpy(out_ptr + total_read, temp_block + block_offset, to_copy);
+
+ total_read += to_copy;
+ }
+
+ file->offset += total_read;
+
+ pmm::freelist::free((std::uint64_t)temp_block - etc::hhdm());
+ file->vnode.fs->lock.unlock();
+
+ return total_read;
+}
+
+uint32_t set_indirect_ptr(ext2_partition* part, uint32_t table_block, uint32_t index, uint32_t new_val) {
+ uint32_t* buffer = (uint32_t*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ ext2_read_block(part, table_block, (char*)buffer);
+ buffer[index] = new_val;
+ ext2_write_block(part, table_block, (char*)buffer);
+ pmm::freelist::free((uint64_t)buffer - etc::hhdm());
+ return new_val;
+}
+
+uint64_t get_or_alloc_phys_block(ext2_partition* part, ext2_inode* node, uint32_t logical_block, bool* dirty) {
+ uint32_t block_size = 1024 << part->sb->s_log_block_size;
+ uint32_t ptrs_per_block = block_size / 4;
+
+ auto alloc_one = [&]() {
+ uint64_t b = 0;
+ ext2_alloc_blocks(part, 1, &b);
+ char* zero = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ klibc::memset(zero, 0, block_size);
+ ext2_write_block(part, b, zero);
+ pmm::freelist::free((uint64_t)zero - etc::hhdm());
+ *dirty = true;
+ return (uint32_t)b;
+ };
+
+ if (logical_block < 12) {
+ if (!node->i_block[logical_block]) node->i_block[logical_block] = alloc_one();
+ return node->i_block[logical_block];
+ }
+ logical_block -= 12;
+
+ if (logical_block < ptrs_per_block) {
+ if (!node->i_block[12]) node->i_block[12] = alloc_one();
+ uint32_t phys = read_indirect_ptr(part, node->i_block[12], logical_block);
+ if (!phys) phys = set_indirect_ptr(part, node->i_block[12], logical_block, alloc_one());
+ return phys;
+ }
+ logical_block -= ptrs_per_block;
+
+ uint64_t doubly_limit = ptrs_per_block * ptrs_per_block;
+ if (logical_block < doubly_limit) {
+ if (!node->i_block[13]) node->i_block[13] = alloc_one();
+ uint32_t a = logical_block / ptrs_per_block;
+ uint32_t b = logical_block % ptrs_per_block;
+
+ uint32_t L1 = read_indirect_ptr(part, node->i_block[13], a);
+ if (!L1) L1 = set_indirect_ptr(part, node->i_block[13], a, alloc_one());
+
+ uint32_t phys = read_indirect_ptr(part, L1, b);
+ if (!phys) phys = set_indirect_ptr(part, L1, b, alloc_one());
+ return phys;
+ }
+ logical_block -= doubly_limit;
+
+ if (!node->i_block[14]) node->i_block[14] = alloc_one();
+ uint32_t a = logical_block / (ptrs_per_block * ptrs_per_block);
+ uint32_t rem = logical_block % (ptrs_per_block * ptrs_per_block);
+ uint32_t b = rem / ptrs_per_block;
+ uint32_t c = rem % ptrs_per_block;
+
+ uint32_t L1 = read_indirect_ptr(part, node->i_block[14], a);
+ if (!L1) L1 = set_indirect_ptr(part, node->i_block[14], a, alloc_one());
+ uint32_t L2 = read_indirect_ptr(part, L1, b);
+ if (!L2) L2 = set_indirect_ptr(part, L1, b, alloc_one());
+ uint32_t phys = read_indirect_ptr(part, L2, c);
+ if (!phys) phys = set_indirect_ptr(part, L2, c, alloc_one());
+
+ return phys;
+}
+
+void ext2_write_inode(ext2_partition* part, uint64_t ino, ext2_inode* inode) {
+ ext2_superblock* sb = part->sb;
+ uint32_t block_size = 1024 << sb->s_log_block_size;
+ uint32_t group = inode_to_block_group(sb, ino);
+ ext2_group_desc* gd = (ext2_group_desc*)((uint64_t)part->cached_group + group * sizeof(ext2_group_desc));
+
+ uint32_t inode_off = inode_to_index(sb, ino) * inode_size(sb);
+ uint32_t block = gd->bg_inode_table + (inode_off / block_size);
+ uint32_t off_in_block = inode_off % block_size;
+
+ char* buf = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ ext2_read_block(part, block, buf);
+ klibc::memcpy(buf + off_in_block, inode, sizeof(ext2_inode));
+ ext2_write_block(part, block, buf);
+ pmm::freelist::free((uint64_t)buf - etc::hhdm());
+}
+
+signed long ext2_write(file_descriptor* file, void* buffer, signed long count) {
+ if (count <= 0) return 0;
+ file->vnode.fs->lock.lock();
+
+ ext2_partition* part = (ext2_partition*)(file->vnode.fs->fs_specific.partition);
+ ext2_inode inode = ext2_get_inode(part, file->fs_specific.ino, nullptr);
+ uint32_t block_size = 1024 << part->sb->s_log_block_size;
+ char* temp_block = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ signed long total_written = 0;
+ const char* in_ptr = (const char*)buffer;
+ bool inode_dirty = false;
+
+ while (total_written < count) {
+ uint64_t logical_block = (file->offset) / block_size;
+ uint64_t block_offset = (file->offset) % block_size;
+ uint32_t to_write = block_size - block_offset;
+ if (to_write > (uint32_t)(count - total_written)) to_write = count - total_written;
+
+ uint64_t phys_block = get_or_alloc_phys_block(part, &inode, logical_block, &inode_dirty);
+
+ if (to_write < block_size) {
+ ext2_read_block(part, phys_block, temp_block);
+ }
+
+ klibc::memcpy(temp_block + block_offset, in_ptr + total_written, to_write);
+ ext2_write_block(part, phys_block, temp_block);
+
+ file->offset += to_write;
+ total_written += to_write;
+
+ if (file->offset > inode.i_size) {
+ inode.i_size = file->offset;
+ inode_dirty = true;
+ }
+ }
+
+ if (inode_dirty) {
+ ext2_write_inode(part, file->fs_specific.ino, &inode);
+ }
+
+ pmm::freelist::free((uint64_t)temp_block - etc::hhdm());
+ file->vnode.fs->lock.unlock();
+ return total_written;
+}
+
+std::uint32_t ext2_open(filesystem* fs, void* file_desc, char* path) {
+ fs->lock.lock();
+ ext2_inode res;
+ std::uint64_t inode_num = 0;
+ std::uint32_t status = ext2_lookup((ext2_partition*)(fs->fs_specific.partition), path, &res, &inode_num);
+ if(status != 0) { fs->lock.unlock();
+ return status; }
+ file_descriptor* fd = (file_descriptor*)file_desc;
+ fd->fs_specific.ino = inode_num;
+ fd->vnode.fs = fs;
+ fd->vnode.read = ext2_read;
+ fd->vnode.write = ext2_write;
+ fs->lock.unlock();
+ return 0;
+}
+
+std::int32_t ext2_stat(file_descriptor* file, stat* out) {
+ std::int32_t status = 0;
+ ext2_partition* part = (ext2_partition*)(file->vnode.fs->fs_specific.partition);
+ ext2_inode inode = ext2_get_inode(part, file->fs_specific.ino, &status);
+
+ if (status != 0) {
+ file->vnode.fs->lock.unlock();
+ return status;
+ }
+
+ out->st_atim.tv_nsec = 0;
+ out->st_atim.tv_sec = inode.i_atime;
+ out->st_ctim.tv_nsec = 0;
+ out->st_ctim.tv_sec = inode.i_ctime;
+ out->st_mtim.tv_nsec = 0;
+ out->st_mtim.tv_sec = inode.i_mtime;
+ out->st_blksize = 1024 << part->sb->s_log_block_size;
+ out->st_blocks = ALIGNUP(inode.i_size, out->st_blksize) / out->st_blksize;
+ out->st_size = inode.i_size;
+ out->st_uid = inode.i_uid;
+ out->st_gid = inode.i_gid;
+ out->st_dev = 0;
+ out->st_rdev = 0; // should be filled by vfs
+ out->st_nlink = inode.i_links_count;
+ out->st_mode = inode.i_mode;
+
+ return 0;
+}
+
+void ext2_load_group_descriptors(ext2_partition* part) {
+ uint32_t block_size = 1024 << part->sb->s_log_block_size;
+
+ uint32_t bgdt_block = (block_size == 1024) ? 2 : 1;
+
+ uint32_t blocks_per_group = part->sb->s_blocks_per_group;
+ uint32_t groups_count = (ext2_blocks_count(part->sb) + blocks_per_group - 1) / blocks_per_group;
+
+ uint32_t table_size_bytes = groups_count * sizeof(ext2_group_desc);
+ uint32_t table_size_blocks = (table_size_bytes + block_size - 1) / block_size;
+
+ for (uint32_t i = 0; i < table_size_blocks; i++) {
+ ext2_read_block(part, bgdt_block + i, (char*)((uint64_t)part->cached_group + (i * block_size)));
+ }
+}
+
+static inline int isprint(int c) {
+ return (c >= 0x20 && c <= 0x7E);
+}
+
+
+static inline void print_buffer(const unsigned char *buffer, std::size_t size) {
+
+ for (std::size_t i = 0; i < size; i++) {
+
+ if(buffer[i] == '\0')
+ continue;
+
+ if (isprint(buffer[i])) {
+ klibc::printf("%c ", buffer[i]);
+ } else {
+ klibc::printf("0x%02X ", buffer[i]);
+ }
+ }
+ klibc::printf("\r\n");
}
void drivers::ext2::init(disk* target_disk, std::uint64_t lba_start) {
bytes_to_block_res b = bytes_to_blocks(1024, 1024, target_disk->lba_size);
char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
target_disk->read(target_disk->arg, buffer, lba_start + b.lba, b.size_in_blocks);
- ext2_superblock *sb = (ext2_superblock*)buffer;
+ ext2_superblock *sb = (ext2_superblock*)((std::uint64_t)buffer + b.offset);
assert(sb->s_magic == EXT2_MAGIC,"its not ext2 partition !");
+
+ if((1024 << sb->s_log_block_size) > PAGE_SIZE) {
+ klibc::printf("ext2: partition block size is bigger than page_size ! (todo mb) \r\n");
+ return;
+ }
+
+ if(sb->revision >= 1) {
+ klibc::printf("ext2: detected features %s %s %s\r\n",(sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) ? "EXT2_FEATURE_RO_COMPAT_LARGE_FILE" : "", (sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? "EXT4_FEATURE_INCOMPAT_64BIT" : "", (sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) ? "EXT4_FEATURE_INCOMPAT_EXTENTS" : "");
+ }
+
+ uint32_t groups_count = (ext2_blocks_count(sb) + sb->s_blocks_per_group - 1);
+
+ ext2_partition* part = new ext2_partition;
+ part->buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ part->lba_start = lba_start;
+ part->lock.unlock();
+ part->sb = sb;
+ part->target_disk = target_disk;
+ part->cached_group = (void*)(pmm::buddy::alloc(groups_count * sizeof(ext2_group_desc)).phys + etc::hhdm());
+
+ ext2_load_group_descriptors(part);
+
+ ext2_inode root = ext2_get_inode(part, 2);
+ klibc::printf("inode 2 size %lli links count %lli mode 0x%p block_size %lli\r\n",root.i_size, root.i_links_count, root.i_mode, 1024 << part->sb->s_log_block_size);
+ klibc::printf("logic blocks for root first block = %lli, second block = %lli\r\n", get_phys_block(part, &root, 0),get_phys_block(part, &root, 1));
+ (void)print_buffer;
+
+ char* buffer2 = (char*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ ext2_read_block(part, get_phys_block(part, &root, 0), buffer2);
+ klibc::printf("dumping first root block\r\n");
+ print_buffer((const unsigned char*)buffer2, 1024 << part->sb->s_log_block_size);
+
+ const char* file_test = "/test1/meow";
+ ext2_inode res = {};
+ std::uint64_t in = 0;
+ std::int32_t status = ext2_lookup(part, file_test, &res, &in);
+
+ klibc::memset(buffer2, 0, PAGE_SIZE);
+ klibc::printf("reading file %s, status %d, size %lli\r\n", file_test, status, res.i_size);
+ ext2_read_block(part, get_phys_block(part, &res, 0), buffer2);
+ klibc::printf("%s\r\n", buffer2);
+
+ klibc::printf("group count %lli (size %lli)\r\n",groups_count,groups_count * sizeof(ext2_group_desc));
+
} \ No newline at end of file
diff --git a/kernel/src/drivers/ext2.hpp b/kernel/src/drivers/ext2.hpp
index bfede39..4fdcd3c 100644
--- a/kernel/src/drivers/ext2.hpp
+++ b/kernel/src/drivers/ext2.hpp
@@ -3,6 +3,14 @@
#include <drivers/disk.hpp>
#include <generic/lock/mutex.hpp>
+//#define EXT2_ORANGE_TRACE
+
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040
+
+#include <stdint.h>
+
struct ext2_superblock {
uint32_t s_inodes_count;
uint32_t s_blocks_count;
@@ -23,7 +31,47 @@ struct ext2_superblock {
uint16_t s_state;
uint16_t s_errors;
uint16_t s_minor_rev_level;
-};
+ uint32_t s_lastcheck;
+ uint32_t s_checkinterval;
+ uint32_t s_creator_os;
+ uint32_t revision;
+ uint16_t s_def_resuid;
+ uint16_t s_def_resgid;
+
+ uint32_t s_first_ino;
+ uint16_t inode_size;
+ uint16_t s_block_group_nr;
+ uint32_t s_feature_compat;
+ uint32_t s_feature_incompat;
+ uint32_t s_feature_ro_compat;
+ uint8_t s_uuid[16];
+ char s_volume_name[16];
+ char s_last_mounted[64];
+ uint32_t s_algo_bitmap;
+
+ uint8_t s_prealloc_blocks;
+ uint8_t s_prealloc_dir_blocks;
+ uint16_t s_reserved_gdt_blocks;
+
+ uint8_t s_journal_uuid[16];
+ uint32_t s_journal_inum;
+ uint32_t s_journal_dev;
+ uint32_t s_last_orphan;
+
+ uint32_t s_hash_seed[4];
+ uint8_t s_def_hash_version;
+ uint8_t s_jnl_backup_type;
+ uint16_t s_desc_size;
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg;
+ uint32_t s_mkfs_time;
+ uint32_t s_jnl_blocks[17];
+
+ uint32_t s_blocks_count_hi;
+ uint32_t s_r_blocks_count_hi;
+ uint32_t s_free_blocks_count_hi;
+} __attribute__((packed));
+
struct ext2_group_desc {
uint32_t bg_block_bitmap;
@@ -68,11 +116,35 @@ struct ext2_dir_entry {
struct ext2_partition {
std::uint64_t lba_start;
ext2_superblock* sb;
+ void* cached_group;
locks::mutex lock;
disk* target_disk;
+ char* temp_buffer2;
char* buffer;
};
+struct ext4_extent_header {
+ uint16_t eh_magic;
+ uint16_t eh_entries;
+ uint16_t eh_max;
+ uint16_t eh_depth;
+ uint32_t eh_generation;
+};
+
+struct ext4_extent {
+ uint32_t ee_block;
+ uint16_t ee_len;
+ uint16_t ee_start_hi;
+ uint32_t ee_start_lo;
+};
+
+struct ext4_extent_idx {
+ uint32_t ei_block;
+ uint32_t ei_leaf_lo;
+ uint16_t ei_leaf_hi;
+ uint16_t ei_unused;
+};
+
#define EXT2_MAGIC 0xEF53
namespace drivers {
diff --git a/kernel/src/drivers/gpt.hpp b/kernel/src/drivers/gpt.hpp
index 9f43b54..109ede6 100644
--- a/kernel/src/drivers/gpt.hpp
+++ b/kernel/src/drivers/gpt.hpp
@@ -1,4 +1,32 @@
#pragma once
#include <cstdint>
+struct __attribute__((packed)) gpt_lba1 {
+ std::uint8_t signature[8];
+ std::uint32_t revision;
+ std::uint32_t size;
+ std::uint32_t crc32;
+ std::uint32_t reserved;
+ std::uint64_t current_lba;
+ std::uint64_t other_lba;
+ std::uint64_t first_usable;
+ std::uint64_t last_usable;
+ std::uint8_t guid[16];
+ std::uint64_t partition_lba;
+ std::uint32_t count_partitions;
+ std::uint32_t size_of_partition;
+};
+
+struct __attribute__((packed)) gpt_partition_entry {
+ std::uint8_t guid[16];
+ std::uint8_t unique_guid[16];
+ std::uint64_t start_lba;
+ std::uint64_t end_lba;
+ std::uint64_t attributes;
+ std::uint8_t name[72];
+};
+
+static_assert(sizeof(gpt_partition_entry) == (0x38 + 72));
+static_assert(sizeof(gpt_lba1) == 0x58);
+
#define GPT_SIGNATURE "EFI PART" \ No newline at end of file
diff --git a/kernel/src/generic/vfs.cpp b/kernel/src/generic/vfs.cpp
index d34ae0c..75c3ed8 100644
--- a/kernel/src/generic/vfs.cpp
+++ b/kernel/src/generic/vfs.cpp
@@ -1,6 +1,140 @@
#include <cstdint>
#include <generic/vfs.hpp>
#include <drivers/disk.hpp>
+#include <klibc/string.hpp>
+#include <utils/errno.hpp>
+#include <klibc/stdio.hpp>
+#include <generic/lock/mutex.hpp>
+
+// /bin/path -> /usr/bin/path
+void __vfs_symlink_resolve_no_at_symlink_follow(char* path, char* out) {
+ char *next = nullptr;
+ char buffer[4096];
+
+ int e = vfs::readlink(path,buffer,4096);
+
+ if(e == ENOSYS)
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+
+ if(e == EINVAL)
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ else if(e == 0) {
+
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ } else if(e == ENOENT) {
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ // maybe it wants directory symlink ?
+ char path0[4096];
+ klibc::memcpy(path0,path,klibc::strlen(path) + 1);
+
+ char result[4096];
+
+ int c = 0;
+
+ char* token = klibc::strtok(&next, path0, "/");
+
+ /* Start building path from null and trying to find symlink */
+ while(token) {
+
+ result[c] = '/';
+ c++;
+
+ std::uint64_t mm = 0;
+ mm = klibc::strlen(token);
+ klibc::memcpy((char*)((std::uint64_t)result + c),token,mm);
+ c += mm;
+ result[c] = '\0';
+
+ e = vfs::readlink(result,buffer,4096);
+ if(e == 0) {
+ char buffer2[4096];
+ vfs::resolve_path(buffer,result,buffer2,0);
+ c = klibc::strlen(buffer2);
+ buffer2[c++] = '/';
+ klibc::memcpy(buffer2 + c, path + klibc::strlen(result) + 1, klibc::strlen(path) - klibc::strlen(result));
+ __vfs_symlink_resolve_no_at_symlink_follow(buffer2,out);
+ return;
+ } else if(e == ENOENT) {
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ }
+
+ token = klibc::strtok(&next,0,"/");
+ }
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ }
+}
+
+void __vfs_symlink_resolve(char* path, char* out, int level) {
+
+ char *next = nullptr;
+
+ char buffer[4096];
+
+ if(level == 25) {
+ // hell no :skull:
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ return;
+ }
+
+ int e = vfs::readlink(path,buffer,4096);
+
+ if(e == ENOSYS)
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+
+ if(e == EINVAL)
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ else if(e == 0) {
+
+ char result[4096];
+ vfs::resolve_path(buffer,path,result,0);
+ __vfs_symlink_resolve(result,out, level + 1);
+ } else if(e == ENOENT) {
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ // maybe it wants directory symlink ?
+ char path0[4096];
+ klibc::memcpy(path0,path,klibc::strlen(path) + 1);
+
+ char result[4096];
+
+ int c = 0;
+
+ char* token = klibc::strtok(&next, path0, "/");
+
+ /* Start building path from null and trying to find symlink */
+ while(token) {
+
+ result[c] = '/';
+ c++;
+
+ std::uint64_t mm = 0;
+ mm = klibc::strlen(token);
+ klibc:: memcpy((char*)((std::uint64_t)result + c),token,mm);
+ c += mm;
+ result[c] = '\0';
+
+ e = vfs::readlink(result,buffer,4096);
+ if(e == 0) {
+ char buffer2[4096];
+ vfs::resolve_path(buffer,result,buffer2,0);
+ c = klibc::strlen(buffer2);
+ buffer2[c++] = '/';
+ klibc::memcpy(buffer2 + c, path + klibc::strlen(result) + 1, klibc::strlen(path) - klibc::strlen(result));
+ __vfs_symlink_resolve(buffer2,out, level + 1);
+ return;
+ } else if(e == ENOENT) {
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ return;
+ } else {
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ return;
+ }
+
+ token = klibc::strtok(&next,0,"/");
+ }
+ klibc::memcpy(out,path,klibc::strlen(path) + 1);
+ }
+}
+
void vfs::init() {
diff --git a/kernel/src/generic/vfs.hpp b/kernel/src/generic/vfs.hpp
index 8736d42..d6fac32 100644
--- a/kernel/src/generic/vfs.hpp
+++ b/kernel/src/generic/vfs.hpp
@@ -37,7 +37,11 @@ struct stat {
struct filesystem {
locks::mutex lock;
- std::uint32_t (*open)(void* file_desc, char* path);
+ union {
+ std::uint64_t partition;
+ } fs_specific;
+
+ std::uint32_t (*open)(filesystem* fs, void* file_desc, char* path);
char path[2048];
};
@@ -45,30 +49,181 @@ struct filesystem {
struct file_descriptor {
file_descriptor_type type;
+
+ std::size_t offset;
std::uint32_t flags;
- union fs_specific {
+ union {
std::uint64_t ino;
std::uint64_t tmpfs_pointer;
- };
+ } fs_specific;
- struct vnode {
+ struct {
disk* target_disk;
filesystem* fs;
signed long (*read)(file_descriptor* file, void* buffer, signed long count);
signed long (*write)(file_descriptor* file, void* buffer, signed long count);
- signed long (*stat)(file_descriptor* file, stat* out);
+ std::int32_t (*stat)(file_descriptor* file, stat* out);
void (*close)(file_descriptor* file);
- };
+ } vnode;
};
namespace vfs {
void init();
- void open(file_descriptor* fd, char* path, bool follow_symlinks );
- void create(char* path, std::uint32_t mode); // mode contains type too
+ std::int32_t open(file_descriptor* fd, char* path, bool follow_symlinks);
+ std::int32_t create(char* path, std::uint32_t mode); // mode contains type too
+ std::int32_t readlink(char* path, char* out, std::uint32_t out_len);
}
-// fs should setup this during open
+// took from old kernel
+namespace vfs {
+ static inline std::uint64_t resolve_count(char* str,std::uint64_t sptr,char delim) {
+ char* current = str;
+ std::uint16_t att = 0;
+ std::uint64_t ptr = sptr;
+ while(current[ptr] != delim) {
+ if(att > 1024)
+ return 0;
+ att++;
+
+ if(ptr != 0) {
+ ptr--;
+ }
+ }
+ return ptr;
+ }
+
+
+ static inline int normalize_path(const char* src, char* dest, std::uint64_t dest_size) {
+ if (!src ||!dest || dest_size < 2) return -1;
+ std::uint64_t j = 0;
+ int prev_slash = 0;
+ for (std::uint64_t i = 0; src[i] && j < dest_size - 1; i++) {
+ if (src[i] == '/') {
+ if (!prev_slash) {
+ dest[j++] = '/';
+ prev_slash = 1;
+ }
+ } else {
+ dest[j++] = src[i];
+ prev_slash = 0;
+ }
+ }
+
+ if (j > 1 && dest[j-1] == '/') j--;
+ if (j >= dest_size) {
+ dest[0] = '\0';
+ return -1;
+ }
+ dest[j] = '\0';
+ return 0;
+ }
+
+ /* I'll use path resolver from my old kernel */
+ static inline void resolve_path(const char* inter0,const char* base, char *result, char spec) {
+ char* next = 0;
+ char buffer2_in_stack[2048];
+ char inter[2048];
+ char* buffer = 0;
+ char* final_buffer = (char*)buffer2_in_stack;
+ std::uint64_t ptr = klibc::strlen((char*)base);
+ char is_first = 1;
+ char is_full = 0;
+
+ klibc::memcpy(inter,inter0,klibc::strlen(inter0) + 1);
+
+ if(klibc::strlen((char*)inter) == 1 && inter[0] == '.') {
+ klibc::memcpy(result,base,klibc::strlen((char*)base) + 1);
+ if(result[0] == '\0') {
+ result[0] = '/';
+ result[1] = '\0';
+ }
+ return;
+ }
+
+ if(!klibc::strcmp(inter,"/")) {
+ klibc::memcpy(result,inter,klibc::strlen((char*)inter) + 1);
+ if(result[0] == '\0') {
+ result[0] = '/';
+ result[1] = '\0';
+ }
+ return;
+ }
+
+ if(inter[0] == '/') {
+ ptr = 0;
+ is_full = 1;
+ } else {
+ klibc::memcpy(final_buffer,base,klibc::strlen((char*)base) + 1);
+ }
+
+ if(spec)
+ is_first = 0;
+
+ if(!klibc::strcmp(base,"/"))
+ is_first = 0;
+
+ buffer = klibc::strtok(&next,(char*)inter,"/");
+ while(buffer) {
+
+ if(is_first && !is_full) {
+ std::uint64_t mm = resolve_count(final_buffer,ptr,'/');
+
+ if(ptr < mm) {
+ final_buffer[0] = '/';
+ final_buffer[1] = '\0';
+ ptr = 1;
+ continue;
+ }
+
+ ptr = mm;
+ final_buffer[ptr] = '\0';
+ is_first = 0;
+ }
+
+ if(!klibc::strcmp(buffer,"..")) {
+ std::uint64_t mm = resolve_count(final_buffer,ptr,'/');
+
+ if(!klibc::strcmp(final_buffer,"/\0")) {
+ buffer = klibc::strtok(&next,0,"/");
+ continue;
+ }
+
+
+ if(ptr < mm) {
+ final_buffer[0] = '/';
+ final_buffer[1] = '\0';
+ ptr = 1;
+ continue;
+ }
+
+ ptr = mm;
+ final_buffer[ptr] = '\0';
+
+
+
+ } else if(klibc::strcmp(buffer,"./") && klibc::strcmp(buffer,".")) {
+
+ final_buffer[ptr] = '/';
+ ptr++;
+
+ std::uint64_t mm = 0;
+ mm = klibc::strlen(buffer);
+ klibc::memcpy((char*)((std::uint64_t)final_buffer + ptr),buffer,mm);
+ ptr += mm;
+ final_buffer[ptr] = '\0';
+ }
+
+ buffer = klibc::strtok(&next,0,"/");
+ }
+ normalize_path(final_buffer,result,2048);
+
+ if(result[0] == '\0') {
+ result[0] = '/';
+ result[1] = '\0';
+ }
+ }
+} \ No newline at end of file
diff --git a/kernel/src/klibc/string.cpp b/kernel/src/klibc/string.cpp
index e4ead45..4663a1d 100644
--- a/kernel/src/klibc/string.cpp
+++ b/kernel/src/klibc/string.cpp
@@ -76,4 +76,110 @@ int klibc::strlen(const char *str) {
len++;
}
return len;
+}
+
+char* klibc::strchr(const char *s, int c) {
+ while (*s) {
+ if (*s == (char)c) return (char *)s;
+ s++;
+ }
+ return nullptr;
+}
+
+char* klibc::strtok(char **next,char *str, const char *delim) {
+ if (str) *next = str;
+ if (!*next) return nullptr;
+
+ char *start = *next;
+ while (*start && strchr(delim, *start)) {
+ start++;
+ }
+ if (!*start) {
+ *next = nullptr;
+ return nullptr;
+ }
+
+ char *end = start;
+ while (*end && !strchr(delim, *end)) {
+ end++;
+ }
+
+ if (*end) {
+ *end = '\0';
+ *next = end + 1;
+ } else {
+ *next = nullptr;
+ }
+
+ return start;
+}
+
+char* klibc::strrchr(const char* str, int ch) {
+ char* last_occurrence = 0;
+
+ while (*str) {
+ if (*str == ch) {
+ last_occurrence = (char*)str;
+ }
+ str++;
+ }
+
+ return last_occurrence;
+}
+
+char* klibc::strcat(char* dest, const char* src) {
+
+ char* ptr = dest;
+ while(*ptr != '\0') {
+ ptr++;
+ }
+
+ while(*src != '\0') {
+ *ptr = *src;
+ ptr++;
+ src++;
+ }
+
+ *ptr = '\0';
+
+ return dest;
+}
+
+int klibc::strncmp(const char *s1, const char *s2, std::size_t n) {
+ std::size_t i = 0;
+ while (i < n && s1[i] && (s1[i] == s2[i])) {
+ i++;
+ }
+ if (i == n) return 0;
+ return (unsigned char)s1[i] - (unsigned char)s2[i];
+}
+
+// tbh i dont remember from what i took this
+int klibc::strcmp(const char *s1, const char *s2) {
+ const unsigned long *w1 = (const unsigned long *)s1;
+ const unsigned long *w2 = (const unsigned long *)s2;
+ const unsigned long himagic = 0x8080808080808080UL;
+ const unsigned long lomagic = 0x0101010101010101UL;
+
+ while (1) {
+ unsigned long word1 = *w1++;
+ unsigned long word2 = *w2++;
+
+ unsigned long diff = word1 ^ word2;
+ unsigned long zeros = (word1 - lomagic) & ~word1 & himagic;
+
+ if (diff != 0 || zeros != 0) {
+ const char *c1 = (const char *)(w1 - 1);
+ const char *c2 = (const char *)(w2 - 1);
+
+ do {
+ unsigned char ch1 = *c1++;
+ unsigned char ch2 = *c2++;
+ if (ch1 != ch2) return ch1 - ch2;
+ if (ch1 == 0) break;
+ } while (1);
+
+ return 0;
+ }
+ }
} \ No newline at end of file
diff --git a/kernel/src/klibc/string.hpp b/kernel/src/klibc/string.hpp
index c900862..5652d21 100644
--- a/kernel/src/klibc/string.hpp
+++ b/kernel/src/klibc/string.hpp
@@ -7,4 +7,10 @@ namespace klibc {
void* memset(void *s, int c, std::size_t n);
void* memmove(void *dest, const void *src, std::size_t n);
int memcmp(const void *s1, const void *s2, std::size_t n);
+ char* strtok(char **next,char *str, const char *delim);
+ char* strchr(const char *s, int c);
+ char* strrchr(const char* str, int ch);
+ char* strcat(char* dest, const char* src);
+ int strncmp(const char *s1, const char *s2, std::size_t n);
+ int strcmp(const char *s1, const char *s2);
}; \ No newline at end of file
diff --git a/kernel/src/utils/math.hpp b/kernel/src/utils/math.hpp
new file mode 100644
index 0000000..4d8f581
--- /dev/null
+++ b/kernel/src/utils/math.hpp
@@ -0,0 +1,3 @@
+#pragma once
+#define is_power_of_two(n) ((n) > 0 && ((n) & ((n) - 1)) == 0)
+#define div_remain(value, full) (value % full) \ No newline at end of file
diff --git a/limine.conf b/limine.conf
index 2d4e09d..4fc44ff 100644
--- a/limine.conf
+++ b/limine.conf
@@ -1,5 +1,5 @@
# Timeout in seconds that Limine will use before automatically booting.
-timeout: 3
+timeout: 2
# The entry name that will be displayed in the boot menu.
/Orange