Start over to clear my head

This commit is contained in:
Caleb Gardner
2025-05-16 05:55:40 -05:00
parent fc068fdbd9
commit 986f308c60
18 changed files with 221 additions and 699 deletions
+18 -19
View File
@@ -1,45 +1,44 @@
const std = @import("std");
const compress = std.compress;
const io = std.io;
const DecompressError = error{
LzoNotSupported,
Lz4NotSupported,
LzoUnsupported,
Lz4Unsupported,
};
pub const CompressionType = enum(u16) {
gzip = 1,
pub const DecompressType = enum(u16) {
zlib = 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();
pub fn decompress(self: DecompressType, alloc: std.mem.Allocator, in: io.AnyReader) !std.ArrayList(u8) {
const out: std.ArrayList(u8) = .init(alloc);
switch (self) {
.gzip => try compress.zlib.decompress(rdr, out.writer()),
.zlib => try std.compress.zlib.decompress(in, out),
.lzma => {
var decomp = try compress.lzma.decompress(alloc, rdr);
const decomp = try std.compress.lzma.decompress(alloc, in);
defer decomp.deinit();
try decomp.reader().readAllArrayList(&out, 1024 * 1024);
try decomp.reader().readAllArrayList(&out, 1048576);
},
.lzo => return DecompressError.LzoNotSupported,
.lzo => return DecompressError.LzoUnsupported,
.xz => {
var decomp = try compress.xz.decompress(alloc, rdr);
const decomp = try std.compress.xz.decompress(alloc, in);
defer decomp.deinit();
try decomp.reader().readAllArrayList(&out, 1024 * 1024);
try decomp.reader().readAllArrayList(&out, 1048576);
},
.lz4 => return DecompressError.Lz4NotSupported,
.lz4 => return DecompressError.Lz4Unsupported,
.zstd => {
const buf = try alloc.alloc(u8, compress.zstd.DecompressorOptions.default_window_buffer_len);
const buf = try alloc.alloc(u8, std.compress.zstd.DecompressorOptions.default_window_buffer_len);
defer alloc.free(buf);
var decomp = compress.zstd.decompressor(rdr, .{
const decomp = std.compress.zstd.decompressor(in, .{
.window_buffer = buf,
});
try decomp.reader().readAllArrayList(&out, 1024 * 1024);
try decomp.reader().readAllArrayList(&out, 1048576);
},
}
return try out.toOwnedSlice();
return out;
}
};
-81
View File
@@ -1,81 +0,0 @@
const std = @import("std");
const CompressionType = @import("decompress.zig").CompressionType;
const DirHeader = packed struct {
count: u32,
inode_block_start: u32,
inode_num: u32,
};
const RawDirEntry = struct {
inode_offset: u16,
inode_num_difference: i16,
inode_type: u16,
name_size: u16,
name: []u8,
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),
.name_size = try rdr.readInt(u16, std.builtin.Endian.little),
.name = undefined,
};
out.name = try alloc.alloc(u8, out.name_size);
_ = try rdr.readAll(out.name);
return out;
}
};
pub const DirEntry = struct {
inode_offset: u16,
inode_block_start: u32,
inode_num: u32,
name: []u8,
fn init(raw: RawDirEntry, hdr: DirHeader) DirEntry {
return .{
.inode_offset = raw.inode_offset,
.inode_block_start = hdr.inode_block_start,
.inode_num = hdr.inode_num + @as(u32, @intCast(raw.inode_num_difference)),
.name = raw.name,
};
}
};
const MetadataHeader = @import("metadata_reader.zig").MetadataHeader;
pub fn readDirEntries(alloc: std.mem.Allocator, comp: CompressionType, rdr: std.io.AnyReader, size: u32) ![]DirEntry {
var total_size: u32 = 3;
var meta_hdr: MetadataHeader = undefined;
var dir_hdr: DirHeader = undefined;
var buf: []u8 = undefined;
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(buf);
} else {
alloc.free(buf);
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) {
raw = try .init(buf_rdr.reader().any(), alloc);
total_size += @sizeOf(RawDirEntry);
try entries.append(.init(raw, dir_hdr));
}
}
return try entries.toOwnedSlice();
}
+1 -94
View File
@@ -1,94 +1 @@
const std = @import("std");
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 dir = @import("directory.zig");
const FileOpenError = error{
NotFound,
NotDirectory,
};
pub const File = struct {
rdr: *Reader,
inode: inode.Inode,
name: []const u8,
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.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());
return .{
.rdr = rdr,
.inode = in,
.name = name,
};
}
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.allocator(),
);
try meta_rdr.skip(ent.inode_offset);
const in = try inode.readInode(meta_rdr.any(), rdr.super.block_size, rdr.alloc.allocator());
return .{
.rdr = rdr,
.inode = in,
.name = ent.name,
};
}
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,
}
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)!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);
}
};
pub const File = struct {}; //TODO
-31
View File
@@ -1,31 +0,0 @@
const std = @import("std");
pub const FileOffsetReader = struct {
file: *std.fs.File,
offset: u64,
pub fn init(file: *std.fs.File, initial_offset: u64) FileOffsetReader {
return .{
.file = file,
.offset = initial_offset,
};
}
pub fn read(self: *FileOffsetReader, bytes: []u8) anyerror!usize {
const red = try self.file.preadAll(bytes, self.offset);
self.offset += @intCast(red);
return red;
}
pub fn any(self: *FileOffsetReader) std.io.AnyReader {
return .{
.context = @ptrCast(self),
.readFn = readOpaque,
};
}
fn readOpaque(context: *const anyopaque, buf: []u8) anyerror!usize {
var self: *FileOffsetReader = @constCast(@ptrCast(@alignCast(context)));
return self.read(buf);
}
};
-113
View File
@@ -1,113 +0,0 @@
const std = @import("std");
pub const InodeRef = packed struct {
offset: u16,
block_start: u32,
_: u16,
};
pub const InodeType = enum(u16) {
dir = 1,
file,
symlink,
block_device,
char_device,
fifo,
socket,
ext_dir,
ext_file,
ext_symlink,
ext_block_device,
ext_char_device,
ext_fifo,
ext_socket,
};
pub const InodeHeader = packed struct {
inode_type: InodeType,
perm: u16,
uid_index: u16,
gid_index: u16,
mod_time: u32,
inode_num: u32,
};
pub const InodeData = union(enum) {
dir: dir.DirInode,
file: file.FileInode,
symlink: sym.SymlinkInode,
block_device: misc.DeviceInode,
char_device: misc.DeviceInode,
fifo: misc.IPCInode,
socket: misc.IPCInode,
ext_dir: dir.ExtDirInode,
ext_file: file.ExtFileInode,
ext_symlink: sym.ExtSymlinkInode,
ext_block_device: misc.ExtDeviceInode,
ext_char_device: misc.ExtDeviceInode,
ext_fifo: misc.ExtIPCInode,
ext_socket: misc.ExtIPCInode,
};
const dir = @import("inode_types/dir.zig");
const file = @import("inode_types/file.zig");
const sym = @import("inode_types/sym.zig");
const misc = @import("inode_types/misc.zig");
pub const Inode = struct {
header: InodeHeader,
data: InodeData,
};
const io = @import("std").io;
pub fn readInode(rdr: io.AnyReader, block_size: u32, alloc: std.mem.Allocator) !Inode {
const hdr = try rdr.readStruct(InodeHeader);
return Inode{
.header = hdr,
.data = switch (hdr.inode_type) {
.dir => .{
.dir = try .init(rdr),
},
.ext_dir => .{
.ext_dir = try .init(rdr, alloc),
},
.file => .{
.file = try .init(rdr, block_size, alloc),
},
.ext_file => .{
.ext_file = try .init(rdr, block_size, alloc),
},
.symlink => .{
.symlink = try .init(rdr, alloc),
},
.ext_symlink => .{
.ext_symlink = try .init(rdr, alloc),
},
.block_device => .{
.block_device = try rdr.readStruct(misc.DeviceInode),
},
.ext_block_device => .{
.ext_block_device = try rdr.readStruct(misc.ExtDeviceInode),
},
.char_device => .{
.char_device = try rdr.readStruct(misc.DeviceInode),
},
.ext_char_device => .{
.ext_char_device = try rdr.readStruct(misc.ExtDeviceInode),
},
.fifo => .{
.fifo = try rdr.readStruct(misc.IPCInode),
},
.ext_fifo => .{
.ext_fifo = try rdr.readStruct(misc.ExtIPCInode),
},
.socket => .{
.socket = try rdr.readStruct(misc.IPCInode),
},
.ext_socket => .{
.ext_socket = try rdr.readStruct(misc.ExtIPCInode),
},
},
};
}
+36
View File
@@ -0,0 +1,36 @@
pub const InodeRef = packed struct {
offset: u16,
block_start: u32,
_: u16,
};
pub const InodeType = enum(u16) {
dir,
file,
sym,
block,
char,
fifo,
sock,
ext_dir,
ext_file,
ext_sym,
ext_block,
ext_char,
ext_fifo,
ext_sock,
};
pub const InodeHeader = packed struct {
inode_type: InodeType,
perm: u16,
uid_idx: u16,
gid_idx: u16,
mod_time: u32,
num: u32,
};
pub const Inode = struct {
header: InodeHeader,
data: void, //TODO
};
-63
View File
@@ -1,63 +0,0 @@
const std = @import("std");
const io = std.io;
pub const DirInode = packed struct {
dir_block_start: u32,
hard_links: u32,
dir_table_size: u16,
dir_block_offset: u16,
parent_inode_num: u32,
pub fn init(rdr: io.AnyReader) !DirInode {
return try rdr.readStruct(DirInode);
}
};
pub const DirIndex = struct {
dir_header_offset: u32,
dir_table_offset: u32,
name_size: u32,
name: []u8,
pub fn init(rdr: io.AnyReader, alloc: std.mem.Allocator) !DirIndex {
var out = DirIndex{
.dir_header_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 = undefined,
};
out.name = try alloc.alloc(u8, out.name_size);
_ = try rdr.readAll(out.name);
return out;
}
};
pub const ExtDirInode = struct {
hard_links: u32,
dir_table_size: u32,
dir_block_start: u32,
parent_inode_num: u32,
dir_index_count: u16,
dir_block_offset: u16,
xattr_index: u32,
indexes: []DirIndex,
pub fn init(rdr: io.AnyReader, alloc: std.mem.Allocator) !ExtDirInode {
var out = ExtDirInode{
.hard_links = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_table_size = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_block_start = try rdr.readInt(u32, std.builtin.Endian.little),
.parent_inode_num = try rdr.readInt(u32, std.builtin.Endian.little),
.dir_index_count = try rdr.readInt(u16, std.builtin.Endian.little),
.dir_block_offset = try rdr.readInt(u16, std.builtin.Endian.little),
.xattr_index = try rdr.readInt(u32, std.builtin.Endian.little),
.indexes = undefined,
};
out.indexes = try alloc.alloc(DirIndex, out.dir_index_count);
var i: u16 = 0;
while (i < out.dir_index_count) : (i += 1) {
out.indexes[i] = try .init(rdr, alloc);
}
return out;
}
};
-57
View File
@@ -1,57 +0,0 @@
const std = @import("std");
pub const FileInode = struct {
start: u32,
frag_index: u32,
frag_block_offset: u32,
size: u32,
block_sizes: []const u32,
pub fn init(rdr: std.io.AnyReader, block_size: u32, alloc: std.mem.Allocator) !FileInode {
var out = FileInode{
.start = 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),
.size = try rdr.readInt(u32, std.builtin.Endian.little),
.block_sizes = undefined,
};
var block_num = out.size / block_size;
if (out.frag_index != 0xFFFFFFFF) {
block_num += 1;
}
out.block_sizes = try alloc.alloc(u32, block_num);
_ = try rdr.readAll(std.mem.asBytes(&out.block_sizes));
return out;
}
};
pub const ExtFileInode = struct {
start: u64,
size: u64,
sparse: u64,
hard_links: u32,
frag_index: u32,
frag_block_offset: u32,
xattr_index: u32,
block_sizes: []const u32,
pub fn init(rdr: std.io.AnyReader, block_size: u32, alloc: std.mem.Allocator) !ExtFileInode {
var out = ExtFileInode{
.start = 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),
.hard_links = 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),
.xattr_index = try rdr.readInt(u32, std.builtin.Endian.little),
.block_sizes = undefined,
};
var block_num = out.size / block_size;
if (out.frag_index != 0xFFFFFFFF and out.size % block_size != 0) {
block_num += 1;
}
out.block_sizes = try alloc.alloc(u32, block_num);
_ = try rdr.readAll(std.mem.asBytes(&out.block_sizes));
return out;
}
};
-21
View File
@@ -1,21 +0,0 @@
const io = @import("std").io;
pub const DeviceInode = packed struct {
hard_links: u32,
device: u32,
};
pub const ExtDeviceInode = packed struct {
hard_links: u32,
device: u32,
xattr_index: u32,
};
pub const IPCInode = packed struct {
hard_links: u32,
};
pub const ExtIPCInode = packed struct {
hard_links: u32,
xattr_index: u32,
};
-39
View File
@@ -1,39 +0,0 @@
const std = @import("std");
const io = std.io;
pub const SymlinkInode = struct {
hard_links: u32,
target_size: u32,
path: []u8,
pub fn init(rdr: io.AnyReader, alloc: std.mem.Allocator) !SymlinkInode {
var out = SymlinkInode{
.hard_links = try rdr.readInt(u32, std.builtin.Endian.little),
.target_size = try rdr.readInt(u32, std.builtin.Endian.little),
.path = undefined,
};
out.path = try alloc.alloc(u8, out.target_size + 1);
_ = try rdr.readAll(out.path);
return out;
}
};
pub const ExtSymlinkInode = struct {
hard_links: u32,
target_size: u32,
path: []u8,
xattr_index: u32,
pub fn init(rdr: io.AnyReader, alloc: std.mem.Allocator) !ExtSymlinkInode {
var out = ExtSymlinkInode{
.hard_links = try rdr.readInt(u32, std.builtin.Endian.little),
.target_size = try rdr.readInt(u32, std.builtin.Endian.little),
.path = undefined,
.xattr_index = undefined,
};
out.path = try alloc.alloc(u8, out.target_size + 1);
_ = try rdr.readAll(out.path);
out.xattr_index = try rdr.readInt(u32, std.builtin.Endian.little);
return out;
}
};
-83
View File
@@ -1,83 +0,0 @@
const std = @import("std");
const io = std.io;
const CompressionType = @import("decompress.zig").CompressionType;
pub const MetadataHeader = packed struct {
size: u15,
not_compressed: bool,
};
pub const MetadataReader = struct {
rdr: std.io.AnyReader,
alloc: std.mem.Allocator,
decomp: CompressionType,
curBlock: []u8,
curOffset: u16,
pub fn init(decomp: CompressionType, rdr: io.AnyReader, alloc: std.mem.Allocator) !MetadataReader {
var out: MetadataReader = .{
.rdr = rdr,
.alloc = alloc,
.decomp = decomp,
.curBlock = &[_]u8{},
.curOffset = 0,
};
try out.readNextBlock();
return out;
}
pub fn deinit(self: *MetadataReader) void {
self.alloc.free(self.curBlock);
}
pub fn any(self: *MetadataReader) io.AnyReader {
return .{
.context = @ptrCast(self),
.readFn = readOpaque,
};
}
pub fn skip(self: *MetadataReader, offset: u16) !void {
var to_skip = offset;
var cur_left = self.curBlock.len - self.curOffset;
while (to_skip > cur_left) {
to_skip -= @intCast(cur_left);
try self.readNextBlock();
cur_left = self.curBlock.len;
}
self.curOffset = to_skip;
}
fn readNextBlock(self: *MetadataReader) !void {
if (self.curBlock.len != 0) {
self.alloc.free(self.curBlock);
}
self.curOffset = 0;
const hdr = try self.rdr.readStruct(MetadataHeader);
if (hdr.not_compressed) {
self.curBlock = try self.alloc.alloc(u8, hdr.size);
_ = 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());
}
}
pub fn read(self: *MetadataReader, bytes: []u8) anyerror!usize {
var cur_read: usize = 0;
var to_read: usize = 0;
while (cur_read < bytes.len) {
if (self.curOffset + 1 == self.curBlock.len) {
try self.readNextBlock();
}
to_read = @min(bytes.len - cur_read, self.curBlock.len - 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);
}
};
+32
View File
@@ -0,0 +1,32 @@
const std = @import("std");
const FileHolder = @import("readers/file_holder.zig").FileHolder;
const Superblock = @import("superblock.zig").Superblock;
pub const Reader = struct {
arena: std.heap.ArenaAllocator,
holder: FileHolder,
super: Superblock,
pub fn init(alloc: std.mem.Allocator, filepath: []const u8, offset: u64) !Reader {
var holder: FileHolder = try .init(filepath, offset);
const super: Superblock = try holder.anyAt(0).readStruct(Superblock);
try super.validate();
const arena: std.heap.ArenaAllocator = .init(alloc);
return .{
.arena = arena,
.holder = holder,
.super = super,
};
}
pub fn deinit(self: *const Reader) void {
self.arena.deinit();
self.holder.deinit();
}
};
test "reader" {
const test_file_path = "testing/LinuxPATest.sfs";
const rdr: Reader = try .init(std.testing.allocator, test_file_path, 0);
defer rdr.deinit();
}
+48
View File
@@ -0,0 +1,48 @@
const std = @import("std");
const fs = std.fs;
const io = std.io;
pub const FileHolder = struct {
file: fs.File,
offset: u64,
pub fn init(path: []const u8, offset: u64) !FileHolder {
const fil = try fs.cwd().openFile(path, .{});
return .{
.file = fil,
.offset = offset,
};
}
pub fn deinit(self: FileHolder) void {
self.file.close();
}
pub fn anyAt(self: FileHolder, offset: u64) io.AnyReader {
var offsetRdr = FileOffsetReader{
.file = self.file,
.offset = self.offset + offset,
};
return offsetRdr.any();
}
};
const FileOffsetReader = struct {
file: fs.File,
offset: u64,
fn read(self: *FileOffsetReader, bytes: []u8) !usize {
const red = try self.file.pread(bytes, self.offset);
self.offset += red;
return red;
}
fn any(self: *FileOffsetReader) io.AnyReader {
return .{
.context = @ptrCast(self),
.readFn = readOpaque,
};
}
fn readOpaque(context: *const anyopaque, bytes: []u8) !usize {
var rdr: *FileOffsetReader = @constCast(@ptrCast(@alignCast(context)));
return try rdr.read(bytes);
}
};
+70
View File
@@ -0,0 +1,70 @@
const std = @import("std");
const io = std.io;
const DecompressType = @import("../decompress.zig").DecompressType;
const MetadataHeader = packed struct {
size: u15,
not_compressed: bool,
};
pub const MetadataReader = struct {
alloc: std.mem.Allocator,
reader: io.AnyReader,
block: []u8,
decomp: DecompressType,
offset: u32,
pub fn init(alloc: std.mem.Allocator, rdr: io.AnyReader, decomp: DecompressType) !MetadataReader {
var out: MetadataReader = .{
.alloc = alloc,
.reader = rdr,
.block = &[0]u8{},
.decomp = decomp,
.offset = 0,
};
try out.readNextBlock();
return out;
}
pub fn deinit(self: *MetadataReader) void {
self.alloc.free(self.block);
}
fn readNextBlock(self: *MetadataReader) !void {
self.offset = 0;
if (self.block.len > 0) self.alloc.free(self.block);
const hdr = try self.reader.readStruct(MetadataHeader);
if (hdr.not_compressed) {
self.block = try self.alloc.alloc(u8, hdr.size);
_ = try self.reader.readAll(self.block);
} else {
const limit = std.io.limitedReader(self.reader, hdr.size);
const dat = try self.decomp.decompress(self.alloc, limit.reader().any());
self.block = dat.toOwnedSlice();
}
}
pub fn any(self: *MetadataReader) io.AnyReader {
return .{
.context = @ptrCast(self),
.readFn = readOpaque,
};
}
pub fn read(self: *MetadataReader, bytes: []u8) !usize {
var cur_read: usize = 0;
var to_read: usize = 0;
while (cur_read < bytes.len) {
if (self.offset >= self.block.len) try self.readNextBlock();
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;
}
fn readOpaque(context: *const anyopaque, bytes: []u8) !usize {
var rdr: *MetadataReader = @constCast(@ptrCast(@alignCast(context)));
return rdr.read(bytes);
}
};
+1 -1
View File
@@ -1,3 +1,3 @@
pub const Reader = @import("squashfs.zig").Reader;
pub const Reader = @import("reader.zig").Reader;
pub const File = @import("file.zig").File;
-54
View File
@@ -1,54 +0,0 @@
const std = @import("std");
const fs = std.fs;
const Superblock = @import("superblock.zig").Superblock;
const inode = @import("inode.zig");
const MetadataReader = @import("metadata_reader.zig").MetadataReader;
const File = @import("file.zig").File;
const FileOffsetReader = @import("file_offset_reader.zig").FileOffsetReader;
pub const Reader = struct {
super: Superblock,
rdr: fs.File,
root: File,
alloc: std.heap.ArenaAllocator,
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,
};
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);
}
};
+15 -30
View File
@@ -1,52 +1,37 @@
const math = @import("std").math;
const InodeRef = @import("inode.zig").InodeRef;
const CompressionType = @import("decompress.zig").CompressionType;
pub const SuperblockError = error{
const SuperblockError = error{
InvalidMagic,
InvalidLog,
InvalidBlockLog,
InvalidVersion,
};
pub const Superblock = packed struct {
magic: u32,
count: u32,
inode_count: u32,
mod_time: u32,
block_size: u32,
frags: u32,
comp: CompressionType,
frag_count: u32,
decomp: @import("decompress.zig").DecompressType,
block_log: u16,
flags: packed struct {
inode_uncomp: bool,
data_uncomp: bool,
_unused: bool,
frag_uncomp: bool,
frag_always: bool,
data_dedupe: bool,
export_table: bool,
xattr_uncomp: bool,
no_xattr: bool,
comp_options: bool,
id_uncomp: bool,
_padding: u5,
},
flags: u16,
id_count: u16,
ver_maj: u16,
ver_min: u16,
root_inode: InodeRef,
root_ref: @import("inode/inode.zig").InodeRef,
size: u64,
id_table: u64,
xattr_table: u64,
inode_table: u64,
dir_table: u64,
frag_table: u64,
export_table: u64,
id_table_start: u64,
xattr_table_start: u64,
inode_table_start: u64,
dir_table_start: u64,
frag_table_start: u64,
export_table_start: u64,
pub fn valid(self: Superblock) SuperblockError!void {
pub fn validate(self: Superblock) SuperblockError!void {
if (self.magic != 0x73717368) {
return SuperblockError.InvalidMagic;
} else if (self.block_log != math.log2(self.block_size)) {
return SuperblockError.InvalidLog;
return SuperblockError.InvalidBlockLog;
} else if (self.ver_maj != 4 or self.ver_min != 0) {
return SuperblockError.InvalidVersion;
}
-13
View File
@@ -1,13 +0,0 @@
const std = @import("std");
const debug = std.debug;
const squashfs = @import("squashfs.zig");
const print = std.debug.print;
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});
}