diff options
Diffstat (limited to 'src/kernel/KernelKit/FileMgr.h')
| -rw-r--r-- | src/kernel/KernelKit/FileMgr.h | 445 |
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 |
