Compare commits
2
Commits
78dbaaed7e
...
e0b697dd0b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0b697dd0b | ||
|
|
9f2a4bcc1e |
+57
-7
@@ -1,11 +1,18 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
|
||||||
|
const File = @import("file.zig");
|
||||||
|
const Inode = @import("inode.zig");
|
||||||
|
const Util = @import("utils/util.zig");
|
||||||
|
const Decomp = @import("decomp.zig");
|
||||||
|
|
||||||
|
const Options = @import("options.zig");
|
||||||
|
|
||||||
const Archive = @This();
|
const Archive = @This();
|
||||||
|
|
||||||
map: Io.File.MemoryMap,
|
map: Io.File.MemoryMap,
|
||||||
|
|
||||||
super: Superblock,
|
super: Super,
|
||||||
|
|
||||||
pub fn open(io: Io, file: Io.File, offset: u64) !Archive {
|
pub fn open(io: Io, file: Io.File, offset: u64) !Archive {
|
||||||
var map = try file.createMemoryMap(io, .{
|
var map = try file.createMemoryMap(io, .{
|
||||||
@@ -14,8 +21,8 @@ pub fn open(io: Io, file: Io.File, offset: u64) !Archive {
|
|||||||
.protection = .{ .read = true },
|
.protection = .{ .read = true },
|
||||||
});
|
});
|
||||||
|
|
||||||
var super: Superblock = std.mem.bytesToValue(Superblock, map.memory[0..@sizeOf(Superblock)]);
|
var superblock = Util.readValue(Superblock, map.memory[0..@sizeOf(Superblock)]);
|
||||||
try super.check();
|
const super = try superblock.check();
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.map = map,
|
.map = map,
|
||||||
@@ -23,10 +30,26 @@ pub fn open(io: Io, file: Io.File, offset: u64) !Archive {
|
|||||||
.super = super,
|
.super = super,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn close(self: *Archive, io: Io) void {
|
||||||
|
self.map.destroy(io);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root(self: *Archive) !File {
|
||||||
|
_ = self;
|
||||||
|
return error.TODO;
|
||||||
|
}
|
||||||
|
pub fn extract(self: *Archive, alloc: std.mem.Allocator, io: Io, ext_loc: []const u8, options: Options) !void {
|
||||||
|
_ = self;
|
||||||
|
_ = alloc;
|
||||||
|
_ = io;
|
||||||
|
_ = ext_loc;
|
||||||
|
_ = options;
|
||||||
|
return error.TODO;
|
||||||
|
}
|
||||||
|
|
||||||
// Superblock
|
// Superblock
|
||||||
|
|
||||||
pub const Superblock = extern struct {
|
const Superblock = extern struct {
|
||||||
pub const MAGIC: u32 = 0x73717368;
|
pub const MAGIC: u32 = 0x73717368;
|
||||||
|
|
||||||
magic: u32,
|
magic: u32,
|
||||||
@@ -34,13 +57,13 @@ pub const Superblock = extern struct {
|
|||||||
mod_time: u32,
|
mod_time: u32,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
frag_count: u32,
|
frag_count: u32,
|
||||||
compression: u16,
|
compression: Decomp.Enum,
|
||||||
block_log: u16,
|
block_log: u16,
|
||||||
flags: u16, // TODO: break out into packed struct.
|
flags: u16, // TODO: break out into packed struct.
|
||||||
id_count: u16,
|
id_count: u16,
|
||||||
version_major: u16,
|
version_major: u16,
|
||||||
version_minor: u16,
|
version_minor: u16,
|
||||||
root_inode_ref: u64, // TODO: Change to inode reference packed struct.
|
root_inode_ref: Inode.Reference, // TODO: Change to inode reference packed struct.
|
||||||
size: u64,
|
size: u64,
|
||||||
id_table_start: u64,
|
id_table_start: u64,
|
||||||
xattr_table_start: u64,
|
xattr_table_start: u64,
|
||||||
@@ -49,12 +72,39 @@ pub const Superblock = extern struct {
|
|||||||
frag_table_start: u64,
|
frag_table_start: u64,
|
||||||
export_table_start: u64,
|
export_table_start: u64,
|
||||||
|
|
||||||
fn check(self: Superblock) !void {
|
fn check(self: Superblock) !Super {
|
||||||
if (self.magic != MAGIC)
|
if (self.magic != MAGIC)
|
||||||
return error.InvalidMagic;
|
return error.InvalidMagic;
|
||||||
if (self.version_major != 4 or self.version_minor != 0)
|
if (self.version_major != 4 or self.version_minor != 0)
|
||||||
return error.IncompatibleVersion;
|
return error.IncompatibleVersion;
|
||||||
if (std.math.log2(self.block_size) != self.block_log)
|
if (std.math.log2(self.block_size) != self.block_log)
|
||||||
return error.BadBlockLog;
|
return error.BadBlockLog;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.block_size = self.block_size,
|
||||||
|
.frag_count = self.frag_count,
|
||||||
|
.decomp_fn = try self.compression.func(),
|
||||||
|
.id_count = self.id_count,
|
||||||
|
.root_inode_ref = self.root_inode_ref,
|
||||||
|
.id_table_start = self.id_table_start,
|
||||||
|
.xattr_table_start = self.xattr_table_start,
|
||||||
|
.inode_table_start = self.inode_table_start,
|
||||||
|
.dir_table_start = self.dir_table_start,
|
||||||
|
.frag_table_start = self.frag_table_start,
|
||||||
|
.export_table_start = self.export_table_start,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
pub const Super = struct {
|
||||||
|
block_size: u32,
|
||||||
|
frag_count: u32,
|
||||||
|
decomp_fn: Decomp.Fn,
|
||||||
|
id_count: u16,
|
||||||
|
root_inode_ref: Inode.Reference,
|
||||||
|
id_table_start: u64,
|
||||||
|
xattr_table_start: u64,
|
||||||
|
inode_table_start: u64,
|
||||||
|
dir_table_start: u64,
|
||||||
|
frag_table_start: u64,
|
||||||
|
export_table_start: u64,
|
||||||
|
};
|
||||||
|
|||||||
+11
-1
@@ -4,6 +4,8 @@ const Writer = Io.Writer;
|
|||||||
|
|
||||||
const config = @import("build_config");
|
const config = @import("build_config");
|
||||||
const squashfs = @import("squashfs");
|
const squashfs = @import("squashfs");
|
||||||
|
const Archive = squashfs.Archive;
|
||||||
|
const Options = squashfs.Options;
|
||||||
|
|
||||||
//TODO: Add more options
|
//TODO: Add more options
|
||||||
const help_mgs =
|
const help_mgs =
|
||||||
@@ -34,7 +36,7 @@ var offset: u64 = 0;
|
|||||||
var threads: usize = 0;
|
var threads: usize = 0;
|
||||||
var force: bool = false;
|
var force: bool = false;
|
||||||
|
|
||||||
var options: squashfs.Options = .default;
|
var options: Options = .default;
|
||||||
|
|
||||||
pub fn main(init: std.process.Init) !void {
|
pub fn main(init: std.process.Init) !void {
|
||||||
var io = init.io;
|
var io = init.io;
|
||||||
@@ -55,4 +57,12 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
});
|
});
|
||||||
io = limited_io.io();
|
io = limited_io.io();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fil = try Io.Dir.cwd().openFile(io, arc_loc, .{});
|
||||||
|
defer fil.close(io);
|
||||||
|
|
||||||
|
var arc: Archive = try .open(io, fil, offset);
|
||||||
|
defer arc.close(io);
|
||||||
|
|
||||||
|
try arc.extract(alloc, io, ext_loc, options);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <zlib-ng.h>
|
|
||||||
#include <zstd.h>
|
|
||||||
#include <lz4.h>
|
#include <lz4.h>
|
||||||
#include <lzma.h>
|
#include <lzma.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
#ifdef ALLOW_LZO
|
#ifdef ALLOW_LZO
|
||||||
#include <lzo/minilzo.h>
|
#include <lzo/minilzo.h>
|
||||||
|
|||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
const build = @import("build_config");
|
||||||
|
|
||||||
|
pub const Enum = enum(u16) {
|
||||||
|
gzip = 1,
|
||||||
|
lzma,
|
||||||
|
lzo,
|
||||||
|
xz,
|
||||||
|
lz4,
|
||||||
|
zstd,
|
||||||
|
|
||||||
|
pub fn func(self: Enum) !Fn {
|
||||||
|
return switch (self) {
|
||||||
|
.gzip => if (build.zig_decomp) zigZlib else cZlib,
|
||||||
|
.lzma => if (build.zig_decomp) zigLzma else cLzma,
|
||||||
|
.lzo => if (build.zig_decomp) error.LzoUnsupported else cLzo,
|
||||||
|
.xz => if (build.zig_decomp) zigXz else cXz,
|
||||||
|
.lz4 => if (build.zig_decomp) error.Lz4Unsupported else cLz4,
|
||||||
|
.zstd => if (build.zig_decomp) zigZstd else cZstd,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pub const Fn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize;
|
||||||
|
|
||||||
|
pub const Error = Io.Reader.Error;
|
||||||
|
|
||||||
|
// Actual decomp functions
|
||||||
|
|
||||||
|
fn zigZlib(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
var rdr: Io.Reader = .fixed(in);
|
||||||
|
var decomp: std.compress.flate.Decompress = .init(&rdr, .zlib, &[0]u8{});
|
||||||
|
|
||||||
|
return decomp.reader.readSliceShort(out);
|
||||||
|
}
|
||||||
|
fn cZlib(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
var stream: c.z_stream = .{
|
||||||
|
.avail_in = @truncate(in.len),
|
||||||
|
.next_in = in.ptr,
|
||||||
|
.avail_out = @truncate(out.len),
|
||||||
|
.next_out = out.ptr,
|
||||||
|
};
|
||||||
|
const res = c.inflate(&stream, c.Z_FULL_FLUSH);
|
||||||
|
if (res != c.Z_OK)
|
||||||
|
return Error.ReadFailed;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zigLzma(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
var rdr: Io.Reader = .fixed(in);
|
||||||
|
var decomp: std.compress.lzma.Decompress = .initOptions(&rdr, alloc, out, .{}, 0);
|
||||||
|
}
|
||||||
|
fn cLzma(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cLzo(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zigXz(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
fn cXz(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cLz4(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zigZstd(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
fn cZstd(alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = alloc;
|
||||||
|
_ = in;
|
||||||
|
_ = out;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
|
||||||
|
const Inode = @import("inode.zig");
|
||||||
|
|
||||||
|
const File = @This();
|
||||||
|
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
name: []const u8,
|
||||||
|
inode: Inode,
|
||||||
|
|
||||||
|
pub fn close(self: File) void {
|
||||||
|
self.inode.deinit(self.alloc);
|
||||||
|
self.alloc.free(self.name);
|
||||||
|
}
|
||||||
+24
-6
@@ -6,12 +6,22 @@ const Inode = @This();
|
|||||||
header: Header,
|
header: Header,
|
||||||
data: Data,
|
data: Data,
|
||||||
|
|
||||||
|
pub fn deinit(self: Inode, alloc: std.mem.Allocator) void {
|
||||||
|
switch (self.data) {
|
||||||
|
.file => |f| alloc.free(f.blocks),
|
||||||
|
.ext_file => |f| alloc.free(f.blocks),
|
||||||
|
.symlink => |s| alloc.free(s.target),
|
||||||
|
.ext_symlink => |s| alloc.free(s.target),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
pub const Reference = packed struct(u64) {
|
pub const Reference = packed struct(u64) {
|
||||||
_: u16,
|
|
||||||
block: u32,
|
|
||||||
offset: u16,
|
offset: u16,
|
||||||
|
block: u32,
|
||||||
|
_: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Type = enum(u16) {
|
pub const Type = enum(u16) {
|
||||||
@@ -76,11 +86,19 @@ pub const ExtDir = extern struct {
|
|||||||
xattr_idx: u32,
|
xattr_idx: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const File = struct {};
|
pub const File = struct {
|
||||||
pub const ExtFile = struct {};
|
blocks: []u64,
|
||||||
|
};
|
||||||
|
pub const ExtFile = struct {
|
||||||
|
blocks: []u64,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Symlink = struct {};
|
pub const Symlink = struct {
|
||||||
pub const ExtSymlink = struct {};
|
target: []const u8,
|
||||||
|
};
|
||||||
|
pub const ExtSymlink = struct {
|
||||||
|
target: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Dev = extern struct {};
|
pub const Dev = extern struct {};
|
||||||
pub const ExtDev = extern struct {};
|
pub const ExtDev = extern struct {};
|
||||||
|
|||||||
+1
-1
@@ -2,5 +2,5 @@ pub const Archive = @import("archive.zig");
|
|||||||
pub const Options = @import("options.zig");
|
pub const Options = @import("options.zig");
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(Archive);
|
@import("std").testing.refAllDecls(@import("tests.zig"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
|
||||||
|
var alloc = std.testing.allocator;
|
||||||
|
var io = std.testing.io;
|
||||||
|
|
||||||
|
const Archive = @import("archive.zig");
|
||||||
|
|
||||||
|
const TEST_ARCHIVE = "testing/LinuxPATest.sfs";
|
||||||
|
|
||||||
|
test "Open" {
|
||||||
|
var archive_file = try Io.Dir.cwd().openFile(io, TEST_ARCHIVE, .{});
|
||||||
|
defer archive_file.close(io);
|
||||||
|
|
||||||
|
var arc: Archive = try .open(io, archive_file, 0);
|
||||||
|
defer arc.close(io);
|
||||||
|
|
||||||
|
std.debug.print("{}\n", .{arc.super});
|
||||||
|
|
||||||
|
var root = try arc.root();
|
||||||
|
defer root.close();
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Decomp = @import("../decomp.zig");
|
||||||
|
|
||||||
|
const MetadataReader = @This();
|
||||||
|
|
||||||
|
data: []u8,
|
||||||
|
decomp: Decomp.Fn,
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
pub fn readValue(comptime T: type, bytes: []u8) T {
|
||||||
|
var res = std.mem.bytesToValue(T, bytes);
|
||||||
|
if (comptime builtin.cpu.arch.endian() != .little) {
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
|
.@"enum" => res = std.mem.nativeToLittle(@typeInfo(T).@"enum".tag_type, res),
|
||||||
|
.@"struct" => |s| {
|
||||||
|
if (s.layout == .@"packed") {
|
||||||
|
res = @bitCast(std.mem.nativeToLittle(s.backing_integer.?, @bitCast(res)));
|
||||||
|
} else {
|
||||||
|
std.mem.byteSwapAllFields(T, &res);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.int => res = std.mem.nativeToLittle(T, res),
|
||||||
|
.array => |a| std.mem.byteSwapAllElements(a.child, res),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user