diff --git a/src/file.zig b/src/file.zig index da5c0ab..461c147 100644 --- a/src/file.zig +++ b/src/file.zig @@ -14,6 +14,7 @@ const MetadataReader = @import("reader/metadata.zig").MetadataReader; pub const FileError = error{ NotRegular, NotDirectory, + NotFound, }; pub fn File(comptime T: type) type { @@ -95,8 +96,19 @@ pub fn File(comptime T: type) type { } return out; } + pub fn initFromRef(rdr: *SfsReader(T), ref: Inode.Ref, name: []const u8) !Self { + var meta: MetadataReader(T) = .init(rdr.alloc, rdr.super.comp, rdr.rdr, ref.block + rdr.super.inode_start); + try meta.skip(ref.offset); + const inode: Inode = try .init(&meta, rdr.alloc, rdr.super.block_size); + return .init(rdr, inode, name); + } + pub fn initFromEntry(rdr: *SfsReader(T), ent: DirEntry) !Self { + var meta: MetadataReader(T) = .init(rdr.alloc, rdr.super.comp, rdr.rdr, ent.block + rdr.super.inode_start); + try meta.skip(ent.offset); + const inode: Inode = try .init(&meta, rdr.alloc, rdr.super.block_size); + return .init(rdr, inode, ent.name); + } pub fn deinit(self: Self) void { - self.rdr.alloc.free(self.name); self.inode.deinit(self.rdr.alloc); if (self.entries != null) { for (self.entries.?) |e| { @@ -109,8 +121,44 @@ pub fn File(comptime T: type) type { } } - pub fn iter(self: Self) !void { - _ = self; + pub fn open(self: Self, path: []const u8) !Self { + if (self.entries == null) return FileError.NotDirectory; + if (path.len == 0) return self; + const idx = std.mem.indexOf(u8, path, "/") orelse path.len; + if (idx == 0) return self.open(path[1..]); + const name = path[0..idx]; + for (self.entries.?) |e| { + if (std.mem.eql(u8, e.name, name)) { + var fil: Self = try .initFromEntry(self.rdr, e); + if (idx >= path.len - 1) return fil; + defer fil.deinit(); + return fil.open(path[idx + 1 ..]); + } + } + return FileError.NotFound; } + pub fn iterate(self: Self) Iterator { + return .{ + .rdr = self.rdr, + .entries = self.entries.?, + }; + } + + const Iterator = struct { + rdr: *SfsReader(T), + entries: []DirEntry, + + idx: u32 = 0, + + pub fn next(self: *Iterator) !?File(T) { + if (self.idx >= self.entries.len) return null; + const out = try Self.initFromEntry(self.rdr, self.entries[self.idx]); + self.idx += 1; + return out; + } + pub fn reset(self: *Iterator) void { + self.idx = 0; + } + }; }; } diff --git a/src/reader.zig b/src/reader.zig index 73b1482..4c20de0 100644 --- a/src/reader.zig +++ b/src/reader.zig @@ -47,22 +47,14 @@ pub fn SfsReader(comptime T: type) type { self.export_table.deinit(); } - pub fn archiveRoot(self: *Self) !File(T) { - var meta = MetadataReader(T).init( - self.alloc, - self.super.comp, - self.rdr, - self.super.inode_start + self.super.root_ref.block, - ); - try meta.skip(self.super.root_ref.offset); - const root_inode: Inode = try .init(&meta, self.alloc, self.super.block_size); - return try .init(self, root_inode, ""); + pub fn root(self: *Self) !File(T) { + return .initFromRef(self, self.super.root_ref, ""); } pub fn open(self: *Self, path: []const u8) !File(T) { - _ = self; - _ = path; - // return self.root.?.open(path); - return error{TODO}.TODO; + var rt = try self.root(); + if (path.len == 0 or (path.len == 1 and path[0] == '/')) return rt; + defer rt.deinit(); + return rt.open(path); } /// Returns the inode with the given Inode Number. diff --git a/src/root.zig b/src/root.zig index 2869353..ae7a282 100644 --- a/src/root.zig +++ b/src/root.zig @@ -7,12 +7,29 @@ pub const SfsFile = SfsReader(std.fs.File); const test_file = "testing/LinuxPATest.sfs"; -test "OpenTest" { +test "OpenFile" { const fil = try std.fs.cwd().openFile(test_file, .{}); defer fil.close(); var rdr: SfsFile = try .init(std.testing.allocator, fil, 0); defer rdr.deinit(); std.debug.print("{}\n", .{rdr.super}); - const root = try rdr.archiveRoot(); + const root = try rdr.root(); + defer root.deinit(); + var iter = root.iterate(); + while (try iter.next()) |f| { + defer f.deinit(); + std.debug.print("{s}\n", .{f.name}); + } + const start = try root.open("Start.exe"); + defer start.deinit(); +} + +test "ReadFile" { + const fil = try std.fs.cwd().openFile(test_file, .{}); + defer fil.close(); + var rdr: SfsFile = try .init(std.testing.allocator, fil, 0); + defer rdr.deinit(); + std.debug.print("{}\n", .{rdr.super}); + const root = try rdr.root(); defer root.deinit(); }