forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -28,6 +28,8 @@ set(KERNEL_SOURCES
 | 
			
		|||
	kernel/FS/ProcFS/Inode.cpp
 | 
			
		||||
	kernel/FS/RamFS/FileSystem.cpp
 | 
			
		||||
	kernel/FS/RamFS/Inode.cpp
 | 
			
		||||
	kernel/FS/TmpFS/FileSystem.cpp
 | 
			
		||||
	kernel/FS/TmpFS/Inode.cpp
 | 
			
		||||
	kernel/FS/VirtualFileSystem.cpp
 | 
			
		||||
	kernel/Input/PS2Controller.cpp
 | 
			
		||||
	kernel/Input/PS2Keyboard.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/Array.h>
 | 
			
		||||
#include <kernel/Memory/Types.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	struct TmpInodeInfo
 | 
			
		||||
	{
 | 
			
		||||
		mode_t		mode	{ 0 };
 | 
			
		||||
		uid_t		uid		{ 0 };
 | 
			
		||||
		gid_t		gid		{ 0 };
 | 
			
		||||
		timespec	atime	{ 0 };
 | 
			
		||||
		timespec	ctime	{ 0 };
 | 
			
		||||
		timespec	mtime	{ 0 };
 | 
			
		||||
		nlink_t		nlink	{ 0 };
 | 
			
		||||
		size_t		size	{ 0 };
 | 
			
		||||
		blkcnt_t	blocks	{ 0 };
 | 
			
		||||
 | 
			
		||||
		// 2x direct blocks
 | 
			
		||||
		// 1x singly indirect
 | 
			
		||||
		// 1x doubly indirect
 | 
			
		||||
		// 1x triply indirect
 | 
			
		||||
		BAN::Array<paddr_t, 5> block;
 | 
			
		||||
		static constexpr size_t direct_block_count = 2;
 | 
			
		||||
		static constexpr size_t max_size =
 | 
			
		||||
			direct_block_count * PAGE_SIZE +
 | 
			
		||||
			(PAGE_SIZE / sizeof(paddr_t)) * PAGE_SIZE +
 | 
			
		||||
			(PAGE_SIZE / sizeof(paddr_t)) * (PAGE_SIZE / sizeof(paddr_t)) * PAGE_SIZE +
 | 
			
		||||
			(PAGE_SIZE / sizeof(paddr_t)) * (PAGE_SIZE / sizeof(paddr_t)) * (PAGE_SIZE / sizeof(paddr_t)) * PAGE_SIZE;
 | 
			
		||||
	};
 | 
			
		||||
	static_assert(sizeof(TmpInodeInfo) == 128);
 | 
			
		||||
 | 
			
		||||
	struct TmpDirectoryEntry
 | 
			
		||||
	{
 | 
			
		||||
		ino_t	ino;
 | 
			
		||||
		uint8_t	type;
 | 
			
		||||
		size_t	name_len;
 | 
			
		||||
		size_t	rec_len;
 | 
			
		||||
		char	name[];
 | 
			
		||||
 | 
			
		||||
		BAN::StringView name_sv() const
 | 
			
		||||
		{
 | 
			
		||||
			ASSERT(type != DT_UNKNOWN);
 | 
			
		||||
			return BAN::StringView(name, name_len);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,119 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/HashMap.h>
 | 
			
		||||
#include <BAN/Iteration.h>
 | 
			
		||||
#include <kernel/FS/FileSystem.h>
 | 
			
		||||
#include <kernel/FS/TmpFS/Inode.h>
 | 
			
		||||
#include <kernel/SpinLock.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	template<typename F>
 | 
			
		||||
	concept for_each_indirect_paddr_allocating_callback = requires(F func, paddr_t paddr, bool was_allocated)
 | 
			
		||||
	{
 | 
			
		||||
		requires BAN::is_same_v<decltype(func(paddr, was_allocated)), BAN::Iteration>;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class TmpFileSystem : public FileSystem
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static constexpr size_t no_page_limit = SIZE_MAX;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<TmpFileSystem*> create(size_t max_pages, mode_t, uid_t, gid_t);
 | 
			
		||||
		~TmpFileSystem();
 | 
			
		||||
 | 
			
		||||
		virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino);
 | 
			
		||||
 | 
			
		||||
		void read_inode(ino_t ino, TmpInodeInfo& out);
 | 
			
		||||
		void write_inode(ino_t ino, const TmpInodeInfo&);
 | 
			
		||||
		void delete_inode(ino_t ino);
 | 
			
		||||
		BAN::ErrorOr<ino_t> allocate_inode(const TmpInodeInfo&);
 | 
			
		||||
 | 
			
		||||
		void read_block(size_t index, BAN::ByteSpan buffer);
 | 
			
		||||
		void write_block(size_t index, BAN::ConstByteSpan buffer);
 | 
			
		||||
		void free_block(size_t index);
 | 
			
		||||
		BAN::ErrorOr<size_t> allocate_block();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		struct PageInfo
 | 
			
		||||
		{
 | 
			
		||||
			enum Flags : paddr_t
 | 
			
		||||
			{
 | 
			
		||||
				Present = 1 << 0,				
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// 12 bottom bits of paddr can be used as flags, since
 | 
			
		||||
			// paddr will always be page aligned.
 | 
			
		||||
			static constexpr size_t  flag_bits = 12;
 | 
			
		||||
			static constexpr paddr_t flags_mask = (1 << flag_bits) - 1;
 | 
			
		||||
			static constexpr paddr_t paddr_mask = ~flags_mask;
 | 
			
		||||
			static_assert((1 << flag_bits) <= PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
			paddr_t paddr() const { return raw & paddr_mask; }
 | 
			
		||||
			paddr_t flags() const { return raw & flags_mask; }
 | 
			
		||||
 | 
			
		||||
			void set_paddr(paddr_t paddr) { raw = (raw & flags_mask) | (paddr & paddr_mask); }
 | 
			
		||||
			void set_flags(paddr_t flags) { raw = (raw & paddr_mask) | (flags & flags_mask); }
 | 
			
		||||
 | 
			
		||||
			paddr_t raw { 0 };
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct InodeLocation
 | 
			
		||||
		{
 | 
			
		||||
			paddr_t paddr;
 | 
			
		||||
			size_t index;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		TmpFileSystem(size_t max_pages);
 | 
			
		||||
		BAN::ErrorOr<void> initialize(mode_t, uid_t, gid_t);
 | 
			
		||||
 | 
			
		||||
		InodeLocation find_inode(ino_t ino);
 | 
			
		||||
 | 
			
		||||
		paddr_t find_block(size_t index);
 | 
			
		||||
 | 
			
		||||
		template<for_each_indirect_paddr_allocating_callback F>
 | 
			
		||||
		BAN::ErrorOr<void> for_each_indirect_paddr_allocating(PageInfo page_info, F callback, size_t depth);
 | 
			
		||||
		template<for_each_indirect_paddr_allocating_callback F>
 | 
			
		||||
		BAN::ErrorOr<BAN::Iteration> for_each_indirect_paddr_allocating_internal(PageInfo page_info, F callback, size_t depth);
 | 
			
		||||
 | 
			
		||||
		paddr_t find_indirect(PageInfo root, size_t index, size_t depth);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		RecursiveSpinLock m_lock;
 | 
			
		||||
 | 
			
		||||
		BAN::HashMap<ino_t, BAN::RefPtr<TmpInode>> m_inode_cache;
 | 
			
		||||
		BAN::RefPtr<TmpDirectoryInode> m_root_inode;
 | 
			
		||||
 | 
			
		||||
		// We store pages with triple indirection.
 | 
			
		||||
		// With 64-bit pointers we can store 512^3 pages of data (512 GiB)
 | 
			
		||||
		// which should be enough for now.
 | 
			
		||||
		// In future this should be dynamically calculated based on maximum
 | 
			
		||||
		// number of pages for this file system.
 | 
			
		||||
		PageInfo m_data_pages {};
 | 
			
		||||
		static constexpr size_t first_data_page = 1;
 | 
			
		||||
		static constexpr size_t max_data_pages =
 | 
			
		||||
			(PAGE_SIZE / sizeof(PageInfo)) *
 | 
			
		||||
			(PAGE_SIZE / sizeof(PageInfo)) *
 | 
			
		||||
			(PAGE_SIZE / sizeof(PageInfo));
 | 
			
		||||
 | 
			
		||||
		// We store inodes in pages with double indirection.
 | 
			
		||||
		// With 64-bit pointers we can store 512^2 pages of inodes
 | 
			
		||||
		// which should be enough for now.
 | 
			
		||||
		// In future this should be dynamically calculated based on maximum
 | 
			
		||||
		// number of pages for this file system.
 | 
			
		||||
		PageInfo m_inode_pages;
 | 
			
		||||
		static constexpr size_t first_inode = 1;
 | 
			
		||||
		static constexpr size_t max_inodes =
 | 
			
		||||
			(PAGE_SIZE / sizeof(PageInfo)) *
 | 
			
		||||
			(PAGE_SIZE / sizeof(PageInfo)) *
 | 
			
		||||
			(PAGE_SIZE / sizeof(TmpInodeInfo));
 | 
			
		||||
 | 
			
		||||
		const size_t m_max_pages;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,103 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/Iteration.h>
 | 
			
		||||
#include <kernel/FS/Inode.h>
 | 
			
		||||
#include <kernel/FS/TmpFS/Definitions.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class TmpFileSystem;
 | 
			
		||||
 | 
			
		||||
	class TmpInode : public Inode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		virtual ino_t		ino()		const override final { return m_ino; }
 | 
			
		||||
		virtual Mode		mode()		const override final { return Mode(m_inode_info.mode); }
 | 
			
		||||
		virtual nlink_t		nlink()		const override final { return m_inode_info.nlink; }
 | 
			
		||||
		virtual uid_t		uid()		const override final { return m_inode_info.uid; }
 | 
			
		||||
		virtual gid_t		gid()		const override final { return m_inode_info.gid; }
 | 
			
		||||
		virtual off_t		size()		const override final { return m_inode_info.size; }
 | 
			
		||||
		virtual timespec	atime()		const override final { return m_inode_info.atime; }
 | 
			
		||||
		virtual timespec	mtime()		const override final { return m_inode_info.mtime; }
 | 
			
		||||
		virtual timespec	ctime()		const override final { return m_inode_info.ctime; }
 | 
			
		||||
		virtual blksize_t	blksize()	const override final { return PAGE_SIZE; }
 | 
			
		||||
		virtual blkcnt_t	blocks()	const override final { return m_inode_info.blocks; }
 | 
			
		||||
		virtual dev_t		dev()		const override final { return 0; } // TODO
 | 
			
		||||
		virtual dev_t		rdev()		const override final { return 0; } // TODO
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
 | 
			
		||||
 | 
			
		||||
		void sync();
 | 
			
		||||
		void free_all_blocks();
 | 
			
		||||
 | 
			
		||||
		size_t block_index(size_t data_block_index);
 | 
			
		||||
		BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		TmpFileSystem& m_fs;
 | 
			
		||||
		TmpInodeInfo m_inode_info;
 | 
			
		||||
		const ino_t m_ino;
 | 
			
		||||
 | 
			
		||||
		// has to be able to increase link count
 | 
			
		||||
		friend class TmpDirectoryInode;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class TmpFileInode : public TmpInode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<TmpFileInode>> create(TmpFileSystem&, mode_t, uid_t, gid_t);
 | 
			
		||||
		~TmpFileInode();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		TmpFileInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
 | 
			
		||||
 | 
			
		||||
		friend class TmpInode;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class TmpSymlinkInode : public TmpInode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		~TmpSymlinkInode();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		TmpSymlinkInode(TmpFileSystem&, ino_t, const TmpInodeInfo&, BAN::StringView target);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	template<typename F>
 | 
			
		||||
	concept for_each_entry_callback = requires(F func, const TmpDirectoryEntry& entry)
 | 
			
		||||
	{
 | 
			
		||||
		requires BAN::is_same_v<decltype(func(entry)), BAN::Iteration>;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class TmpDirectoryInode : public TmpInode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<TmpDirectoryInode>> create_root(TmpFileSystem&, mode_t, uid_t, gid_t);
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<TmpDirectoryInode>> create_new(TmpFileSystem&, mode_t, uid_t, gid_t, TmpInode& parent);
 | 
			
		||||
 | 
			
		||||
		~TmpDirectoryInode();
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;
 | 
			
		||||
		virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override final;
 | 
			
		||||
		virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
 | 
			
		||||
		virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
 | 
			
		||||
		virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override final;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		TmpDirectoryInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<void> link_inode(TmpInode&, BAN::StringView);
 | 
			
		||||
 | 
			
		||||
		template<for_each_entry_callback F>
 | 
			
		||||
		void for_each_entry(F callback);
 | 
			
		||||
 | 
			
		||||
		friend class TmpInode;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,268 @@
 | 
			
		|||
#include <kernel/FS/TmpFS/FileSystem.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/PageTable.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<TmpFileSystem*> TmpFileSystem::create(size_t max_pages, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto* result = new TmpFileSystem(max_pages);
 | 
			
		||||
		if (result == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		TRY(result->initialize(mode, uid, gid));
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpFileSystem::TmpFileSystem(size_t max_pages)
 | 
			
		||||
		: m_max_pages(max_pages)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> TmpFileSystem::initialize(mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		paddr_t data_paddr = Heap::get().take_free_page();
 | 
			
		||||
		if (data_paddr == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		m_data_pages.set_paddr(data_paddr);
 | 
			
		||||
		m_data_pages.set_flags(PageInfo::Flags::Present);
 | 
			
		||||
		PageTable::with_fast_page(data_paddr, [&] {
 | 
			
		||||
			memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		paddr_t inodes_paddr = Heap::get().take_free_page();
 | 
			
		||||
		if (inodes_paddr == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		m_inode_pages.set_paddr(inodes_paddr);
 | 
			
		||||
		m_inode_pages.set_flags(PageInfo::Flags::Present);
 | 
			
		||||
		PageTable::with_fast_page(inodes_paddr, [&] {
 | 
			
		||||
			memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		m_root_inode = TRY(TmpDirectoryInode::create_root(*this, mode, uid, gid));
 | 
			
		||||
		TRY(m_inode_cache.insert(m_root_inode->ino(), m_root_inode));
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpFileSystem::~TmpFileSystem()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT_NOT_REACHED();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<TmpInode>> TmpFileSystem::open_inode(ino_t ino)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_inode_cache.contains(ino))
 | 
			
		||||
			return m_inode_cache[ino];
 | 
			
		||||
 | 
			
		||||
		TmpInodeInfo inode_info;
 | 
			
		||||
 | 
			
		||||
		auto inode_location = find_inode(ino);
 | 
			
		||||
		PageTable::with_fast_page(inode_location.paddr, [&] {
 | 
			
		||||
			inode_info = PageTable::fast_page_as_sized<TmpInodeInfo>(inode_location.index);
 | 
			
		||||
		});
 | 
			
		||||
		
 | 
			
		||||
		auto inode = TRY(TmpInode::create_from_existing(*this, ino, inode_info));
 | 
			
		||||
		TRY(m_inode_cache.insert(ino, inode));
 | 
			
		||||
		return inode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpFileSystem::read_inode(ino_t ino, TmpInodeInfo& out)
 | 
			
		||||
	{
 | 
			
		||||
		auto inode_location = find_inode(ino);
 | 
			
		||||
		PageTable::with_fast_page(inode_location.paddr, [&] {
 | 
			
		||||
			out = PageTable::fast_page_as_sized<TmpInodeInfo>(inode_location.index);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpFileSystem::write_inode(ino_t ino, const TmpInodeInfo& info)
 | 
			
		||||
	{
 | 
			
		||||
		auto inode_location = find_inode(ino);
 | 
			
		||||
		PageTable::with_fast_page(inode_location.paddr, [&] {
 | 
			
		||||
			auto& inode_info = PageTable::fast_page_as_sized<TmpInodeInfo>(inode_location.index);
 | 
			
		||||
			inode_info = info;
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpFileSystem::delete_inode(ino_t ino)
 | 
			
		||||
	{
 | 
			
		||||
		auto inode_location = find_inode(ino);
 | 
			
		||||
		PageTable::with_fast_page(inode_location.paddr, [&] {
 | 
			
		||||
			auto& inode_info = PageTable::fast_page_as_sized<TmpInodeInfo>(inode_location.index);
 | 
			
		||||
			ASSERT_EQ(inode_info.nlink, 0);
 | 
			
		||||
			for (auto paddr : inode_info.block)
 | 
			
		||||
				ASSERT_EQ(paddr, 0);
 | 
			
		||||
			inode_info = {};
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<ino_t> TmpFileSystem::allocate_inode(const TmpInodeInfo& info)
 | 
			
		||||
	{
 | 
			
		||||
		constexpr size_t inodes_per_page = PAGE_SIZE / sizeof(TmpInodeInfo);
 | 
			
		||||
 | 
			
		||||
		ino_t ino = first_inode;
 | 
			
		||||
		TRY(for_each_indirect_paddr_allocating(m_inode_pages, [&](paddr_t paddr, bool) {
 | 
			
		||||
			BAN::Iteration result = BAN::Iteration::Continue;
 | 
			
		||||
			PageTable::with_fast_page(paddr, [&] {
 | 
			
		||||
				for (size_t i = 0; i < inodes_per_page; i++, ino++)
 | 
			
		||||
				{
 | 
			
		||||
					auto& inode_info = PageTable::fast_page_as_sized<TmpInodeInfo>(i);
 | 
			
		||||
					if (inode_info.mode != 0)
 | 
			
		||||
						continue;
 | 
			
		||||
					inode_info = info;
 | 
			
		||||
					result = BAN::Iteration::Break;
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			return result;
 | 
			
		||||
		}, 2));
 | 
			
		||||
 | 
			
		||||
		return ino;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpFileSystem::InodeLocation TmpFileSystem::find_inode(ino_t ino)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT_GTE(ino, first_inode);
 | 
			
		||||
		ASSERT_LT(ino, max_inodes);
 | 
			
		||||
 | 
			
		||||
		constexpr size_t inodes_per_page = PAGE_SIZE / sizeof(TmpInodeInfo);
 | 
			
		||||
 | 
			
		||||
		size_t index_of_page = (ino - first_inode) / inodes_per_page;
 | 
			
		||||
		size_t index_in_page = (ino - first_inode) % inodes_per_page;
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			.paddr = find_indirect(m_inode_pages, index_of_page, 2),
 | 
			
		||||
			.index = index_in_page
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpFileSystem::read_block(size_t index, BAN::ByteSpan buffer)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(buffer.size() >= PAGE_SIZE);
 | 
			
		||||
		paddr_t block_paddr = find_block(index);
 | 
			
		||||
		PageTable::with_fast_page(block_paddr, [&] {
 | 
			
		||||
			memcpy(buffer.data(), PageTable::fast_page_as_ptr(), PAGE_SIZE);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpFileSystem::write_block(size_t index, BAN::ConstByteSpan buffer)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(buffer.size() >= PAGE_SIZE);
 | 
			
		||||
		paddr_t block_paddr = find_block(index);
 | 
			
		||||
		PageTable::with_fast_page(block_paddr, [&] {
 | 
			
		||||
			memcpy(PageTable::fast_page_as_ptr(), buffer.data(), PAGE_SIZE);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpFileSystem::free_block(size_t index)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT_NOT_REACHED();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<size_t> TmpFileSystem::allocate_block()
 | 
			
		||||
	{
 | 
			
		||||
		size_t result = first_data_page;
 | 
			
		||||
		TRY(for_each_indirect_paddr_allocating(m_data_pages, [&] (paddr_t paddr, bool allocated) {
 | 
			
		||||
			if (allocated)
 | 
			
		||||
				return BAN::Iteration::Break;
 | 
			
		||||
			result++;
 | 
			
		||||
			return BAN::Iteration::Continue;
 | 
			
		||||
		}, 3));
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paddr_t TmpFileSystem::find_block(size_t index)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT_GT(index, 0);
 | 
			
		||||
		return find_indirect(m_data_pages, index - first_data_page, 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paddr_t TmpFileSystem::find_indirect(PageInfo root, size_t index, size_t depth)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(root.flags() & PageInfo::Flags::Present);
 | 
			
		||||
		if (depth == 0)
 | 
			
		||||
			return root.paddr();
 | 
			
		||||
 | 
			
		||||
		constexpr size_t addresses_per_page = PAGE_SIZE / sizeof(PageInfo);
 | 
			
		||||
 | 
			
		||||
		size_t divisor = 1;
 | 
			
		||||
		for (size_t i = 0; i < depth; i++)
 | 
			
		||||
			divisor *= addresses_per_page;
 | 
			
		||||
 | 
			
		||||
		size_t index_of_page = index / divisor;
 | 
			
		||||
		size_t index_in_page = index % divisor;
 | 
			
		||||
 | 
			
		||||
		ASSERT(index_of_page < addresses_per_page);
 | 
			
		||||
 | 
			
		||||
		PageInfo next;
 | 
			
		||||
		PageTable::with_fast_page(root.paddr(), [&] {
 | 
			
		||||
			next = PageTable::fast_page_as_sized<PageInfo>(index_of_page);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		return find_indirect(next, index_in_page, depth - 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<for_each_indirect_paddr_allocating_callback F>
 | 
			
		||||
	BAN::ErrorOr<BAN::Iteration> TmpFileSystem::for_each_indirect_paddr_allocating_internal(PageInfo page_info, F callback, size_t depth)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT_GT(depth, 0);
 | 
			
		||||
		ASSERT(page_info.flags() & PageInfo::Flags::Present);
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < PAGE_SIZE / sizeof(PageInfo); i++)
 | 
			
		||||
		{
 | 
			
		||||
			PageInfo next_info;
 | 
			
		||||
			PageTable::with_fast_page(page_info.paddr(), [&] {
 | 
			
		||||
				next_info = PageTable::fast_page_as_sized<PageInfo>(i);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			bool allocated = false;
 | 
			
		||||
 | 
			
		||||
			if (!(next_info.flags() & PageInfo::Flags::Present))
 | 
			
		||||
			{
 | 
			
		||||
				paddr_t new_paddr = Heap::get().take_free_page();
 | 
			
		||||
				if (new_paddr == 0)
 | 
			
		||||
					return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
 | 
			
		||||
				PageTable::with_fast_page(new_paddr, [&] {
 | 
			
		||||
					memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				next_info.set_paddr(new_paddr);
 | 
			
		||||
				next_info.set_flags(PageInfo::Flags::Present);
 | 
			
		||||
 | 
			
		||||
				PageTable::with_fast_page(page_info.paddr(), [&] {
 | 
			
		||||
					auto& to_update_info = PageTable::fast_page_as_sized<PageInfo>(i);
 | 
			
		||||
					to_update_info = next_info;
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				allocated = true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			BAN::Iteration result;
 | 
			
		||||
			if (depth == 1)
 | 
			
		||||
				result = callback(next_info.paddr(), allocated);
 | 
			
		||||
			else
 | 
			
		||||
				result = TRY(for_each_indirect_paddr_allocating_internal(next_info, callback, depth - 1));
 | 
			
		||||
 | 
			
		||||
			switch (result)
 | 
			
		||||
			{
 | 
			
		||||
				case BAN::Iteration::Continue:
 | 
			
		||||
					break;
 | 
			
		||||
				case BAN::Iteration::Break:
 | 
			
		||||
					return BAN::Iteration::Break;
 | 
			
		||||
				default:
 | 
			
		||||
					ASSERT_NOT_REACHED();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Iteration::Continue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<for_each_indirect_paddr_allocating_callback F>
 | 
			
		||||
	BAN::ErrorOr<void> TmpFileSystem::for_each_indirect_paddr_allocating(PageInfo page_info, F callback, size_t depth)
 | 
			
		||||
	{
 | 
			
		||||
		BAN::Iteration result = TRY(for_each_indirect_paddr_allocating_internal(page_info, callback, depth));
 | 
			
		||||
		ASSERT(result == BAN::Iteration::Break);
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,303 @@
 | 
			
		|||
#include <kernel/FS/TmpFS/FileSystem.h>
 | 
			
		||||
#include <kernel/FS/TmpFS/Inode.h>
 | 
			
		||||
#include <kernel/Timer/Timer.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	static TmpInodeInfo create_inode_info(mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto current_time = SystemTimer::get().real_time();
 | 
			
		||||
 | 
			
		||||
		TmpInodeInfo info;
 | 
			
		||||
		info.uid = uid;
 | 
			
		||||
		info.gid = gid;
 | 
			
		||||
		info.mode = mode;
 | 
			
		||||
		info.atime = current_time;
 | 
			
		||||
		info.mtime = current_time;
 | 
			
		||||
		info.ctime = current_time;
 | 
			
		||||
 | 
			
		||||
		return info;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static uint8_t inode_mode_to_dt_type(Inode::Mode mode)
 | 
			
		||||
	{
 | 
			
		||||
		if (mode.ifreg())
 | 
			
		||||
			return DT_REG;
 | 
			
		||||
		if (mode.ifdir())
 | 
			
		||||
			return DT_DIR;
 | 
			
		||||
		if (mode.ifchr())
 | 
			
		||||
			return DT_CHR;
 | 
			
		||||
		if (mode.ifblk())
 | 
			
		||||
			return DT_BLK;
 | 
			
		||||
		if (mode.ififo())
 | 
			
		||||
			return DT_FIFO;
 | 
			
		||||
		if (mode.ifsock())
 | 
			
		||||
			return DT_SOCK;
 | 
			
		||||
		if (mode.iflnk())
 | 
			
		||||
			return DT_LNK;
 | 
			
		||||
		ASSERT_NOT_REACHED();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* GENERAL INODE */
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<TmpInode>> TmpInode::create_from_existing(TmpFileSystem& fs, ino_t ino, const TmpInodeInfo& info)
 | 
			
		||||
	{
 | 
			
		||||
		TmpInode* inode_ptr = nullptr;
 | 
			
		||||
		switch (info.mode & Mode::TYPE_MASK)
 | 
			
		||||
		{
 | 
			
		||||
			case Mode::IFDIR:
 | 
			
		||||
				inode_ptr = new TmpDirectoryInode(fs, ino, info);
 | 
			
		||||
				break;
 | 
			
		||||
			case Mode::IFREG:
 | 
			
		||||
				inode_ptr = new TmpFileInode(fs, ino, info);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
		if (inode_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return BAN::RefPtr<TmpInode>::adopt(inode_ptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpInode::TmpInode(TmpFileSystem& fs, ino_t ino, const TmpInodeInfo& info)
 | 
			
		||||
		: m_fs(fs)
 | 
			
		||||
		, m_inode_info(info)
 | 
			
		||||
		, m_ino(ino)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void TmpInode::sync()
 | 
			
		||||
	{
 | 
			
		||||
		m_fs.write_inode(m_ino, m_inode_info);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TmpInode::free_all_blocks()
 | 
			
		||||
	{
 | 
			
		||||
		for (auto block : m_inode_info.block)
 | 
			
		||||
			ASSERT(block == 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t TmpInode::block_index(size_t data_block_index)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(data_block_index < TmpInodeInfo::direct_block_count);
 | 
			
		||||
		ASSERT(m_inode_info.block[data_block_index]);
 | 
			
		||||
		return m_inode_info.block[data_block_index];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<size_t> TmpInode::block_index_with_allocation(size_t data_block_index)
 | 
			
		||||
	{
 | 
			
		||||
		if (data_block_index >= TmpInodeInfo::direct_block_count)
 | 
			
		||||
		{
 | 
			
		||||
			dprintln("only {} blocks supported :D", TmpInodeInfo::direct_block_count);
 | 
			
		||||
			return BAN::Error::from_errno(ENOSPC);
 | 
			
		||||
		}
 | 
			
		||||
		if (m_inode_info.block[data_block_index] == 0)
 | 
			
		||||
		{
 | 
			
		||||
			m_inode_info.block[data_block_index] = TRY(m_fs.allocate_block());
 | 
			
		||||
			m_inode_info.blocks++;
 | 
			
		||||
		}
 | 
			
		||||
		return m_inode_info.block[data_block_index];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FILE INODE */
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<TmpFileInode>> TmpFileInode::create(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto info = create_inode_info(Mode::IFREG | mode, uid, gid);
 | 
			
		||||
		ino_t ino = TRY(fs.allocate_inode(info));
 | 
			
		||||
 | 
			
		||||
		auto* inode_ptr = new TmpFileInode(fs, ino, info);
 | 
			
		||||
		if (inode_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
 | 
			
		||||
		return BAN::RefPtr<TmpFileInode>::adopt(inode_ptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpFileInode::TmpFileInode(TmpFileSystem& fs, ino_t ino, const TmpInodeInfo& info)
 | 
			
		||||
		: TmpInode(fs, ino, info)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(mode().ifreg());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpFileInode::~TmpFileInode()
 | 
			
		||||
	{
 | 
			
		||||
		if (nlink() > 0)
 | 
			
		||||
		{
 | 
			
		||||
			sync();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		free_all_blocks();
 | 
			
		||||
		m_fs.delete_inode(ino());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* DIRECTORY INODE */
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<TmpDirectoryInode>> TmpDirectoryInode::create_root(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto info = create_inode_info(Mode::IFDIR | mode, uid, gid);
 | 
			
		||||
		ino_t ino = TRY(fs.allocate_inode(info));
 | 
			
		||||
 | 
			
		||||
		auto* inode_ptr = new TmpDirectoryInode(fs, ino, info);
 | 
			
		||||
		if (inode_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
 | 
			
		||||
		auto inode = BAN::RefPtr<TmpDirectoryInode>::adopt(inode_ptr);
 | 
			
		||||
		TRY(inode->link_inode(*inode, "."sv));
 | 
			
		||||
		TRY(inode->link_inode(*inode, ".."sv));
 | 
			
		||||
 | 
			
		||||
		return inode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<TmpDirectoryInode>> TmpDirectoryInode::create_new(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid, TmpInode& parent)
 | 
			
		||||
	{
 | 
			
		||||
		auto info = create_inode_info(Mode::IFDIR | mode, uid, gid);
 | 
			
		||||
		ino_t ino = TRY(fs.allocate_inode(info));
 | 
			
		||||
 | 
			
		||||
		auto* inode_ptr = new TmpDirectoryInode(fs, ino, info);
 | 
			
		||||
		if (inode_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
 | 
			
		||||
		auto inode = BAN::RefPtr<TmpDirectoryInode>::adopt(inode_ptr);
 | 
			
		||||
		TRY(inode->link_inode(*inode, "."sv));
 | 
			
		||||
		TRY(inode->link_inode(parent, "."sv));
 | 
			
		||||
 | 
			
		||||
		return inode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpDirectoryInode::TmpDirectoryInode(TmpFileSystem& fs, ino_t ino, const TmpInodeInfo& info)
 | 
			
		||||
		: TmpInode(fs, ino, info)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(mode().ifdir());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TmpDirectoryInode::~TmpDirectoryInode()
 | 
			
		||||
	{
 | 
			
		||||
		if (nlink() >= 2)
 | 
			
		||||
		{
 | 
			
		||||
			sync();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		free_all_blocks();
 | 
			
		||||
		m_fs.delete_inode(ino());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name)
 | 
			
		||||
	{
 | 
			
		||||
		ino_t result = 0;
 | 
			
		||||
 | 
			
		||||
		for_each_entry([&](const TmpDirectoryEntry& entry) {
 | 
			
		||||
			if (entry.type == DT_UNKNOWN)
 | 
			
		||||
				return BAN::Iteration::Continue;
 | 
			
		||||
			if (entry.name_sv() != name)
 | 
			
		||||
				return BAN::Iteration::Continue;
 | 
			
		||||
			result = entry.ino;
 | 
			
		||||
			return BAN::Iteration::Break;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		if (result == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOENT);
 | 
			
		||||
		
 | 
			
		||||
		auto inode = TRY(m_fs.open_inode(result));
 | 
			
		||||
		return BAN::RefPtr<Inode>(inode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> TmpDirectoryInode::list_next_inodes_impl(off_t, DirectoryEntryList*, size_t)
 | 
			
		||||
	{
 | 
			
		||||
		return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> TmpDirectoryInode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto new_inode = TRY(TmpFileInode::create(m_fs, mode, uid, gid));
 | 
			
		||||
		TRY(link_inode(*new_inode, name));
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> TmpDirectoryInode::create_directory_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto new_inode = TRY(TmpDirectoryInode::create_new(m_fs, mode, uid, gid, *this));
 | 
			
		||||
		TRY(link_inode(*new_inode, name));
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView)
 | 
			
		||||
	{
 | 
			
		||||
		return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> TmpDirectoryInode::link_inode(TmpInode& inode, BAN::StringView name)
 | 
			
		||||
	{
 | 
			
		||||
		static constexpr size_t directory_entry_alignment = 16;
 | 
			
		||||
 | 
			
		||||
		size_t current_size = size();
 | 
			
		||||
 | 
			
		||||
		size_t new_entry_size = sizeof(TmpDirectoryEntry) + name.size();
 | 
			
		||||
		if (auto rem = new_entry_size % directory_entry_alignment)
 | 
			
		||||
			new_entry_size += directory_entry_alignment - rem;
 | 
			
		||||
		ASSERT(new_entry_size < (size_t)blksize());
 | 
			
		||||
 | 
			
		||||
		size_t new_entry_offset = current_size % blksize();
 | 
			
		||||
 | 
			
		||||
		// Target is the last block, or if it doesn't fit the new entry, the next one.
 | 
			
		||||
		size_t target_data_block = current_size / blksize();
 | 
			
		||||
		if (blksize() - new_entry_offset < new_entry_size)
 | 
			
		||||
			target_data_block++;
 | 
			
		||||
 | 
			
		||||
		size_t block_index = TRY(block_index_with_allocation(target_data_block));
 | 
			
		||||
		
 | 
			
		||||
		BAN::Vector<uint8_t> buffer;
 | 
			
		||||
		TRY(buffer.resize(blksize()));
 | 
			
		||||
 | 
			
		||||
		BAN::ByteSpan bytespan = buffer.span();
 | 
			
		||||
 | 
			
		||||
		m_fs.read_block(block_index, bytespan);
 | 
			
		||||
 | 
			
		||||
		auto& new_entry = bytespan.slice(new_entry_offset).as<TmpDirectoryEntry>();
 | 
			
		||||
		new_entry.type = inode_mode_to_dt_type(inode.mode());
 | 
			
		||||
		new_entry.ino = inode.ino();
 | 
			
		||||
		new_entry.name_len = name.size();
 | 
			
		||||
		new_entry.rec_len = new_entry_size;
 | 
			
		||||
		memcpy(new_entry.name, name.data(), name.size());
 | 
			
		||||
 | 
			
		||||
		m_fs.write_block(block_index, bytespan);
 | 
			
		||||
 | 
			
		||||
		// increase current size
 | 
			
		||||
		m_inode_info.size += new_entry_size;
 | 
			
		||||
 | 
			
		||||
		// add link to linked inode
 | 
			
		||||
		inode.m_inode_info.nlink++;
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<for_each_entry_callback F>
 | 
			
		||||
	void TmpDirectoryInode::for_each_entry(F callback)
 | 
			
		||||
	{
 | 
			
		||||
		size_t full_offset = 0;
 | 
			
		||||
		while (full_offset < (size_t)size())
 | 
			
		||||
		{
 | 
			
		||||
			size_t data_block_index = full_offset / blksize();
 | 
			
		||||
			size_t block_index = this->block_index(data_block_index);
 | 
			
		||||
 | 
			
		||||
			// FIXME: implement fast heap pages?
 | 
			
		||||
			BAN::Vector<uint8_t> buffer;
 | 
			
		||||
			MUST(buffer.resize(blksize()));
 | 
			
		||||
 | 
			
		||||
			BAN::ByteSpan bytespan = buffer.span();
 | 
			
		||||
			m_fs.read_block(block_index, bytespan);
 | 
			
		||||
 | 
			
		||||
			size_t byte_count = BAN::Math::min<size_t>(blksize(), size() - full_offset);
 | 
			
		||||
 | 
			
		||||
			bytespan = bytespan.slice(0, byte_count);
 | 
			
		||||
			while (bytespan.size() > 0)
 | 
			
		||||
			{
 | 
			
		||||
				auto& entry = bytespan.as<TmpDirectoryEntry>();
 | 
			
		||||
				callback(entry);
 | 
			
		||||
				bytespan = bytespan.slice(entry.rec_len);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			full_offset += blksize();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue