Finished up some errors

Kinda finished extraction
This commit is contained in:
Caleb Gardner
2026-05-13 06:21:01 -05:00
parent 78d1ee2937
commit 700993b0e3
9 changed files with 190 additions and 61 deletions
+16 -7
View File
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
block_size: u32, block_size: u32,
buffers: std.ArrayList(Buffer), buffers: std.ArrayList(Buffer),
buffer_queue: std.SinglyLinkedList, buffer_queue: std.SinglyLinkedList = .{},
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self { pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
return .{ return .{
@@ -37,22 +37,31 @@ pub fn deinit(self: Self) void {
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize { fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
if (d == null) { if (d == null) {
const buf = try alloc.alloc(u8, in.len * 2); var buf = try alloc.alloc(u8, in.len * 2);
defer alloc.free(buf); defer alloc.free(buf);
return lzmaDecomp(buf, in, out); return lzmaDecomp(alloc, &buf, in, out) catch |err| return switch (err) {
error.OutOfMemory => Error.OutOfMemory,
else => Error.ReadFailed,
};
} }
var self: Self = @fieldParentPtr("interface", d.?); var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
const buf_node = self.buffer_queue.popFirst(); const buf_node = self.buffer_queue.popFirst();
var buf: *Buffer = undefined; var buf: *Buffer = undefined;
if (buf_node == null) { if (buf_node == null) {
const new_buf = try self.buffers.addOne(self.alloc); const new_buf = try self.buffers.addOne(self.alloc);
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size + lzma.block_size_max) }; new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
buf = new_buf; buf = new_buf;
} else { } else {
buf = @fieldParentPtr("node", buf_node); buf = @fieldParentPtr("node", buf_node.?);
} }
defer self.buffer_queue.prepend(&buf.node); defer self.buffer_queue.prepend(&buf.node);
return lzmaDecomp(self.alloc, &buf.buf, in, out); return lzmaDecomp(self.alloc, &buf.buf, in, out) catch |err| {
// self.err = err;
return switch (err) {
error.OutOfMemory => Error.OutOfMemory,
else => Error.ReadFailed,
};
};
} }
inline fn lzmaDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize { inline fn lzmaDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize {
+12 -9
View File
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
block_size: u32, block_size: u32,
buffers: std.ArrayList(Buffer), buffers: std.ArrayList(Buffer),
buffer_queue: std.SinglyLinkedList, buffer_queue: std.SinglyLinkedList = .{},
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self { pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
return .{ return .{
@@ -37,25 +37,28 @@ pub fn deinit(self: Self) void {
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize { fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
if (d == null) { if (d == null) {
const buf = try alloc.alloc(u8, in.len * 2); var buf = try alloc.alloc(u8, in.len * 2);
defer alloc.free(buf); defer alloc.free(buf);
return lzmaDecomp(buf, in, out); return xzDecomp(alloc, &buf, in, out) catch return Error.ReadFailed;
} }
var self: Self = @fieldParentPtr("interface", d.?); var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
const buf_node = self.buffer_queue.popFirst(); const buf_node = self.buffer_queue.popFirst();
var buf: *Buffer = undefined; var buf: *Buffer = undefined;
if (buf_node == null) { if (buf_node == null) {
const new_buf = try self.buffers.addOne(self.alloc); const new_buf = try self.buffers.addOne(self.alloc);
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size + xz.block_size_max) }; new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
buf = new_buf; buf = new_buf;
} else { } else {
buf = @fieldParentPtr("node", buf_node); buf = @fieldParentPtr("node", buf_node.?);
} }
defer self.buffer_queue.prepend(&buf.node); defer self.buffer_queue.prepend(&buf.node);
return lzmaDecomp(self.alloc, &buf.buf, in, out); return xzDecomp(self.alloc, &buf.buf, in, out) catch {
// self.err = err;
return Error.ReadFailed;
};
} }
inline fn lzmaDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize { inline fn xzDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize {
var rdr: Reader = .fixed(in); var rdr: Reader = .fixed(in);
var d = try xz.Decompress.init(&rdr, alloc, buffer.*); var d = try xz.Decompress.init(&rdr, alloc, buffer.*);
defer { defer {
@@ -73,5 +76,5 @@ pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp
fn statelessDecomp(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize { fn statelessDecomp(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
var buf = try alloc.alloc(u8, in.len); var buf = try alloc.alloc(u8, in.len);
defer alloc.free(buf); defer alloc.free(buf);
return lzmaDecomp(alloc, &buf, in, out) catch return Error.ReadFailed; return xzDecomp(alloc, &buf, in, out) catch return Error.ReadFailed;
} }
+4 -4
View File
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
block_size: u32, block_size: u32,
buffers: std.ArrayList(Buffer), buffers: std.ArrayList(Buffer),
buffer_queue: std.SinglyLinkedList, buffer_queue: std.SinglyLinkedList = .{},
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self { pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
return .{ return .{
@@ -41,15 +41,15 @@ fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8
defer alloc.free(buf); defer alloc.free(buf);
return zlibDecomp(buf, in, out); return zlibDecomp(buf, in, out);
} }
var self: Self = @fieldParentPtr("interface", d.?); var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
const buf_node = self.buffer_queue.popFirst(); const buf_node = self.buffer_queue.popFirst();
var buf: *Buffer = undefined; var buf: *Buffer = undefined;
if (buf_node == null) { if (buf_node == null) {
const new_buf = try self.buffers.addOne(self.alloc); const new_buf = try self.buffers.addOne(self.alloc);
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size) }; new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
buf = new_buf; buf = new_buf;
} else { } else {
buf = @fieldParentPtr("node", buf_node); buf = @fieldParentPtr("node", buf_node.?);
} }
defer self.buffer_queue.prepend(&buf.node); defer self.buffer_queue.prepend(&buf.node);
return zlibDecomp(buf.buf, in, out); return zlibDecomp(buf.buf, in, out);
+4 -4
View File
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
block_size: u32, block_size: u32,
buffers: std.ArrayList(Buffer), buffers: std.ArrayList(Buffer),
buffer_queue: std.SinglyLinkedList, buffer_queue: std.SinglyLinkedList = .{},
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self { pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
return .{ return .{
@@ -41,15 +41,15 @@ fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8
defer alloc.free(buf); defer alloc.free(buf);
return zstdDecomp(buf, in, out); return zstdDecomp(buf, in, out);
} }
var self: Self = @fieldParentPtr("interface", d.?); var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
const buf_node = self.buffer_queue.popFirst(); const buf_node = self.buffer_queue.popFirst();
var buf: *Buffer = undefined; var buf: *Buffer = undefined;
if (buf_node == null) { if (buf_node == null) {
const new_buf = try self.buffers.addOne(self.alloc); const new_buf = try self.buffers.addOne(self.alloc);
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size + zstd.block_size_max) }; new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size + zstd.block_size_max) };
buf = new_buf; buf = new_buf;
} else { } else {
buf = @fieldParentPtr("node", buf_node); buf = @fieldParentPtr("node", buf_node.?);
} }
defer self.buffer_queue.prepend(&buf.node); defer self.buffer_queue.prepend(&buf.node);
return zstdDecomp(buf.buf, in, out); return zstdDecomp(buf.buf, in, out);
+1 -1
View File
@@ -31,7 +31,7 @@ pub fn readDirectory(alloc: std.mem.Allocator, rdr: *Reader, size: u32) ![]DirEn
tot_red += @sizeOf(Header); tot_red += @sizeOf(Header);
for (hdr.count + 1) |_| { for (0..hdr.count + 1) |_| {
try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little); try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little);
const new_name = try alloc.alloc(u8, raw.name_size + 1); const new_name = try alloc.alloc(u8, raw.name_size + 1);
+2 -2
View File
@@ -63,12 +63,12 @@ pub fn open(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8)
alloc.free(entries); alloc.free(entries);
} }
const path = std.mem.trim(u8, filepath, "/"); const path = std.mem.trim(u8, filepath, "/");
const first_element: []u8 = std.mem.sliceTo(path, "/"); const first_element: []const u8 = std.mem.sliceTo(path, '/');
var search_slice = entries; var search_slice = entries;
var idx: usize = undefined; var idx: usize = undefined;
while (search_slice.len > 0) { while (search_slice.len > 0) {
idx = search_slice / 2; idx = search_slice.len / 2;
const middle = search_slice[idx]; const middle = search_slice[idx];
switch (std.mem.order(u8, first_element, middle.name)) { switch (std.mem.order(u8, first_element, middle.name)) {
.eq => break, .eq => break,
+144 -24
View File
@@ -224,7 +224,7 @@ const Tables = struct {
pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void { pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {
var decomp = switch (super.compression) { var decomp = switch (super.compression) {
.gzip => try @import("decomp/zlib.zig").init(alloc, super.block_size), .gzip => try @import("decomp/zlib.zig").init(alloc, super.block_size),
.lzma => try @import("decomp/lzma.zig").init(alloc, super.block_sizee), .lzma => try @import("decomp/lzma.zig").init(alloc, super.block_size),
.xz => try @import("decomp/xz.zig").init(alloc, super.block_size), .xz => try @import("decomp/xz.zig").init(alloc, super.block_size),
.zstd => try @import("decomp/zstd.zig").init(alloc, super.block_size), .zstd => try @import("decomp/zstd.zig").init(alloc, super.block_size),
else => unreachable, else => unreachable,
@@ -240,15 +240,33 @@ pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, s
defer que.close(io); defer que.close(io);
switch (self.hdr.inode_type) { switch (self.hdr.inode_type) {
.dir, .ext_dir => group.async(io, extractDir, .{ self, alloc, io, fil, super, path, options, &que }), .dir, .ext_dir => group.async(io, extractDir, .{
.file, .ext_file => group.async(io, extractRegFile, .{ self, alloc, io, file, super, path, options, &que }), self,
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, alloc, io, super, path, options, &que }), alloc,
.char_dev, io,
.block_dev, fil,
.ext_char_dev, &decomp.interface,
.ext_block_dev, &frag_table,
=> group.async(io, extractDevice, .{ self, alloc, io, super, path, options, &que }), super.block_size,
else => group.async(io, extractIPC, .{ self, alloc, io, super, path, options, &que }), super.dir_start,
path,
options,
&que,
}),
.file, .ext_file => group.async(io, extractRegFile, .{
self,
alloc,
io,
file,
&decomp.interface,
&frag_table,
super.block_size,
path,
options,
&que,
}),
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, io, path, options, &que }),
else => group.async(io, extractDevice, .{ self, alloc, io, super, path, options, &que }),
} }
var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count); var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
@@ -271,7 +289,7 @@ pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, s
// TODO: Check error. // TODO: Check error.
const xattr_res = std.os.linux.fsetxattr(ret_file.handle, x.key, x.value.ptr, x.value.len, 0); const xattr_res = std.os.linux.fsetxattr(ret_file.handle, x.key, x.value.ptr, x.value.len, 0);
if (xattr_res != 0 and options.verbose) if (xattr_res != 0 and options.verbose)
options.verbose_writer.?.print("setxattr failed with code: {}\n", .{xattr_res}); options.verbose_writer.?.print("setxattr failed with code: {}\n", .{xattr_res}) catch {};
} }
} }
} }
@@ -279,7 +297,7 @@ pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, s
try ret_file.setPermissions(io, inode.hdr.permissions); try ret_file.setPermissions(io, inode.hdr.permissions);
try ret_file.setOwner(io, try id_table.get(io, inode.hdr.uid_idx), try id_table.get(io, inode.hdr.gid_idx)); try ret_file.setOwner(io, try id_table.get(io, inode.hdr.uid_idx), try id_table.get(io, inode.hdr.gid_idx));
} }
if (group.token.raw == null and !que.type_erased.closed) que.close(io); if (!que.type_erased.closed and group.token.raw == null) que.close(io);
} }
} }
pub fn extractDir( pub fn extractDir(
@@ -288,12 +306,70 @@ pub fn extractDir(
io: Io, io: Io,
fil: OffsetFile, fil: OffsetFile,
decomp: *const Decompressor, decomp: *const Decompressor,
frag: *LookupTable.CachedTable(FragEntry),
block_size: u32, block_size: u32,
dir_start: u64, dir_start: u64,
inode_start: u64,
path: []const u8, path: []const u8,
options: ExtractionOptions, options: ExtractionOptions,
que: *Io.Queue(FileRet), que: *Io.Queue(FileRet),
) !void {} ) !void {
defer alloc.free(path);
const dirs = try self.readDirectory(alloc, io, fil, decomp, dir_start);
defer {
for (dirs) |d|
d.deinit(alloc);
alloc.free(dirs);
}
var group: Io.Group = .init;
defer group.cancel(io);
for (dirs) |d| {
var rdr = try fil.readerAt(io, d.block_start + inode_start, &[0]u8{});
var meta: MetadataReader = .init(alloc, &rdr.interface, decomp);
try meta.interface.discardAll(d.block_offset);
const inode = try read(alloc, &meta.interface, block_size);
const new_path = try std.mem.concat(alloc, u8, &[_][]const u8{ path, "/", d.name });
switch (inode.hdr.inode_type) {
.dir, .ext_dir => group.async(io, extractDir, .{
self,
alloc,
io,
fil,
&decomp.interface,
&frag,
block_size,
dir_start,
new_path,
options,
&que,
}),
.file, .ext_file => group.async(io, extractRegFile, .{
self,
alloc,
io,
file,
&decomp.interface,
&frag,
block_size,
new_path,
options,
&que,
}),
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, alloc, io, new_path, options, &que }),
else => group.async(io, extractDevice, .{ self, alloc, io, new_path, options, &que }),
}
}
try group.await(io);
try que.putOne(io, .{ .file = try Io.Dir.cwd().openFile(io, path, .{}), .inode = self });
}
pub fn extractRegFile( pub fn extractRegFile(
self: Inode, self: Inode,
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
@@ -306,6 +382,9 @@ pub fn extractRegFile(
options: ExtractionOptions, options: ExtractionOptions,
que: *Io.Queue(FileRet), que: *Io.Queue(FileRet),
) !void { ) !void {
_ = options;
defer alloc.free(path);
const atom = try Io.Dir.cwd().createFileAtomic(io, path, .{}); const atom = try Io.Dir.cwd().createFileAtomic(io, path, .{});
defer atom.deinit(io); defer atom.deinit(io);
@@ -332,7 +411,7 @@ pub fn extractRegFile(
else => unreachable, else => unreachable,
} }
const ext: DataExtractor = .init(fil, cache, decomp, block_size, size, start, blocks); const ext: DataExtractor = .init(fil, decomp, block_size, size, start, blocks);
ext.addFrag(frag_offset, try frag.get(io, frag_idx)); ext.addFrag(frag_offset, try frag.get(io, frag_idx));
var group: Io.Group = .init; var group: Io.Group = .init;
@@ -353,7 +432,18 @@ pub fn extractSymlink(
path: []const u8, path: []const u8,
options: ExtractionOptions, options: ExtractionOptions,
que: *Io.Queue(FileRet), que: *Io.Queue(FileRet),
) !void {} ) !void {
defer alloc.free(path);
_ = options;
_ = que;
// TODO: handle symlink options
const target = try self.symlinkTarget();
try Io.Dir.cwd().symLink(io, target, path, .{});
// TODO: On Linux you can't set permission & xattrs on symlinks (they inherit from their target), but on Mac you can.
}
pub fn extractDevice( pub fn extractDevice(
self: Inode, self: Inode,
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
@@ -361,15 +451,45 @@ pub fn extractDevice(
path: []const u8, path: []const u8,
options: ExtractionOptions, options: ExtractionOptions,
que: *Io.Queue(FileRet), que: *Io.Queue(FileRet),
) !void {} ) !void {
pub fn extractIPC( defer alloc.free(path);
self: Inode,
alloc: std.mem.Allocator, var dev: u32 = 0;
io: Io, var mode: u32 = undefined;
path: []const u8,
options: ExtractionOptions, switch (self.data) {
que: *Io.Queue(FileRet), .char_dev => |d| {
) !void {} dev = d.dev;
mode = std.posix.DT.CHR;
},
.block_dev => |d| {
dev = d.dev;
mode = std.posix.DT.BLK;
},
.ext_char_dev => |d| {
dev = d.dev;
mode = std.posix.DT.BLK;
},
.ext_block_dev => |d| {
dev = d.dev;
mode = std.posix.DT.BLK;
},
.fifo, .ext_fifo => mode = std.posix.DT.FIFO,
.socket, .ext_socket => mode = std.posix.DT.SOCK,
else => unreachable,
}
const sentinel_path = try std.mem.concatMaybeSentinel(alloc, u8, &[1][]const u8{path}, 0);
defer alloc.free(sentinel_path);
const res = std.os.linux.mknod(sentinel_path, mode, dev);
if (res != 0 and options.verbose)
options.verbose_writer.?.print("mknod failed with code: {}\n", .{res}) catch {};
try que.putOne(io, .{
.file = try Io.Dir.cwd().openFile(io, path, .{}),
.inode = self,
});
}
fn applyMetadataLoop(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, super: Archive.Superblock, que: *Io.Queue(FileRet), options: ExtractionOptions) !void { fn applyMetadataLoop(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, super: Archive.Superblock, que: *Io.Queue(FileRet), options: ExtractionOptions) !void {
var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count); var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
+3 -3
View File
@@ -12,7 +12,7 @@ const SharedCache = @import("shared_cache.zig");
const DataExtractor = @This(); const DataExtractor = @This();
fil: OffsetFile, fil: OffsetFile,
cache: *SharedCache, // cache: *SharedCache,
decomp: *const Decompressor, decomp: *const Decompressor,
block_size: u32, block_size: u32,
@@ -23,10 +23,10 @@ blocks: []BlockSize,
frag_offset: u32 = 0, frag_offset: u32 = 0,
frag_entry: ?FragEntry = null, frag_entry: ?FragEntry = null,
pub fn init(fil: OffsetFile, cache: *SharedCache, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) DataExtractor { pub fn init(fil: OffsetFile, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) DataExtractor {
return .{ return .{
.fil = fil, .fil = fil,
.cache = cache, // .cache = cache,
.decomp = decomp, .decomp = decomp,
.block_size = block_size, .block_size = block_size,
+4 -7
View File
@@ -18,7 +18,7 @@ alloc: std.mem.Allocator,
fil: OffsetFile, fil: OffsetFile,
io: Io, io: Io,
cache: *SharedCache, // cache: *SharedCache,
decomp: *const Decompressor, decomp: *const Decompressor,
block_size: u32, block_size: u32,
@@ -34,7 +34,7 @@ sparse_block: bool = false,
interface: Io.Reader, interface: Io.Reader,
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, cache: *SharedCache, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) !DataReader { pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) !DataReader {
return .{ return .{
.alloc = alloc, .alloc = alloc,
@@ -48,7 +48,7 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, cache: *SharedCac
.blocks = blocks, .blocks = blocks,
.interface = .{ .interface = .{
.buffer = try cache.getCache(io), .buffer = try alloc.alloc(u8, block_size),
.seek = 0, .seek = 0,
.end = 0, .end = 0,
.vtable = &.{ .vtable = &.{
@@ -60,10 +60,7 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, cache: *SharedCac
}; };
} }
pub fn deinit(self: *DataReader) void { pub fn deinit(self: *DataReader) void {
if (self.interface.buffer.len > 0) { self.alloc.free(self.interface.buffer);
const buf_nod: *SharedCache.BufferNode = @fieldParentPtr("cache", self.interface.buffer);
self.cache.returnCache(buf_nod);
}
} }
pub fn addFrag(self: *DataReader, frag_offset: u32, entry: FragEntry) void { pub fn addFrag(self: *DataReader, frag_offset: u32, entry: FragEntry) void {
self.frag_offset = frag_offset; self.frag_offset = frag_offset;