forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -26,8 +26,6 @@ set(KERNEL_SOURCES
 | 
			
		|||
	kernel/FS/Pipe.cpp
 | 
			
		||||
	kernel/FS/ProcFS/FileSystem.cpp
 | 
			
		||||
	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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,47 +0,0 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/HashMap.h>
 | 
			
		||||
#include <BAN/Iteration.h>
 | 
			
		||||
#include <kernel/FS/FileSystem.h>
 | 
			
		||||
#include <kernel/SpinLock.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class RamInode;
 | 
			
		||||
	class RamDirectoryInode;
 | 
			
		||||
 | 
			
		||||
	class RamFileSystem : public FileSystem
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<RamFileSystem*> create(size_t size, mode_t, uid_t, gid_t);
 | 
			
		||||
		virtual ~RamFileSystem() = default;
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<void> set_root_inode(BAN::RefPtr<RamDirectoryInode>);
 | 
			
		||||
		virtual BAN::RefPtr<Inode> root_inode() override { return m_inodes[m_root_inode]; }
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<void> add_inode(BAN::RefPtr<RamInode>);
 | 
			
		||||
		BAN::ErrorOr<BAN::RefPtr<RamInode>> get_inode(ino_t);
 | 
			
		||||
 | 
			
		||||
		blksize_t blksize() const { return m_blksize; }
 | 
			
		||||
		ino_t next_ino() { return m_next_ino++; }
 | 
			
		||||
 | 
			
		||||
		void for_each_inode(const BAN::Function<BAN::Iteration(BAN::RefPtr<RamInode>)>& callback);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		RamFileSystem(size_t size)
 | 
			
		||||
			: m_size(size)
 | 
			
		||||
		{ }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		RecursiveSpinLock m_lock;
 | 
			
		||||
		size_t m_size { 0 };
 | 
			
		||||
 | 
			
		||||
		BAN::HashMap<ino_t, BAN::RefPtr<RamInode>> m_inodes;
 | 
			
		||||
		ino_t m_root_inode { 0 };
 | 
			
		||||
 | 
			
		||||
		const blksize_t m_blksize = PAGE_SIZE;
 | 
			
		||||
		ino_t m_next_ino { 1 };
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,141 +0,0 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <kernel/FS/Inode.h>
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class RamFileSystem;
 | 
			
		||||
 | 
			
		||||
	class RamInode : public Inode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		virtual ~RamInode() = default;
 | 
			
		||||
 | 
			
		||||
		virtual ino_t		ino()		const override { return m_inode_info.ino; }
 | 
			
		||||
		virtual Mode		mode()		const override { return { m_inode_info.mode }; }
 | 
			
		||||
		virtual nlink_t		nlink()		const override { return m_inode_info.nlink; }
 | 
			
		||||
		virtual uid_t		uid()		const override { return m_inode_info.uid; }
 | 
			
		||||
		virtual gid_t		gid()		const override { return m_inode_info.gid; }
 | 
			
		||||
		virtual off_t		size()		const override { return m_inode_info.size; }
 | 
			
		||||
		virtual timespec	atime()		const override { return m_inode_info.atime; }
 | 
			
		||||
		virtual timespec	mtime()		const override { return m_inode_info.mtime; }
 | 
			
		||||
		virtual timespec	ctime()		const override { return m_inode_info.ctime; }
 | 
			
		||||
		virtual blksize_t	blksize()	const override { return m_inode_info.blksize; }
 | 
			
		||||
		virtual blkcnt_t	blocks()	const override { return m_inode_info.blocks; }
 | 
			
		||||
		virtual dev_t		dev()		const override { return m_inode_info.dev; }
 | 
			
		||||
		virtual dev_t		rdev()		const override { return m_inode_info.rdev; }
 | 
			
		||||
 | 
			
		||||
		void add_link() { m_inode_info.nlink++; }
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		struct FullInodeInfo
 | 
			
		||||
		{
 | 
			
		||||
			FullInodeInfo(RamFileSystem&, mode_t, uid_t, gid_t);
 | 
			
		||||
			ino_t		ino;
 | 
			
		||||
			mode_t		mode;
 | 
			
		||||
			nlink_t		nlink;
 | 
			
		||||
			uid_t		uid;
 | 
			
		||||
			gid_t		gid;
 | 
			
		||||
			off_t		size;
 | 
			
		||||
			timespec	atime;
 | 
			
		||||
			timespec	mtime;
 | 
			
		||||
			timespec	ctime;
 | 
			
		||||
			blksize_t	blksize;
 | 
			
		||||
			blkcnt_t	blocks;
 | 
			
		||||
			dev_t		dev;
 | 
			
		||||
			dev_t		rdev;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		RamInode(RamFileSystem& fs, const FullInodeInfo& inode_info)
 | 
			
		||||
			: m_fs(fs)
 | 
			
		||||
			, m_inode_info(inode_info)
 | 
			
		||||
		{
 | 
			
		||||
			ASSERT((inode_info.mode & Inode::Mode::TYPE_MASK) == 0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		RamFileSystem& m_fs;
 | 
			
		||||
		FullInodeInfo m_inode_info;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class RamFileInode : public RamInode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<RamFileInode>> create(RamFileSystem&, mode_t, uid_t, gid_t);
 | 
			
		||||
		~RamFileInode() = default;
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		RamFileInode(RamFileSystem&, const FullInodeInfo&);
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
 | 
			
		||||
		virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
 | 
			
		||||
		virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BAN::Vector<uint8_t> m_data;
 | 
			
		||||
 | 
			
		||||
		friend class RamFileSystem;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class RamDirectoryInode : public RamInode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<RamDirectoryInode>> create(RamFileSystem&, ino_t parent, mode_t, uid_t, gid_t);
 | 
			
		||||
		~RamDirectoryInode() = default;
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<void> add_inode(BAN::StringView, BAN::RefPtr<RamInode>);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		RamDirectoryInode(RamFileSystem&, const FullInodeInfo&, ino_t parent);
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
 | 
			
		||||
		virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
 | 
			
		||||
		virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
 | 
			
		||||
		virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
 | 
			
		||||
		virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		static constexpr size_t m_name_max = NAME_MAX;
 | 
			
		||||
		struct Entry
 | 
			
		||||
		{
 | 
			
		||||
			char name[m_name_max + 1];
 | 
			
		||||
			size_t name_len = 0;
 | 
			
		||||
			ino_t ino;
 | 
			
		||||
			uint8_t type;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BAN::Vector<Entry> m_entries;
 | 
			
		||||
		const ino_t m_parent;
 | 
			
		||||
 | 
			
		||||
		friend class RamFileSystem;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class RamSymlinkInode final : public RamInode
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<RamSymlinkInode>> create(RamFileSystem&, BAN::StringView target, mode_t, uid_t, gid_t);
 | 
			
		||||
		~RamSymlinkInode() = default;
 | 
			
		||||
 | 
			
		||||
		virtual off_t size() const override { return m_target.size(); }
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<void> set_link_target(BAN::StringView);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		RamSymlinkInode(RamFileSystem&, const FullInodeInfo&, BAN::String&&);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BAN::String m_target;
 | 
			
		||||
 | 
			
		||||
		friend class RamFileSystem;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,65 +0,0 @@
 | 
			
		|||
#include <BAN/ScopeGuard.h>
 | 
			
		||||
#include <kernel/FS/RamFS/FileSystem.h>
 | 
			
		||||
#include <kernel/FS/RamFS/Inode.h>
 | 
			
		||||
#include <kernel/LockGuard.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<RamFileSystem*> RamFileSystem::create(size_t size, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto* ramfs = new RamFileSystem(size);
 | 
			
		||||
		if (ramfs == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
 | 
			
		||||
		BAN::ScopeGuard deleter([ramfs] { delete ramfs; });
 | 
			
		||||
 | 
			
		||||
		auto root_inode = TRY(RamDirectoryInode::create(*ramfs, 0, mode, uid, gid));
 | 
			
		||||
		TRY(ramfs->set_root_inode(root_inode));;
 | 
			
		||||
 | 
			
		||||
		deleter.disable();
 | 
			
		||||
 | 
			
		||||
		return ramfs;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamFileSystem::set_root_inode(BAN::RefPtr<RamDirectoryInode> root_inode)
 | 
			
		||||
	{
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
		ASSERT(m_root_inode == 0);
 | 
			
		||||
		TRY(add_inode(root_inode));
 | 
			
		||||
		m_root_inode = root_inode->ino();
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamFileSystem::add_inode(BAN::RefPtr<RamInode> inode)
 | 
			
		||||
	{
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
		if (m_inodes.contains(inode->ino()))
 | 
			
		||||
			return BAN::Error::from_errno(EEXIST);
 | 
			
		||||
		TRY(m_inodes.insert(inode->ino(), inode));
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<RamInode>> RamFileSystem::get_inode(ino_t ino)
 | 
			
		||||
	{
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
		if (!m_inodes.contains(ino))
 | 
			
		||||
			return BAN::Error::from_errno(ENOENT);
 | 
			
		||||
		return m_inodes[ino];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RamFileSystem::for_each_inode(const BAN::Function<BAN::Iteration(BAN::RefPtr<RamInode>)>& callback)
 | 
			
		||||
	{
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
		for (auto& [_, inode] : m_inodes)
 | 
			
		||||
		{
 | 
			
		||||
			auto decision = callback(inode);
 | 
			
		||||
			if (decision == BAN::Iteration::Break)
 | 
			
		||||
				break;
 | 
			
		||||
			if (decision == BAN::Iteration::Continue)
 | 
			
		||||
				continue;
 | 
			
		||||
			ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,321 +0,0 @@
 | 
			
		|||
#include <kernel/FS/RamFS/FileSystem.h>
 | 
			
		||||
#include <kernel/FS/RamFS/Inode.h>
 | 
			
		||||
#include <kernel/Timer/Timer.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	RamInode::FullInodeInfo::FullInodeInfo(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		timespec current_time = SystemTimer::get().real_time();
 | 
			
		||||
 | 
			
		||||
		this->ino = fs.next_ino();
 | 
			
		||||
		this->mode = mode;
 | 
			
		||||
		this->nlink = 1;
 | 
			
		||||
		this->uid = uid;
 | 
			
		||||
		this->gid = gid;
 | 
			
		||||
		this->size = 0;
 | 
			
		||||
		this->atime = current_time;
 | 
			
		||||
		this->mtime = current_time;
 | 
			
		||||
		this->ctime = current_time;
 | 
			
		||||
		this->blksize = fs.blksize();
 | 
			
		||||
		this->blocks = 0;
 | 
			
		||||
 | 
			
		||||
		// TODO
 | 
			
		||||
		this->dev = 0;
 | 
			
		||||
		this->rdev = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamInode::chmod_impl(mode_t mode)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
 | 
			
		||||
		m_inode_info.mode = (m_inode_info.mode & Inode::Mode::TYPE_MASK) | mode;
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
 | 
			
		||||
		RAM FILE INODE
 | 
			
		||||
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<RamFileInode>> RamFileInode::create(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		FullInodeInfo inode_info(fs, mode, uid, gid);
 | 
			
		||||
 | 
			
		||||
		auto* ram_inode = new RamFileInode(fs, inode_info);
 | 
			
		||||
		if (ram_inode == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return BAN::RefPtr<RamFileInode>::adopt(ram_inode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RamFileInode::RamFileInode(RamFileSystem& fs, const FullInodeInfo& inode_info)
 | 
			
		||||
		: RamInode(fs, inode_info)
 | 
			
		||||
	{
 | 
			
		||||
		m_inode_info.mode |= Inode::Mode::IFREG;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<size_t> RamFileInode::read_impl(off_t offset, BAN::ByteSpan buffer)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(offset >= 0);
 | 
			
		||||
		if (offset >= size())
 | 
			
		||||
			return 0;
 | 
			
		||||
		size_t to_copy = BAN::Math::min<size_t>(m_inode_info.size - offset, buffer.size());
 | 
			
		||||
		memcpy(buffer.data(), m_data.data() + offset, to_copy);
 | 
			
		||||
		return to_copy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<size_t> RamFileInode::write_impl(off_t offset, BAN::ConstByteSpan buffer)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(offset >= 0);
 | 
			
		||||
		if (offset + buffer.size() > (size_t)size())
 | 
			
		||||
			TRY(truncate_impl(offset + buffer.size()));
 | 
			
		||||
		memcpy(m_data.data() + offset, buffer.data(), buffer.size());
 | 
			
		||||
		return buffer.size();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamFileInode::truncate_impl(size_t new_size)
 | 
			
		||||
	{
 | 
			
		||||
		TRY(m_data.resize(new_size, 0));
 | 
			
		||||
		m_inode_info.size   = m_data.size();
 | 
			
		||||
		m_inode_info.blocks = BAN::Math::div_round_up<size_t>(size(), blksize());
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
 | 
			
		||||
		RAM DIRECTORY INODE
 | 
			
		||||
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<RamDirectoryInode>> RamDirectoryInode::create(RamFileSystem& fs, ino_t parent, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		FullInodeInfo inode_info(fs, mode, uid, gid);
 | 
			
		||||
 | 
			
		||||
		// "." links to this
 | 
			
		||||
		inode_info.nlink++;
 | 
			
		||||
 | 
			
		||||
		// ".." links to this or parent
 | 
			
		||||
		if (parent)
 | 
			
		||||
			TRY(fs.get_inode(parent))->add_link();
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			inode_info.nlink++;
 | 
			
		||||
			parent = inode_info.ino;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto* ram_inode = new RamDirectoryInode(fs, inode_info, parent);
 | 
			
		||||
		if (ram_inode == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return BAN::RefPtr<RamDirectoryInode>::adopt(ram_inode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RamDirectoryInode::RamDirectoryInode(RamFileSystem& fs, const FullInodeInfo& inode_info, ino_t parent)
 | 
			
		||||
		: RamInode(fs, inode_info)
 | 
			
		||||
		, m_parent(parent)
 | 
			
		||||
	{
 | 
			
		||||
		m_inode_info.mode |= Inode::Mode::IFDIR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<Inode>> RamDirectoryInode::find_inode_impl(BAN::StringView name)
 | 
			
		||||
	{
 | 
			
		||||
		if (name == "."sv)
 | 
			
		||||
		{
 | 
			
		||||
			BAN::RefPtr<Inode> inode = TRY(m_fs.get_inode(ino()));
 | 
			
		||||
			return inode;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (name == ".."sv)
 | 
			
		||||
		{
 | 
			
		||||
			BAN::RefPtr<Inode> inode = TRY(m_fs.get_inode(m_parent));
 | 
			
		||||
			return inode;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (const auto& entry : m_entries)
 | 
			
		||||
		{
 | 
			
		||||
			if (name == entry.name)
 | 
			
		||||
			{
 | 
			
		||||
				BAN::RefPtr<Inode> inode = TRY(m_fs.get_inode(entry.ino));
 | 
			
		||||
				return inode;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Error::from_errno(ENOENT);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamDirectoryInode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(offset >= 0);
 | 
			
		||||
 | 
			
		||||
		// TODO: don't require memory for all entries on single call
 | 
			
		||||
		if (offset != 0)
 | 
			
		||||
		{
 | 
			
		||||
			list->entry_count = 0;
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t needed_size = sizeof(DirectoryEntryList);
 | 
			
		||||
		needed_size += sizeof(DirectoryEntry) + 2; // "."
 | 
			
		||||
		needed_size += sizeof(DirectoryEntry) + 3; // ".."
 | 
			
		||||
		for (auto& entry : m_entries)
 | 
			
		||||
			needed_size += sizeof(DirectoryEntry) + entry.name_len + 1;
 | 
			
		||||
		if (needed_size > list_size)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		DirectoryEntry* ptr = list->array;
 | 
			
		||||
 | 
			
		||||
		// "."
 | 
			
		||||
		{
 | 
			
		||||
			ptr->dirent.d_ino = ino();
 | 
			
		||||
			ptr->dirent.d_type = DT_DIR;
 | 
			
		||||
			ptr->rec_len = sizeof(DirectoryEntry) + 2;
 | 
			
		||||
			strcpy(ptr->dirent.d_name, ".");
 | 
			
		||||
			ptr = ptr->next();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ".."
 | 
			
		||||
		{
 | 
			
		||||
			ptr->dirent.d_ino = m_parent;
 | 
			
		||||
			ptr->dirent.d_type = DT_DIR;
 | 
			
		||||
			ptr->rec_len = sizeof(DirectoryEntry) + 3;
 | 
			
		||||
			strcpy(ptr->dirent.d_name, "..");
 | 
			
		||||
			ptr = ptr->next();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto& entry : m_entries)
 | 
			
		||||
		{
 | 
			
		||||
			ptr->dirent.d_ino = entry.ino;
 | 
			
		||||
			ptr->dirent.d_type = entry.type;
 | 
			
		||||
			ptr->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
 | 
			
		||||
			strcpy(ptr->dirent.d_name, entry.name);
 | 
			
		||||
			ptr = ptr->next();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		list->entry_count = m_entries.size() + 2;
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamDirectoryInode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		BAN::RefPtr<RamInode> inode;
 | 
			
		||||
		if (Mode(mode).ifreg())
 | 
			
		||||
			inode = TRY(RamFileInode::create(m_fs, mode & ~Inode::Mode::TYPE_MASK, uid, gid));
 | 
			
		||||
		else
 | 
			
		||||
			return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
		TRY(add_inode(name, inode));
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamDirectoryInode::create_directory_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		if (!Mode(mode).ifdir())
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		auto inode = TRY(RamDirectoryInode::create(m_fs, ino(), mode & ~Inode::Mode::TYPE_MASK, uid, gid));
 | 
			
		||||
		TRY(add_inode(name, inode));
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static uint8_t get_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;
 | 
			
		||||
		return DT_UNKNOWN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamDirectoryInode::add_inode(BAN::StringView name, BAN::RefPtr<RamInode> inode)
 | 
			
		||||
	{
 | 
			
		||||
		if (name.size() > m_name_max)
 | 
			
		||||
			return BAN::Error::from_errno(ENAMETOOLONG);
 | 
			
		||||
		
 | 
			
		||||
		for (auto& entry : m_entries)
 | 
			
		||||
			if (name == entry.name)
 | 
			
		||||
				return BAN::Error::from_errno(EEXIST);
 | 
			
		||||
		
 | 
			
		||||
		TRY(m_entries.push_back({ }));
 | 
			
		||||
		Entry& entry = m_entries.back();
 | 
			
		||||
		strcpy(entry.name, name.data());
 | 
			
		||||
		entry.name_len = name.size();
 | 
			
		||||
		entry.ino = inode->ino();
 | 
			
		||||
		entry.type = get_type(inode->mode());
 | 
			
		||||
 | 
			
		||||
		if (auto ret = m_fs.add_inode(inode); ret.is_error())
 | 
			
		||||
		{
 | 
			
		||||
			m_entries.pop_back();
 | 
			
		||||
			return ret.release_error();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamDirectoryInode::unlink_impl(BAN::StringView name)
 | 
			
		||||
	{
 | 
			
		||||
		// FIXME: delete inodes contents only after they are closed
 | 
			
		||||
		for (size_t i = 0; i < m_entries.size(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (name == m_entries[i].name)
 | 
			
		||||
			{
 | 
			
		||||
				m_entries.remove(i);
 | 
			
		||||
				return {};
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return BAN::Error::from_errno(ENOENT);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
 | 
			
		||||
		RAM SYMLINK INODE
 | 
			
		||||
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<RamSymlinkInode>> RamSymlinkInode::create(RamFileSystem& fs, BAN::StringView target_sv, mode_t mode, uid_t uid, gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		FullInodeInfo inode_info(fs, mode, uid, gid);
 | 
			
		||||
 | 
			
		||||
		BAN::String target_str;
 | 
			
		||||
		TRY(target_str.append(target_sv));
 | 
			
		||||
 | 
			
		||||
		auto* ram_inode = new RamSymlinkInode(fs, inode_info, BAN::move(target_str));
 | 
			
		||||
		if (ram_inode == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return BAN::RefPtr<RamSymlinkInode>::adopt(ram_inode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RamSymlinkInode::RamSymlinkInode(RamFileSystem& fs, const FullInodeInfo& inode_info, BAN::String&& target)
 | 
			
		||||
		: RamInode(fs, inode_info)
 | 
			
		||||
		, m_target(BAN::move(target))
 | 
			
		||||
	{
 | 
			
		||||
		m_inode_info.mode |= Inode::Mode::IFLNK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::String> RamSymlinkInode::link_target_impl()
 | 
			
		||||
	{
 | 
			
		||||
		BAN::String result;
 | 
			
		||||
		TRY(result.append(m_target));
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> RamSymlinkInode::set_link_target(BAN::StringView target)
 | 
			
		||||
	{
 | 
			
		||||
		BAN::String temp;
 | 
			
		||||
		TRY(temp.append(target));
 | 
			
		||||
		m_target = BAN::move(temp);
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue