Further progress

Mainly focusing on getting things more consistent
This commit is contained in:
Caleb Gardner
2025-07-12 02:13:41 -05:00
parent 61c86c9fea
commit 69d90242ba
9 changed files with 206 additions and 27 deletions
+22 -4
View File
@@ -1,6 +1,24 @@
dereference_symlinks: bool, const std = @import("std");
unbreak_symlinks: bool,
ignore_permissions: bool, const Self = @This();
/// Replace symlinks with their targets
dereference_symlinks: bool = false,
/// Always extract a symlink's target if it's part of the archive.
/// May result in the symlink's target being changed.
unbreak_symlinks: bool = false,
/// Do not set file's permissions & owner when extracted.
ignore_permissions: bool = false,
processor_count: u16,
// max_memory: u64, // max_memory: u64,
pol: std.Thread.Pool = undefined,
pub fn init(alloc: std.mem.Allocator, thread_count: u16) !Self {
var out: Self = .{};
out.pol.init(.{
.allocator = alloc,
.n_jobs = thread_count,
});
return out;
}
+82 -1
View File
@@ -1,3 +1,84 @@
const std = @import("std");
const dir = @import("directory.zig");
const DirEntry = dir.Entry;
const Inode = @import("inode.zig");
const SfsReader = @import("reader.zig").SfsReader;
const ToReader = @import("reader/to_read.zig").ToRead;
const ExtractionOptions = @import("extract_options.zig");
const Compression = @import("superblock.zig").Compression;
const MetadataReader = @import("reader/metadata.zig").MetadataReader;
pub const FileError = error{
NotRegular,
NotDirectory,
};
pub fn File(comptime T: type) type { pub fn File(comptime T: type) type {
return struct {}; return struct {
const Self = @This();
rdr: *SfsReader(T),
inode: Inode,
name: []const u8,
/// Directory entries. Only populated on directories.
entries: ?[]DirEntry = null,
/// File reader. Only populated on regular files.
// data_reader: ?DataReader
pub fn init(rdr: *SfsReader(T), inode: Inode, name: []const u8) !Self {
var out = Self{
.rdr = rdr,
.inode = inode,
.name = name,
};
switch (inode.data) {
.dir => |d| {
const meta = MetadataReader(T).init(
rdr.alloc,
rdr.super.comp,
rdr.rdr,
d.block + rdr.super.dir_start,
);
try meta.skip(d.offset);
out.entries = try dir.readDirectory(rdr.alloc, meta, d.size);
},
.ext_dir => |d| {
const meta = MetadataReader(T).init(
rdr.alloc,
rdr.super.comp,
rdr.rdr,
d.block + rdr.super.dir_start,
);
try meta.skip(d.offset);
out.entries = try dir.readDirectory(rdr.alloc, meta, d.size);
},
.file => |f| {
_ = f;
//TODO
},
.ext_file => |f| {
_ = f;
//TODO
},
}
return out;
}
pub fn deinit(self: Self) void {
self.rdr.alloc.free(self.name);
self.inode.deinit(self.rdr.alloc);
if (self.entries != null) {
for (self.entries.?) |e| {
e.deinit(self.rdr.alloc);
}
self.rdr.alloc.free(self.entries.?);
}
// if(self.data_reader != null){
// self.data_reader.?.deinit();
// }
}
};
} }
+9 -6
View File
@@ -4,6 +4,8 @@ const dir = @import("inode/dir.zig");
const file = @import("inode/file.zig"); const file = @import("inode/file.zig");
const misc = @import("inode/misc.zig"); const misc = @import("inode/misc.zig");
const Reader = @import("reader.zig");
const DirEntry = @import("directory.zig").Entry;
const ToRead = @import("reader/to_read.zig").ToRead; const ToRead = @import("reader/to_read.zig").ToRead;
const Compression = @import("superblock.zig").Compression; const Compression = @import("superblock.zig").Compression;
const MetadataReader = @import("reader/metadata.zig").MetadataReader; const MetadataReader = @import("reader/metadata.zig").MetadataReader;
@@ -86,10 +88,11 @@ pub fn init(rdr: anytype, alloc: std.mem.Allocator, block_size: u32) !Self {
.data = data, .data = data,
}; };
} }
pub fn initFromRef(p_rdr: anytype, comp: Compression, ref: Ref, table_start: u64, alloc: std.mem.Allocator, block_size: u32) !Self { pub fn deinit(self: Self, alloc: std.mem.Allocator) void {
const rdr: ToRead(@TypeOf(p_rdr)) = .init(p_rdr, ref.block + table_start); switch (self.data) {
const meta_rdr: MetadataReader(ToRead(@TypeOf(p_rdr))) = try .init(alloc, comp, rdr); .file => |f| alloc.free(f.block_sizes),
defer meta_rdr.deinit(); .ext_file => |f| alloc.free(f.block_sizes),
try meta_rdr.skip(ref.offset); .symlink => |s| alloc.free(s.target),
return init(meta_rdr, alloc, block_size); .ext_symlink => |s| alloc.free(s.target),
}
} }
+18 -5
View File
@@ -5,8 +5,13 @@ const Table = @import("table.zig").Table;
const PRead = @import("reader/p_read.zig").PRead; const PRead = @import("reader/p_read.zig").PRead;
const FragEntry = @import("fragment.zig").FragEntry; const FragEntry = @import("fragment.zig").FragEntry;
const Superblock = @import("superblock.zig").Superblock; const Superblock = @import("superblock.zig").Superblock;
const MetadataReader = @import("reader/metadata.zig").MetadataReader;
pub fn Reader(comptime T: type) type { pub const SfsError = error{
NotExportable,
};
pub fn SfsReader(comptime T: type) type {
comptime std.debug.assert(std.meta.hasFn(T, "pread")); comptime std.debug.assert(std.meta.hasFn(T, "pread"));
return struct { return struct {
@@ -40,14 +45,22 @@ pub fn Reader(comptime T: type) type {
self.id_table.deinit(); self.id_table.deinit();
self.frag_table.deinit(); self.frag_table.deinit();
self.export_table.deinit(); self.export_table.deinit();
// if (self.root != null) self.root.?.deinit();
} }
/// Returns the inode with the given Inode Number. /// Returns the inode with the given Inode Number.
/// Requires for the archive to have an export table. /// Requires the archive to have an export table.
pub fn InodeAt(self: Self, num: u32) !Inode { pub fn inodeAt(self: Self, num: u32) !Inode {
if (!self.super.flags.has_export) return SfsError.NotExportable;
const ref = try self.export_table.get(num - 1); const ref = try self.export_table.get(num - 1);
_ = ref; const meta = MetadataReader(T).init(
return error{TODO}.TODO; self.alloc,
self.super.comp,
self.rdr,
self.super.inode_start + ref.block,
);
try meta.skip(ref.offset);
return .init(meta, self.alloc, self.super.block_size);
} }
}; };
} }
+55
View File
@@ -0,0 +1,55 @@
const std = @import("std");
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;
pub fn DataReader(comptime T: type) type {
return struct {
const Self = @This();
alloc: std.mem.Allocator,
rdr: PRead(T),
comp: Compression,
offsets: []BlockSize,
file_size: u64,
block_size: u32,
sizes: []BlockSize,
frag: []u8 = undefined,
pub fn init(
alloc: std.mem.Allocator,
rdr: PRead(T),
comp: Compression,
init_offset: u64,
file_size: u64,
sizes: []BlockSize,
block_size: u32,
) !Self {
var cur_offset = init_offset;
const offsets = alloc.alloc(u64, sizes.len);
for (0..sizes.len) |i| {
offsets[i] = cur_offset;
cur_offset += sizes[i].size;
}
return .{
.alloc = alloc,
.rdr = rdr,
.comp = comp,
.offsets = offsets,
.file_size = file_size,
.block_size = block_size,
.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:
}
};
}
+16 -7
View File
@@ -1,5 +1,6 @@
const std = @import("std"); const std = @import("std");
const PRead = @import("p_read.zig").PRead;
const Compression = @import("../superblock.zig").Compression; const Compression = @import("../superblock.zig").Compression;
const MetaHeader = packed struct { const MetaHeader = packed struct {
@@ -14,36 +15,44 @@ pub fn MetadataReader(comptime T: type) type {
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
comp: Compression, comp: Compression,
rdr: T, rdr: PRead(T),
offset: u64,
block: [8192]u8 = undefined, block: [8192]u8 = undefined,
block_size: usize = 0, block_size: usize = 0,
block_offset: u32 = 0, block_offset: u32 = 0,
pub fn init(alloc: std.mem.Allocator, comp: Compression, rdr: T) !Self { pub fn init(alloc: std.mem.Allocator, comp: Compression, rdr: PRead(T), offset: u64) Self {
var out: Self = .{ return .{
.alloc = alloc, .alloc = alloc,
.comp = comp, .comp = comp,
.rdr = rdr, .rdr = rdr,
.offset = offset,
}; };
try out.readNextBlock();
return out;
} }
fn readNextBlock(self: *Self) !void { fn readNextBlock(self: *Self) !void {
const hdr: MetaHeader = undefined; const hdr: MetaHeader = undefined;
_ = try self.rdr.read(std.mem.asBytes(hdr)); _ = try self.rdr.pread(std.mem.asBytes(hdr), self.offset);
self.offset += 2;
self.block_size = try self.comp.decompress( self.block_size = try self.comp.decompress(
8192, 8192,
self.alloc, self.alloc,
std.io.limitedReader(self.rdr, hdr.size), std.io.limitedReader(self.rdr.readerAt(self.offset), hdr.size),
self.block, self.block,
); );
self.offset += hdr.size;
self.block_offset = 0; self.block_offset = 0;
} }
pub fn skip(self: *Self, offset: u32) !void { pub fn skip(self: *Self, offset: u32) !void {
var skipped = 0; var skipped = 0;
const hdr: MetaHeader = undefined;
while (offset - skipped >= 8192) {
_ = try self.rdr.pread(std.mem.asBytes(hdr), self.offset);
self.offset += 2 + hdr.size;
skipped += 8192;
}
var to_skip = 0; var to_skip = 0;
while (skipped < offset) { while (skipped < offset) {
if (self.block_offset >= self.block_size) try self.readNextBlock(); if (self.block_offset >= self.block_size) try self.readNextBlock();
+2 -2
View File
@@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
pub const Reader = @import("reader.zig").Reader; pub const SfsReader = @import("reader.zig").SfsReader;
pub const ExtractionOptions = @import("extract_options.zig"); pub const ExtractionOptions = @import("extract_options.zig");
pub const FileReader = Reader(std.fs.File); pub const FileReader = SfsReader(std.fs.File);
+1 -1
View File
@@ -38,7 +38,7 @@ pub const Superblock = packed struct {
export_start: u64, export_start: u64,
}; };
const DecompressError = error{ pub const DecompressError = error{
LzoUnavailable, LzoUnavailable,
Lz4Unavailable, Lz4Unavailable,
}; };
+1 -1
View File
@@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const TableError = error{ pub const TableError = error{
InvalidIndex, InvalidIndex,
}; };