diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | compile_flags.txt | 2 | ||||
| -rw-r--r-- | dev/kernel/FSKit/HeFS.h | 7 | ||||
| -rw-r--r-- | dev/kernel/src/FS/HeFS.cc | 72 | ||||
| -rw-r--r-- | tooling/dist/.keep | 0 | ||||
| -rw-r--r-- | tooling/hefs.h | 161 | ||||
| -rw-r--r-- | tooling/mkfs.hefs.cc | 165 | ||||
| -rw-r--r-- | tooling/mkfs.hefs.json | 16 |
8 files changed, 389 insertions, 36 deletions
@@ -19,6 +19,8 @@ public/frameworks/*/dist/* neoskrnl/neoskrnl.xcodeproj/project.xcworkspace/xcshareddata/ +tooling/dist/mkfs.hefs + html/ latex/ diff --git a/compile_flags.txt b/compile_flags.txt index cef28da1..be8085bd 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -13,6 +13,8 @@ -Ipublic/tools/open -Ipublic/frameworks -Idev/boot/BootKit +-Itooling/ +-I./ -std=c++20 -D__NE_AMD64__ -D__NEOSKRNL__ diff --git a/dev/kernel/FSKit/HeFS.h b/dev/kernel/FSKit/HeFS.h index 693ec2d3..a2dd9fe0 100644 --- a/dev/kernel/FSKit/HeFS.h +++ b/dev/kernel/FSKit/HeFS.h @@ -29,7 +29,10 @@ #define kHeFSDefaultVoluneName u"HeFS Volume"
#define kHeFSDIMBootDir u"boot-x/dir"
-#define kHeFSDIMBootFile u"boot-x/file"
+#define kHeFSMIMEBootFile u"boot-x/file"
+
+#define kHeFSDIMSystemDir u"system-x/dir"
+#define kHeFSMIMESystemFile u"system-x/file"
#define kHeFSSearchAllStr u"*"
@@ -123,7 +126,7 @@ struct PACKED HEFS_BOOT_NODE final { };
inline constexpr Kernel::ATime kHeFSTimeInvalid = 0x0000000000000000;
-inline constexpr Kernel::ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF;
+inline constexpr Kernel::ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1;
/// @brief HeFS index node.
/// @details This structure is used to store the file information of a file.
diff --git a/dev/kernel/src/FS/HeFS.cc b/dev/kernel/src/FS/HeFS.cc index 81316ba5..13d79c8f 100644 --- a/dev/kernel/src/FS/HeFS.cc +++ b/dev/kernel/src/FS/HeFS.cc @@ -78,29 +78,20 @@ namespace Detail { hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, HEFS_BOOT_NODE* node, Lba& start) { NE_UNUSED(node); - if (!dir) { - ke_panic(RUNTIME_CHECK_FILESYSTEM, "Error: Invalid directory node in RB-Tree traversal.\r"); + if (!dir || !node) { + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Error: Invalid directory node/boot_node in RB-Tree traversal."); } - start = dir->fNext; - - if (dir->fColor == kHeFSBlack && start == 0) { - if (dir->fParent != 0) start = dir->fParent; - } else if (dir->fColor == kHeFSRed && start == 0) { - if (dir->fChild != 0) - start = dir->fChild; - else if (dir->fNext != 0) - start = dir->fNext; - else if (dir->fPrev != 0) - start = dir->fPrev; - else - start = dir->fParent; - } - - if (start == 0) { - ke_panic(RUNTIME_CHECK_FILESYSTEM, "Error: Invalid start value in RB-Tree traversal.\r"); - - return; + if (dir->fChild != 0) { + start = dir->fChild; + } else if (dir->fNext != 0) { + start = dir->fNext; + } else if (dir->fParent != 0) { + start = dir->fParent; + } else if (dir->fPrev != 0) { + start = dir->fPrev; + } else { + start = node->fStartIND; } } @@ -324,13 +315,16 @@ namespace Detail { return NO; } - if (parent->fDeleted) { + if (parent->fDeleted || + !parent->fCreated) { mnt->fPacket.fPacketLba = start; mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); mnt->fPacket.fPacketContent = dir; mnt->fOutput(mnt->fPacket); + hefsi_balance_filesystem(root, mnt); + return YES; } @@ -866,14 +860,14 @@ _Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* drive, _Input wrt_copy_memory((VoidPtr) u"/", root_dir->fName, wrt_string_len(u"/")); wrt_copy_memory((VoidPtr) kHeFSDIMBootDir, root_dir->fDim, wrt_string_len(kHeFSDIMBootDir)); - root_dir->fKind = kHeFSFileKindDirectory; - root_dir->fColor = kHeFSBlack; // Every RB-Tree root starts black. (a condition of the algorithm) - root_dir->fParent = 0; // No parent (it's the real root) - root_dir->fChild = 0; // No children yet - root_dir->fNext = 0; // No next - root_dir->fPrev = 0; // No previous + root_dir->fKind = kHeFSFileKindDirectory; + root_dir->fColor = kHeFSBlack; // Every RB-Tree root starts black. (a condition of the algorithm) + root_dir->fParent = root->fStartIND; // No parent (it's the real root) + root_dir->fChild = root->fEndIND; // No children yet + root_dir->fNext = 0; // No next + root_dir->fPrev = 0; // No previous - root_dir->fEntryCount = 0; + root_dir->fEntryCount = 1; drive->fPacket.fPacketLba = drive->fLbaStart + sizeof(HEFS_BOOT_NODE) + sizeof(HEFS_BOOT_NODE); drive->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); @@ -881,6 +875,8 @@ _Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* drive, _Input drive->fOutput(drive->fPacket); + Detail::hefsi_balance_filesystem(root, drive); + delete root_dir; delete root; @@ -942,6 +938,8 @@ _Output Bool HeFileSystemParser::CreateDirectory(_Input DriveTrait* drive, _Inpu drive->fInput(drive->fPacket); + Detail::hefsi_balance_filesystem(root, drive); + auto dirent = Detail::hefs_fetch_index_node_directory(root, drive, dir); if (dirent) { @@ -963,20 +961,22 @@ _Output Bool HeFileSystemParser::CreateDirectory(_Input DriveTrait* drive, _Inpu wrt_copy_memory((VoidPtr) dir, dirent->fName, wrt_string_len(dir)); dirent->fAccessed = 0; - dirent->fCreated = 0; + dirent->fCreated = 0; /// TODO: Add the current time. dirent->fDeleted = 0; dirent->fModified = 0; dirent->fEntryCount = 0; - dirent->fParent = 0; // No parent (it's the real root) - dirent->fChild = 0; // No children yet - dirent->fNext = 0; // No next - dirent->fPrev = 0; // No previous + dirent->fParent = root->fStartIND; // No parent (it's the real root) + dirent->fChild = root->fEndIND; // No children yet + dirent->fNext = 0; // No next + dirent->fPrev = 0; // No previous dirent->fKind = kHeFSFileKindDirectory; dirent->fFlags = flags; dirent->fChecksum = 0; + dirent->fEntryCount = 1; + if (Detail::hefs_allocate_index_directory_node(root, drive, dirent)) { delete dirent; dirent = nullptr; @@ -1033,6 +1033,8 @@ _Output Bool HeFileSystemParser::CreateFile(_Input DriveTrait* drive, _Input con drive->fInput(drive->fPacket); + Detail::hefsi_balance_filesystem(root, drive); + auto dirent = Detail::hefs_fetch_index_node_directory(root, drive, dir); if (!dirent) { @@ -1077,6 +1079,8 @@ _Output Bool HeFileSystemParser::CreateFile(_Input DriveTrait* drive, _Input con return NO; } +/// @brief Initialize the HeFS filesystem. +/// @return To check its status, see err_local_get(). Boolean fs_init_hefs(Void) noexcept { kout << "Creating main disk with HeFS in it...\r"; diff --git a/tooling/dist/.keep b/tooling/dist/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tooling/dist/.keep diff --git a/tooling/hefs.h b/tooling/hefs.h new file mode 100644 index 00000000..a85cb2bc --- /dev/null +++ b/tooling/hefs.h @@ -0,0 +1,161 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <cstdint> +#include <cstring> + +#define kHeFSVersion (0x0101) +#define kHeFSMagic " HeFS" +#define kHeFSMagicLen (8) + +#define kHeFSFileNameLen (256U) +#define kHeFSPartNameLen (128U) + +#define kHeFSMinimumDiskSize (gib_cast(4)) + +#define kHeFSDefaultVoluneName u"HeFS Volume" + +#define kHeFSDIMBootDir u"boot-x/dir" +#define kHeFSMIMEBootFile u"boot-x/file" + +#define kHeFSDIMSystemDir u"system-x/dir" +#define kHeFSMIMESystemFile u"system-x/file" + +#define kHeFSSearchAllStr u"*" + +namespace mkfs::hefs { +enum { + kHeFSHardDrive = 0xC0, // Hard Drive + kHeFSSolidStateDrive = 0xC1, // Solid State Drive + kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD + kHeFSMassStorageDevice = 0xCC, // USB + kHeFSScsiDrive = 0xC4, // SCSI Hard Drive + kHeFSFlashDrive = 0xC6, + kHeFSUnknown = 0xFF, // Unknown device. + kHeFSDriveCount = 7, +}; + +enum { + kHeFSStatusUnlocked = 0x18, + kHeFSStatusLocked, + kHeFSStatusError, + kHeFSStatusInvalid, + kHeFSStatusCount, +}; + +enum { + kHeFSEncodingUTF8 = 0x00, + kHeFSEncodingUTF16, + kHeFSEncodingUTF32, + kHeFSEncodingUTF16BE, + kHeFSEncodingUTF16LE, + kHeFSEncodingUTF32BE, + kHeFSEncodingUTF32LE, + kHeFSEncodingUTF8BE, + kHeFSEncodingUTF8LE, + kHeFSEncodingBinary, + kHeFSEncodingCount, +}; + +// Constants +constexpr std::size_t kHeFSBlockCount = 16; + +// Types +using ATime = std::uint64_t; + +inline constexpr uint16_t kHeFSFileKindRegular = 0x00; +inline constexpr uint16_t kHeFSFileKindDirectory = 0x01; +inline constexpr uint16_t kHeFSFileKindBlock = 0x02; +inline constexpr uint16_t kHeFSFileKindCharacter = 0x03; +inline constexpr uint16_t kHeFSFileKindFIFO = 0x04; +inline constexpr uint16_t kHeFSFileKindSocket = 0x05; +inline constexpr uint16_t kHeFSFileKindSymbolicLink = 0x06; +inline constexpr uint16_t kHeFSFileKindUnknown = 0x07; +inline constexpr uint16_t kHeFSFileKindCount = 0x08; + +// Basic Time Constants +inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; +inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; + +// Boot Node (Superblock Equivalent) +struct alignas(8) BootNode { + char magic[kHeFSMagicLen]{}; + char16_t volumeName[kHeFSPartNameLen]{}; + std::uint32_t version{}; + std::uint64_t badSectors{}; + std::uint64_t sectorCount{}; + std::uint64_t sectorSize{}; + std::uint32_t checksum{}; + std::uint8_t diskKind{}; + std::uint8_t encoding{}; + std::uint64_t startIND{}; + std::uint64_t endIND{}; + std::uint64_t indCount{}; + std::uint64_t diskSize{}; + std::uint16_t diskStatus{}; + std::uint16_t diskFlags{}; + std::uint16_t vid{}; + std::uint64_t reserved{}; + std::uint64_t reserved2{}; + std::uint64_t reserved3{}; + std::uint64_t reserved4{}; +}; + +// File Node (Index Node) +struct alignas(8) IndexNode { + char16_t name[kHeFSFileNameLen]{}; + std::uint32_t flags{}; + std::uint16_t kind{}; + std::uint32_t size{}; + std::uint32_t checksum{}; + std::uint32_t recoverChecksum{}; + std::uint32_t blockChecksum{}; + std::uint32_t linkChecksum{}; + char16_t mime[kHeFSFileNameLen]{}; + bool symbolicLink{false}; + ATime created{}; + ATime accessed{}; + ATime modified{}; + ATime deleted{}; + std::uint32_t uid{}; + std::uint32_t gid{}; + std::uint32_t mode{}; + std::uint64_t blockLinkStart[kHeFSBlockCount]{}; + std::uint64_t blockLinkEnd[kHeFSBlockCount]{}; + std::uint64_t blockStart[kHeFSBlockCount]{}; + std::uint64_t blockEnd[kHeFSBlockCount]{}; + std::uint64_t blockRecoveryStart[kHeFSBlockCount]{}; + std::uint64_t blockRecoveryEnd[kHeFSBlockCount]{}; +}; + +// Directory Node (Red-Black Tree Node) +struct alignas(8) IndexNodeDirectory { + char16_t name[kHeFSFileNameLen]{}; + std::uint32_t flags{}; + std::uint16_t kind{}; + std::uint32_t entryCount{}; + std::uint32_t checksum{}; + std::uint32_t indexNodeChecksum{}; + char16_t dim[kHeFSFileNameLen]{}; + ATime created{}; + ATime accessed{}; + ATime modified{}; + ATime deleted{}; + std::uint32_t uid{}; + std::uint32_t gid{}; + std::uint32_t mode{}; + std::uint64_t indexNodeStart[kHeFSBlockCount]{}; + std::uint64_t indexNodeEnd[kHeFSBlockCount]{}; + std::uint8_t color{}; + std::uint64_t next{}; + std::uint64_t prev{}; + std::uint64_t child{}; + std::uint64_t parent{}; +}; + +} // namespace mkfs::hefs diff --git a/tooling/mkfs.hefs.cc b/tooling/mkfs.hefs.cc new file mode 100644 index 00000000..15b18a8a --- /dev/null +++ b/tooling/mkfs.hefs.cc @@ -0,0 +1,165 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <tooling/hefs.h> +#include <cstdlib> +#include <fstream> +#include <iostream> +#include <string> + +/// @internal +namespace detail { +/// @brief Helper function to get the option value from command line arguments. +template <typename CharType> +static std::basic_string<CharType> get_option(const std::basic_string<CharType>& args, + const std::basic_string<CharType>& option) { + size_t pos = args.find(option + CharType('=')); + + if (pos != std::string::npos) { + size_t start = pos + option.length() + 1; + size_t end = args.find(' ', start); + return args.substr(start, end - start); + } + + return std::basic_string<CharType>{}; +} +} // namespace detail + +static size_t kDiskSize = 1024 * 1024 * 1024 * 4UL; +static uint16_t kVersion = kHeFSVersion; +static std::u16string kLabel = kHeFSDefaultVoluneName; +static size_t kSectorSize = 512; + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "mkfs.hefs: Error: Missing required arguments." << std::endl; + std::cerr << "mkfs.hefs: Usage: mkfs.hefs -L <label> -s <sector_size> -p <part_start> -e " + "<part_end> -S <disk_size> -o <output_device>" + << std::endl; + return 1; + } + + std::string args; + std::u16string args_wide; + + for (int i = 1; i < argc; ++i) { + args += argv[i]; + args += " "; + + + std::string str = argv[i]; + + for (auto& ch : str) + { + args_wide.push_back(ch); + } + + args_wide += u" "; + } + + auto output_device = detail::get_option<char>(args, "-o"); + + kSectorSize = std::strtol(detail::get_option<char>(args, "-s").data(), nullptr, 10); + kLabel = detail::get_option<char16_t>(args_wide, u"-L"); + + if (kLabel.empty()) + kLabel = kHeFSDefaultVoluneName; + + kDiskSize = + std::strtol(detail::get_option<char>(args, "-S").data(), nullptr, 10) * 1024 * 1024 * 1024; + + if (kDiskSize == 0) { + std::cerr << "mkfs.hefs: Error: Invalid size specified." << std::endl; + return EXIT_FAILURE; + } + + // Open the output_device + std::ofstream filesystem(output_device, std::ios::binary); + + if (!filesystem.good()) { + std::cerr << "mkfs.hefs: Error: Unable to open output_device " << output_device << std::endl; + return EXIT_FAILURE; + } + + // create a boot node, and then allocate a index node directory tree. + mkfs::hefs::BootNode bootNode{{}, {}, 0, 0, 0, 0, 0, 0, 0, 0}; + + auto start_ind = std::strtol(detail::get_option<char>(args, "-p").data(), nullptr, 10); + start_ind += sizeof(mkfs::hefs::BootNode); + + auto end_ind = std::strtol(detail::get_option<char>(args, "-e").data(), nullptr, 10); + + bootNode.version = kVersion; + bootNode.diskKind = mkfs::hefs::kHeFSHardDrive; + bootNode.encoding = mkfs::hefs::kHeFSEncodingUTF16; + bootNode.diskSize = kDiskSize; + bootNode.sectorSize = kSectorSize; + bootNode.startIND = start_ind; + bootNode.endIND = end_ind; + bootNode.diskStatus = mkfs::hefs::kHeFSStatusUnlocked; + + std::memcpy(bootNode.magic, kHeFSMagic, kHeFSMagicLen); + std::memcpy(bootNode.volumeName, kLabel.data(), kLabel.size() * sizeof(char16_t)); + + filesystem.seekp(std::strtol(detail::get_option<char>(args, "-p").data(), nullptr, 10)); + filesystem.write(reinterpret_cast<const char*>(&bootNode), sizeof(mkfs::hefs::BootNode)); + + if (!filesystem.good()) { + std::cerr << "mkfs.hefs: Error: Unable to write to output_device " << output_device + << std::endl; + return 1; + } + + filesystem.seekp(bootNode.startIND); + + auto cnt = end_ind / sizeof(mkfs::hefs::IndexNodeDirectory); + + // Pre-allocate index node directory tree + for (size_t i = 0; i < cnt; ++i) { + mkfs::hefs::IndexNodeDirectory indexNode{}; + + std::memcpy(indexNode.name, u"$UNALLOCATED$", std::u16string(u"$UNALLOCATED$").size() * sizeof(char16_t)); + + indexNode.flags = 0; + indexNode.kind = mkfs::hefs::kHeFSFileKindDirectory; + indexNode.deleted = mkfs::hefs::kHeFSTimeMax; + + indexNode.entryCount = 1; + + indexNode.checksum = 0; + indexNode.indexNodeChecksum = 0; + + indexNode.uid = 0; + indexNode.gid = 0; + indexNode.mode = 0; + indexNode.color = 0; + indexNode.next = 0; + indexNode.prev = 0; + indexNode.child = 0; + + indexNode.parent = bootNode.startIND; + indexNode.child = bootNode.endIND; + + indexNode.next = 0; + indexNode.prev = 0; + + filesystem.write(reinterpret_cast<const char*>(&indexNode), + sizeof(mkfs::hefs::IndexNodeDirectory)); + + if (!filesystem.good()) { + std::cerr << "mkfs.hefs: Error: Unable to write index node to output_device " << output_device + << std::endl; + return 1; + } + } + + filesystem.flush(); + filesystem.close(); + + std::cout << "mkfs.hefs: HeFS filesystem created on " << output_device << std::endl; + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/tooling/mkfs.hefs.json b/tooling/mkfs.hefs.json new file mode 100644 index 00000000..d29b7f73 --- /dev/null +++ b/tooling/mkfs.hefs.json @@ -0,0 +1,16 @@ +{ + "compiler_path": "g++", + "compiler_std": "c++20", + "headers_path": [ + "../" + ], + "sources_path": [ + "mkfs.hefs.cc" + ], + "output_name": "./dist/mkfs.hefs", + "cpp_macros": [ + "kMKFSHEFSVersion=0x0100", + "kMKFSHEFSVersionHighest=0x0100", + "kMKFSHEFSVersionLowest=0x0100" + ] +}
\ No newline at end of file |
