Almost kind of working

This commit is contained in:
Caleb Gardner
2025-05-14 01:59:19 -05:00
parent a866804853
commit 3684a958a0
9 changed files with 135 additions and 66 deletions
+45
View File
@@ -0,0 +1,45 @@
const std = @import("std");
const compress = std.compress;
const DecompressError = error{
LzoNotSupported,
Lz4NotSupported,
};
pub const CompressionType = enum(u16) {
gzip = 1,
lzma,
lzo,
xz,
lz4,
zstd,
pub fn Decompress(self: CompressionType, alloc: std.mem.Allocator, rdr: std.io.AnyReader) ![]u8 {
var out = std.ArrayList(u8).init(alloc);
defer out.deinit();
switch (self) {
.gzip => try compress.zlib.decompress(rdr, out.writer()),
.lzma => {
var decomp = try compress.lzma.decompress(alloc, rdr);
defer decomp.deinit();
try decomp.reader().readAllArrayList(&out, 1024 * 1024);
},
.lzo => return DecompressError.LzoNotSupported,
.xz => {
var decomp = try compress.xz.decompress(alloc, rdr);
defer decomp.deinit();
try decomp.reader().readAllArrayList(&out, 1024 * 1024);
},
.lz4 => return DecompressError.Lz4NotSupported,
.zstd => {
const buf = try alloc.alloc(u8, compress.zstd.DecompressorOptions.default_window_buffer_len);
defer alloc.free(buf);
var decomp = compress.zstd.decompressor(rdr, .{
.window_buffer = buf,
});
try decomp.reader().readAllArrayList(&out, 1024 * 1024);
},
}
return try out.toOwnedSlice();
}
};
+5 -5
View File
@@ -45,8 +45,8 @@ pub const InodeData = union(enum) {
ext_symlink: sym.ExtSymlinkInode, ext_symlink: sym.ExtSymlinkInode,
ext_block_device: misc.ExtDeviceInode, ext_block_device: misc.ExtDeviceInode,
ext_char_device: misc.ExtDeviceInode, ext_char_device: misc.ExtDeviceInode,
ext_fifo: misc.IPCInode, ext_fifo: misc.ExtIPCInode,
ext_socket: misc.IPCInode, ext_socket: misc.ExtIPCInode,
}; };
const dir = @import("inode_types/dir.zig"); const dir = @import("inode_types/dir.zig");
@@ -61,13 +61,13 @@ pub const Inode = struct {
const io = @import("std").io; const io = @import("std").io;
pub fn readInode(rdr: io.AnyReader, block_size: u64, alloc: std.heap.Allocator) !Inode { pub fn readInode(rdr: io.AnyReader, block_size: u32, alloc: std.mem.Allocator) !Inode {
const hdr = try rdr.readStruct(InodeHeader); const hdr = try rdr.readStruct(InodeHeader);
return Inode{ return Inode{
.header = hdr, .header = hdr,
.data = switch (hdr.inode_type) { .data = switch (hdr.inode_type) {
.dir => .{ .dir => .{
.dir = dir.readDirInode(rdr), .dir = try dir.readDirInode(rdr),
}, },
.ext_dir => .{ .ext_dir => .{
.ext_dir = try dir.readExtDirInode(rdr, alloc), .ext_dir = try dir.readExtDirInode(rdr, alloc),
@@ -79,7 +79,7 @@ pub fn readInode(rdr: io.AnyReader, block_size: u64, alloc: std.heap.Allocator)
.ext_file = try file.readExtFileInode(rdr, block_size, alloc), .ext_file = try file.readExtFileInode(rdr, block_size, alloc),
}, },
.symlink => .{ .symlink => .{
.block_device = try misc.readSymlinkInode(rdr, alloc), .symlink = try sym.readSymlinkInode(rdr, alloc),
}, },
.ext_symlink => .{ .ext_symlink => .{
.ext_symlink = try sym.readExtSymlinkInode(rdr, alloc), .ext_symlink = try sym.readExtSymlinkInode(rdr, alloc),
+16 -16
View File
@@ -17,18 +17,18 @@ pub const DirIndex = struct {
dir_header_offset: u32, dir_header_offset: u32,
dir_table_offset: u32, dir_table_offset: u32,
name_size: u32, name_size: u32,
name: []const u8, name: []u8,
}; };
fn readDirIndex(rdr: io.AnyReader, alloc: std.heap.Allocator) !DirIndex { fn readDirIndex(rdr: io.AnyReader, alloc: std.mem.Allocator) !DirIndex {
const out = DirIndex{ var out = DirIndex{
.dir_header_offset = try rdr.readInt(u32, std.builtin.Endian.little), .dir_header_offset = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_table_offset = try rdr.readInt(u32, std.builtin.Endian.little), .dir_table_offset = try rdr.readInt(u32, std.builtin.Endian.little),
.name_size = try rdr.readInt(u32, std.builtin.Endian.little), .name_size = try rdr.readInt(u32, std.builtin.Endian.little),
.name = undefined, .name = undefined,
}; };
out.name = try alloc.alloc(u8, out.name_size); out.name = try alloc.alloc(u8, out.name_size);
try rdr.read(out.name); _ = try rdr.readAll(out.name);
return out; return out;
} }
@@ -40,23 +40,23 @@ pub const ExtDirInode = struct {
dir_index_count: u16, dir_index_count: u16,
dir_block_offset: u16, dir_block_offset: u16,
xattr_index: u32, xattr_index: u32,
indexes: []const DirIndex, indexes: []DirIndex,
}; };
pub fn readExtDirInode(rdr: io.AnyReader, alloc: std.heap.Allocator) !ExtDirInode { pub fn readExtDirInode(rdr: io.AnyReader, alloc: std.mem.Allocator) !ExtDirInode {
const out = ExtDirInode{ var out = ExtDirInode{
.hard_links = rdr.readInt(u32, std.builtin.Endian.little), .hard_links = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_table_size = rdr.readInt(u32, std.builtin.Endian.little), .dir_table_size = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_block_start = rdr.readInt(u32, std.builtin.Endian.little), .dir_block_start = try rdr.readInt(u32, std.builtin.Endian.little),
.parent_inode_num = rdr.readInt(u32, std.builtin.Endian.little), .parent_inode_num = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_index_count = rdr.readInt(u16, std.builtin.Endian.little), .dir_index_count = try rdr.readInt(u16, std.builtin.Endian.little),
.dir_block_offset = rdr.readInt(u16, std.builtin.Endian.little), .dir_block_offset = try rdr.readInt(u16, std.builtin.Endian.little),
.xattr_index = rdr.readInt(u32, std.builtin.Endian.little), .xattr_index = try rdr.readInt(u32, std.builtin.Endian.little),
.indexes = undefined, .indexes = undefined,
}; };
const tmp = std.ArrayList(DirIndex).init(alloc); var tmp = std.ArrayList(DirIndex).init(alloc);
try tmp.resize(out.dir_index_count); try tmp.resize(out.dir_index_count);
const i: u16 = 0; var i: u16 = 0;
while (i < out.dir_index_count) : (i += 1) { while (i < out.dir_index_count) : (i += 1) {
tmp.items[i] = try readDirIndex(rdr, alloc); tmp.items[i] = try readDirIndex(rdr, alloc);
} }
+6 -6
View File
@@ -8,8 +8,8 @@ pub const FileInode = struct {
block_sizes: []const u32, block_sizes: []const u32,
}; };
pub fn readFileInode(rdr: std.io.AnyReader, block_size: u32, alloc: std.heap.Allocator) !FileInode { pub fn readFileInode(rdr: std.io.AnyReader, block_size: u32, alloc: std.mem.Allocator) !FileInode {
const out = FileInode{ var out = FileInode{
.start = try rdr.readInt(u32, std.builtin.Endian.little), .start = try rdr.readInt(u32, std.builtin.Endian.little),
.frag_index = try rdr.readInt(u32, std.builtin.Endian.little), .frag_index = try rdr.readInt(u32, std.builtin.Endian.little),
.frag_block_offset = try rdr.readInt(u32, std.builtin.Endian.little), .frag_block_offset = try rdr.readInt(u32, std.builtin.Endian.little),
@@ -21,7 +21,7 @@ pub fn readFileInode(rdr: std.io.AnyReader, block_size: u32, alloc: std.heap.All
block_num += 1; block_num += 1;
} }
out.block_sizes = try alloc.alloc(u32, block_num); out.block_sizes = try alloc.alloc(u32, block_num);
try rdr.read(std.mem.asBytes(&out.block_sizes)); _ = try rdr.readAll(std.mem.asBytes(&out.block_sizes));
return out; return out;
} }
@@ -36,8 +36,8 @@ pub const ExtFileInode = struct {
block_sizes: []const u32, block_sizes: []const u32,
}; };
pub fn readExtFileInode(rdr: std.io.AnyReader, block_size: u32, alloc: std.heap.Allocator) !ExtFileInode { pub fn readExtFileInode(rdr: std.io.AnyReader, block_size: u32, alloc: std.mem.Allocator) !ExtFileInode {
const out = ExtFileInode{ var out = ExtFileInode{
.start = try rdr.readInt(u64, std.builtin.Endian.little), .start = try rdr.readInt(u64, std.builtin.Endian.little),
.size = try rdr.readInt(u64, std.builtin.Endian.little), .size = try rdr.readInt(u64, std.builtin.Endian.little),
.sparse = try rdr.readInt(u64, std.builtin.Endian.little), .sparse = try rdr.readInt(u64, std.builtin.Endian.little),
@@ -52,6 +52,6 @@ pub fn readExtFileInode(rdr: std.io.AnyReader, block_size: u32, alloc: std.heap.
block_num += 1; block_num += 1;
} }
out.block_sizes = try alloc.alloc(u32, block_num); out.block_sizes = try alloc.alloc(u32, block_num);
try rdr.read(std.mem.asBytes(&out.block_sizes)); _ = try rdr.readAll(std.mem.asBytes(&out.block_sizes));
return out; return out;
} }
+8 -8
View File
@@ -4,36 +4,36 @@ const io = std.io;
pub const SymlinkInode = struct { pub const SymlinkInode = struct {
hard_links: u32, hard_links: u32,
target_size: u32, target_size: u32,
path: []const u8, path: []u8,
}; };
pub fn readSymlinkInode(rdr: io.AnyReader, alloc: std.heap.Allocator) !SymlinkInode { pub fn readSymlinkInode(rdr: io.AnyReader, alloc: std.mem.Allocator) !SymlinkInode {
const out = SymlinkInode{ var out = SymlinkInode{
.hard_links = try rdr.readInt(u32, std.builtin.Endian.little), .hard_links = try rdr.readInt(u32, std.builtin.Endian.little),
.target_size = try rdr.readInt(u32, std.builtin.Endian.little), .target_size = try rdr.readInt(u32, std.builtin.Endian.little),
.path = undefined, .path = undefined,
}; };
out.path = try alloc.alloc(u8, out.target_size + 1); out.path = try alloc.alloc(u8, out.target_size + 1);
try rdr.read(out.path); _ = try rdr.readAll(out.path);
return out; return out;
} }
pub const ExtSymlinkInode = struct { pub const ExtSymlinkInode = struct {
hard_links: u32, hard_links: u32,
target_size: u32, target_size: u32,
path: []const u8, path: []u8,
xattr_index: u32, xattr_index: u32,
}; };
pub fn readExtSymlinkInode(rdr: io.AnyReader, alloc: std.heap.Allocator) !SymlinkInode { pub fn readExtSymlinkInode(rdr: io.AnyReader, alloc: std.mem.Allocator) !ExtSymlinkInode {
const out = ExtSymlinkInode{ var out = ExtSymlinkInode{
.hard_links = try rdr.readInt(u32, std.builtin.Endian.little), .hard_links = try rdr.readInt(u32, std.builtin.Endian.little),
.target_size = try rdr.readInt(u32, std.builtin.Endian.little), .target_size = try rdr.readInt(u32, std.builtin.Endian.little),
.path = undefined, .path = undefined,
.xattr_index = undefined, .xattr_index = undefined,
}; };
out.path = try alloc.alloc(u8, out.target_size + 1); out.path = try alloc.alloc(u8, out.target_size + 1);
try rdr.read(out.path); _ = try rdr.readAll(out.path);
out.xattr_index = try rdr.readInt(u32, std.builtin.Endian.little); out.xattr_index = try rdr.readInt(u32, std.builtin.Endian.little);
return out; return out;
} }
+41 -14
View File
@@ -1,45 +1,72 @@
const std = @import("std"); const std = @import("std");
const io = std.io; const io = std.io;
const CompressionType = @import("decompress.zig").CompressionType;
const MetadataHeader = packed struct { const MetadataHeader = packed struct {
not_compressed: bool, not_compressed: bool,
size: u15, size: u15,
}; };
const MetadataReader = struct { pub const MetadataReader = struct {
rdr: std.io.AnyReader, rdr: std.io.AnyReader,
alloc: std.heap.Allocator, alloc: std.mem.Allocator,
curBlock: []const u8, decomp: CompressionType,
curBlock: []u8,
curOffset: u16, curOffset: u16,
pub fn init(rdr: io.AnyReader, alloc: std.heap.Allocator) !MetadataReader { pub fn init(decomp: CompressionType, rdr: io.AnyReader, alloc: std.mem.Allocator) !MetadataReader {
const out = .{ var out: MetadataReader = .{
.rdr = rdr, .rdr = rdr,
.alloc = alloc, .alloc = alloc,
.curBlock = undefined, .decomp = decomp,
.curBlock = &[_]u8{},
.curOffset = 0, .curOffset = 0,
}; };
try out.readNextBlock(); try out.readNextBlock();
return out; return out;
} }
pub fn any(self: MetadataReader) !io.AnyReader { pub fn any(self: *MetadataReader) io.AnyReader {
return .{ return .{
.context = @ptrCast(&self), .context = @ptrCast(self),
.readFn = typeErasedReadFn, .readFn = readOpaque,
}; };
} }
fn readNextBlock(self: MetadataReader) !void { fn readNextBlock(self: *MetadataReader) !void {
if (self.curBlock != undefined) { if (self.curBlock.len != 0) {
self.alloc.free(self.curBlock); self.alloc.free(self.curBlock);
} }
self.curOffset = 0; self.curOffset = 0;
const hdr = try self.rdr.readStruct(MetadataHeader); const hdr = try self.rdr.readStruct(MetadataHeader);
const buf = try self.alloc.alloc(u8, hdr.size);
if (hdr.not_compressed) { if (hdr.not_compressed) {
self.curBlock = buf; self.curBlock = try self.alloc.alloc(u8, hdr.size);
_ = try self.rdr.readAll(self.curBlock);
} else { } else {
//TODO: decompress var limit_rdr = std.io.limitedReader(self.rdr, hdr.size);
self.curBlock = try self.decomp.Decompress(self.alloc, limit_rdr.reader().any());
} }
} }
pub fn read(self: *MetadataReader, bytes: []u8) anyerror!usize {
var cur_read: usize = 0;
var to_read: usize = 0;
while (cur_read < bytes.len) {
std.debug.print("hello there!, {}\n", .{cur_read});
if (self.curOffset + 1 == self.curBlock.len) {
try self.readNextBlock();
}
to_read = @min(bytes.len - cur_read, self.curBlock.len - self.curOffset);
std.debug.print("{} {} {}\n", .{ cur_read, to_read, self.curOffset });
std.mem.copyForwards(u8, bytes[cur_read..], self.curBlock[self.curOffset .. self.curOffset + to_read]);
self.curOffset += @truncate(to_read);
cur_read += to_read;
}
return cur_read;
}
fn readOpaque(context: *const anyopaque, bytes: []u8) anyerror!usize {
var self: *MetadataReader = @constCast(@ptrCast(@alignCast(context)));
return self.read(bytes);
}
}; };
+11 -6
View File
@@ -2,30 +2,35 @@ const std = @import("std");
const fs = std.fs; const fs = std.fs;
const Superblock = @import("superblock.zig").Superblock; const Superblock = @import("superblock.zig").Superblock;
const Inode = @import("inode.zig").Inode; const inode = @import("inode.zig");
const MetadataReader = @import("metadata_reader.zig").MetadataReader;
pub const Reader = struct { pub const Reader = struct {
super: Superblock, super: Superblock,
rdr: fs.File, rdr: fs.File,
root: Inode, root: inode.Inode,
alloc: std.heap.GeneralPurposeAllocator(.{}), alloc: std.heap.GeneralPurposeAllocator(.{}),
pub fn close(self: Reader) void { pub fn close(self: *Reader) void {
self.rdr.close(); self.rdr.close();
self.alloc.deinit(); _ = self.alloc.deinit();
} }
}; };
pub fn newReader(filename: []const u8) !Reader { pub fn newReader(filename: []const u8) !Reader {
const file = try std.fs.cwd().openFile(filename, .{}); const file = try std.fs.cwd().openFile(filename, .{});
errdefer file.close(); errdefer file.close();
const alloc = std.heap.GeneralPurposeAllocator(.{}).init(); var alloc: std.heap.GeneralPurposeAllocator(.{}) = .init;
errdefer alloc.deinit(); errdefer _ = alloc.deinit();
const super = try file.reader().readStruct(Superblock); const super = try file.reader().readStruct(Superblock);
try super.valid(); try super.valid();
try file.seekTo(super.inode_table + super.root_inode.block_start);
var root_reader: MetadataReader = try .init(super.comp, file.reader().any(), alloc.allocator());
const root_inode = try inode.readInode(root_reader.any(), super.block_size, alloc.allocator());
return Reader{ return Reader{
.super = super, .super = super,
.rdr = file, .rdr = file,
.root = root_inode,
.alloc = alloc, .alloc = alloc,
}; };
} }
+2 -10
View File
@@ -1,5 +1,6 @@
const math = @import("std").math; const math = @import("std").math;
const InodeRef = @import("inode.zig").InodeRef; const InodeRef = @import("inode.zig").InodeRef;
const CompressionType = @import("decompress.zig").CompressionType;
pub const SuperblockError = error{ pub const SuperblockError = error{
InvalidMagic, InvalidMagic,
@@ -7,22 +8,13 @@ pub const SuperblockError = error{
InvalidVersion, InvalidVersion,
}; };
pub const CompressionType = enum(u16) {
gzip = 1,
lzma,
lzo,
xz,
lz4,
zstd,
};
pub const Superblock = packed struct { pub const Superblock = packed struct {
magic: u32, magic: u32,
count: u32, count: u32,
mod_time: u32, mod_time: u32,
block_size: u32, block_size: u32,
frags: u32, frags: u32,
comp: u16, comp: CompressionType,
block_log: u16, block_log: u16,
flags: packed struct { flags: packed struct {
inode_uncomp: bool, inode_uncomp: bool,
+1 -1
View File
@@ -5,6 +5,6 @@ const squashfs = @import("squashfs.zig");
const testFileName = "testing/LinuxPATest.sfs"; const testFileName = "testing/LinuxPATest.sfs";
test "open test file" { test "open test file" {
const reader = try squashfs.newReader(testFileName); var reader = try squashfs.newReader(testFileName);
defer reader.close(); defer reader.close();
} }