Fixed a few bugs preventing basic functions

Worked on extraction, including creating DataReader
Added proper access to id, fragment, and export tables
This commit is contained in:
Caleb J. Gardner
2026-01-28 06:50:26 -06:00
parent 5d4e7b1435
commit 2c392cf250
9 changed files with 276 additions and 37 deletions
+99 -13
View File
@@ -12,6 +12,7 @@ const FileError = error{
NotDirectory,
NotRegularFile,
NotFound,
InvalidExtractionPath,
};
const File = @This();
@@ -49,6 +50,13 @@ pub fn deinit(self: File) void {
self.inode.deinit(alloc);
}
pub fn ownerUid(self: File) !u16 {
return self.archive.id(self.inode.hdr.uid_idx);
}
pub fn ownerGid(self: File) !u16 {
return self.archive.id(self.inode.hdr.gid_idx);
}
fn getEntries(self: File) ![]DirEntry {
if (!self.isDir()) return FileError.NotDirectory;
var block_start: u32 = undefined;
@@ -71,7 +79,7 @@ fn getEntries(self: File) ![]DirEntry {
const alloc = self.archive.allocator();
var meta: MetadataReader = .init(alloc, &rdr.interface, &self.archive.decomp);
try meta.interface.discardAll(block_offset);
return DirEntry.readDir(alloc, &rdr.interface, size);
return DirEntry.readDir(alloc, &meta.interface, size);
}
pub fn isDir(self: File) bool {
@@ -80,6 +88,10 @@ pub fn isDir(self: File) bool {
else => false,
};
}
pub fn iter(self: File) !Iterator {
var entries = try self.getEntries();
return error.TODO;
}
/// Open a file/folder within a directory at the given path.
/// If path is ".", "/", or "./", this File is returned.
@@ -92,13 +104,13 @@ pub fn open(self: File, path: []const u8) !File {
if (path[path.len - 1] == '/') return self.open(path[0 .. path.len - 1]);
const idx = std.mem.indexOf(u8, path, "/") orelse path.len;
const first_element = path[0..idx];
if (std.mem.eql(u8, first_element, ".")) return self;
if (std.mem.eql(u8, first_element, ".")) return self.open(path[idx + 1 ..]);
const entries = try self.getEntries();
var cur_slice = entries;
var split = cur_slice.len / 2;
while (cur_slice.len == 0) {
while (cur_slice.len > 0) {
split = cur_slice.len / 2;
const comp = std.mem.order(u8, entries[split].name, first_element);
const comp = std.mem.order(u8, first_element, cur_slice[split].name);
switch (comp) {
.eq => {
var fil: File = try .fromEntry(self.archive, cur_slice[split]);
@@ -109,27 +121,101 @@ pub fn open(self: File, path: []const u8) !File {
return fil.open(path[idx + 1 ..]);
},
.lt => cur_slice = cur_slice[0..split],
.gt => cur_slice = cur_slice[split..],
.gt => cur_slice = cur_slice[split + 1 ..],
}
}
return FileError.NotFound;
}
pub fn extract(self: *File, path: []const u8, options: ExtractionOptions) !void {
_ = self;
_ = path;
_ = options;
return error.TODO;
std.Options = .{
.log_level = options.log_level,
};
var alloc = self.archive.allocator();
var ext_path: []u8 = undefined;
if (std.fs.cwd().statFile(path)) |stat| {
if (stat.kind == .directory) {
if (!self.isDir()) {
const has_end_sep = path[path.len - 1] == '/';
const alloc_size = if (has_end_sep)
path.len + self.name.len
else
path.len + self.name.len + 1;
ext_path = alloc.alloc(u8, alloc_size);
@memcpy(ext_path[0..path.len], path);
@memcpy(ext_path[ext_path.len - self.name.len ..], self.name);
if (!has_end_sep) ext_path[path.len] = '/';
} else {
ext_path = path;
}
} else return FileError.InvalidExtractionPath;
} else |err| {
if (err == .FileNotFound) {
ext_path = path;
} else {
std.log.err("Error stat-ing extraction path {s}: {}\n", .{ path, err });
return err;
}
}
defer if (ext_path.len > path.len) alloc.free(ext_path);
var pool: std.Thread.Pool = .{};
try pool.init(.{ .allocator = alloc });
var wg: WaitGroup = .{};
defer pool.deinit();
var err: ?anyerror = null;
self.extractReal(ext_path, options, &pool, &wg, &err, null);
wg.wait();
if (err != null) return err.?;
}
const ParentInfo = struct {
fil: *File,
mut: Mutex = .{},
fn finish(self: *ParentInfo) void {}
};
fn extractReal(self: *File, path: []const u8, options: ExtractionOptions) void {
_ = self;
_ = path;
_ = options;
fn extractReal(self: *File, path: []const u8, options: ExtractionOptions, pol: *std.Thread.Pool, wg: *WaitGroup, out_err: *?anyerror, parent: ?ParentInfo) void {
std.log.info("Extracting {s} (inode {}) to {s}\n", .{ self.name, self.inode.hdr.num, path });
defer if (parent != null) parent.?.finish();
switch (self.inode.hdr.inode_type) {
.file, .ext_file => {
var fil = std.fs.cwd().createFile(path, .{}) catch |err| {
std.log.err("Error creating {}: {}\n", .{ path, err });
out_err = err;
return;
};
//TODO:
self.setPerm(fil, options) catch |err| {
std.log.err("Error setting permissions for {}: {}\n", .{ path, err });
out_err = err;
return;
};
},
.symlink, .ext_symlink => {},
.block_dev,
.char_dev,
.fifo,
.ext_block_dev,
.ext_char_dev,
.ext_fifo,
=> {},
.dir, .ext_dir => {
var parent_info: ParentInfo = .{
.fil = self,
};
var dir_wg: WaitGroup = .{};
var iter: Iterator = self.iter() catch |err| {};
},
.socket, .ext_socket => {
std.log.info("Ignoring socket file {s} (inode {})\n", .{ self.name, self.inode.hdr.num });
},
}
}
pub fn setPerm(self: File, fil: *std.fs.File, options: ExtractionOptions) !void {
if (!options.ignoreOwner) try fil.chmod(self.inode.hdr.permissions);
if (!options.ignorePermissions) try fil.chown(try self.ownerUid(), try self.ownerGid());
}
pub fn pathIsSelf(path: []const u8) bool {