From c3d0432036d860893818e5ea05f05047243eb5a9 Mon Sep 17 00:00:00 2001 From: Sam Tebbs Date: Sun, 24 Oct 2021 18:41:17 +0100 Subject: [PATCH 1/4] Add directory listing --- src/kernel/filesystem/vfs.zig | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/kernel/filesystem/vfs.zig b/src/kernel/filesystem/vfs.zig index 8a906b04..e3807114 100644 --- a/src/kernel/filesystem/vfs.zig +++ b/src/kernel/filesystem/vfs.zig @@ -174,6 +174,12 @@ pub const FileSystem = struct { /// The function for retrieving the root node getRootNode: GetRootNode, + initDirIterator: fn (dir: *const DirNode) void, + + deinitDirIterator: fn (dir: *const DirNode) void, + + listDirIterator: fn (dir: *const DirNode, i: usize) ?*const Node, + /// Points to a usize field within the underlying filesystem so that the close, read, write and open functions can access its low-level implementation using @fieldParentPtr. For example, this could point to a usize field within a FAT32 filesystem data structure, which stores all the data and state that is needed in order to interact with a physical disk /// The value of instance is reserved for future use and so should be left as 0 instance: *usize, @@ -209,6 +215,27 @@ pub const DirNode = struct { /// The directory that this directory is mounted to, else null mount: ?*const DirNode, + const DirIterator = struct { + dir: *const DirNode, + i: usize, + + const Self = @This(); + + pub fn init(node: *const DirNode) DirIterator { + node.fs.initDirIterator(node); + return DirIterator{ .dir = node, .i = 0 }; + } + + pub fn next(self: *Self) ?*const Node { + self.i += 1; + return self.dir.fs.listDirIterator(dir, self.i - 1); + } + + pub fn deinit(self: *Self) void { + return self.dir.fs.deinitDirIterator(self.dir); + } + }; + /// See the documentation for FileSystem.Open pub fn open(self: *const DirNode, name: []const u8, flags: OpenFlags, args: OpenArgs) (Allocator.Error || Error)!*Node { var fs = self.fs; @@ -233,6 +260,10 @@ pub const DirNode = struct { } return fs.close(fs, cast_node); } + + pub fn list(self: *const DirNode) DirIterator { + return DirIterator.init(self.mount orelse self); + } }; pub const SymlinkNode = struct { @@ -716,6 +747,17 @@ const TestFS = struct { } return Error.NoSuchFileOrDir; } + + pub fn initDirIterator(node: *const DirNode) void {} + + pub fn deinitDirIterator(node: *const DirNode) void {} + + pub fn listDirIterator(node: *const DirNode, i: usize) ?*const Node { + var test_fs = @fieldParentPtr(TestFS, "instance", node.fs.instance); + const tree_node = (try getTreeNode(test_fs, node)) orelse unreachable; + if (tree_node.children.items.len <= i) return null; + return tree_node.children.items[i].val; + } }; fn testInitFs(allocator: Allocator) !*TestFS { @@ -745,6 +787,9 @@ fn testInitFs(allocator: Allocator) !*TestFS { .write = TestFS.write, .instance = &testfs.instance, .getRootNode = TestFS.getRootNode, + .initDirIterator = TestFS.initDirIterator, + .deinitDirIterator = TestFS.deinitDirIterator, + .listDirIterator = TestFS.listDirIterator, }; return testfs; } @@ -1009,3 +1054,23 @@ test "write" { _ = try test_file.write(str2); try testing.expect(std.mem.eql(u8, str2, f_data.* orelse unreachable)); } + +test "list" { + var testfs = try testInitFs(testing.allocator); + defer testing.allocator.destroy(testfs); + defer testfs.deinit(); + root = testfs.tree.val; + + const child_1 = try openFile("/child1.txt", .CREATE_FILE); + const child_2 = try openFile("/child2.txt", .CREATE_FILE); + const child_3 = try openDir("/child3", .CREATE_DIR); + + var iterator = root.Dir.list(); + defer iterator.deinit(); + testing.expectEqual(child_1, iterator.next()); + testing.expectEqual(child_2, iterator.next()); + testing.expectEqual(null, iterator.next()); + + iterator = child_3.list(); + testing.expectEqual(null, iterator.next()); +} From f97c1e7d5bf01b4a9b4e9de13143528e36cb6f01 Mon Sep 17 00:00:00 2001 From: Sam Tebbs Date: Sun, 24 Oct 2021 19:12:40 +0100 Subject: [PATCH 2/4] Add error type --- src/kernel/filesystem/vfs.zig | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/kernel/filesystem/vfs.zig b/src/kernel/filesystem/vfs.zig index e3807114..3f1123d5 100644 --- a/src/kernel/filesystem/vfs.zig +++ b/src/kernel/filesystem/vfs.zig @@ -174,7 +174,7 @@ pub const FileSystem = struct { /// The function for retrieving the root node getRootNode: GetRootNode, - initDirIterator: fn (dir: *const DirNode) void, + initDirIterator: fn (dir: *const DirNode) std.mem.Allocator.Error!void, deinitDirIterator: fn (dir: *const DirNode) void, @@ -221,8 +221,8 @@ pub const DirNode = struct { const Self = @This(); - pub fn init(node: *const DirNode) DirIterator { - node.fs.initDirIterator(node); + pub fn init(node: *const DirNode) std.mem.Allocator.Error!DirIterator { + try node.fs.initDirIterator(node); return DirIterator{ .dir = node, .i = 0 }; } @@ -619,6 +619,7 @@ const TestFS = struct { fs: *FileSystem, allocator: Allocator, open_count: usize, + dir_iter_dummy_memory: std.AutoHashMap(*const DirNode, u8[1]), instance: usize, const Self = @This(); @@ -748,9 +749,17 @@ const TestFS = struct { return Error.NoSuchFileOrDir; } - pub fn initDirIterator(node: *const DirNode) void {} + pub fn initDirIterator(node: *const DirNode) std.mem.Allocator.Error!void { + // Allocate some dummy memory to test initialisation and deinitialisation + var test_fs = @fieldParentPtr(TestFS, "instance", node.fs.instance); + if (test_fs.dir_iter_dummy_memory.get(node) == null) try test_fs.dir_iter_dummy_memory.put(node, test_fs.allocator.alloc(u8, 1)); + } - pub fn deinitDirIterator(node: *const DirNode) void {} + pub fn deinitDirIterator(node: *const DirNode) void { + // De-allocate the dummy memory allocated to test initialisation and deinitialisation + var test_fs = @fieldParentPtr(TestFS, "instance", node.fs.instance); + test_fs.allocator.free(test_fs.dir_iter_dummy_memory.get(node) orelse unreachable); + } pub fn listDirIterator(node: *const DirNode, i: usize) ?*const Node { var test_fs = @fieldParentPtr(TestFS, "instance", node.fs.instance); @@ -1071,6 +1080,7 @@ test "list" { testing.expectEqual(child_2, iterator.next()); testing.expectEqual(null, iterator.next()); - iterator = child_3.list(); - testing.expectEqual(null, iterator.next()); + var iterator2 = child_3.list(); + defer iterator2.deinit(); + testing.expectEqual(null, iterator2.next()); } From f2e6992375c0a3c38304555e35fdfd2dd907900b Mon Sep 17 00:00:00 2001 From: Sam Tebbs Date: Fri, 29 Oct 2021 13:00:33 +0100 Subject: [PATCH 3/4] Make iterator return string --- src/kernel/filesystem/vfs.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/kernel/filesystem/vfs.zig b/src/kernel/filesystem/vfs.zig index 3f1123d5..f12bed50 100644 --- a/src/kernel/filesystem/vfs.zig +++ b/src/kernel/filesystem/vfs.zig @@ -178,7 +178,7 @@ pub const FileSystem = struct { deinitDirIterator: fn (dir: *const DirNode) void, - listDirIterator: fn (dir: *const DirNode, i: usize) ?*const Node, + listDirIterator: fn (dir: *const DirNode, i: usize) ?[]const u8, /// Points to a usize field within the underlying filesystem so that the close, read, write and open functions can access its low-level implementation using @fieldParentPtr. For example, this could point to a usize field within a FAT32 filesystem data structure, which stores all the data and state that is needed in order to interact with a physical disk /// The value of instance is reserved for future use and so should be left as 0 @@ -226,7 +226,7 @@ pub const DirNode = struct { return DirIterator{ .dir = node, .i = 0 }; } - pub fn next(self: *Self) ?*const Node { + pub fn next(self: *Self) ?[]const u8 { self.i += 1; return self.dir.fs.listDirIterator(dir, self.i - 1); } @@ -761,11 +761,11 @@ const TestFS = struct { test_fs.allocator.free(test_fs.dir_iter_dummy_memory.get(node) orelse unreachable); } - pub fn listDirIterator(node: *const DirNode, i: usize) ?*const Node { + pub fn listDirIterator(node: *const DirNode, i: usize) ?[]const u8 { var test_fs = @fieldParentPtr(TestFS, "instance", node.fs.instance); const tree_node = (try getTreeNode(test_fs, node)) orelse unreachable; if (tree_node.children.items.len <= i) return null; - return tree_node.children.items[i].val; + return tree_node.children.items[i].name; } }; From f9a3608bd4436df64c9795a56f1c509ecafd1cf8 Mon Sep 17 00:00:00 2001 From: Sam Tebbs Date: Fri, 29 Oct 2021 13:00:39 +0100 Subject: [PATCH 4/4] Add test --- src/kernel/filesystem/vfs.zig | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/kernel/filesystem/vfs.zig b/src/kernel/filesystem/vfs.zig index f12bed50..a46c019f 100644 --- a/src/kernel/filesystem/vfs.zig +++ b/src/kernel/filesystem/vfs.zig @@ -1070,17 +1070,33 @@ test "list" { defer testfs.deinit(); root = testfs.tree.val; - const child_1 = try openFile("/child1.txt", .CREATE_FILE); - const child_2 = try openFile("/child2.txt", .CREATE_FILE); - const child_3 = try openDir("/child3", .CREATE_DIR); + const child_1_name = "child1.txt"; + const child_2_name = "child2.txt"; + const child_3_name = "child3"; + const child_3_1_name = "child3_1.txt"; + const child_3_2_name = "child3_2.txt"; + + const child_1 = try openFile("/" ++ child_1_name, .CREATE_FILE); + const child_2 = try openFile("/" ++ child_2_name, .CREATE_FILE); + const child_3 = try openDir("/" ++ child_3_name, .CREATE_DIR); var iterator = root.Dir.list(); defer iterator.deinit(); - testing.expectEqual(child_1, iterator.next()); - testing.expectEqual(child_2, iterator.next()); - testing.expectEqual(null, iterator.next()); + testing.expectEqualSlices(child_1_name, iterator.next()); + testing.expectEqualSlices(child_2_name, iterator.next()); + testing.expectEqualSlices(child_3_name, iterator.next()); + testing.expectEqualSlices(null, iterator.next()); var iterator2 = child_3.list(); defer iterator2.deinit(); - testing.expectEqual(null, iterator2.next()); + testing.expectEqualSlices(null, iterator2.next()); + + const child_3_1 = try openDir("/" ++ child_3_name ++ "/" ++ child_3_1_name, .CREATE_DIR); + testing.expectEqualSlices(child_3_1_name, iterator2.next()); + testing.expectEqualSlices(null, iterator2.next()); + + const child_3_2 = try openDir("/" ++ child_3_name ++ "/" ++ child_3_2_name, .CREATE_DIR); + testing.expectEqualSlices(child_3_1_name, iterator2.next()); + testing.expectEqualSlices(child_3_2_name, iterator2.next()); + testing.expectEqualSlices(null, iterator2.next()); }