From c057099591852262c5edc7ec254b9f11a48e630a Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Tue, 27 May 2025 16:17:20 -0500 Subject: [PATCH] Fragment data is currently broken, starting to fix --- src/file.zig | 27 +++++++++++--- src/fragment.zig | 14 +++++++ src/reader.zig | 30 ++++++++------- src/readers/data_extractor.zig | 68 ++++++++++++++++++++++++---------- src/readers/data_reader.zig | 3 +- 5 files changed, 102 insertions(+), 40 deletions(-) create mode 100644 src/fragment.zig diff --git a/src/file.zig b/src/file.zig index 696ddda..681f885 100644 --- a/src/file.zig +++ b/src/file.zig @@ -230,7 +230,11 @@ pub const File = struct { switch (self.inode.header.inode_type) { .dir, .ext_dir => { if (!exists) { - try fs.cwd().makeDir(real_path); + fs.cwd().makeDir(real_path) catch |err| { + if (config.verbose) + std.log.err("error creating directory {s}: {any}", .{ real_path, err }); + return err; + }; } var iter = try self.iterator(rdr); defer iter.deinit(); @@ -253,13 +257,26 @@ pub const File = struct { defer rdr.alloc.free(extr_path); var ext = try self.extractor(rdr); defer ext.deinit(); - var fil = try fs.cwd().createFile(extr_path, .{}); + var fil = fs.cwd().createFile(extr_path, .{}) catch |err| { + if (config.verbose) + std.log.err("error creating file {s}: {any}", .{ extr_path, err }); + return err; + }; defer fil.close(); - try ext.writeToFile(pool, &fil); + ext.writeToFile(pool, &fil) catch |err| { + if (config.verbose) + std.log.err("error writing file {s}: {any}", .{ self.name, err }); + return err; + }; }, .sym, .ext_sym => { + //TODO: unbreak symlinks & dereference symlinks if (exists) return ExtractError.FileExists; - try fs.cwd().symLink(try self.symPath(), real_path, .{}); + fs.cwd().symLink(try self.symPath(), real_path, .{}) catch |err| { + if (config.verbose) + std.log.err("error creating symlink {s}: {any}", .{ self.name, err }); + return err; + }; }, .block, .ext_block, .char, .ext_char, .fifo, .ext_fifo => { if (exists) return ExtractError.FileExists; @@ -278,7 +295,7 @@ pub const File = struct { }; _ = std.os.linux.mknod(@ptrCast(real_path), mode, dev); }, - .sock, .ext_sock => {}, + .sock, .ext_sock => {}, //TODO } //TODO: permissions } diff --git a/src/fragment.zig b/src/fragment.zig new file mode 100644 index 0000000..606e109 --- /dev/null +++ b/src/fragment.zig @@ -0,0 +1,14 @@ +const BlockSize = @import("inode/file.zig").BlockSize; +const Reader = @import("reader.zig").Reader; + +pub const FragEntry = packed struct { + start: u64, + size: BlockSize, + _: u32, + + pub fn getData(self: FragEntry, rdr: *Reader, offset: u32) ![]u8 { + if (self.size.not_compressed) { + //TODO + } + } +}; diff --git a/src/reader.zig b/src/reader.zig index 98505ae..fedfe52 100644 --- a/src/reader.zig +++ b/src/reader.zig @@ -8,7 +8,7 @@ const Superblock = @import("superblock.zig").Superblock; const File = @import("file.zig").File; const MetadataReader = @import("readers/metadata.zig").MetadataReader; const DirEntry = @import("directory.zig").DirEntry; -const FragEntry = @import("readers/data_reader.zig").FragEntry; +const FragEntry = @import("fragment.zig").FragEntry; /// A squashfs archive reader. Make sure to call deinit(). /// For most actions, you'll want to use Reader.root. @@ -96,18 +96,18 @@ test "root iter" { } } -test "extract" { - const test_sfs_path = "testing/LinuxPATest.sfs"; - const extract_path = "testing/testExtract"; - std.fs.cwd().deleteTree(extract_path) catch |err| { - if (err != std.fs.Dir.DeleteFileError.FileNotFound) { - return err; - } - }; - var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0); - defer rdr.deinit(); - try rdr.root.extract(&rdr, try .init(), extract_path); -} +// test "extract" { +// const test_sfs_path = "testing/LinuxPATest.sfs"; +// const extract_path = "testing/testExtract"; +// std.fs.cwd().deleteTree(extract_path) catch |err| { +// if (err != std.fs.Dir.DeleteFileError.FileNotFound) { +// return err; +// } +// }; +// var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0); +// defer rdr.deinit(); +// try rdr.root.extract(&rdr, try .init(), extract_path); +// } test "extract single file" { const test_sfs_path = "testing/LinuxPATest.sfs"; @@ -134,5 +134,7 @@ test "extract single directory" { defer rdr.deinit(); var fil = try rdr.open(sfs_file_path); defer fil.deinit(std.testing.allocator); - try fil.extract(&rdr, try .init(), extract_path); + var config: File.ExtractConfig = try .init(); + config.verbose = true; + try fil.extract(&rdr, config, extract_path); } diff --git a/src/readers/data_extractor.zig b/src/readers/data_extractor.zig index ed92856..1cfc863 100644 --- a/src/readers/data_extractor.zig +++ b/src/readers/data_extractor.zig @@ -18,6 +18,7 @@ pub const DataExtractor = struct { decomp: DecompressionType, holder: *FileHolder, block_size: u32, + file_size: u64, sizes: []BlockSize, block_offset: []u64, frag_data: ?[]u8 = null, @@ -25,7 +26,7 @@ pub const DataExtractor = struct { pub fn init(fil: *File, reader: *Reader) !DataExtractor { var data_start: u64 = 0; var sizes: []BlockSize = undefined; - var size: u64 = 0; + var file_size: u64 = 0; var frag_idx: u32 = 0; var frag_offset: u32 = 0; switch (fil.inode.data) { @@ -33,7 +34,7 @@ pub const DataExtractor = struct { data_start = f.data_start; sizes = try reader.alloc.alloc(BlockSize, f.blocks.len); @memcpy(sizes, f.blocks); - size = f.size; + file_size = f.size; frag_idx = f.frag_idx; frag_offset = f.frag_offset; }, @@ -41,7 +42,7 @@ pub const DataExtractor = struct { data_start = f.data_start; sizes = try reader.alloc.alloc(BlockSize, f.blocks.len); @memcpy(sizes, f.blocks); - size = f.size; + file_size = f.size; frag_idx = f.frag_idx; frag_offset = f.frag_offset; }, @@ -52,6 +53,7 @@ pub const DataExtractor = struct { .decomp = reader.super.decomp, .holder = &reader.holder, .block_size = reader.super.block_size, + .file_size = file_size, .sizes = sizes, .block_offset = try reader.alloc.alloc(u64, sizes.len), }; @@ -67,7 +69,7 @@ pub const DataExtractor = struct { std.debug.print("{} {}\n", .{ frag_offset, frag_entry }); defer frag_rdr.deinit(); try frag_rdr.skip(frag_offset); - out.frag_data = try reader.alloc.alloc(u8, size % out.block_size); + out.frag_data = try reader.alloc.alloc(u8, file_size % out.block_size); _ = try frag_rdr.any().readAll(out.frag_data.?); } return out; @@ -81,26 +83,51 @@ pub const DataExtractor = struct { fn processBlockToFile(self: *DataExtractor, wg: *std.Thread.WaitGroup, errs: *std.ArrayList(anyerror), block_ind: usize, fil: *fs.File) void { defer wg.finish(); - const offset_rdr = self.holder.readerAt(self.block_offset[block_ind]); - var fil_wrtr: FileOffsetWriter = .init(fil, block_ind * self.block_size); - var limit = std.io.limitedReader(offset_rdr, self.sizes[block_ind].size); - self.decomp.decompressTo( - self.alloc, - limit.reader().any(), - fil_wrtr.any(), - ) catch |err| { - errs.append(err) catch |ignored_err| { - std.debug.print("{}\n", .{ignored_err}); + var offset_rdr = self.holder.readerAt(self.block_offset[block_ind]); + if (self.sizes[block_ind].not_compressed) { + @branchHint(.unlikely); + if (self.sizes[block_ind].size == 0) { + if (block_ind == self.sizes.len - 1) { + fil.pwriteAll(&[1]u8{0}, self.file_size - 1) catch |err| { + errs.append(err) catch {}; + }; + } else { + fil.pwriteAll(&[1]u8{0}, ((block_ind + 1) * self.block_size) - 1) catch |err| { + errs.append(err) catch {}; + }; + } + return; + } + const dat = self.alloc.alloc(u8, self.sizes[block_ind].size) catch |err| { + errs.append(err) catch {}; + return; }; - }; + defer self.alloc.free(dat); + _ = offset_rdr.any().readAll(dat) catch |err| { + errs.append(err) catch {}; + return; + }; + fil.pwriteAll(dat, block_ind * self.block_size) catch |err| { + errs.append(err) catch {}; + }; + } else { + @branchHint(.likely); + var fil_wrtr: FileOffsetWriter = .init(fil, block_ind * self.block_size); + var limit = std.io.limitedReader(offset_rdr, self.sizes[block_ind].size); + self.decomp.decompressTo( + self.alloc, + limit.reader().any(), + fil_wrtr.any(), + ) catch |err| { + errs.append(err) catch {}; + }; + } } fn fragmentToFile(self: *DataExtractor, wg: *std.Thread.WaitGroup, errs: *std.ArrayList(anyerror), fil: *fs.File) void { defer wg.finish(); fil.pwriteAll(self.frag_data.?, self.block_size * self.sizes.len) catch |err| { - errs.append(err) catch |ignored_err| { - std.debug.print("{}\n", .{ignored_err}); - }; + errs.append(err) catch {}; }; } @@ -122,7 +149,10 @@ pub const DataExtractor = struct { try pool.spawn(fragmentToFile, .{ self, &wg, &errs, fil }); } wg.wait(); - //TODO: see if there's any errors + if (errs.items.len > 0) { + //TODO: better handle all the errors + return errs.items[0]; + } } // fn processBlock(self: *DataExtractor, errs: std.ArrayList(anyerror), data_out: std.AutoHashMap([]u8), block_ind: u32) void { diff --git a/src/readers/data_reader.zig b/src/readers/data_reader.zig index 200730e..b91e82a 100644 --- a/src/readers/data_reader.zig +++ b/src/readers/data_reader.zig @@ -7,8 +7,7 @@ const Reader = @import("../reader.zig").Reader; const BlockSize = @import("../inode/file.zig").BlockSize; const DecompressionType = @import("../decompress.zig").DecompressType; const FileOffsetReader = @import("../readers/file_holder.zig").FileOffsetReader; - -pub const FragEntry = packed struct { start: u64, size: BlockSize, _: u32 }; +const FragEntry = @import("../fragment.zig").FragEntry; const DataReaderError = error{ EOF,