Things are working (though slowly)
This commit is contained in:
@@ -31,7 +31,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
exe_mod.addOptions("config", opt);
|
exe_mod.addOptions("config", opt);
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.linkage = .static,
|
.linkage = .static,
|
||||||
.name = "zig-unsquashfs",
|
.name = "unsquashfs",
|
||||||
.root_module = exe_mod,
|
.root_module = exe_mod,
|
||||||
.version = sem_ver,
|
.version = sem_ver,
|
||||||
});
|
});
|
||||||
|
|||||||
+19
-5
@@ -51,10 +51,10 @@ const ListTypes = enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var alloc: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
const alloc = std.heap.smp_allocator;
|
||||||
extr_files = .init(alloc.allocator());
|
extr_files = .init(alloc);
|
||||||
defer extr_files.deinit();
|
defer extr_files.deinit();
|
||||||
var args = std.process.argsWithAllocator(alloc.allocator()) catch {
|
var args = std.process.argsWithAllocator(alloc) catch {
|
||||||
_ = try stdout.writeAll("Unable to allocate memory");
|
_ = try stdout.writeAll("Unable to allocate memory");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -119,8 +119,10 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const fil = try std.fs.cwd().openFile(filename, .{});
|
const fil = try std.fs.cwd().openFile(filename, .{});
|
||||||
|
defer fil.close();
|
||||||
|
var th_alloc: std.heap.ThreadSafeAllocator = .{ .child_allocator = std.heap.smp_allocator };
|
||||||
var rdr = squashfs.SfsFile.init(
|
var rdr = squashfs.SfsFile.init(
|
||||||
alloc.allocator(),
|
th_alloc.allocator(),
|
||||||
fil,
|
fil,
|
||||||
offset,
|
offset,
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
@@ -128,5 +130,17 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
defer rdr.deinit();
|
defer rdr.deinit();
|
||||||
//TODO
|
//TODO: list and extr_files;
|
||||||
|
var op: squashfs.ExtractionOptions = squashfs.ExtractionOptions.init() catch |err| {
|
||||||
|
try std.fmt.format(stdout.writer(), "Error setting extraction options: {any}\n", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
op.verbose = verbose;
|
||||||
|
op.dereference_symlinks = deref;
|
||||||
|
op.unbreak_symlinks = unbreak;
|
||||||
|
if (processors != 0) op.thread_count = processors;
|
||||||
|
rdr.extract(op, extr_location) catch |err| {
|
||||||
|
try std.fmt.format(stdout.writer(), "Error extracting archive: {any}\n", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+173
-44
@@ -219,7 +219,7 @@ pub fn File(comptime T: type) type {
|
|||||||
defer pol.deinit();
|
defer pol.deinit();
|
||||||
var errs: std.ArrayList(anyerror) = .init(self.rdr.alloc);
|
var errs: std.ArrayList(anyerror) = .init(self.rdr.alloc);
|
||||||
defer errs.deinit();
|
defer errs.deinit();
|
||||||
try self.extractReal(op, path, &errs, &wg, &pol, true);
|
self.extractReal(op, path, &errs, &wg, &pol, true);
|
||||||
wg.wait();
|
wg.wait();
|
||||||
if (errs.items.len > 0) return errs.items[0];
|
if (errs.items.len > 0) return errs.items[0];
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ pub fn File(comptime T: type) type {
|
|||||||
wg: *WaitGroup,
|
wg: *WaitGroup,
|
||||||
pol: *Pool,
|
pol: *Pool,
|
||||||
first: bool,
|
first: bool,
|
||||||
) !void {
|
) void {
|
||||||
if (errs.items.len > 0) return;
|
if (errs.items.len > 0) return;
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
std.fmt.format(
|
std.fmt.format(
|
||||||
@@ -242,18 +242,22 @@ pub fn File(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
return switch (self.inode.hdr.type) {
|
return switch (self.inode.hdr.type) {
|
||||||
.dir, .ext_dir => {
|
.dir, .ext_dir => {
|
||||||
|
var complete = false;
|
||||||
wg.start();
|
wg.start();
|
||||||
defer std.debug.print("{}\n", .{wg.state.raw});
|
defer if (!complete) wg.finish();
|
||||||
errdefer wg.finish();
|
|
||||||
std.fs.cwd().makeDir(path) catch |err| {
|
std.fs.cwd().makeDir(path) catch |err| {
|
||||||
if (err != std.fs.Dir.MakeError.PathAlreadyExists) {
|
if (err != std.fs.Dir.MakeError.PathAlreadyExists) {
|
||||||
return err;
|
errs.append(err) catch {};
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var dir_wg = try self.rdr.alloc.create(WaitGroup);
|
const dir_wg = self.rdr.alloc.create(WaitGroup) catch |err| {
|
||||||
|
errs.append(err) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
dir_wg.* = .{};
|
dir_wg.* = .{};
|
||||||
for (self.entries.?) |ent| {
|
for (self.entries.?) |ent| {
|
||||||
var fil = initFromEntry(self.rdr, ent) catch |err| {
|
const fil = initFromEntry(self.rdr, ent) catch |err| {
|
||||||
std.fmt.format(
|
std.fmt.format(
|
||||||
op.verbose_logger,
|
op.verbose_logger,
|
||||||
"error extracting inode {} \"{s}\": {}\n",
|
"error extracting inode {} \"{s}\": {}\n",
|
||||||
@@ -285,39 +289,109 @@ pub fn File(comptime T: type) type {
|
|||||||
) catch {};
|
) catch {};
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
fil.extractReal(op, ext_path, errs, dir_wg, pol, false) catch |err| {
|
var thr = std.Thread.spawn(.{ .allocator = self.rdr.alloc }, extractReal, .{
|
||||||
std.fmt.format(
|
fil,
|
||||||
op.verbose_logger,
|
op,
|
||||||
"error extracting inode {} \"{s}\": {}\n",
|
ext_path,
|
||||||
.{ ent.num, path, err },
|
errs,
|
||||||
) catch {};
|
dir_wg,
|
||||||
|
pol,
|
||||||
|
false,
|
||||||
|
}) catch |err| {
|
||||||
|
self.rdr.alloc.free(ext_path);
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error extracting inode {} \"{s}\": {}\n",
|
||||||
|
.{ ent.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
thr.detach();
|
||||||
}
|
}
|
||||||
dir_wg.wait();
|
var thr = std.Thread.spawn(
|
||||||
wg.finish();
|
.{ .allocator = self.rdr.alloc },
|
||||||
std.debug.print("finished: {s}\n", .{path});
|
extractDirWait,
|
||||||
|
.{
|
||||||
|
self,
|
||||||
|
op,
|
||||||
|
path,
|
||||||
|
dir_wg,
|
||||||
|
wg,
|
||||||
|
first,
|
||||||
|
},
|
||||||
|
) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error spawning wait thread for \"{s}\": {}\n",
|
||||||
|
.{ path, err },
|
||||||
|
) catch {};
|
||||||
|
}
|
||||||
|
self.extractDirWait(op, path, dir_wg, wg, first);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
thr.detach();
|
||||||
|
complete = true;
|
||||||
},
|
},
|
||||||
.file, .ext_file => {
|
.file, .ext_file => {
|
||||||
|
var complete = false;
|
||||||
wg.start();
|
wg.start();
|
||||||
errdefer wg.finish();
|
defer if (!complete) wg.finish();
|
||||||
var ext_fil = try std.fs.cwd().createFile(path, .{});
|
var ext_fil = std.fs.cwd().createFile(path, .{}) catch |err| {
|
||||||
errdefer ext_fil.close();
|
if (op.verbose) {
|
||||||
var fil_errs = try self.rdr.alloc.create(std.ArrayList(anyerror));
|
std.fmt.format(
|
||||||
errdefer self.rdr.alloc.destroy(fil_errs);
|
op.verbose_logger,
|
||||||
|
"error creating file \"{s}\": {}\n",
|
||||||
|
.{ path, err },
|
||||||
|
) catch {};
|
||||||
|
}
|
||||||
|
errs.append(err) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
defer if (!complete) ext_fil.close();
|
||||||
|
var fil_errs = self.rdr.alloc.create(std.ArrayList(anyerror)) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error allocating memory: {}\n",
|
||||||
|
.{err},
|
||||||
|
) catch {};
|
||||||
|
}
|
||||||
|
errs.append(err) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
defer if (!complete) self.rdr.alloc.destroy(fil_errs);
|
||||||
fil_errs.* = .init(self.rdr.alloc);
|
fil_errs.* = .init(self.rdr.alloc);
|
||||||
errdefer fil_errs.deinit();
|
defer if (!complete) fil_errs.deinit();
|
||||||
@constCast(&self.data_reader.?).setPool(pol);
|
@constCast(&self.data_reader.?).setPool(pol);
|
||||||
try self.data_reader.?.writeToNoBlock(errs, ext_fil, extractRegFinish, .{
|
self.data_reader.?.writeToNoBlock(
|
||||||
self,
|
|
||||||
op,
|
|
||||||
path,
|
|
||||||
fil_errs,
|
|
||||||
errs,
|
errs,
|
||||||
wg,
|
|
||||||
ext_fil,
|
ext_fil,
|
||||||
first,
|
extractRegFinish,
|
||||||
});
|
.{
|
||||||
|
self,
|
||||||
|
op,
|
||||||
|
path,
|
||||||
|
fil_errs,
|
||||||
|
errs,
|
||||||
|
wg,
|
||||||
|
ext_fil,
|
||||||
|
first,
|
||||||
|
},
|
||||||
|
) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error extracting file \"{s}\": {}\n",
|
||||||
|
.{ path, err },
|
||||||
|
) catch {};
|
||||||
|
}
|
||||||
|
errs.append(err) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
complete = true;
|
||||||
},
|
},
|
||||||
.symlink, .ext_symlink => {},
|
.symlink, .ext_symlink => {},
|
||||||
.block_dev, .ext_block_dev, .char_dev, .ext_char_dev, .fifo, .ext_fifo => {
|
.block_dev, .ext_block_dev, .char_dev, .ext_char_dev, .fifo, .ext_fifo => {
|
||||||
@@ -334,14 +408,66 @@ pub fn File(comptime T: type) type {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// fn extractFileFinish(
|
fn extractDirWait(
|
||||||
// self: Self,
|
self: Self,
|
||||||
// op: ExtractionOptions,
|
op: ExtractionOptions,
|
||||||
// path: []const u8,
|
path: []const u8,
|
||||||
// dir_wg: *WaitGroup,
|
dir_wg: *WaitGroup,
|
||||||
// dir_wg_mut: *Mutex,
|
wg: *WaitGroup,
|
||||||
// wg: *WaitGroup,
|
first: bool,
|
||||||
// ) void {}
|
) void {
|
||||||
|
dir_wg.wait();
|
||||||
|
self.rdr.alloc.destroy(dir_wg);
|
||||||
|
defer {
|
||||||
|
wg.finish();
|
||||||
|
if (!first) {
|
||||||
|
self.rdr.alloc.free(path);
|
||||||
|
self.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (op.ignore_permissions) return;
|
||||||
|
const dir_uid = self.uid() catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error getting uid for inode {} \"{s}\": {}\n",
|
||||||
|
.{ self.inode.hdr.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
const dir_gid = self.gid() catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error getting gid for inode {} \"{s}\": {}\n",
|
||||||
|
.{ self.inode.hdr.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
var ext_dir = std.fs.cwd().openFile(path, .{}) catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error setting owner & permissions for \"{s}\": {}\n",
|
||||||
|
.{ path, err },
|
||||||
|
) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
defer ext_dir.close();
|
||||||
|
ext_dir.chmod(self.inode.hdr.perm) catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error setting permissions for inode {} \"{s}\": {}\n",
|
||||||
|
.{ self.inode.hdr.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
ext_dir.chown(dir_uid, dir_gid) catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error setting owner for inode {} \"{s}\": {}\n",
|
||||||
|
.{ self.inode.hdr.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
fn extractRegFinish(
|
fn extractRegFinish(
|
||||||
self: Self,
|
self: Self,
|
||||||
op: ExtractionOptions,
|
op: ExtractionOptions,
|
||||||
@@ -352,12 +478,15 @@ pub fn File(comptime T: type) type {
|
|||||||
fil: std.fs.File,
|
fil: std.fs.File,
|
||||||
first: bool,
|
first: bool,
|
||||||
) void {
|
) void {
|
||||||
defer std.debug.print("{}\n", .{wg.state.raw});
|
defer {
|
||||||
defer wg.finish();
|
wg.finish();
|
||||||
defer fil.close();
|
fil.close();
|
||||||
defer self.rdr.alloc.destroy(fil_errs);
|
self.rdr.alloc.destroy(fil_errs);
|
||||||
defer if (!first) self.deinit();
|
if (!first) {
|
||||||
defer if (!first) self.rdr.alloc.free(path);
|
self.deinit();
|
||||||
|
self.rdr.alloc.free(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (fil_errs.items.len > 0) {
|
if (fil_errs.items.len > 0) {
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
std.fmt.format(
|
std.fmt.format(
|
||||||
|
|||||||
+10
-4
@@ -188,6 +188,10 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
on_finish_args: anytype,
|
on_finish_args: anytype,
|
||||||
) !void {
|
) !void {
|
||||||
if (self.pool == null) return DataReaderError.ThreadPoolNotSet;
|
if (self.pool == null) return DataReaderError.ThreadPoolNotSet;
|
||||||
|
if (self.numBlocks() == 0) {
|
||||||
|
@call(.auto, on_finish, on_finish_args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var mut: std.Thread.Mutex = .{};
|
var mut: std.Thread.Mutex = .{};
|
||||||
var cur_idx: usize = 0;
|
var cur_idx: usize = 0;
|
||||||
var block_wg = try self.alloc.create(std.Thread.WaitGroup);
|
var block_wg = try self.alloc.create(std.Thread.WaitGroup);
|
||||||
@@ -200,7 +204,8 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
block_wg.startMany(self.numBlocks());
|
block_wg.startMany(self.numBlocks());
|
||||||
for (0..self.numBlocks()) |i| {
|
for (0..self.numBlocks()) |i| {
|
||||||
try self.pool.?.spawn(
|
var thr = try std.Thread.spawn(
|
||||||
|
.{ .allocator = self.alloc },
|
||||||
comptime blk: {
|
comptime blk: {
|
||||||
if (std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
if (std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
||||||
break :blk noBlockThreadPWrite;
|
break :blk noBlockThreadPWrite;
|
||||||
@@ -215,6 +220,7 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
thr.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,12 +359,12 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
self.writeBlockToPWrite(errs, idx, writer);
|
self.writeBlockToPWrite(errs, idx, writer);
|
||||||
finish_mut.lock();
|
finish_mut.lock();
|
||||||
block_wg.finish();
|
block_wg.finish();
|
||||||
|
const isDone = block_wg.isDone();
|
||||||
defer {
|
defer {
|
||||||
const done = block_wg.isDone();
|
|
||||||
finish_mut.unlock();
|
finish_mut.unlock();
|
||||||
if (done) self.alloc.destroy(finish_mut);
|
if (isDone) self.alloc.destroy(finish_mut);
|
||||||
}
|
}
|
||||||
if (block_wg.isDone()) {
|
if (isDone) {
|
||||||
self.alloc.destroy(block_wg);
|
self.alloc.destroy(block_wg);
|
||||||
@call(.auto, on_finish, on_finish_args);
|
@call(.auto, on_finish, on_finish_args);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -26,8 +26,8 @@ test "OpenFile" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "ExtractSingleFile" {
|
test "ExtractSingleFile" {
|
||||||
const single_file = "Start.exe";
|
const single_file = "PortableApps/Notepad++Portable/App/Notepad++/doLocalConf.xml";
|
||||||
const single_file_extr_loc = "testing/Start.exe";
|
const single_file_extr_loc = "testing/doLocalConf.xml";
|
||||||
|
|
||||||
std.fs.cwd().deleteFile(single_file_extr_loc) catch {};
|
std.fs.cwd().deleteFile(single_file_extr_loc) catch {};
|
||||||
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
||||||
@@ -49,7 +49,7 @@ test "ExtractAll" {
|
|||||||
defer sfs_fil.close();
|
defer sfs_fil.close();
|
||||||
var rdr: SfsFile = try .init(std.testing.allocator, sfs_fil, 0);
|
var rdr: SfsFile = try .init(std.testing.allocator, sfs_fil, 0);
|
||||||
defer rdr.deinit();
|
defer rdr.deinit();
|
||||||
var op: ExtractionOptions = try .init();
|
const op: ExtractionOptions = try .init();
|
||||||
op.verbose = true;
|
// op.verbose = true;
|
||||||
try rdr.extract(op, extr_dir);
|
try rdr.extract(op, extr_dir);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user