From b0dced90bcdb210327b4baaf48e96c1dabfae252 Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Mon, 14 Jul 2025 01:40:04 -0500 Subject: [PATCH] MORE PROGRESS --- src/inode.zig | 1 + src/reader.zig | 29 +++++++++++++- src/reader/data.zig | 85 +++++++++++++++++++++++++++++++++++++---- src/reader/metadata.zig | 3 +- src/superblock.zig | 4 +- 5 files changed, 109 insertions(+), 13 deletions(-) diff --git a/src/inode.zig b/src/inode.zig index b36ceca..e959a4f 100644 --- a/src/inode.zig +++ b/src/inode.zig @@ -94,5 +94,6 @@ pub fn deinit(self: Self, alloc: std.mem.Allocator) void { .ext_file => |f| alloc.free(f.block_sizes), .symlink => |s| alloc.free(s.target), .ext_symlink => |s| alloc.free(s.target), + else => {}, } } diff --git a/src/reader.zig b/src/reader.zig index 9328de8..4f982c4 100644 --- a/src/reader.zig +++ b/src/reader.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Inode = @import("inode.zig"); +const File = @import("file.zig").File; const Table = @import("table.zig").Table; const PRead = @import("reader/p_read.zig").PRead; const FragEntry = @import("fragment.zig").FragEntry; @@ -28,7 +29,7 @@ pub fn SfsReader(comptime T: type) type { /// Export table. Each element is an inode referce. /// If accessing directly, keep in mind, the table starts at inode 1, as such it's recommended to use the InodeAt function instead. export_table: Table(Inode.Ref, T) = undefined, - root: ?Inode = null, + root: ?File(T) = null, pub fn init(alloc: std.mem.Allocator, rdr: T, offset: u64) !Self { var out: Self = .{ @@ -45,7 +46,31 @@ pub fn SfsReader(comptime T: type) type { self.id_table.deinit(); self.frag_table.deinit(); self.export_table.deinit(); - // if (self.root != null) self.root.?.deinit(); + if (self.root != null) self.root.?.deinit(); + } + + fn populateRoot(self: *Self) !void { + if (self.root != null) return; + const 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); + self.root = try .init(self, root_inode, ""); + } + + pub fn archiveRoot(self: *Self) !File { + if (self.root == null) try self.populateRoot(); + return self.root.?; + } + pub fn open(self: *Self, path: []const u8) !File { + if (self.root == null) try self.populateRoot(); + _ = path; + // return self.root.?.open(path); + return error{TODO}.TODO; } /// Returns the inode with the given Inode Number. diff --git a/src/reader/data.zig b/src/reader/data.zig index 258decd..d71d924 100644 --- a/src/reader/data.zig +++ b/src/reader/data.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const PRead = @import("p_read.zig").Pread; +const PRead = @import("p_read.zig").PRead; const FragEntry = @import("../fragment.zig").FragEntry; const BlockSize = @import("../inode/file.zig").BlockSize; const Compression = @import("../superblock.zig").Compression; @@ -10,16 +10,21 @@ pub fn DataReader(comptime T: type) type { const Self = @This(); alloc: std.mem.Allocator, + pool: ?*std.Thread.Pool = null, rdr: PRead(T), comp: Compression, - offsets: []BlockSize, + offsets: []u64, file_size: u64, block_size: u32, sizes: []BlockSize, - frag: []u8 = undefined, + frag: []u8 = &[0]u8{}, + + read_block: []u8, + read_offset: u64, + read_idx: u32 = 0, pub fn init( alloc: std.mem.Allocator, @@ -46,10 +51,76 @@ pub fn DataReader(comptime T: type) type { .sizes = sizes, }; } - - pub fn addFragment(self: *Self, entry: FragEntry, offset: u32) void { - self.frag = self.alloc.alloc(u8, self.file_size % self.block_size); - //TODO: + pub fn deinit(self: Self) void { + self.alloc.free(self.offsets); + self.alloc.free(self.frag); } + + pub fn addFragment(self: *Self, entry: FragEntry, offset: u32) !void { + self.frag = try self.alloc.alloc(u8, self.file_size % self.block_size); + if (entry.size.size == 0) { + @memset(self.frag, 0); + return; + } else if (entry.size.uncompressed) { + _ = try self.rdr.pread(self.frag, entry.block + offset); + return; + } + const block = try self.alloc.alloc(u8, offset + self.frag.len); + defer self.alloc.free(block); + _ = try self.comp.decompress( + self.alloc, + std.io.limitedReader( + self.rdr.readerAt(entry.block), + entry.size.size, + ), + block, + ); + @memcpy(self.frag, block[offset..]); + } + pub fn setPool(self: *Self, pool: *std.Thread.Pool) void { + self.pool = pool; + } + + fn blockAt(self: Self, idx: u32) ![]u8 { + const size = if (idx == self.sizes.len - 1 and self.frag.len == 0) { + self.file_size % self.block_size; + } else { + self.block_size; + }; + const block = try self.alloc.alloc(u8, size); + errdefer self.alloc.free(block); + if (self.sizes[idx].size == 0) { + @memset(block, 0); + return block; + } else if (self.sizes[idx].uncompressed) { + _ = try self.rdr.pread(block, self.offsets[idx]); + return block; + } + _ = try self.comp.decompress( + self.alloc, + std.io.limitedReader( + self.rdr.readerAt(self.offsets[idx]), + self.sizes[idx].size, + ), + block, + ); + return block; + } + + pub fn read(self: *Self, buf: []u8) !usize { + var cur_red: usize = 0; + while (cur_red < buf.len) { + if (self.read_offset >= self.read_block.len) { + //TODO: + } + //TODO: + } + return cur_red; + } + + /// Write the entire file's contents to the writer. + /// If availble, pwrite will be used. + /// If a thread pool is not set via setPool, one is created based on cpu thread count. + pub fn writeTo(self: Self, writer: anytype) !usize {} }; } diff --git a/src/reader/metadata.zig b/src/reader/metadata.zig index ee9f8a5..054a032 100644 --- a/src/reader/metadata.zig +++ b/src/reader/metadata.zig @@ -36,10 +36,9 @@ pub fn MetadataReader(comptime T: type) type { _ = try self.rdr.pread(std.mem.asBytes(hdr), self.offset); self.offset += 2; self.block_size = try self.comp.decompress( - 8192, self.alloc, std.io.limitedReader(self.rdr.readerAt(self.offset), hdr.size), - self.block, + &self.block, ); self.offset += hdr.size; self.block_offset = 0; diff --git a/src/superblock.zig b/src/superblock.zig index f20bddc..48ad5b5 100644 --- a/src/superblock.zig +++ b/src/superblock.zig @@ -51,7 +51,7 @@ pub const Compression = enum(u16) { lz4, zstd, - pub fn decompress(self: Compression, comptime max_size: u16, alloc: std.mem.Allocator, source: anytype, dest: *[max_size]u8) !usize { + pub fn decompress(self: Compression, alloc: std.mem.Allocator, source: anytype, dest: []u8) !usize { switch (self) { .gzip => { const decomp = std.compress.zlib.decompressor(source); @@ -70,7 +70,7 @@ pub const Compression = enum(u16) { }, .lz4 => return DecompressError.Lz4Unavailable, .zstd => { - const window: [@min(std.compress.zstd.DecompressorOptions.default_window_buffer_len, max_size)]u8 = undefined; + const window: [@min(std.compress.zstd.DecompressorOptions.default_window_buffer_len, dest.len)]u8 = undefined; const decomp = std.compress.zstd.decompressor(source, .{ .window_buffer = window }); return decomp.read(dest); },