aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/kernel/filesystems/devfs/inode.cpp56
-rw-r--r--kernel/kernel/filesystems/devfs/inode.tests.cpp36
2 files changed, 69 insertions, 23 deletions
diff --git a/kernel/kernel/filesystems/devfs/inode.cpp b/kernel/kernel/filesystems/devfs/inode.cpp
index fb26e34e..dad4e381 100644
--- a/kernel/kernel/filesystems/devfs/inode.cpp
+++ b/kernel/kernel/filesystems/devfs/inode.cpp
@@ -27,7 +27,9 @@ namespace kernel::filesystems::devfs
namespace
{
constexpr auto static sentinel = kapi::filesystem::directory_cursor{std::numeric_limits<std::uint64_t>::max()};
- constexpr auto static root_inode_number = std::numeric_limits<std::uint64_t>::max() - 1;
+ constexpr auto static root_inode_number = 1;
+ constexpr auto static dot_flag = std::uint64_t{1} << 16;
+ constexpr auto static dot_dot_flag = std::uint64_t{1} << 17;
} // namespace
auto inode::read(std::span<std::byte>, kstd::bytes) const -> kstd::result<kstd::bytes>
@@ -49,7 +51,8 @@ namespace kernel::filesystems::devfs
{
return vfs::inode::status().transform([](auto status) {
status.inode_number = root_inode_number;
- status.mode = 0544; // NOLINT(readability-magic-numbers)
+ status.mode =
+ std::to_underlying(kapi::filesystem::file_type::directory) | 0544; // NOLINT(readability-magic-numbers)
return status;
});
}
@@ -69,10 +72,41 @@ namespace kernel::filesystems::devfs
return std::pair{0, sentinel};
}
+ auto flags = position.value & (dot_flag | dot_dot_flag);
+ auto count = 0uz;
+
+ if (!(flags & dot_flag))
+ {
+ entries[count++] = kapi::filesystem::directory_entry{
+ .name = ".",
+ .type = kapi::filesystem::file_type::directory,
+ .inode_number = root_inode_number,
+ };
+ flags |= dot_flag;
+ if (count == requested)
+ {
+ return std::pair{count, kapi::filesystem::directory_cursor{position.value | flags}};
+ }
+ }
+
+ if (!(flags & dot_dot_flag))
+ {
+ entries[count++] = kapi::filesystem::directory_entry{
+ .name = "..",
+ .type = kapi::filesystem::file_type::directory,
+ .inode_number = root_inode_number,
+ };
+ flags |= dot_dot_flag;
+ if (count == requested)
+ {
+ return std::pair{count, kapi::filesystem::directory_cursor{position.value | flags}};
+ }
+ }
+
auto devices = vfs::device_number_registry::get().all();
if (devices.empty())
{
- return std::pair{0, position};
+ return std::pair{0, kapi::filesystem::directory_cursor{position.value | flags}};
}
std::ranges::stable_sort(devices, std::ranges::less{}, &vfs::device_number_registry::entry::number);
@@ -82,30 +116,32 @@ namespace kernel::filesystems::devfs
auto const begin = std::ranges::lower_bound(devices, device_number, std::ranges::less{},
&vfs::device_number_registry::entry::number);
auto const end = std::ranges::end(devices);
- auto const to_read = std::min(requested, static_cast<std::size_t>(std::ranges::distance(begin, end)));
+ auto const to_read = std::min(requested - count, static_cast<std::size_t>(std::ranges::distance(begin, end)));
if (to_read == 0)
{
- return std::pair{0, position};
+ return std::pair{0, kapi::filesystem::directory_cursor{position.value | flags}};
}
- std::ranges::transform(begin, begin + to_read, std::ranges::begin(entries), [](auto const & entry) {
+ std::ranges::transform(begin, begin + to_read, std::ranges::begin(entries) + count, [](auto const & entry) {
return kapi::filesystem::directory_entry{
.name = entry.name,
.type = entry.type,
.inode_number = std::bit_cast<std::uint16_t>(entry.number),
};
});
+ count += to_read;
auto const last_copied = begin + to_read;
if (last_copied == end)
{
- return std::pair{to_read, sentinel};
+ return std::pair{count, sentinel};
}
auto const new_device_number = last_copied->number;
- auto const new_cursor = kapi::filesystem::directory_cursor{
- static_cast<std::uint64_t>(new_device_number.minor) | (static_cast<std::uint64_t>(new_device_number.major) << 8)};
- return std::pair{to_read, new_cursor};
+ auto const new_cursor =
+ kapi::filesystem::directory_cursor{flags | static_cast<std::uint64_t>(new_device_number.minor) |
+ (static_cast<std::uint64_t>(new_device_number.major) << 8)};
+ return std::pair{count, new_cursor};
}
} // namespace kernel::filesystems::devfs \ No newline at end of file
diff --git a/kernel/kernel/filesystems/devfs/inode.tests.cpp b/kernel/kernel/filesystems/devfs/inode.tests.cpp
index 4e315a7a..b923aeb5 100644
--- a/kernel/kernel/filesystems/devfs/inode.tests.cpp
+++ b/kernel/kernel/filesystems/devfs/inode.tests.cpp
@@ -17,7 +17,9 @@
#include <algorithm>
#include <cstddef>
+#include <ranges>
#include <tuple>
+#include <vector>
using namespace kstd::units_literals;
@@ -111,20 +113,24 @@ SCENARIO("Devfs inode directory listing", "[filesystem][devfs][inode]")
WHEN("the directory listing is requested with a buffer large enough for all of them")
{
- auto entries = kstd::vector<kapi::filesystem::directory_entry>{4};
- auto result = root.read_directory(kapi::filesystem::directory_cursor{}, entries);
+ auto buffer = kstd::vector<kapi::filesystem::directory_entry>{6};
+ auto result = root.read_directory(kapi::filesystem::directory_cursor{}, buffer);
+
+ auto entries = std::ranges::to<std::vector>(buffer | std::views::filter([](auto const & e) {
+ return e.type == kapi::filesystem::file_type::block_device;
+ }));
THEN("all devices are listed")
{
REQUIRE(result);
auto [count, next] = *result;
- REQUIRE(count == 3);
+ REQUIRE(count == 5);
auto names = kstd::vector<kstd::string>{3};
- for (auto i = 0uz; i < count; ++i)
+ for (auto & entry : entries)
{
- REQUIRE(entries[i].type == kapi::filesystem::file_type::block_device);
- names.push_back(entries[i].name);
+ REQUIRE(entry.type == kapi::filesystem::file_type::block_device);
+ names.push_back(entry.name);
}
REQUIRE(std::ranges::find(names, "devfs_readdir_device1") != names.end());
@@ -133,7 +139,7 @@ SCENARIO("Devfs inode directory listing", "[filesystem][devfs][inode]")
AND_THEN("listing again with the returned cursor reports 'end-of-directory'")
{
- auto result = root.read_directory(next, entries);
+ auto result = root.read_directory(next, buffer);
REQUIRE(result);
auto [count, cursor] = *result;
@@ -148,7 +154,7 @@ SCENARIO("Devfs inode directory listing", "[filesystem][devfs][inode]")
auto seen = kstd::vector<kstd::string>{};
auto position = kapi::filesystem::directory_cursor{};
- for (auto guard = 0; guard < 4; ++guard)
+ for (auto guard = 0; guard < 5; ++guard)
{
auto one = kstd::vector<kapi::filesystem::directory_entry>(1);
auto result = root.read_directory(position, one);
@@ -164,11 +170,11 @@ SCENARIO("Devfs inode directory listing", "[filesystem][devfs][inode]")
THEN("nothing is skipped or duplicated across the paginated calls")
{
- REQUIRE(seen.size() == 3);
+ REQUIRE(seen.size() == 5);
auto sorted = seen;
std::ranges::sort(sorted);
std::ignore = std::ranges::unique(sorted);
- REQUIRE(sorted.size() == 3);
+ REQUIRE(sorted.size() == 5);
}
}
@@ -193,15 +199,19 @@ SCENARIO("Devfs inode read_directory orders by device number, not registration o
WHEN("read_directory is called with room for both remaining entries")
{
- auto entries = kstd::vector<kapi::filesystem::directory_entry>(2);
- auto result = root.read_directory(kapi::filesystem::directory_cursor{}, entries);
+ auto buffer = kstd::vector<kapi::filesystem::directory_entry>(4);
+ auto result = root.read_directory(kapi::filesystem::directory_cursor{}, buffer);
+
+ auto entries = std::ranges::to<std::vector>(buffer | std::views::filter([](auto const & e) {
+ return e.type == kapi::filesystem::file_type::block_device;
+ }));
THEN("later_in (the reused, lower device number) comes back before still_in, by number, not by "
"when each was registered")
{
REQUIRE(result);
auto [count, next] = *result;
- REQUIRE(count == 2);
+ REQUIRE(count == 4);
REQUIRE(entries[0].name == "readdir_reuse_later_in");
REQUIRE(entries[1].name == "readdir_reuse_still_in");
}