diff --git a/src/directory.zig b/src/directory.zig index de41ff9..30fec13 100644 --- a/src/directory.zig +++ b/src/directory.zig @@ -15,8 +15,8 @@ const RawDirEntry = struct { name_size: u16, name: []u8, - fn init(rdr: std.io.AnyReader, alloc: std.mem.Allocator) !DirEntry { - var out: DirEntry = .{ + fn init(rdr: std.io.AnyReader, alloc: std.mem.Allocator) !RawDirEntry { + var out: RawDirEntry = .{ .inode_offset = try rdr.readInt(u16, std.builtin.Endian.little), .inode_num_difference = try rdr.readInt(i16, std.builtin.Endian.little), .inode_type = try rdr.readInt(u16, std.builtin.Endian.little), @@ -39,7 +39,7 @@ pub const DirEntry = struct { return .{ .inode_offset = raw.inode_offset, .inode_block_start = hdr.inode_block_start, - .inode_num = hdr.inode_num - raw.inode_num_difference, + .inode_num = hdr.inode_num + @as(u32, @intCast(raw.inode_num_difference)), .name = raw.name, }; } @@ -52,25 +52,29 @@ pub fn readDirEntries(alloc: std.mem.Allocator, comp: CompressionType, rdr: std. var meta_hdr: MetadataHeader = undefined; var dir_hdr: DirHeader = undefined; var buf: []u8 = undefined; - var buf_rdr: std.io.FixedBufferStream(u8) = undefined; - var i = 0; - var entries: std.ArrayList(DirEntry) = .init(alloc); defer alloc.free(buf); + var buf_rdr: std.io.FixedBufferStream([]u8) = undefined; + var i: u32 = 0; + var entries: std.ArrayList(DirEntry) = .init(alloc); + var raw: RawDirEntry = undefined; while (total_size < size) { meta_hdr = try rdr.readStruct(MetadataHeader); if (meta_hdr.not_compressed) { buf = try alloc.realloc(buf, meta_hdr.size); - _ = try rdr.readAll(rdr); + _ = try rdr.readAll(buf); } else { alloc.free(buf); - buf = try comp.Decompress(alloc, std.io.limitedReader(rdr, meta_hdr.size)); + var limit = std.io.limitedReader(rdr, meta_hdr.size); + buf = try comp.decompress(alloc, limit.reader().any()); } buf_rdr = std.io.fixedBufferStream(buf); dir_hdr = try buf_rdr.reader().readStruct(DirHeader); total_size += 12; i = 0; while (i < dir_hdr.count) : (i += 1) { - entries.append(try .init(try .init(buf_rdr, alloc), dir_hdr)); + raw = try .init(buf_rdr.reader().any(), alloc); + total_size += @sizeOf(RawDirEntry); + try entries.append(.init(raw, dir_hdr)); } } return try entries.toOwnedSlice(); diff --git a/src/file.zig b/src/file.zig index 149f71b..a447b71 100644 --- a/src/file.zig +++ b/src/file.zig @@ -4,7 +4,7 @@ const inode = @import("inode.zig"); const Reader = @import("squashfs.zig").Reader; const MetadataReader = @import("metadata_reader.zig").MetadataReader; const FileOffsetReader = @import("file_offset_reader.zig").FileOffsetReader; -const DirEntry = @import("directory.zig").DirEntry; +const dir = @import("directory.zig"); const FileOpenError = error{ NotFound, @@ -15,10 +15,10 @@ pub const File = struct { rdr: *Reader, inode: inode.Inode, name: []const u8, - dir_entries: []DirEntry = undefined, + dir_entries: []dir.DirEntry = &[0]dir.DirEntry{}, pub fn fromRef(rdr: *Reader, ref: inode.InodeRef, name: []const u8) !File { - var offset_rdr: FileOffsetReader = .init(rdr.file, rdr.super.inode_table + ref.block_start); + var offset_rdr: FileOffsetReader = .init(rdr.rdr, rdr.super.inode_table + ref.block_start); var meta_rdr: MetadataReader = .init(rdr.super.comp, offset_rdr.any(), rdr.alloc.allocator()); try meta_rdr.skip(ref.offset); const in = try inode.readInode(meta_rdr, rdr.super.block_size, rdr.alloc.allocator()); @@ -29,15 +29,15 @@ pub const File = struct { }; } - pub fn fromDirEntry(rdr: *Reader, ent: DirEntry) !File { - var offset_rdr: FileOffsetReader = .init(rdr.file, rdr.super.inode_table + ent.inode_block_start); - var meta_rdr: MetadataReader = .init( + pub fn fromDirEntry(rdr: *Reader, ent: dir.DirEntry) !File { + var offset_rdr: FileOffsetReader = .init(&rdr.rdr, rdr.super.inode_table + ent.inode_block_start); + var meta_rdr: MetadataReader = try .init( rdr.super.comp, offset_rdr.any(), - rdr.alloc, + rdr.alloc.allocator(), ); try meta_rdr.skip(ent.inode_offset); - const in = try inode.readInode(meta_rdr, rdr.super.block_size, rdr.alloc.allocator()); + const in = try inode.readInode(meta_rdr.any(), rdr.super.block_size, rdr.alloc.allocator()); return .{ .rdr = rdr, .inode = in, @@ -45,18 +45,50 @@ pub const File = struct { }; } - pub fn open(self: File, path: []const u8) (anyerror || FileOpenError)!File { + pub fn open(self: *File, path: []const u8) (anyerror || FileOpenError)!File { + if (path.len == 0) return self.*; + const clean_path: []const u8 = std.mem.trimLeft(u8, path, "/"); + if (clean_path.len == 0 or std.mem.eql(u8, clean_path, ".")) { + return self.*; + } switch (self.inode.header.inode_type) { .dir, .ext_dir => {}, else => return FileOpenError.NotDirectory, } - const clean_path: []const u8 = if (std.mem.startsWith(u8, path, "/")) { - return path[1..]; - } else { - return path; - }; - const path_split = std.mem.splitAny(u8, clean_path, "/"); + try self.readDirEntries(); + const file_name = std.mem.sliceTo(clean_path, '/'); + for (self.dir_entries) |ent| { + std.debug.print("yo {}\n", .{ent}); + if (std.mem.eql(u8, file_name, ent.name)) { + return try File.fromDirEntry(self.rdr, ent); + } + } + return FileOpenError.NotFound; } - fn readDirEntries(self: *File) (anyerror || FileOpenError)!File {} + fn readDirEntries(self: *File) (anyerror || FileOpenError)!void { + if (self.dir_entries.len != 0) { + return; + } + var dir_block_offset: u32 = undefined; + var dir_block_start: u32 = undefined; + var size: u32 = undefined; + switch (self.inode.data) { + .dir => |d| { + dir_block_start = d.dir_block_start; + dir_block_offset = d.dir_block_offset; + size = d.dir_table_size; + }, + .ext_dir => |d| { + dir_block_start = d.dir_block_start; + dir_block_offset = d.dir_block_offset; + size = d.dir_table_size; + }, + else => return FileOpenError.NotDirectory, + } + std.debug.print("{}\n", .{self.rdr}); + var offset_rdr: FileOffsetReader = .init(&self.rdr.rdr, self.rdr.super.dir_table + dir_block_start); + var meta_rdr: MetadataReader = try .init(self.rdr.super.comp, offset_rdr.any(), self.rdr.alloc.allocator()); + self.dir_entries = try dir.readDirEntries(self.rdr.alloc.allocator(), self.rdr.super.comp, meta_rdr.any(), size); + } }; diff --git a/src/file_offset_reader.zig b/src/file_offset_reader.zig index baf1168..9978c9f 100644 --- a/src/file_offset_reader.zig +++ b/src/file_offset_reader.zig @@ -1,10 +1,10 @@ const std = @import("std"); pub const FileOffsetReader = struct { - file: std.fs.File, + file: *std.fs.File, offset: u64, - pub fn init(file: std.fs.File, initial_offset: u64) FileOffsetReader { + pub fn init(file: *std.fs.File, initial_offset: u64) FileOffsetReader { return .{ .file = file, .offset = initial_offset, diff --git a/src/metadata_reader.zig b/src/metadata_reader.zig index 8a5f105..01c9ba8 100644 --- a/src/metadata_reader.zig +++ b/src/metadata_reader.zig @@ -14,7 +14,6 @@ pub const MetadataReader = struct { decomp: CompressionType, curBlock: []u8, curOffset: u16, - free: bool = false, pub fn init(decomp: CompressionType, rdr: io.AnyReader, alloc: std.mem.Allocator) !MetadataReader { var out: MetadataReader = .{ @@ -58,7 +57,7 @@ pub const MetadataReader = struct { _ = try self.rdr.readAll(self.curBlock); } else { var limit_rdr = std.io.limitedReader(self.rdr, hdr.size); - self.curBlock = try self.decomp.Decompress(self.alloc, limit_rdr.reader().any()); + self.curBlock = try self.decomp.decompress(self.alloc, limit_rdr.reader().any()); } } diff --git a/src/squashfs.zig b/src/squashfs.zig index 8bb3118..c04adc5 100644 --- a/src/squashfs.zig +++ b/src/squashfs.zig @@ -11,39 +11,44 @@ pub const Reader = struct { super: Superblock, rdr: fs.File, root: File, - alloc: std.heap.GeneralPurposeAllocator(.{}), + alloc: std.heap.ArenaAllocator, - pub fn deinit(self: *Reader) void { - self.rdr.close(); - // _ = self.alloc.deinit(); - } -}; - -pub fn newReader(filename: []const u8) !Reader { - const file = try std.fs.cwd().openFile(filename, .{}); - errdefer file.close(); - var alloc: std.heap.GeneralPurposeAllocator(.{}) = .init; - errdefer _ = alloc.deinit(); - const super = try file.reader().readStruct(Superblock); - try super.valid(); - var offset_rdr: FileOffsetReader = .init(file, super.inode_table + super.root_inode.block_start); - var root_reader: MetadataReader = try .init( - super.comp, - offset_rdr.any(), - alloc.allocator(), - ); - defer root_reader.deinit(); - try root_reader.skip(super.root_inode.offset); - var out: Reader = undefined; - out = Reader{ - .super = super, - .rdr = file, - .root = .{ + pub fn init(filename: []const u8) !Reader { + var file = try std.fs.cwd().openFile(filename, .{}); + errdefer file.close(); + var alloc: std.heap.ArenaAllocator = .init(std.heap.smp_allocator); + errdefer _ = alloc.deinit(); + const super = try file.reader().readStruct(Superblock); + try super.valid(); + var offset_rdr: FileOffsetReader = .init(&file, super.inode_table + super.root_inode.block_start); + var root_reader: MetadataReader = try .init( + super.comp, + offset_rdr.any(), + alloc.allocator(), + ); + defer root_reader.deinit(); + try root_reader.skip(super.root_inode.offset); + var out: Reader = .{ + .super = super, + .rdr = file, + .root = undefined, + .alloc = alloc, + }; + out.root = .{ .inode = try inode.readInode(root_reader.any(), super.block_size, alloc.allocator()), .name = "", .rdr = &out, - }, - .alloc = alloc, - }; - return out; -} + }; + std.debug.print("init {}\n", .{out}); + return out; + } + + pub fn deinit(self: *Reader) void { + self.rdr.close(); + self.alloc.deinit(); + } + + pub fn open(self: *Reader, path: []const u8) !File { + return self.root.open(path); + } +}; diff --git a/src/test_squashfs.zig b/src/test_squashfs.zig index 3222bc5..510f897 100644 --- a/src/test_squashfs.zig +++ b/src/test_squashfs.zig @@ -8,4 +8,6 @@ const testFileName = "testing/LinuxPATest.sfs"; test "open test file" { var reader = try squashfs.newReader(testFileName); defer reader.deinit(); + const fil = try reader.open("PortableApps/Desktop.ini"); + std.debug.print("{s}\n", .{fil.name}); }