summaryrefslogtreecommitdiffhomepage
path: root/src/kernel/KernelKit/FileMgr.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/KernelKit/FileMgr.h')
-rw-r--r--src/kernel/KernelKit/FileMgr.h445
1 files changed, 445 insertions, 0 deletions
diff --git a/src/kernel/KernelKit/FileMgr.h b/src/kernel/KernelKit/FileMgr.h
new file mode 100644
index 00000000..93d5f580
--- /dev/null
+++ b/src/kernel/KernelKit/FileMgr.h
@@ -0,0 +1,445 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss , licensed under the Apache 2.0 license.
+
+ File: FileMgr.h
+ Purpose: Kernel file manager.
+ Author: Amlal El Mahrouss (amlal@nekernel.org)
+
+======================================== */
+
+/* ========================================
+
+ Revision History:
+
+ 31/01/24: Update documentation (amlel)
+ 05/07/24: NeFS support, and fork support, updated constants and specs
+ as well.
+ 18/01/25: Patches to FileStream class.
+
+ ======================================== */
+
+#ifndef INC_FILEMGR_H
+#define INC_FILEMGR_H
+
+/// @file FileMgr.h
+/// @brief File Manager System.
+/// @author Amlal El Mahrouss (amlal@nekernel.org)
+
+//! Include filesystems that NeKernel supports.
+#include <FSKit/Ext2+IFS.h>
+#include <FSKit/NeFS.h>
+#include <FSKit/OpenHeFS.h>
+
+#include <CompilerKit/CompilerKit.h>
+#include <KernelKit/DebugOutput.h>
+#include <KernelKit/HeapMgr.h>
+#include <KernelKit/KPC.h>
+#include <NeKit/ErrorOr.h>
+#include <NeKit/Ref.h>
+#include <NeKit/Stream.h>
+#include <hint/CompilerHint.h>
+
+/// @brief Filesystem manager, abstraction over mounted filesystem.
+/// Works like an VFS (Virtual File System) or IFS subsystem on NT/OS 2.
+
+#define kRestrictR "r"
+#define kRestrictRB "rb"
+#define kRestrictW "w"
+#define kRestrictWR "rw"
+#define kRestrictWRB "rwb"
+
+#define kRestrictMax (5U)
+
+#define rtl_node_cast(PTR) reinterpret_cast<Kernel::NodePtr>(PTR)
+
+#define kFileMimeGeneric "ne-application-kind/all"
+
+/** @brief invalid position. (n-pos) */
+#define kFileMgrNPos (~0UL)
+
+namespace Kernel {
+enum {
+ kFileIOInvalid = 0,
+ kFileWriteAll = 100,
+ kFileReadAll = 101,
+ kFileReadChunk = 102,
+ kFileWriteChunk = 103,
+ // File flags (HFS+, NeFS specific)
+ kFileFlagRsrc = 104,
+ kFileFlagData = 105,
+ kFileIOCnt = (kFileFlagData - kFileWriteAll) + 1,
+};
+
+using NodePtr = VoidPtr;
+
+/**
+@brief Filesystem Mgr Interface class
+@brief Used to provide common I/O for a specific filesystem.
+*/
+class IFilesystemMgr {
+ public:
+ explicit IFilesystemMgr() = default;
+ virtual ~IFilesystemMgr() = default;
+
+ public:
+ NE_COPY_DEFAULT(IFilesystemMgr)
+
+ public:
+ /// @brief Mounts a new filesystem into an active state.
+ /// @param interface the filesystem interface
+ /// @return
+ static bool Mount(IFilesystemMgr* interface);
+
+ /// @brief Unmounts the active filesystem
+ /// @return
+ static IFilesystemMgr* Unmount();
+
+ /// @brief Getter, gets the active filesystem.
+ /// @return
+ static IFilesystemMgr* GetMounted();
+
+ public:
+ virtual NodePtr Create(_Input const Char* path) = 0;
+ virtual NodePtr CreateAlias(_Input const Char* path) = 0;
+ virtual NodePtr CreateDirectory(_Input const Char* path) = 0;
+ virtual NodePtr CreateSwapFile(const Char* path) = 0;
+
+ public:
+ virtual bool Remove(_Input const Char* path) = 0;
+
+ public:
+ virtual NodePtr Open(_Input const Char* path, _Input const Char* r) = 0;
+
+ public:
+ virtual Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT size) = 0;
+
+ virtual _Output VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) = 0;
+
+ virtual Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data,
+ _Input Int32 flags, _Input SizeT size) = 0;
+
+ virtual _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags,
+ _Input SizeT sz) = 0;
+
+ public:
+ virtual bool Seek(_Input NodePtr node, _Input SizeT off) = 0;
+
+ public:
+ virtual SizeT Tell(_Input NodePtr node) = 0;
+ virtual bool Rewind(_Input NodePtr node) = 0;
+};
+
+#ifdef __FSKIT_INCLUDES_NEFS__
+/**
+ * @brief Based of IFilesystemMgr, takes care of managing NeFS
+ * disks.
+ */
+class NeFileSystemMgr final : public IFilesystemMgr {
+ public:
+ explicit NeFileSystemMgr();
+ ~NeFileSystemMgr() override;
+
+ public:
+ NE_COPY_DEFAULT(NeFileSystemMgr)
+
+ public:
+ NodePtr Create(const Char* path) override;
+ NodePtr CreateAlias(const Char* path) override;
+ NodePtr CreateDirectory(const Char* path) override;
+ NodePtr CreateSwapFile(const Char* path) override;
+
+ public:
+ bool Remove(_Input const Char* path) override;
+ NodePtr Open(_Input const Char* path, _Input const Char* r) override;
+ Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT sz) override;
+ VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override;
+ bool Seek(_Input NodePtr node, _Input SizeT off) override;
+ SizeT Tell(_Input NodePtr node) override;
+ bool Rewind(_Input NodePtr node) override;
+
+ Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT size) override;
+
+ _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags,
+ _Input SizeT sz) override;
+
+ public:
+ /// @brief Get NeFS parser class.
+ /// @return The filesystem parser class.
+ NeFileSystemParser* GetParser() noexcept;
+
+ private:
+ NeFileSystemParser* mParser{nullptr};
+};
+
+#endif // ifdef __FSKIT_INCLUDES_NEFS__
+
+#ifdef __FSKIT_INCLUDES_EXT2__
+/**
+ * @brief Based of IFilesystemMgr, takes care of managing NeFS
+ * disks.
+ */
+class Ext2FileSystemMgr final : public IFilesystemMgr {
+ public:
+ explicit Ext2FileSystemMgr();
+ ~Ext2FileSystemMgr() override;
+
+ public:
+ NE_COPY_DEFAULT(Ext2FileSystemMgr)
+
+ public:
+ NodePtr Create(const Char* path) override;
+ NodePtr CreateAlias(const Char* path) override;
+ NodePtr CreateDirectory(const Char* path) override;
+ NodePtr CreateSwapFile(const Char* path) override;
+
+ public:
+ bool Remove(_Input const Char* path) override;
+ NodePtr Open(_Input const Char* path, _Input const Char* r) override;
+ Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT sz) override;
+ VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override;
+ bool Seek(_Input NodePtr node, _Input SizeT off) override;
+ SizeT Tell(_Input NodePtr node) override;
+ bool Rewind(_Input NodePtr node) override;
+
+ Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT size) override;
+
+ _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags,
+ _Input SizeT sz) override;
+
+ public:
+ /// @brief Get NeFS parser class.
+ /// @return The filesystem parser class.
+ Ext2FileSystemParser* GetParser() noexcept;
+
+ private:
+ Ext2FileSystemParser* mParser{nullptr};
+};
+
+#endif // ifdef __FSKIT_INCLUDES_EXT2__
+
+#ifdef __FSKIT_INCLUDES_OPENHEFS__
+/**
+ * @brief Based of IFilesystemMgr, takes care of managing NeFS
+ * disks.
+ */
+class HeFileSystemMgr final : public IFilesystemMgr {
+ public:
+ explicit HeFileSystemMgr();
+ ~HeFileSystemMgr() override;
+
+ public:
+ NE_COPY_DEFAULT(HeFileSystemMgr)
+
+ public:
+ NodePtr Create(const Char* path) override;
+ NodePtr CreateAlias(const Char* path) override;
+ NodePtr CreateDirectory(const Char* path) override;
+ NodePtr CreateSwapFile(const Char* path) override;
+
+ public:
+ bool Remove(_Input const Char* path) override;
+ NodePtr Open(_Input const Char* path, _Input const Char* r) override;
+ Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT sz) override;
+ VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override;
+ bool Seek(_Input NodePtr node, _Input SizeT off) override;
+ SizeT Tell(_Input NodePtr node) override;
+ bool Rewind(_Input NodePtr node) override;
+
+ Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, _Input Int32 flags,
+ _Input SizeT size) override;
+
+ _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags,
+ _Input SizeT sz) override;
+
+ public:
+ /// @brief Get NeFS parser class.
+ /// @return The filesystem parser class.
+ HeFileSystemParser* GetParser() noexcept;
+
+ private:
+ HeFileSystemParser* mParser{nullptr};
+};
+
+#endif // ifdef __FSKIT_INCLUDES_OPENHEFS__
+
+/**
+ * FileStream class.
+ * @tparam Encoding file encoding (char, wchar_t...)
+ * @tparam FSClass Filesystem contract who takes care of it.
+ */
+template <typename Encoding = Char, typename FSClass = IFilesystemMgr>
+class FileStream final {
+ public:
+ explicit FileStream(const Encoding* path, const Encoding* restrict_type);
+ ~FileStream();
+
+ public:
+ FileStream& operator=(const FileStream&);
+ FileStream(const FileStream&);
+
+ public:
+ ErrorOr<Int64> Write(SizeT offset, const VoidPtr data, SizeT len) noexcept {
+ if (this->fFileRestrict != kFileMgrRestrictReadWrite &&
+ this->fFileRestrict != kFileMgrRestrictReadWriteBinary &&
+ this->fFileRestrict != kFileMgrRestrictWrite &&
+ this->fFileRestrict != kFileMgrRestrictWriteBinary)
+ return ErrorOr<Int64>(kErrorInvalidData);
+
+ if (data == nullptr) return ErrorOr<Int64>(kErrorInvalidData);
+
+ auto man = FSClass::GetMounted();
+
+ if (man) {
+ man->Write(offset, fFile, data, len);
+ return ErrorOr<Int64>(kErrorSuccess);
+ }
+
+ return ErrorOr<Int64>(kErrorInvalidData);
+ }
+
+ ErrorOr<Int64> Write(const Char* name, const VoidPtr data, SizeT len) noexcept {
+ if (this->fFileRestrict != kFileMgrRestrictReadWrite &&
+ this->fFileRestrict != kFileMgrRestrictReadWriteBinary &&
+ this->fFileRestrict != kFileMgrRestrictWrite &&
+ this->fFileRestrict != kFileMgrRestrictWriteBinary)
+ return ErrorOr<Int64>(kErrorInvalidData);
+
+ if (data == nullptr) return ErrorOr<Int64>(kErrorInvalidData);
+
+ auto man = FSClass::GetMounted();
+
+ if (man) {
+ man->Write(name, fFile, data, 0, len);
+ return ErrorOr<Int64>(kErrorSuccess);
+ }
+
+ return ErrorOr<Int64>(kErrorInvalidData);
+ }
+
+ VoidPtr Read(const Char* name, SizeT sz) noexcept {
+ if (this->fFileRestrict != kFileMgrRestrictReadWrite &&
+ this->fFileRestrict != kFileMgrRestrictReadWriteBinary &&
+ this->fFileRestrict != kFileMgrRestrictRead &&
+ this->fFileRestrict != kFileMgrRestrictReadBinary)
+ return nullptr;
+
+ auto man = FSClass::GetMounted();
+
+ if (man) {
+ VoidPtr ret = man->Read(name, fFile, kFileReadAll, sz);
+ return ret;
+ }
+
+ return nullptr;
+ }
+
+ VoidPtr Read(SizeT offset, SizeT sz) {
+ if (this->fFileRestrict != kFileMgrRestrictReadWrite &&
+ this->fFileRestrict != kFileMgrRestrictReadWriteBinary &&
+ this->fFileRestrict != kFileMgrRestrictRead &&
+ this->fFileRestrict != kFileMgrRestrictReadBinary)
+ return nullptr;
+
+ auto man = FSClass::GetMounted();
+
+ if (man) {
+ man->Seek(fFile, offset);
+ auto ret = man->Read(fFile, kFileReadChunk, sz);
+
+ return ret;
+ }
+
+ return nullptr;
+ }
+
+ public:
+ /// @brief Leak node pointer.
+ /// @return The node pointer.
+ NodePtr Leak() { return fFile; }
+
+ /// @brief Leak MIME.
+ /// @return The MIME.
+ Char* MIME() noexcept { return const_cast<Char*>(fMime); }
+
+ enum {
+ kFileMgrRestrictRead = 100,
+ kFileMgrRestrictReadBinary,
+ kFileMgrRestrictWrite,
+ kFileMgrRestrictWriteBinary,
+ kFileMgrRestrictReadWrite,
+ kFileMgrRestrictReadWriteBinary,
+ };
+
+ private:
+ NodePtr fFile{nullptr};
+ Int32 fFileRestrict{kFileMgrRestrictReadBinary};
+ const Char* fMime{kFileMimeGeneric};
+};
+
+using FileStreamASCII = FileStream<Char>;
+using FileStreamUTF8 = FileStream<Utf8Char>;
+using FileStreamUTF16 = FileStream<WideChar>;
+
+typedef UInt64 CursorType;
+
+inline STATIC const auto kRestrictStrLen = 8U;
+
+/// @brief restrict information about the file descriptor.
+struct FILEMGR_RESTRICT final {
+ Char fRestrict[kRestrictStrLen];
+ Int32 fMappedTo;
+};
+
+/// @brief constructor
+template <typename Encoding, typename Class>
+inline FileStream<Encoding, Class>::FileStream(const Encoding* path, const Encoding* restrict_type)
+ : fFile(Class::GetMounted()->Open(path, restrict_type)) {
+ SizeT kRestrictCount = kRestrictMax;
+ const FILEMGR_RESTRICT kRestrictList[] = {{
+ .fRestrict = kRestrictR,
+ .fMappedTo = kFileMgrRestrictRead,
+ },
+ {
+ .fRestrict = kRestrictRB,
+ .fMappedTo = kFileMgrRestrictReadBinary,
+ },
+ {
+ .fRestrict = kRestrictWRB,
+ .fMappedTo = kFileMgrRestrictReadWriteBinary,
+ },
+ {
+ .fRestrict = kRestrictW,
+ .fMappedTo = kFileMgrRestrictWrite,
+ },
+ {
+ .fRestrict = kRestrictWR,
+ .fMappedTo = kFileMgrRestrictReadWrite,
+ }};
+
+ for (SizeT index = 0; index < kRestrictCount; ++index) {
+ if (rt_string_cmp(restrict_type, kRestrictList[index].fRestrict,
+ rt_string_len(kRestrictList[index].fRestrict)) == 0) {
+ fFileRestrict = kRestrictList[index].fMappedTo;
+ break;
+ }
+ }
+
+ kout << "FileMgr: Open file at: " << path << ".\r";
+}
+
+/// @brief destructor of the file stream.
+template <typename Encoding, typename Class>
+inline FileStream<Encoding, Class>::~FileStream() {
+ mm_free_ptr(fFile);
+ fFile = nullptr;
+}
+} // namespace Kernel
+
+#endif // ifndef INC_FILEMGR_H