From 128ed9f001bedc28c8a568140ae201fcdb140532 Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Mon, 19 May 2025 09:49:23 -0500 Subject: [PATCH] Started work on data readers --- src/file.zig | 49 ++++++++++------ src/reader.zig | 4 +- src/readers/data.zig | 114 ++++++++++++++++++++++++++++++++++++ src/readers/file_holder.zig | 8 ++- src/readers/metadata.zig | 16 ++--- src/root.zig | 2 - 6 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 src/readers/data.zig diff --git a/src/file.zig b/src/file.zig index a8bbe1a..efb2241 100644 --- a/src/file.zig +++ b/src/file.zig @@ -3,23 +3,25 @@ const io = std.io; const inode = @import("inode/inode.zig"); const directory = @import("directory.zig"); +const data = @import("readers/data.zig"); const Reader = @import("reader.zig").Reader; const DirEntry = @import("directory.zig").DirEntry; const MetadataReader = @import("readers/metadata.zig").MetadataReader; -const FileError = error{ - NotDirectory, - NotNormalFile, - NotSymlink, - NotFound, -}; - pub const File = struct { name: []const u8, inode: inode.Inode, - dirEntries: std.StringHashMap(DirEntry) = undefined, - hasEntries: bool = false, + dirEntries: ?std.StringHashMap(DirEntry) = null, + + data_rdr: ?data.DataReader = null, + + pub const FileError = error{ + NotDirectory, + NotNormalFile, + NotSymlink, + NotFound, + }; pub fn deinit(self: *File, alloc: std.mem.Allocator) void { self.inode.deinit(); @@ -47,9 +49,7 @@ pub const File = struct { .dir, .ext_dir => {}, else => return FileError.NotDirectory, } - if (!self.hasEntries) { - try self.readDirEntries(reader); - } + try self.readDirEntries(reader); const split_idx = std.mem.indexOf(u8, clean_path, "/") orelse clean_path.len; const name = clean_path[0..split_idx]; const ent = self.dirEntries.get(name); @@ -69,6 +69,7 @@ pub const File = struct { } fn readDirEntries(self: *File, reader: *Reader) !void { + if (self.dirEntries != null) return; var block_start: u32 = 0; var offset: u16 = 0; var size: u32 = 0; @@ -86,36 +87,48 @@ pub const File = struct { else => return FileError.NotDirectory, } var offset_rdr = reader.holder.readerAt(reader.super.dir_table_start + block_start); - var meta_rdr: MetadataReader = try .init( + var meta_rdr: MetadataReader = .init( reader.alloc, - offset_rdr.any(), reader.super.decomp, + offset_rdr.any(), ); defer meta_rdr.deinit(); try meta_rdr.skip(offset); self.dirEntries = try directory.readDirectory(reader.alloc, meta_rdr.any(), size); self.hasEntries = true; } + + pub fn read(self: *File, bytes: []u8) !usize { + if (self.data_rdr == null) { + return FileError.NotNormalFile; + } + return self.data_rdr.?.read(bytes); + } }; fn fileFromDirEntry(read: *Reader, ent: DirEntry) !File { var offset_rdr = read.holder.readerAt(ent.block_start + read.super.inode_table_start); - var meta_rdr: MetadataReader = try .init( + var meta_rdr: MetadataReader = .init( read.alloc, - offset_rdr.any(), read.super.decomp, + offset_rdr.any(), ); defer meta_rdr.deinit(); try meta_rdr.skip(ent.offset); // Copy name so we can clean-up the DirEntrys without causing issues. const name = try read.alloc.alloc(u8, ent.name.len); std.mem.copyForwards(u8, name, ent.name); - return .{ + var out: File = .{ .name = name, - .inode = try .init( + .inode = .init( read.alloc, meta_rdr.any(), read.super.block_size, ), }; + out.data_rdr = switch (out.inode.data) { + .file, .ext_file => try .init(&out, read), + else => null, + }; + return out; } diff --git a/src/reader.zig b/src/reader.zig index 023d9d8..de3f216 100644 --- a/src/reader.zig +++ b/src/reader.zig @@ -34,10 +34,10 @@ pub const Reader = struct { fn fileFromRef(self: *Reader, ref: inode.InodeRef, name: []const u8) !File { var offset_rdr = self.holder.readerAt(ref.block_start + self.super.inode_table_start); - var meta_rdr: MetadataReader = try .init( + var meta_rdr: MetadataReader = .init( self.alloc, - offset_rdr.any(), self.super.decomp, + offset_rdr.any(), ); defer meta_rdr.deinit(); try meta_rdr.skip(ref.offset); diff --git a/src/readers/data.zig b/src/readers/data.zig new file mode 100644 index 0000000..12cea94 --- /dev/null +++ b/src/readers/data.zig @@ -0,0 +1,114 @@ +const std = @import("std"); +const io = std.io; + +const File = @import("../file.zig").File; +const Reader = @import("../reader.zig").Reader; +const BlockSize = @import("../inode/file.zig").BlockSize; +const DecompressionType = @import("../decompress.zig").DecompressType; + +const DataReaderError = error{ + EOF, +}; + +pub const DataReader = struct { + alloc: std.mem.Allocator, + decomp: DecompressionType, + rdr: io.AnyReader, + block_size: u32, + sizes: []BlockSize, + frag_rdr: ?io.AnyReader, + + next_block_num: u32 = 0, + cur_bloc: []u8 = undefined, + cur_offset: u32 = 0, + + pub fn init(fil: *File, reader: *Reader) !DataReader { + const data_start: u64 = 0; + const sizes: []BlockSize = undefined; + const size: u64 = 0; + const frag_idx: u32 = 0; + const frag_offset: u32 = 0; + switch (fil.inode.data) { + .file => |f| { + sizes = try reader.alloc.alloc(BlockSize, f.blocks.len); + std.mem.copyForwards(BlockSize, sizes, f.blocks); + data_start = f.data_start; + size = f.size; + frag_idx = f.frag_idx; + frag_offset = f.frag_offset; + }, + .ext_file => |f| { + sizes = try reader.alloc.alloc(BlockSize, f.blocks.len); + std.mem.copyForwards(BlockSize, sizes, f.blocks); + data_start = f.data_start; + size = f.size; + frag_idx = f.frag_idx; + frag_offset = f.frag_offset; + }, + else => return File.FileError.NotNormalFile, + } + //TODO: set-up frag_rdr + } + + pub fn deinit(self: *DataReader) void { + if (self.cur_bloc.len > 0) self.alloc.free(self.cur_bloc); + } + + pub fn skip(self: *DataReader, offset: u32) !void { + var cur_skip: u32 = 0; + var to_skip: u32 = 0; + while (cur_skip < offset) { + if (self.offset >= self.block.len) try self.readNextBlock(); + to_skip = @min(offset - cur_skip, self.block.len - self.offset); + cur_skip += to_skip; + self.offset += to_skip; + } + } + + fn readNextBlock(self: *DataReader) !void { + if (self.next_block_num == self.sizes.len) { + if (self.cur_bloc.len > 0) self.alloc.free(self.cur_bloc); + return DataReaderError.EOF; + } + const siz = self.sizes[self.next_block_num]; + self.next_block_num += 1; + if (self.next_block_num == self.sizes.len - 1 and self.frag_rdr != null) { + _ = try self.frag_rdr.?.readAll(self.cur_bloc); + return; + } + if (siz.size == 0) {} + if (siz.not_compressed) {} + } + + pub fn read(self: *DataReader, bytes: []u8) !usize { + var cur_read: usize = 0; + var to_read: usize = 0; + while (cur_read < bytes.len) { + if (self.offset >= self.block.len) { + if (self.readNextBlock()) |err| { + if (err == DataReaderError.EOF) return cur_read; + return err; + } + } + to_read = @min(bytes.len - cur_read, self.block.len - self.offset); + std.mem.copyForwards(u8, bytes[cur_read..], self.block[self.offset .. @as(usize, self.offset) + to_read]); + self.offset += @truncate(to_read); + cur_read += to_read; + } + return cur_read; + } + + pub fn any(self: *DataReader) io.AnyReader { + return .{ + .context = @ptrCast(self), + .readFn = readOpaque, + }; + } + + fn readOpaque(context: *const anyopaque, bytes: []u8) !usize { + var self: *DataReader = @constCast(@ptrCast(@alignCast(context))); + return self.read(bytes); + } +}; + +pub const DataExtractor = struct {}; diff --git a/src/readers/file_holder.zig b/src/readers/file_holder.zig index b0abcf0..2d812c6 100644 --- a/src/readers/file_holder.zig +++ b/src/readers/file_holder.zig @@ -2,8 +2,10 @@ const std = @import("std"); const fs = std.fs; const io = std.io; +const File = std.fs.File; + pub const FileHolder = struct { - file: fs.File, + file: File, offset: u64, pub fn init(path: []const u8, offset: u64) !FileHolder { @@ -16,7 +18,7 @@ pub const FileHolder = struct { self.file.close(); } - pub fn reader(self: *FileHolder) fs.File.Reader { + pub fn reader(self: *FileHolder) File.Reader { return self.file.reader(); } pub fn readerAt(self: *FileHolder, offset: u64) FileOffsetReader { @@ -28,7 +30,7 @@ pub const FileHolder = struct { }; const FileOffsetReader = struct { - file: *fs.File, + file: *File, offset: u64, pub fn read(self: *FileOffsetReader, bytes: []u8) !usize { diff --git a/src/readers/metadata.zig b/src/readers/metadata.zig index a3cf54b..153e782 100644 --- a/src/readers/metadata.zig +++ b/src/readers/metadata.zig @@ -10,21 +10,17 @@ const MetadataHeader = packed struct { pub const MetadataReader = struct { alloc: std.mem.Allocator, - reader: io.AnyReader, - block: []u8, decomp: DecompressType, - offset: u32, + reader: io.AnyReader, + block: []u8 = &[0]u8{}, + offset: u32 = 0, - pub fn init(alloc: std.mem.Allocator, rdr: io.AnyReader, decomp: DecompressType) !MetadataReader { - var out: MetadataReader = .{ + pub fn init(alloc: std.mem.Allocator, decomp: DecompressType, rdr: io.AnyReader) MetadataReader { + return .{ .alloc = alloc, - .reader = rdr, - .block = &[0]u8{}, .decomp = decomp, - .offset = 0, + .reader = rdr, }; - try out.readNextBlock(); - return out; } pub fn deinit(self: *MetadataReader) void { self.alloc.free(self.block); diff --git a/src/root.zig b/src/root.zig index fc03aa5..b64c197 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,3 +1 @@ pub const Reader = @import("reader.zig").Reader; - -pub const File = @import("file.zig").File;