Compare commits

...

16 Commits

Author SHA1 Message Date
Bananymous a0fbf18d3b meminfo: better format for files without permissions 2023-11-07 02:41:01 +02:00
Bananymous 1acc0abf2e Kernel: Make unlinking from /proc always fail with EPERM 2023-11-07 02:40:27 +02:00
Bananymous c20f773c5d Kernel: /tmp is now TmpFS instead of RamFS 2023-11-07 02:36:22 +02:00
Bananymous a46b2f43d9 Kernel: Make ProcFS use the new TmpFS internally 2023-11-07 02:35:44 +02:00
Bananymous a20f8607de Kernel: Implement TmpFS Inode unlinking and deletion 2023-11-06 21:49:12 +02:00
Bananymous af330f7b8e Kernel: TmpFS directory inodes now iterate over only valid entries 2023-11-06 21:41:51 +02:00
Bananymous e33b3bcdff Kernel: Fix TmpFS directory entry enumeration early return 2023-11-06 21:06:10 +02:00
Bananymous 181d139c7d Kernel: Fix ext2 directory listing for big directories 2023-11-06 21:05:58 +02:00
Bananymous 639fd8804c Kernel: Implement TmpFS directory listing 2023-11-06 21:05:58 +02:00
Bananymous cbb2c37e00 Kernel: Implement TmpFS inode chmod 2023-11-06 20:11:34 +02:00
Bananymous ab4f033385 Kernel: Cleanup TmpFS code and block access doesn't require allocs
TmpFS blocks are now accessed with a simple wrapper
2023-11-06 20:07:09 +02:00
Bananymous 1ed08f62d3 Kernel: TmpInode blocks are on demand allocated 2023-11-06 10:44:37 +02:00
Bananymous 8164c15b6c Kernel: Implement read/write/truncate for TmpFileInode 2023-11-05 02:28:43 +02:00
Bananymous f9bf47ab30 Kernel: Start work on proper TmpFS in Heap instead of kmalloc memory 2023-11-04 18:18:45 +02:00
Bananymous e5ffadb109 Kernel: Add better APIs for fast page 2023-11-04 18:13:16 +02:00
Bananymous 061d10e635 BAN: Update bytespan -> span API 2023-11-04 18:12:46 +02:00
16 changed files with 1195 additions and 47 deletions

View File

@ -97,8 +97,7 @@ namespace BAN
}
template<typename S>
requires(is_const_v<S>)
Span<S> as_span() const
const Span<S> as_span() const
{
ASSERT(m_data);
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));

View File

@ -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

View File

@ -1,13 +1,13 @@
#pragma once
#include <kernel/FS/RamFS/FileSystem.h>
#include <kernel/FS/RamFS/Inode.h>
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Process.h>
namespace Kernel
{
class ProcFileSystem final : public RamFileSystem
class ProcFileSystem final : public TmpFileSystem
{
public:
static void initialize();
@ -17,10 +17,7 @@ namespace Kernel
void on_process_delete(Process&);
private:
ProcFileSystem(size_t size);
private:
BAN::RefPtr<RamDirectoryInode> m_root_inode;
ProcFileSystem();
};
}

View File

@ -1,41 +1,46 @@
#pragma once
#include <kernel/FS/RamFS/FileSystem.h>
#include <kernel/FS/RamFS/Inode.h>
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Process.h>
namespace Kernel
{
class ProcPidInode final : public RamDirectoryInode
class ProcPidInode final : public TmpDirectoryInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> create(Process&, RamFileSystem&, mode_t, uid_t, gid_t);
static BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> create_new(Process&, TmpFileSystem&, mode_t, uid_t, gid_t);
~ProcPidInode() = default;
void cleanup();
protected:
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override { return BAN::Error::from_errno(EPERM); }
private:
ProcPidInode(Process&, RamFileSystem&, const FullInodeInfo&);
ProcPidInode(Process&, TmpFileSystem&, const TmpInodeInfo&);
private:
Process& m_process;
};
class ProcROInode final : public RamInode
class ProcROInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcROInode>> create(Process&, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, RamFileSystem&, mode_t, uid_t, gid_t);
static BAN::ErrorOr<BAN::RefPtr<ProcROInode>> create_new(Process&, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem&, mode_t, uid_t, gid_t);
~ProcROInode() = default;
protected:
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
// You may not write here and this is always non blocking
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); }
virtual bool has_data_impl() const override { return true; }
private:
ProcROInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, RamFileSystem&, const FullInodeInfo&);
ProcROInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, TmpFileSystem&, const TmpInodeInfo&);
private:
Process& m_process;

View File

@ -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);
}
};
}

View File

@ -0,0 +1,150 @@
#pragma once
#include <BAN/HashMap.h>
#include <BAN/Iteration.h>
#include <kernel/FS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/SpinLock.h>
namespace Kernel
{
namespace TmpFuncs
{
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>;
};
template<typename F>
concept with_block_buffer_callback = requires(F func, BAN::ByteSpan buffer)
{
requires BAN::is_same_v<decltype(func(buffer)), void>;
};
}
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);
BAN::ErrorOr<void> add_to_cache(BAN::RefPtr<TmpInode>);
void remove_from_cache(BAN::RefPtr<TmpInode>);
// FIXME: read_block and write_block should not require external buffer
// probably some wrapper like PageTable::with_fast_page could work?
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&);
template<TmpFuncs::with_block_buffer_callback F>
void with_block_buffer(size_t index, F callback);
void free_block(size_t index);
BAN::ErrorOr<size_t> allocate_block();
private:
struct PageInfo
{
enum Flags : paddr_t
{
Present = 1 << 0,
Internal = 1 << 1,
};
// 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;
};
protected:
TmpFileSystem(size_t max_pages);
BAN::ErrorOr<void> initialize(mode_t, uid_t, gid_t);
private:
InodeLocation find_inode(ino_t ino);
paddr_t find_block(size_t index);
template<TmpFuncs::for_each_indirect_paddr_allocating_callback F>
BAN::ErrorOr<void> for_each_indirect_paddr_allocating(PageInfo page_info, F callback, size_t depth);
template<TmpFuncs::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;
};
template<TmpFuncs::with_block_buffer_callback F>
void TmpFileSystem::with_block_buffer(size_t index, F callback)
{
paddr_t block_paddr = find_block(index);
PageTable::with_fast_page(block_paddr, [&] {
BAN::ByteSpan buffer(reinterpret_cast<uint8_t*>(PageTable::fast_page()), PAGE_SIZE);
callback(buffer);
});
}
}

View File

@ -0,0 +1,123 @@
#pragma once
#include <BAN/Iteration.h>
#include <BAN/Optional.h>
#include <kernel/FS/Inode.h>
#include <kernel/FS/TmpFS/Definitions.h>
namespace Kernel
{
namespace TmpFuncs
{
template<typename F>
concept for_each_valid_entry_callback = requires(F func, TmpDirectoryEntry& entry)
{
requires BAN::is_same_v<decltype(func(entry)), BAN::Iteration>;
};
}
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&);
~TmpInode();
protected:
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
void sync();
void free_all_blocks();
virtual BAN::ErrorOr<void> prepare_unlink() { return {}; };
BAN::Optional<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_new(TmpFileSystem&, mode_t, uid_t, gid_t);
~TmpFileInode();
protected:
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;
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
virtual bool has_data_impl() const override { return true; }
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);
};
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();
BAN::ErrorOr<void> link_inode(TmpInode&, BAN::StringView);
protected:
TmpDirectoryInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
virtual BAN::ErrorOr<void> prepare_unlink() override;
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;
private:
template<TmpFuncs::for_each_valid_entry_callback F>
void for_each_valid_entry(F callback);
friend class TmpInode;
};
TmpInodeInfo create_inode_info(mode_t mode, uid_t uid, gid_t gid);
}

View File

@ -1,12 +1,20 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Traits.h>
#include <kernel/CriticalScope.h>
#include <kernel/Memory/Types.h>
#include <kernel/SpinLock.h>
namespace Kernel
{
template<typename F>
concept with_fast_page_callback = requires(F func)
{
requires BAN::is_same_v<decltype(func()), void>;
};
class PageTable
{
public:
@ -33,6 +41,15 @@ namespace Kernel
static void unmap_fast_page();
static constexpr vaddr_t fast_page() { return KERNEL_OFFSET; }
template<with_fast_page_callback F>
static void with_fast_page(paddr_t paddr, F callback)
{
CriticalScope _;
map_fast_page(paddr);
callback();
unmap_fast_page();
}
// FIXME: implement sized checks, return span, etc
static void* fast_page_as_ptr(size_t offset = 0)
{
@ -47,6 +64,14 @@ namespace Kernel
return *reinterpret_cast<T*>(fast_page() + offset);
}
// Retrieves index'th element from fast_page
template<typename T>
static T& fast_page_as_sized(size_t index)
{
ASSERT((index + 1) * sizeof(T) <= PAGE_SIZE);
return *reinterpret_cast<T*>(fast_page() + index * sizeof(T));
}
static bool is_valid_pointer(uintptr_t);
static BAN::ErrorOr<PageTable*> create_userspace();

View File

@ -60,6 +60,8 @@ namespace Kernel
bool is_session_leader() const { return pid() == sid(); }
const Credentials& credentials() const { return m_credentials; }
BAN::ErrorOr<long> sys_exit(int status);
BAN::ErrorOr<long> sys_gettermios(::termios*);

View File

@ -306,8 +306,7 @@ done:
ASSERT(mode().ifdir());
ASSERT(offset >= 0);
const uint32_t data_block_count = blocks();
if (offset >= data_block_count)
if (offset >= max_used_data_block_count())
{
list->entry_count = 0;
return {};

View File

@ -1,6 +1,5 @@
#include <kernel/FS/ProcFS/FileSystem.h>
#include <kernel/FS/ProcFS/Inode.h>
#include <kernel/FS/RamFS/Inode.h>
#include <kernel/LockGuard.h>
namespace Kernel
@ -11,11 +10,10 @@ namespace Kernel
void ProcFileSystem::initialize()
{
ASSERT(s_instance == nullptr);
s_instance = new ProcFileSystem(1024 * 1024);
s_instance = new ProcFileSystem();
ASSERT(s_instance);
s_instance->m_root_inode = MUST(RamDirectoryInode::create(*s_instance, 0, 0555, 0, 0));
MUST(s_instance->set_root_inode(s_instance->m_root_inode));
MUST(s_instance->TmpFileSystem::initialize(0555, 0, 0));
}
ProcFileSystem& ProcFileSystem::get()
@ -24,23 +22,28 @@ namespace Kernel
return *s_instance;
}
ProcFileSystem::ProcFileSystem(size_t size)
: RamFileSystem(size)
ProcFileSystem::ProcFileSystem()
: TmpFileSystem(-1)
{
}
BAN::ErrorOr<void> ProcFileSystem::on_process_create(Process& process)
{
auto path = BAN::String::formatted("{}", process.pid());
auto inode = TRY(ProcPidInode::create(process, *this, 0555, 0, 0));
TRY(m_root_inode->add_inode(path, inode));
auto inode = TRY(ProcPidInode::create_new(process, *this, 0555, process.credentials().ruid(), process.credentials().rgid()));
TRY(reinterpret_cast<TmpDirectoryInode*>(root_inode().ptr())->link_inode(*inode, path));
return {};
}
void ProcFileSystem::on_process_delete(Process& process)
{
auto path = BAN::String::formatted("{}", process.pid());
MUST(m_root_inode->unlink(path));
auto inode = MUST(root_inode()->find_inode(path));
reinterpret_cast<ProcPidInode*>(inode.ptr())->cleanup();
if (auto ret = root_inode()->unlink(path); ret.is_error())
dwarnln("{}", ret.error());
}
}

View File

@ -3,31 +3,38 @@
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> ProcPidInode::create(Process& process, RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> ProcPidInode::create_new(Process& process, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
{
FullInodeInfo inode_info(fs, mode, uid, gid);
auto inode_info = create_inode_info(Mode::IFDIR | mode, uid, gid);
auto* inode_ptr = new ProcPidInode(process, fs, inode_info);
if (inode_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto inode = BAN::RefPtr<ProcPidInode>::adopt(inode_ptr);
TRY(inode->add_inode("meminfo"sv, MUST(ProcROInode::create(process, &Process::proc_meminfo, fs, 0755, 0, 0))));
TRY(inode->add_inode("cmdline"sv, MUST(ProcROInode::create(process, &Process::proc_cmdline, fs, 0755, 0, 0))));
TRY(inode->add_inode("environ"sv, MUST(ProcROInode::create(process, &Process::proc_environ, fs, 0755, 0, 0))));
TRY(inode->link_inode(*MUST(ProcROInode::create_new(process, &Process::proc_meminfo, fs, 0400, uid, gid)), "meminfo"sv));
TRY(inode->link_inode(*MUST(ProcROInode::create_new(process, &Process::proc_cmdline, fs, 0400, uid, gid)), "cmdline"sv));
TRY(inode->link_inode(*MUST(ProcROInode::create_new(process, &Process::proc_environ, fs, 0400, uid, gid)), "environ"sv));
return inode;
}
ProcPidInode::ProcPidInode(Process& process, RamFileSystem& fs, const FullInodeInfo& inode_info)
: RamDirectoryInode(fs, inode_info, fs.root_inode()->ino())
ProcPidInode::ProcPidInode(Process& process, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
: TmpDirectoryInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
, m_process(process)
{
}
BAN::ErrorOr<BAN::RefPtr<ProcROInode>> ProcROInode::create(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
void ProcPidInode::cleanup()
{
FullInodeInfo inode_info(fs, mode, uid, gid);
(void)TmpDirectoryInode::unlink_impl("meminfo"sv);
(void)TmpDirectoryInode::unlink_impl("cmdline"sv);
(void)TmpDirectoryInode::unlink_impl("environ"sv);
}
BAN::ErrorOr<BAN::RefPtr<ProcROInode>> ProcROInode::create_new(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
{
auto inode_info = create_inode_info(Mode::IFREG | mode, uid, gid);
auto* inode_ptr = new ProcROInode(process, callback, fs, inode_info);
if (inode_ptr == nullptr)
@ -35,8 +42,8 @@ namespace Kernel
return BAN::RefPtr<ProcROInode>::adopt(inode_ptr);
}
ProcROInode::ProcROInode(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, RamFileSystem& fs, const FullInodeInfo& inode_info)
: RamInode(fs, inode_info)
ProcROInode::ProcROInode(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
: TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
, m_process(process)
, m_callback(callback)
{

View File

@ -0,0 +1,276 @@
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/Memory/Heap.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));
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;
}
BAN::ErrorOr<void> TmpFileSystem::add_to_cache(BAN::RefPtr<TmpInode> inode)
{
if (!m_inode_cache.contains(inode->ino()))
TRY(m_inode_cache.insert(inode->ino(), inode));
return {};
}
void TmpFileSystem::remove_from_cache(BAN::RefPtr<TmpInode> inode)
{
ASSERT(m_inode_cache.contains(inode->ino()));
m_inode_cache.remove(inode->ino());
}
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 = {};
});
ASSERT(!m_inode_cache.contains(ino));
}
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::free_block(size_t index)
{
constexpr size_t addresses_per_page = PAGE_SIZE / sizeof(PageInfo);
const size_t index_of_page = (index - first_data_page) / addresses_per_page;
const size_t index_in_page = (index - first_data_page) % addresses_per_page;
paddr_t page_containing = find_indirect(m_data_pages, index_of_page, 2);
PageTable::with_fast_page(page_containing, [&] {
auto& page_info = PageTable::fast_page_as_sized<PageInfo>(index_in_page);
ASSERT(page_info.flags() & PageInfo::Flags::Present);
Heap::get().release_page(page_info.paddr());
page_info.set_paddr(0);
page_info.set_flags(0);
});
}
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)
{
ASSERT(index == 0);
return root.paddr();
}
constexpr size_t addresses_per_page = PAGE_SIZE / sizeof(PageInfo);
size_t divisor = 1;
for (size_t i = 1; 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<TmpFuncs::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(page_info.flags() & PageInfo::Flags::Present);
if (depth == 0)
{
bool is_new_block = page_info.flags() & PageInfo::Flags::Internal;
return callback(page_info.paddr(), is_new_block);
}
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);
});
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;
});
// Don't sync the internal bit to actual memory
next_info.set_flags(PageInfo::Flags::Internal | PageInfo::Flags::Present);
}
auto 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<TmpFuncs::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 {};
}
}

View File

@ -0,0 +1,504 @@
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Timer/Timer.h>
namespace Kernel
{
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)
{
// FIXME: this should be able to fail
MUST(fs.add_to_cache(this));
}
TmpInode::~TmpInode()
{
if (nlink() > 0)
{
sync();
return;
}
free_all_blocks();
m_fs.delete_inode(ino());
}
void TmpInode::sync()
{
m_fs.write_inode(m_ino, m_inode_info);
}
void TmpInode::free_all_blocks()
{
for (size_t i = 0; i < TmpInodeInfo::direct_block_count; i++)
{
if (m_inode_info.block[i])
m_fs.free_block(m_inode_info.block[i]);
m_inode_info.block[i] = 0;
}
for (auto block : m_inode_info.block)
ASSERT(block == 0);
}
BAN::Optional<size_t> TmpInode::block_index(size_t data_block_index)
{
ASSERT(data_block_index < TmpInodeInfo::direct_block_count);
if (m_inode_info.block[data_block_index])
return m_inode_info.block[data_block_index];
return {};
}
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_new(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()
{
}
BAN::ErrorOr<size_t> TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer)
{
if (offset >= size() || out_buffer.size() == 0)
return 0;
const size_t bytes_to_read = BAN::Math::min<size_t>(size() - offset, out_buffer.size());
size_t read_done = 0;
while (read_done < bytes_to_read)
{
const size_t data_block_index = (read_done + offset) / blksize();
const size_t block_offset = (read_done + offset) % blksize();
const auto block_index = this->block_index(data_block_index);
const size_t bytes = BAN::Math::min<size_t>(bytes_to_read - read_done, blksize() - block_offset);
if (block_index.has_value())
m_fs.with_block_buffer(block_index.value(), [&](BAN::ByteSpan block_buffer) {
memcpy(out_buffer.data() + read_done, block_buffer.data() + block_offset, bytes);
});
else
memset(out_buffer.data() + read_done, 0x00, bytes);
read_done += bytes;
}
return read_done;
}
BAN::ErrorOr<size_t> TmpFileInode::write_impl(off_t offset, BAN::ConstByteSpan in_buffer)
{
// FIXME: handle overflow
if (offset + in_buffer.size() > (size_t)size())
TRY(truncate_impl(offset + in_buffer.size()));
const size_t bytes_to_write = in_buffer.size();
size_t write_done = 0;
while (write_done < bytes_to_write)
{
const size_t data_block_index = (write_done + offset) / blksize();
const size_t block_offset = (write_done + offset) % blksize();
const size_t block_index = TRY(block_index_with_allocation(data_block_index));
const size_t bytes = BAN::Math::min<size_t>(bytes_to_write - write_done, blksize() - block_offset);
m_fs.with_block_buffer(block_index, [&](BAN::ByteSpan block_buffer) {
memcpy(block_buffer.data() + block_offset, in_buffer.data() + write_done, bytes);
});
write_done += bytes;
}
return write_done;
}
BAN::ErrorOr<void> TmpFileInode::truncate_impl(size_t new_size)
{
m_inode_info.size = new_size;
return {};
}
BAN::ErrorOr<void> TmpFileInode::chmod_impl(mode_t new_mode)
{
m_inode_info.mode = new_mode;
return {};
}
/* 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()
{
}
BAN::ErrorOr<void> TmpDirectoryInode::prepare_unlink()
{
ino_t dot_ino = 0;
ino_t dotdot_ino = 0;
bool is_empty = true;
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() == "."sv)
dot_ino = entry.ino;
else if (entry.name_sv() == ".."sv)
dotdot_ino = entry.ino;
else
{
is_empty = false;
return BAN::Iteration::Break;
}
return BAN::Iteration::Continue;
});
if (!is_empty)
return BAN::Error::from_errno(ENOTEMPTY);
// FIXME: can these leak inodes?
if (dot_ino)
{
auto inode = TRY(m_fs.open_inode(dot_ino));
ASSERT(inode->nlink() > 0);
inode->m_inode_info.nlink--;
}
if (dotdot_ino)
{
auto inode = TRY(m_fs.open_inode(dotdot_ino));
ASSERT(inode->nlink() > 0);
inode->m_inode_info.nlink--;
}
return {};
}
BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name)
{
ino_t result = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
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 data_block_index, DirectoryEntryList* list, size_t list_len)
{
if (list_len < (size_t)blksize())
{
dprintln("buffer is too small");
return BAN::Error::from_errno(ENOBUFS);
}
auto block_index = this->block_index(data_block_index);
list->entry_count = 0;
// if we reach a non-allocated block, it marks the end
if (!block_index.has_value())
return {};
auto* dirp = list->array;
const size_t byte_count = BAN::Math::min<size_t>(size() - data_block_index * blksize(), blksize());
m_fs.with_block_buffer(block_index.value(), [&](BAN::ByteSpan bytespan) {
bytespan = bytespan.slice(0, byte_count);
while (bytespan.size() > 0)
{
const auto& entry = bytespan.as<TmpDirectoryEntry>();
if (entry.type != DT_UNKNOWN)
{
// TODO: dirents should be aligned
dirp->dirent.d_ino = entry.ino;
dirp->dirent.d_type = entry.type;
strncpy(dirp->dirent.d_name, entry.name, entry.name_len);
dirp->dirent.d_name[entry.name_len] = '\0';
dirp->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
dirp = dirp->next();
list->entry_count++;
}
bytespan = bytespan.slice(entry.rec_len);
}
});
return {};
}
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_new(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 name)
{
ino_t entry_ino = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name)
return BAN::Iteration::Continue;
entry_ino = entry.ino;
return BAN::Iteration::Break;
});
if (entry_ino == 0)
return BAN::Error::from_errno(ENOENT);
auto inode = TRY(m_fs.open_inode(entry_ino));
ASSERT(inode->nlink() > 0);
TRY(inode->prepare_unlink());
inode->m_inode_info.nlink--;
if (inode->nlink() == 0)
m_fs.remove_from_cache(inode);
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name)
return BAN::Iteration::Continue;
entry.ino = 0;
entry.type = DT_UNKNOWN;
return BAN::Iteration::Break;
});
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::link_inode(TmpInode& inode, BAN::StringView name)
{
static constexpr size_t directory_entry_alignment = 16;
auto find_result = find_inode_impl(name);
if (!find_result.is_error())
return BAN::Error::from_errno(EEXIST);
if (find_result.error().get_error_code() != ENOENT)
return find_result.release_error();
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 = size() % blksize();
// Target is the last block, or if it doesn't fit the new entry, the next one.
size_t target_data_block = size() / blksize();
if (blksize() - new_entry_offset < new_entry_size)
{
// insert an empty entry at the end of current block
m_fs.with_block_buffer(block_index(target_data_block).value(), [&](BAN::ByteSpan bytespan) {
auto& empty_entry = bytespan.slice(new_entry_offset).as<TmpDirectoryEntry>();
empty_entry.type = DT_UNKNOWN;
empty_entry.ino = 0;
empty_entry.rec_len = blksize() - new_entry_offset;
});
m_inode_info.size += blksize() - new_entry_offset;
target_data_block++;
new_entry_offset = 0;
}
size_t block_index = TRY(block_index_with_allocation(target_data_block));
m_fs.with_block_buffer(block_index, [&](BAN::ByteSpan bytespan) {
auto& new_entry = bytespan.slice(new_entry_offset).as<TmpDirectoryEntry>();
ASSERT(new_entry.type == DT_UNKNOWN);
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());
});
// increase current size
m_inode_info.size += new_entry_size;
// add link to linked inode
inode.m_inode_info.nlink++;
return {};
}
template<TmpFuncs::for_each_valid_entry_callback F>
void TmpDirectoryInode::for_each_valid_entry(F callback)
{
bool done = false;
for (size_t data_block_index = 0; !done && data_block_index * blksize() < (size_t)size(); data_block_index++)
{
const size_t block_index = this->block_index(data_block_index).value();
const size_t byte_count = BAN::Math::min<size_t>(size() - data_block_index * blksize(), blksize());
m_fs.with_block_buffer(block_index, [&](BAN::ByteSpan bytespan) {
bytespan = bytespan.slice(0, byte_count);
while (bytespan.size() > 0)
{
auto& entry = bytespan.as<TmpDirectoryEntry>();
if (entry.type != DT_UNKNOWN)
{
switch (callback(entry))
{
case BAN::Iteration::Continue:
break;
case BAN::Iteration::Break:
done = true;
return;
default:
ASSERT_NOT_REACHED();
}
}
bytespan = bytespan.slice(entry.rec_len);
}
});
}
}
}

View File

@ -3,8 +3,7 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/Ext2/FileSystem.h>
#include <kernel/FS/ProcFS/FileSystem.h>
#include <kernel/FS/RamFS/FileSystem.h>
#include <kernel/FS/RamFS/Inode.h>
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h>
#include <fcntl.h>
@ -31,7 +30,7 @@ namespace Kernel
MUST(s_instance->mount(root_creds, &ProcFileSystem::get(), "/proc"sv));
auto* tmpfs = MUST(RamFileSystem::create(1024 * 1024, 0777, 0, 0));
auto* tmpfs = MUST(TmpFileSystem::create(1024, 0777, 0, 0));
MUST(s_instance->mount(root_creds, tmpfs, "/tmp"sv));
}

View File

@ -1,5 +1,6 @@
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
@ -30,8 +31,6 @@ int main()
if (!is_only_digits(proc_ent->d_name))
continue;
printf("process: ");
{
strcpy(path_buffer, proc_ent->d_name);
strcat(path_buffer, "/cmdline");
@ -39,10 +38,13 @@ int main()
int fd = openat(dirfd(proc), path_buffer, O_RDONLY);
if (fd == -1)
{
perror("openat");
if (errno != EACCES)
perror("openat");
continue;
}
printf("process: ");
while (ssize_t nread = read(fd, path_buffer, sizeof(path_buffer) - 1))
{
if (nread < 0)
@ -61,10 +63,12 @@ int main()
written += printf("%s ", path_buffer + written);
}
printf("\n");
close(fd);
}
printf("\n pid: %s\n", proc_ent->d_name);
printf(" pid: %s\n", proc_ent->d_name);
{
strcpy(path_buffer, proc_ent->d_name);