Re-added tests
Fixed compile errors from tests
This commit is contained in:
+1
-1
@@ -67,7 +67,7 @@ pub fn extract(self: Archive, alloc: std.mem.Allocator, io: Io, location: []cons
|
||||
);
|
||||
defer root_inode.deinit(alloc);
|
||||
|
||||
root_inode.extract(alloc, io, self.super, self.map.memory, self.decomp, location, options);
|
||||
return root_inode.extract(alloc, io, self.super, self.map.memory, self.decomp, location, options);
|
||||
}
|
||||
|
||||
// Superblock
|
||||
|
||||
+10
-4
@@ -7,9 +7,9 @@ const Error = @import("decomp.zig").Error;
|
||||
pub fn zlib(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||
var stream: c.z_stream = .{
|
||||
.next_in = in.ptr,
|
||||
.avail_in = in.len,
|
||||
.avail_in = @truncate(in.len),
|
||||
.next_out = out.ptr,
|
||||
.avail_out = out.len,
|
||||
.avail_out = @truncate(out.len),
|
||||
};
|
||||
var res = c.inflateInit(&stream);
|
||||
if (res != c.Z_OK)
|
||||
@@ -30,7 +30,7 @@ pub fn lzma(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||
if (res != c.LZMA_OK)
|
||||
return Error.DecompressionFailed;
|
||||
while (res == c.LZMA_OK)
|
||||
res = c.lzma_code(&stream);
|
||||
res = c.lzma_code(&stream, c.LZMA_RUN);
|
||||
if (res != c.LZMA_STREAM_END)
|
||||
return Error.DecompressionFailed;
|
||||
return stream.total_out;
|
||||
@@ -40,9 +40,15 @@ pub fn lz4(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||
in.ptr,
|
||||
out.ptr,
|
||||
@intCast(in.len),
|
||||
out.len,
|
||||
@intCast(out.len),
|
||||
);
|
||||
if (res < 0)
|
||||
return Error.DecompressionFailed;
|
||||
return @abs(res);
|
||||
}
|
||||
pub fn zstd(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
||||
if (c.ZSTD_isError(res) != 0)
|
||||
return Error.DecompressionFailed;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ size: u64,
|
||||
frag_data: ?[]u8 = null,
|
||||
frag_offset: u32 = 0,
|
||||
|
||||
cache: ?Cache = null,
|
||||
cache: ?*Cache = null,
|
||||
|
||||
pub fn init(data: []u8, decomp: Decomp.Fn, block_size: u32, blocks: []DataBlock, start: u64, size: u64) Extractor {
|
||||
return .{
|
||||
@@ -37,7 +37,7 @@ pub fn addFrag(self: *Extractor, frag_data: []u8, frag_offset: u32) void {
|
||||
self.frag_data = frag_data;
|
||||
self.frag_offset = frag_offset;
|
||||
}
|
||||
pub fn addCache(self: *Extractor, cache: Cache) void {
|
||||
pub fn addCache(self: *Extractor, cache: *Cache) void {
|
||||
self.cache = cache;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ pub fn extractAsync(self: Extractor, alloc: std.mem.Allocator, io: Io, file: Io.
|
||||
|
||||
var read_offset: u64 = self.start;
|
||||
for (0.., self.blocks) |i, block| {
|
||||
group.async(io, blockThread, .{ self, alloc, map.memory, read_offset, i, &err });
|
||||
group.async(io, blockThread, .{ self, alloc, io, map.memory, read_offset, @truncate(i), &err });
|
||||
read_offset += block.size;
|
||||
}
|
||||
if (self.frag_data != null)
|
||||
@@ -66,12 +66,12 @@ pub fn extractAsync(self: Extractor, alloc: std.mem.Allocator, io: Io, file: Io.
|
||||
try group.await(io);
|
||||
|
||||
if (err != null)
|
||||
return err;
|
||||
return err.?;
|
||||
|
||||
try map.write(io);
|
||||
}
|
||||
|
||||
fn blockThread(self: Extractor, alloc: std.mem.Allocator, map_data: []u8, read_offset: u64, block_idx: u32, err: *?Error) error{Canceled}!void {
|
||||
fn blockThread(self: Extractor, alloc: std.mem.Allocator, io: Io, map_data: []u8, read_offset: u64, block_idx: u32, err: *?Error) error{Canceled}!void {
|
||||
const size = if (self.frag_data == null and block_idx == (self.size - 1 / self.block_size))
|
||||
self.size % self.block_size
|
||||
else
|
||||
@@ -93,7 +93,7 @@ fn blockThread(self: Extractor, alloc: std.mem.Allocator, map_data: []u8, read_o
|
||||
}
|
||||
|
||||
if (self.cache != null) {
|
||||
const decomp_block = self.cache.?.get(read_offset, block.size) catch |inner_err| {
|
||||
const decomp_block = self.cache.?.get(io, read_offset, block.size) catch |inner_err| {
|
||||
switch (inner_err) {
|
||||
error.Canceled => return error.Canceled,
|
||||
else => |e| err.* = e,
|
||||
|
||||
+8
-6
@@ -24,7 +24,8 @@ sparse_block: bool = false,
|
||||
frag_data: ?[]u8 = null,
|
||||
frag_offset: u32 = 0,
|
||||
|
||||
cache: ?Cache = null,
|
||||
io: ?Io = null,
|
||||
cache: ?*Cache = null,
|
||||
|
||||
block: [1024 * 1024]u8 = undefined,
|
||||
|
||||
@@ -58,7 +59,8 @@ pub fn addFrag(self: *Reader, frag_data: []u8, frag_offset: u32) void {
|
||||
self.frag_data = frag_data;
|
||||
self.frag_offset = frag_offset;
|
||||
}
|
||||
pub fn addCache(self: *Reader, cache: Cache) void {
|
||||
pub fn addCache(self: *Reader, io: Io, cache: *Cache) void {
|
||||
self.io = io;
|
||||
self.cache = cache;
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ fn advance(self: *Reader) Io.Reader.Error!void {
|
||||
|
||||
if (block.size == 0) {
|
||||
self.sparse_block = true;
|
||||
self.end = size;
|
||||
self.interface.end = size;
|
||||
return;
|
||||
} else {
|
||||
self.sparse_block = false;
|
||||
@@ -109,7 +111,7 @@ fn advance(self: *Reader) Io.Reader.Error!void {
|
||||
self.interface.buffer = self.block[0..size];
|
||||
self.interface.end = size;
|
||||
} else {
|
||||
self.interface.buffer = self.cache.?.get(self.io, self.offset, block.size) catch return error.ReadFailed;
|
||||
self.interface.buffer = self.cache.?.get(self.io.?, self.offset, block.size) catch return error.ReadFailed;
|
||||
self.interface.end = self.interface.buffer.len;
|
||||
}
|
||||
}
|
||||
@@ -119,7 +121,7 @@ fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!u
|
||||
if (r.seek >= r.end)
|
||||
try self.advance();
|
||||
|
||||
if (limit == .nothing) return;
|
||||
if (limit == .nothing) return 0;
|
||||
|
||||
const to_write = @min(@intFromEnum(limit), r.end - r.seek);
|
||||
|
||||
@@ -136,7 +138,7 @@ fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize {
|
||||
const self: *Reader = @fieldParentPtr("interface", r);
|
||||
try self.advance();
|
||||
}
|
||||
if (limit == .nothing) return;
|
||||
if (limit == .nothing) return 0;
|
||||
|
||||
const to_discard = @min(@intFromEnum(limit), r.end - r.seek);
|
||||
|
||||
|
||||
+3
-3
@@ -6,10 +6,10 @@ const zig = @import("zig_decomp.zig");
|
||||
|
||||
pub fn getFn(e: Enum) !Fn {
|
||||
return switch (e) {
|
||||
.gzip => if (build.use_zig_decomp) zig.gzip else c.gzip,
|
||||
.gzip => if (build.use_zig_decomp) zig.zlib else c.zlib,
|
||||
.lzma => if (build.use_zig_decomp) zig.lzma else c.lzma,
|
||||
.lzo => if (build.use_zig_decomp or !build.allow_lzo) error.LzoUnsupported else c.lzo,
|
||||
.xz => if (build.use_zig_decomp) zig.xz else c.xz,
|
||||
.xz => if (build.use_zig_decomp) zig.xz else c.lzma,
|
||||
.lz4 => if (build.use_zig_decomp) error.Lz4Unsupported else c.lz4,
|
||||
.zstd => if (build.use_zig_decomp) zig.zstd else c.zstd,
|
||||
};
|
||||
@@ -17,7 +17,7 @@ pub fn getFn(e: Enum) !Fn {
|
||||
|
||||
// Types
|
||||
|
||||
pub const Fn = *fn (std.mem.Allocator, in: []u8, out: []u8) Error!usize;
|
||||
pub const Fn = *const fn (std.mem.Allocator, in: []u8, out: []u8) Error!usize;
|
||||
|
||||
pub const Enum = enum(u16) {
|
||||
gzip = 1,
|
||||
|
||||
+5
-5
@@ -15,7 +15,7 @@ pub fn init(alloc: std.mem.Allocator, rdr: *Reader, size: u64) !Directory {
|
||||
|
||||
var read: u64 = 3;
|
||||
|
||||
var out: std.ArrayList(Entry) = .initCapacity(alloc, 50);
|
||||
var out: std.ArrayList(Entry) = try .initCapacity(alloc, 50);
|
||||
errdefer {
|
||||
for (out.items) |entry|
|
||||
entry.deinit(alloc);
|
||||
@@ -29,13 +29,13 @@ pub fn init(alloc: std.mem.Allocator, rdr: *Reader, size: u64) !Directory {
|
||||
try out.ensureUnusedCapacity(alloc, hdr.count + 1);
|
||||
|
||||
for (0..hdr.count + 1) |_| {
|
||||
try rdr.readSliceEndian(Entry, @ptrCast(&raw), .little);
|
||||
try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little);
|
||||
|
||||
const name = try alloc.alloc(u8, raw.name_size + 1);
|
||||
|
||||
try rdr.readSliceEndian(u8, name, .little);
|
||||
|
||||
const entry = out.addOneAssumeCapacity(alloc);
|
||||
const entry = out.addOneAssumeCapacity();
|
||||
|
||||
entry.* = .{
|
||||
.name = name,
|
||||
@@ -48,7 +48,7 @@ pub fn init(alloc: std.mem.Allocator, rdr: *Reader, size: u64) !Directory {
|
||||
}
|
||||
}
|
||||
|
||||
return out.toOwnedSlice(alloc);
|
||||
return .{ .entries = try out.toOwnedSlice(alloc) };
|
||||
}
|
||||
pub fn deinit(self: Directory, alloc: std.mem.Allocator) void {
|
||||
for (self.entries) |entry|
|
||||
@@ -64,7 +64,7 @@ pub const Entry = struct {
|
||||
name: []const u8,
|
||||
block_start: u32,
|
||||
block_offset: u16,
|
||||
type: Inode.type,
|
||||
type: Inode.Type,
|
||||
|
||||
pub fn deinit(self: Entry, alloc: std.mem.Allocator) void {
|
||||
alloc.free(self.name);
|
||||
|
||||
+66
-27
@@ -22,7 +22,7 @@ pub fn extract(
|
||||
ext_loc: []const u8,
|
||||
options: ExtractionOptions,
|
||||
) !void {
|
||||
const path = std.mem.trim(ext_loc, "/");
|
||||
const path = std.mem.trim(u8, ext_loc, "/");
|
||||
|
||||
var id_table: Lookup.Table(u16) = .init(alloc, data, decomp, super.id_start, super.id_count);
|
||||
defer id_table.deinit();
|
||||
@@ -42,7 +42,7 @@ pub fn extract(
|
||||
else => {},
|
||||
};
|
||||
|
||||
var loop = io.async(io, finishLoop, .{ alloc, io, &sel, &id_table, &xattr_table, inode.hdr.num, options });
|
||||
var loop = io.async(finishLoop, .{ alloc, io, &sel, &id_table, &xattr_table, inode.hdr.num, options });
|
||||
|
||||
var cache: Cache = .init(alloc, data, decomp);
|
||||
defer cache.deinit();
|
||||
@@ -51,22 +51,22 @@ pub fn extract(
|
||||
defer frag_table.deinit();
|
||||
|
||||
switch (inode.hdr.type) {
|
||||
.file, .ext_file => try sel.async(
|
||||
.file, .ext_file => sel.async(
|
||||
.path,
|
||||
extractFile,
|
||||
.{ alloc, io, data, decomp, super.block_size, &cache, &frag_table, inode, path, true },
|
||||
),
|
||||
.dir, .ext_dir => try sel.async(
|
||||
.dir, .ext_dir => sel.async(
|
||||
.path,
|
||||
extractDir,
|
||||
.{ alloc, io, super, data, decomp, &sel, &cache, &frag_table, inode, path, true },
|
||||
),
|
||||
.symlink, .ext_symlink => try sel.async(
|
||||
.symlink, .ext_symlink => sel.async(
|
||||
.void,
|
||||
extractSymlink,
|
||||
.{ alloc, io, inode, path, true },
|
||||
),
|
||||
else => try sel.async(
|
||||
else => sel.async(
|
||||
.path,
|
||||
extractNod,
|
||||
.{ alloc, inode, path, true },
|
||||
@@ -76,7 +76,7 @@ pub fn extract(
|
||||
try loop.await(io);
|
||||
}
|
||||
|
||||
fn dirOrder(a: PathReturn, b: PathReturn) std.math.Order {
|
||||
fn dirOrder(_: void, a: PathReturn, b: PathReturn) std.math.Order {
|
||||
return std.math.order(std.mem.count(u8, a.path, "/"), std.mem.count(u8, b.path, "/"));
|
||||
}
|
||||
fn finishLoop(alloc: std.mem.Allocator, io: Io, sel: *Io.Select(ReturnUnion), id_table: *Lookup.Table(u16), xattr_table: *XattrTable, start_num: u32, options: ExtractionOptions) !void {
|
||||
@@ -88,12 +88,19 @@ fn finishLoop(alloc: std.mem.Allocator, io: Io, sel: *Io.Select(ReturnUnion), id
|
||||
while (true) {
|
||||
const value: ReturnUnion = try sel.await();
|
||||
|
||||
switch (value) {
|
||||
.void => continue,
|
||||
else => {},
|
||||
}
|
||||
const path_ret = switch (value) {
|
||||
.void => {
|
||||
_ = sel.group.token.load(.unordered) orelse break;
|
||||
continue;
|
||||
},
|
||||
.path => |p| try p,
|
||||
};
|
||||
|
||||
const path_ret: PathReturn = value.path;
|
||||
if (options.ignore_permissions and (options.ignore_xattr or path_ret.xattr_idx == null)) {
|
||||
if (path_ret.hdr.num != start_num)
|
||||
alloc.free(path_ret.path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (path_ret.hdr.type == .dir or path_ret.hdr.type == .ext_dir) {
|
||||
dirs.push(alloc, path_ret) catch |err| {
|
||||
@@ -106,17 +113,43 @@ fn finishLoop(alloc: std.mem.Allocator, io: Io, sel: *Io.Select(ReturnUnion), id
|
||||
defer if (path_ret.hdr.num != start_num)
|
||||
alloc.free(path_ret.path);
|
||||
|
||||
if (options.ignore_permissions and (options.ignore_xattr or path_ret.xattr_idx == null)) continue;
|
||||
|
||||
var file = try Io.Dir.cwd().openFile(io, path_ret.path, .{});
|
||||
defer file.close();
|
||||
defer file.close(io);
|
||||
|
||||
if (!options.ignore_xattr and path_ret.xattr_idx != null) {
|
||||
const xattr = try xattr_table.get(alloc, io, path_ret.xattr_idx.?);
|
||||
defer xattr.deinit(alloc);
|
||||
|
||||
for (xattr.kvs) |kv| {
|
||||
const res = std.os.linux.fsetxattr(file.handle, kv.key, kv.value, kv.value.len, 0);
|
||||
const res = std.os.linux.fsetxattr(file.handle, kv.key, kv.value.ptr, kv.value.len, 0);
|
||||
if (res != 0)
|
||||
return error.SetXattrError;
|
||||
}
|
||||
}
|
||||
if (!options.ignore_permissions) {
|
||||
try file.setTimestamps(io, .{
|
||||
.modify_timestamp = .init(Io.Timestamp.fromNanoseconds(@as(i96, @intCast(path_ret.hdr.mod_time)) * std.time.ns_per_s)),
|
||||
});
|
||||
try file.setPermissions(io, @enumFromInt(path_ret.hdr.permissions));
|
||||
try file.setOwner(io, try id_table.get(io, path_ret.hdr.uid_idx), try id_table.get(io, path_ret.hdr.gid_idx));
|
||||
}
|
||||
|
||||
_ = sel.group.token.load(.unordered) orelse break;
|
||||
}
|
||||
|
||||
while (dirs.popMax()) |path_ret| {
|
||||
if (path_ret.hdr.num != start_num)
|
||||
alloc.free(path_ret.path);
|
||||
|
||||
var file = try Io.Dir.cwd().openFile(io, path_ret.path, .{});
|
||||
defer file.close(io);
|
||||
|
||||
if (!options.ignore_xattr and path_ret.xattr_idx != null) {
|
||||
const xattr = try xattr_table.get(alloc, io, path_ret.xattr_idx.?);
|
||||
defer xattr.deinit(alloc);
|
||||
|
||||
for (xattr.kvs) |kv| {
|
||||
const res = std.os.linux.fsetxattr(file.handle, kv.key, kv.value.ptr, kv.value.len, 0);
|
||||
if (res != 0)
|
||||
return error.SetXattrError;
|
||||
}
|
||||
@@ -159,7 +192,7 @@ fn extractDir(
|
||||
var meta: MetadataReader = .init(alloc, data, decomp, d.block_start);
|
||||
try meta.interface.discardAll(d.block_offset);
|
||||
|
||||
break :blk Directory.init(alloc, &meta.interface, d.size);
|
||||
break :blk try Directory.init(alloc, &meta.interface, d.size);
|
||||
},
|
||||
.ext_dir => |d| blk: {
|
||||
if (d.xattr_idx != 0xFFFFFFFF) ret.xattr_idx = d.xattr_idx;
|
||||
@@ -167,7 +200,7 @@ fn extractDir(
|
||||
var meta: MetadataReader = .init(alloc, data, decomp, d.block_start);
|
||||
try meta.interface.discardAll(d.block_offset);
|
||||
|
||||
break :blk Directory.init(alloc, &meta.interface, d.size);
|
||||
break :blk try Directory.init(alloc, &meta.interface, d.size);
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
@@ -176,7 +209,7 @@ fn extractDir(
|
||||
for (dir.entries) |entry| {
|
||||
var new_inode: Inode = try .initEntry(alloc, data, decomp, super.inode_start, super.block_size, entry);
|
||||
|
||||
const new_path = std.mem.concat(alloc, &.{ path, "/", entry.name }) catch |err| {
|
||||
const new_path = std.mem.concat(alloc, u8, &.{ path, "/", entry.name }) catch |err| {
|
||||
new_inode.deinit(alloc);
|
||||
return err;
|
||||
};
|
||||
@@ -184,10 +217,12 @@ fn extractDir(
|
||||
switch (entry.type) {
|
||||
.dir => sel.async(.path, extractDir, .{ alloc, io, super, data, decomp, sel, cache, frag_table, new_inode, new_path, false }),
|
||||
.file => sel.async(.path, extractFile, .{ alloc, io, data, decomp, super.block_size, cache, frag_table, new_inode, new_path, false }),
|
||||
.symlink => sel.async(.void, extractSymlink, .{ alloc, io, data, decomp, new_inode, new_path, false }),
|
||||
else => sel.async(.path, extractNod, .{ alloc, data, decomp, new_inode, new_path, false }),
|
||||
.symlink => sel.async(.void, extractSymlink, .{ alloc, io, new_inode, new_path, false }),
|
||||
else => sel.async(.path, extractNod, .{ alloc, new_inode, new_path, false }),
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
fn extractFile(
|
||||
alloc: std.mem.Allocator,
|
||||
@@ -220,10 +255,12 @@ fn extractFile(
|
||||
|
||||
const entry: Lookup.FragEntry = try frag_table.get(io, f.frag_idx);
|
||||
if (entry.size.uncompressed) {
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size]);
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size], f.frag_offset);
|
||||
} else {
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size));
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size.size), f.frag_offset);
|
||||
}
|
||||
|
||||
break :blk rdr;
|
||||
},
|
||||
.ext_file => |f| blk: {
|
||||
if (f.xattr_idx != 0xFFFFFFFF) ret.xattr_idx = f.xattr_idx;
|
||||
@@ -235,10 +272,12 @@ fn extractFile(
|
||||
|
||||
const entry: Lookup.FragEntry = try frag_table.get(io, f.frag_idx);
|
||||
if (entry.size.uncompressed) {
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size]);
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size], f.frag_offset);
|
||||
} else {
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size));
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size.size), f.frag_offset);
|
||||
}
|
||||
|
||||
break :blk rdr;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
@@ -329,11 +368,11 @@ fn extractNod(alloc: std.mem.Allocator, inode: Inode, path: []const u8, origin:
|
||||
|
||||
const ReturnUnion = union(enum) {
|
||||
path: Error!PathReturn,
|
||||
dir: Error!PathReturn,
|
||||
void: Error!void,
|
||||
};
|
||||
|
||||
const Error = error{} || Decomp.Error || Directory.Error || DataExtractor.Error;
|
||||
const Error = error{MknodError} || Decomp.Error || Directory.Error || DataExtractor.Error || Io.Dir.CreateDirPathError ||
|
||||
Io.Dir.SymLinkError || Io.File.Atomic.LinkError;
|
||||
|
||||
const PathReturn = struct {
|
||||
hdr: Inode.Header,
|
||||
|
||||
+15
-11
@@ -22,7 +22,7 @@ pub fn extract(
|
||||
ext_loc: []const u8,
|
||||
options: ExtractionOptions,
|
||||
) !void {
|
||||
const path = std.mem.trim(ext_loc, "/");
|
||||
const path = std.mem.trim(u8, ext_loc, "/");
|
||||
|
||||
var cache: Cache = .init(alloc, data, decomp);
|
||||
defer cache.deinit();
|
||||
@@ -84,7 +84,7 @@ pub fn extractReal(
|
||||
var meta: MetadaReader = .init(alloc, data, decomp, d.block_start);
|
||||
try meta.interface.discardAll(d.block_offset);
|
||||
|
||||
break :blk Directory.init(alloc, &meta.interface, d.size);
|
||||
break :blk try Directory.init(alloc, &meta.interface, d.size);
|
||||
},
|
||||
.ext_dir => |d| blk: {
|
||||
if (d.xattr_idx != 0xFFFFFFFF) xattr_idx = d.xattr_idx;
|
||||
@@ -92,7 +92,7 @@ pub fn extractReal(
|
||||
var meta: MetadaReader = .init(alloc, data, decomp, d.block_start);
|
||||
try meta.interface.discardAll(d.block_offset);
|
||||
|
||||
break :blk Directory.init(alloc, &meta.interface, d.size);
|
||||
break :blk try Directory.init(alloc, &meta.interface, d.size);
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
@@ -101,7 +101,7 @@ pub fn extractReal(
|
||||
for (dir.entries) |entry| {
|
||||
var new_inode: Inode = try .initEntry(alloc, data, decomp, super.inode_start, super.block_size, entry);
|
||||
|
||||
const new_path = std.mem.concat(alloc, &.{ path, "/", entry.name }) catch |err| {
|
||||
const new_path = std.mem.concat(alloc, u8, &.{ path, "/", entry.name }) catch |err| {
|
||||
new_inode.deinit(alloc);
|
||||
return err;
|
||||
};
|
||||
@@ -113,31 +113,35 @@ pub fn extractReal(
|
||||
var rdr: DataReader = switch (inode.data) {
|
||||
.file => |f| blk: {
|
||||
var rdr: DataReader = .init(alloc, data, decomp, super.block_size, f.blocks, f.size, f.block_start);
|
||||
rdr.addCache(cache);
|
||||
rdr.addCache(io, cache);
|
||||
|
||||
if (f.frag_idx == 0xFFFFFFFF) break :blk rdr;
|
||||
|
||||
const entry: Lookup.FragEntry = try frag_table.get(io, f.frag_idx);
|
||||
if (entry.size.uncompressed) {
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size]);
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size], f.frag_offset);
|
||||
} else {
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size));
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size.size), f.frag_offset);
|
||||
}
|
||||
|
||||
break :blk rdr;
|
||||
},
|
||||
.ext_file => |f| blk: {
|
||||
if (f.xattr_idx != 0xFFFFFFFF) xattr_idx = f.xattr_idx;
|
||||
|
||||
var rdr: DataReader = .init(alloc, data, decomp, super.block_size, f.blocks, f.size, f.block_start);
|
||||
rdr.addCache(cache);
|
||||
rdr.addCache(io, cache);
|
||||
|
||||
if (f.frag_idx == 0xFFFFFFFF) break :blk rdr;
|
||||
|
||||
const entry: Lookup.FragEntry = try frag_table.get(io, f.frag_idx);
|
||||
if (entry.size.uncompressed) {
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size]);
|
||||
rdr.addFrag(data[entry.block_start..][0..entry.size.size], f.frag_offset);
|
||||
} else {
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size));
|
||||
rdr.addFrag(try cache.get(io, entry.block_start, entry.size.size), f.frag_offset);
|
||||
}
|
||||
|
||||
break :blk rdr;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
@@ -221,7 +225,7 @@ pub fn extractReal(
|
||||
defer xattr.deinit(alloc);
|
||||
|
||||
for (xattr.kvs) |kv| {
|
||||
const res = std.os.linux.fsetxattr(fil.handle, kv.key, kv.value, kv.value.len, 0);
|
||||
const res = std.os.linux.fsetxattr(fil.handle, kv.key, kv.value.ptr, kv.value.len, 0);
|
||||
if (res != 0)
|
||||
return error.SetXattrError;
|
||||
}
|
||||
|
||||
+10
-10
@@ -40,7 +40,7 @@ pub fn initEntry(alloc: std.mem.Allocator, super: Superblock, data: []u8, decomp
|
||||
const inode: Inode = try .initEntry(alloc, data, decomp, super.inode_start, super.block_size, entry);
|
||||
errdefer inode.deinit(alloc);
|
||||
|
||||
const new_name = try alloc.dupe(entry.name);
|
||||
const new_name = try alloc.dupe(u8, entry.name);
|
||||
|
||||
return init(alloc, super, data, decomp, new_name, inode);
|
||||
}
|
||||
@@ -49,22 +49,22 @@ pub fn initRef(alloc: std.mem.Allocator, super: Superblock, data: []u8, decomp:
|
||||
const inode: Inode = try .initRef(alloc, data, decomp, super.inode_start, super.block_size, ref);
|
||||
errdefer inode.deinit(alloc);
|
||||
|
||||
const new_name = try alloc.dupe(name);
|
||||
const new_name = try alloc.dupe(u8, name);
|
||||
|
||||
return init(alloc, super, data, decomp, new_name, inode);
|
||||
}
|
||||
pub fn copy(self: File, alloc: std.mem.Allocator) !File {
|
||||
const inode = self.inode;
|
||||
var inode = self.inode;
|
||||
switch (inode.data) {
|
||||
.file => |*f| f.blocks = try alloc.dupe(self.inode.data.file.blocks),
|
||||
.ext_file => |*f| f.blocks = try alloc.dupe(self.inode.data.file.blocks),
|
||||
.symlink => |*s| s.target = try alloc.dupe(self.inode.data.symlink.target),
|
||||
.ext_symlink => |*s| s.target = try alloc.dupe(self.inode.data.symlink.target),
|
||||
.file => |*f| f.blocks = try alloc.dupe(Inode.DataBlock, self.inode.data.file.blocks),
|
||||
.ext_file => |*f| f.blocks = try alloc.dupe(Inode.DataBlock, self.inode.data.file.blocks),
|
||||
.symlink => |*s| s.target = try alloc.dupe(u8, self.inode.data.symlink.target),
|
||||
.ext_symlink => |*s| s.target = try alloc.dupe(u8, self.inode.data.symlink.target),
|
||||
else => {},
|
||||
}
|
||||
errdefer inode.deinit(alloc);
|
||||
|
||||
const new_name = try alloc.dupe(self.name);
|
||||
const new_name = try alloc.dupe(u8, self.name);
|
||||
|
||||
return init(alloc, self.super, self.data, self.decomp, new_name, inode);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File {
|
||||
try meta.interface.discardAll(d.block_offset);
|
||||
break :blk meta;
|
||||
},
|
||||
else => error.NotDirectory,
|
||||
else => return error.NotDirectory,
|
||||
};
|
||||
|
||||
const path = std.mem.trim(u8, filepath, "/");
|
||||
@@ -100,7 +100,7 @@ pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File {
|
||||
if (path.len == 0 or (path.len == 1 and path[0] == '.'))
|
||||
return self.copy(alloc);
|
||||
|
||||
const first_element: []u8 = std.mem.sliceTo(path, '/');
|
||||
const first_element: []const u8 = std.mem.sliceTo(path, '/');
|
||||
|
||||
const file: File = blk: {
|
||||
var directory: Directory = try .init(alloc, &meta.interface, size);
|
||||
|
||||
+5
-5
@@ -40,13 +40,13 @@ pub fn initRef(alloc: std.mem.Allocator, data: []u8, decomp: Decomp.Fn, inode_st
|
||||
var meta: MetadataReader = .init(alloc, data, decomp, inode_start + ref.block_start);
|
||||
try meta.interface.discardAll(ref.block_offset);
|
||||
|
||||
return .init(alloc, &meta.interface, block_size);
|
||||
return .init(alloc, block_size, &meta.interface);
|
||||
}
|
||||
pub fn initEntry(alloc: std.mem.Allocator, data: []u8, decomp: Decomp.Fn, inode_start: u64, block_size: u32, entry: Directory.Entry) !Inode {
|
||||
var meta: MetadataReader = .init(alloc, data, decomp, inode_start + entry.block_start);
|
||||
try meta.interface.discardAll(entry.block_offset);
|
||||
|
||||
return .init(alloc, &meta.interface, block_size);
|
||||
return .init(alloc, block_size, &meta.interface);
|
||||
}
|
||||
pub fn deinit(self: Inode, alloc: std.mem.Allocator) void {
|
||||
switch (self.data) {
|
||||
@@ -64,7 +64,7 @@ pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, super: Superblock,
|
||||
|
||||
// Types
|
||||
|
||||
pub const Ref = packed struct {
|
||||
pub const Ref = packed struct(u64) {
|
||||
block_offset: u16,
|
||||
block_start: u32,
|
||||
_: u16,
|
||||
@@ -191,7 +191,7 @@ pub const ExtFile = struct {
|
||||
var data: [40]u8 = undefined;
|
||||
try rdr.readSliceAll(&data);
|
||||
|
||||
const frag_idx = std.mem.readInt(u32, data[28..], .little);
|
||||
const frag_idx = std.mem.readInt(u32, data[28..32], .little);
|
||||
const size = std.mem.readInt(u64, data[8..16], .little);
|
||||
|
||||
var blocks_num = size / block_size;
|
||||
@@ -238,7 +238,7 @@ pub const ExtSymlink = struct {
|
||||
xattr_idx: u32,
|
||||
|
||||
fn init(alloc: std.mem.Allocator, rdr: *Reader) !ExtSymlink {
|
||||
const sym: Symlink = .init(alloc, rdr);
|
||||
const sym: Symlink = try .init(alloc, rdr);
|
||||
|
||||
var xattr_idx: u32 = undefined;
|
||||
try rdr.readSliceEndian(u32, @ptrCast(&xattr_idx), .little);
|
||||
|
||||
+24
-9
@@ -4,7 +4,7 @@ const Io = std.Io;
|
||||
const DataBlock = @import("inode.zig").DataBlock;
|
||||
const Decomp = @import("decomp.zig");
|
||||
const MetadataReader = @import("meta_rdr.zig");
|
||||
const ProtectedMap = @import("util/protected_map.zig");
|
||||
const ProtectedMap = @import("util/protected_map.zig").ProtectedMap;
|
||||
|
||||
pub fn Table(comptime T: anytype) type {
|
||||
return struct {
|
||||
@@ -21,7 +21,15 @@ pub fn Table(comptime T: anytype) type {
|
||||
table: ProtectedMap(u32, []T, getBlock),
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator, data: []u8, decomp: Decomp.Fn, table_start: u64, table_num: u32) Self {
|
||||
return .{ .data = data, .decomp = decomp, .table_start = table_start, .table_num = table_num, .table = .init(alloc) };
|
||||
return .{
|
||||
.data = data,
|
||||
.decomp = decomp,
|
||||
|
||||
.table_start = table_start,
|
||||
.table_num = table_num,
|
||||
|
||||
.table = .init(alloc),
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *Self) void {
|
||||
var iter = self.table.map.valueIterator();
|
||||
@@ -38,20 +46,27 @@ pub fn Table(comptime T: anytype) type {
|
||||
const block = idx / VALUES_PER_BLOCK;
|
||||
const block_idx = idx % VALUES_PER_BLOCK;
|
||||
|
||||
const values = try self.table.getOrPut(io, block, .{ self.*, block });
|
||||
const values = try self.table.getOrPut(io, block, .{
|
||||
self.table.alloc,
|
||||
self.data,
|
||||
self.decomp,
|
||||
self.table_start,
|
||||
self.table_num,
|
||||
block,
|
||||
});
|
||||
|
||||
return values[block_idx];
|
||||
return values.*[block_idx];
|
||||
}
|
||||
|
||||
pub fn getBlock(self: Self, block_idx: u32) ![]T {
|
||||
const offset: u64 = std.mem.readInt(u64, self.data[self.table_start + (block_idx * 8) ..][0..8], .little);
|
||||
pub fn getBlock(alloc: std.mem.Allocator, data: []u8, decomp: Decomp.Fn, table_start: u64, table_num: u32, block_idx: u32) ![]T {
|
||||
const offset: u64 = std.mem.readInt(u64, data[table_start + (block_idx * 8) ..][0..8], .little);
|
||||
|
||||
const block = try self.table.alloc(T, if (block_idx == (self.table_num - 1 / VALUES_PER_BLOCK))
|
||||
self.table_num % VALUES_PER_BLOCK
|
||||
const block = try alloc.alloc(T, if (block_idx == (table_num - 1 / VALUES_PER_BLOCK))
|
||||
table_num % VALUES_PER_BLOCK
|
||||
else
|
||||
VALUES_PER_BLOCK);
|
||||
|
||||
var meta: MetadataReader = .init(self.table.alloc, self.data, self.decomp, offset);
|
||||
var meta: MetadataReader = .init(alloc, data, decomp, offset);
|
||||
try meta.interface.readSliceEndian(T, block, .little);
|
||||
|
||||
return block;
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ fn advance(self: *MetadataReader) Reader.Error!void {
|
||||
self.interface.seek = 0;
|
||||
errdefer self.interface.end = 0;
|
||||
|
||||
const hdr: Header = @intCast(std.mem.readInt(u16, self.data[self.cur_offset..][0..2], .little));
|
||||
const hdr: Header = @bitCast(std.mem.readInt(u16, self.data[self.cur_offset..][0..2], .little));
|
||||
defer self.cur_offset += hdr.size;
|
||||
|
||||
const block = self.data[self.cur_offset + 2 ..][0..hdr.size];
|
||||
|
||||
+81
-4
@@ -6,16 +6,93 @@ const Archive = @import("archive.zig");
|
||||
|
||||
const TestArchive = "testing/LinuxPATest.sfs";
|
||||
|
||||
test "Basics" {}
|
||||
test "Basics" {
|
||||
const io = testing.io;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var archive_file = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||
defer archive_file.close(io);
|
||||
|
||||
var archive: Archive = try .init(io, archive_file, 0);
|
||||
defer archive.deinit(io);
|
||||
|
||||
try testing.expectEqualDeep(archive.super, LinuxPATestCorrectSuperblock);
|
||||
|
||||
var root = try archive.root(alloc);
|
||||
defer root.deinit();
|
||||
}
|
||||
|
||||
const TestFile = "Start.exe";
|
||||
const TestFileExtractLocation = "testing/Start.exe";
|
||||
|
||||
test "ExtractSingleFile" {}
|
||||
test "ExtractSingleFile" {
|
||||
const io = testing.io;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
const TestFullExtractLocation = "testing/TestExtract";
|
||||
Io.Dir.cwd().deleteFile(io, TestFileExtractLocation) catch {};
|
||||
|
||||
test "ExtractCompleteArchive" {}
|
||||
var archive_file = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||
defer archive_file.close(io);
|
||||
|
||||
var archive: Archive = try .init(io, archive_file, 0);
|
||||
defer archive.deinit(io);
|
||||
|
||||
var start_exe = try archive.open(alloc, TestFile);
|
||||
defer start_exe.deinit();
|
||||
|
||||
try start_exe.extract(alloc, io, TestFileExtractLocation, .default);
|
||||
}
|
||||
|
||||
const TestFullExtractLocationMT = "testing/TestExtractMT";
|
||||
|
||||
test "ExtractCompleteArchiveMultiThreaded" {
|
||||
const io = testing.io;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
Io.Dir.cwd().deleteFile(io, TestFullExtractLocationMT) catch {};
|
||||
|
||||
var archive_file = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||
defer archive_file.close(io);
|
||||
|
||||
var archive: Archive = try .init(io, archive_file, 0);
|
||||
defer archive.deinit(io);
|
||||
|
||||
try archive.extract(alloc, io, TestFullExtractLocationMT, .default);
|
||||
}
|
||||
|
||||
const TestFullExtractLocationSTOption = "testing/TestExtractSTOption";
|
||||
|
||||
test "ExtractCompleteArchiveSingleThreadedOption" {
|
||||
const io = testing.io;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
Io.Dir.cwd().deleteFile(io, TestFullExtractLocationSTOption) catch {};
|
||||
|
||||
var archive_file = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||
defer archive_file.close(io);
|
||||
|
||||
var archive: Archive = try .init(io, archive_file, 0);
|
||||
defer archive.deinit(io);
|
||||
|
||||
try archive.extract(alloc, io, TestFullExtractLocationSTOption, .single_threaded_default);
|
||||
}
|
||||
|
||||
const TestFullExtractLocationSTIo = "testing/TestExtractSTIo";
|
||||
|
||||
test "ExtractCompleteArchiveSingleThreadedIo" {
|
||||
const io = Io.Threaded.global_single_threaded.io();
|
||||
const alloc = testing.allocator;
|
||||
|
||||
Io.Dir.cwd().deleteFile(io, TestFullExtractLocationSTIo) catch {};
|
||||
|
||||
var archive_file = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||
defer archive_file.close(io);
|
||||
|
||||
var archive: Archive = try .init(io, archive_file, 0);
|
||||
defer archive.deinit(io);
|
||||
|
||||
try archive.extract(alloc, io, TestFullExtractLocationSTIo, .default);
|
||||
}
|
||||
|
||||
const LinuxPATestCorrectSuperblock: Archive.Superblock = .{
|
||||
.magic = std.mem.readInt(u32, "hsqs", .little),
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ pub fn deinit(self: *Cache) void {
|
||||
}
|
||||
|
||||
pub fn get(self: *Cache, io: Io, offset: u64, compressed_size: u32) Error![]u8 {
|
||||
const res: CachedBlock = try self.cache.getOrPut(io, offset, .{ self.alloc, self.data, self.decomp, offset, compressed_size });
|
||||
const res: *CachedBlock = try self.cache.getOrPut(io, offset, .{ self.alloc, self.data, self.decomp, offset, compressed_size });
|
||||
return res.block[0..res.size];
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,14 @@ const std = @import("std");
|
||||
const Io = std.Io;
|
||||
|
||||
pub fn ProtectedMap(comptime K: anytype, comptime T: anytype, comptime create_fn: anytype) type {
|
||||
std.debug.assert(std.meta.activeTag(@typeInfo(create_fn)) == .@"fn");
|
||||
const fn_info = @typeInfo(@TypeOf(create_fn));
|
||||
std.debug.assert(std.meta.activeTag(fn_info) == .@"fn");
|
||||
|
||||
const ret_info = @typeInfo(create_fn).@"fn".return_type;
|
||||
const ret_info = fn_info.@"fn".return_type;
|
||||
|
||||
std.debug.assert(ret_info != null);
|
||||
std.debug.assert(ret_info == T or
|
||||
(std.meta.activeTag(@typeInfo(ret_info)) == .error_union and @typeInfo(ret_info).error_union.payload == T));
|
||||
(std.meta.activeTag(@typeInfo(ret_info.?)) == .error_union and @typeInfo(ret_info.?).error_union.payload == T));
|
||||
|
||||
return struct {
|
||||
const Map = @This();
|
||||
@@ -28,7 +30,7 @@ pub fn ProtectedMap(comptime K: anytype, comptime T: anytype, comptime create_fn
|
||||
self.map.deinit();
|
||||
}
|
||||
|
||||
pub fn getOrPut(self: *Map, io: Io, key: K, create_fn_args: std.meta.ArgsTuple(create_fn)) Error!*T {
|
||||
pub fn getOrPut(self: *Map, io: Io, key: K, create_fn_args: std.meta.ArgsTuple(@TypeOf(create_fn))) Error!*T {
|
||||
{
|
||||
try self.mut.lockShared(io);
|
||||
defer self.mut.unlockShared(io);
|
||||
@@ -36,9 +38,9 @@ pub fn ProtectedMap(comptime K: anytype, comptime T: anytype, comptime create_fn
|
||||
const value = self.map.getPtr(key);
|
||||
if (value != null) {
|
||||
if (!value.?.filled.isSet())
|
||||
value.?.filled.wait(io);
|
||||
if (value.?.err != null) return value.?.err != null;
|
||||
return value.?.value;
|
||||
try value.?.filled.wait(io);
|
||||
if (value.?.err != null) return value.?.err.?;
|
||||
return &value.?.value;
|
||||
}
|
||||
}
|
||||
try self.mut.lock(io);
|
||||
@@ -54,7 +56,7 @@ pub fn ProtectedMap(comptime K: anytype, comptime T: anytype, comptime create_fn
|
||||
res.value_ptr.* = .{};
|
||||
defer res.value_ptr.filled.set(io);
|
||||
|
||||
res.mut.unlock(io);
|
||||
self.mut.unlock(io);
|
||||
|
||||
self.mut.lockSharedUncancelable(io);
|
||||
defer self.mut.unlockShared(io);
|
||||
@@ -64,8 +66,11 @@ pub fn ProtectedMap(comptime K: anytype, comptime T: anytype, comptime create_fn
|
||||
} else {
|
||||
res.value_ptr.value = @call(.auto, create_fn, create_fn_args) catch |err| {
|
||||
res.value_ptr.err = err;
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
return &res.value_ptr.value;
|
||||
}
|
||||
|
||||
// Map Types
|
||||
@@ -73,7 +78,7 @@ pub fn ProtectedMap(comptime K: anytype, comptime T: anytype, comptime create_fn
|
||||
pub const Error = error{ Canceled, OutOfMemory } ||
|
||||
if (@TypeOf(CreateError) == void) error{} else CreateError;
|
||||
|
||||
const CreateError: type = switch (@typeInfo(@typeInfo(create_fn).@"fn".return_type)) {
|
||||
const CreateError: type = switch (@typeInfo(ret_info.?)) {
|
||||
.error_union => |e| e.error_set,
|
||||
else => void,
|
||||
};
|
||||
|
||||
+3
-1
@@ -28,7 +28,7 @@ pub fn deinit(self: *XattrTable) void {
|
||||
pub fn get(self: *XattrTable, alloc: std.mem.Allocator, io: Io, idx: u32) !Xattr {
|
||||
const entry: Entry = try self.table.get(io, idx);
|
||||
|
||||
const out: std.ArrayList(KeyValue) = try .initCapacity(alloc, entry.count);
|
||||
var out: std.ArrayList(KeyValue) = try .initCapacity(alloc, entry.count);
|
||||
errdefer {
|
||||
for (out.items) |kv|
|
||||
kv.deinit(alloc);
|
||||
@@ -75,6 +75,8 @@ pub fn get(self: *XattrTable, alloc: std.mem.Allocator, io: Io, idx: u32) !Xattr
|
||||
.value = value,
|
||||
};
|
||||
}
|
||||
|
||||
return .{ .kvs = try out.toOwnedSlice(alloc) };
|
||||
}
|
||||
|
||||
fn readValue(alloc: std.mem.Allocator, rdr: *Io.Reader) ![]u8 {
|
||||
|
||||
Reference in New Issue
Block a user