Some initial work
Some basic Inode stuff Some basic Archive stuff
This commit is contained in:
@@ -0,0 +1,85 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Inode = @import("inode.zig");
|
||||||
|
|
||||||
|
const Archive = @This();
|
||||||
|
|
||||||
|
super: Superblock,
|
||||||
|
|
||||||
|
pub fn init(fil: std.fs.File, offset: u64) !Archive {
|
||||||
|
var super: Superblock = undefined;
|
||||||
|
var fil_rdr = fil.reader(&[0]u8{});
|
||||||
|
try fil_rdr.seekTo(offset);
|
||||||
|
try fil_rdr.interface.readSliceEndian(Superblock, @ptrCast(&super), .little);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.super = super,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Superblock
|
||||||
|
|
||||||
|
const SQUASHFS_MAGIC: u32 = std.mem.readInt(u32, "hsqs", .little);
|
||||||
|
|
||||||
|
const SuperblockError = error{
|
||||||
|
InvalidMagic,
|
||||||
|
InvalidBlockLog,
|
||||||
|
InvalidVersion,
|
||||||
|
InvalidCheck,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A squashfs Superblock
|
||||||
|
pub const Superblock = packed struct {
|
||||||
|
magic: u32,
|
||||||
|
inode_count: u32,
|
||||||
|
mod_time: u32,
|
||||||
|
block_size: u32,
|
||||||
|
frag_count: u32,
|
||||||
|
compression: enum(u16) {
|
||||||
|
gzip = 1,
|
||||||
|
lzma,
|
||||||
|
lzo,
|
||||||
|
xz,
|
||||||
|
lz4,
|
||||||
|
zstd,
|
||||||
|
},
|
||||||
|
block_log: u16,
|
||||||
|
flags: packed struct {
|
||||||
|
inode_uncompressed: bool,
|
||||||
|
data_uncompressed: bool,
|
||||||
|
check: bool,
|
||||||
|
frag_uncompressed: bool,
|
||||||
|
fragment_never: bool,
|
||||||
|
fragment_always: bool,
|
||||||
|
duplicates: bool,
|
||||||
|
exportable: bool,
|
||||||
|
xattr_uncompressed: bool,
|
||||||
|
xattr_never: bool,
|
||||||
|
compression_options: bool,
|
||||||
|
ids_uncompressed: bool,
|
||||||
|
_: u4,
|
||||||
|
},
|
||||||
|
id_count: u16,
|
||||||
|
ver_maj: u16,
|
||||||
|
ver_min: u16,
|
||||||
|
root_ref: Inode.Ref,
|
||||||
|
size: u64,
|
||||||
|
id_start: u64,
|
||||||
|
xattr_start: u64,
|
||||||
|
inode_start: u64,
|
||||||
|
dir_start: u64,
|
||||||
|
frag_start: u64,
|
||||||
|
export_start: u64,
|
||||||
|
|
||||||
|
/// Validate the Superblock. If an error is returned, it's likely the archive is corrupted or not a squashfs archive.
|
||||||
|
fn validate(self: Superblock) !void {
|
||||||
|
if (self.magic != SQUASHFS_MAGIC)
|
||||||
|
return SuperblockError.InvalidMagic;
|
||||||
|
if (self.flags.check)
|
||||||
|
return SuperblockError.InvalidCheck;
|
||||||
|
if (self.ver_maj != 4 or self.ver_min != 0)
|
||||||
|
return SuperblockError.InvalidVersion;
|
||||||
|
if (std.math.log2(self.block_size) != self.block_log)
|
||||||
|
return SuperblockError.InvalidBlockLog;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
|
||||||
|
const Dir = @import("inode/dir.zig");
|
||||||
|
const File = @import("inode/file.zig");
|
||||||
|
const Misc = @import("inode/misc.zig");
|
||||||
|
const Sym = @import("inode/sym.zig");
|
||||||
|
|
||||||
|
const Inode = @This();
|
||||||
|
|
||||||
|
hdr: Header,
|
||||||
|
data: Data,
|
||||||
|
|
||||||
|
pub fn read(alloc: std.mem.Allocator, rdr: *Reader, block_size: u32) !Inode {
|
||||||
|
var hdr: Header = undefined;
|
||||||
|
try rdr.readSliceEndian(Header, @ptrCast(&hdr), .little);
|
||||||
|
return .{
|
||||||
|
.hdr = hdr,
|
||||||
|
.data = switch (hdr.inode_type) {
|
||||||
|
.dir => .{ .dir = .read(rdr) },
|
||||||
|
.file => .{ .file = .read(alloc, rdr, block_size) },
|
||||||
|
.symlink => .{ .symlink = .read(alloc, rdr) },
|
||||||
|
.block => .{ .block = .read(rdr) },
|
||||||
|
.char => .{ .char = .read(rdr) },
|
||||||
|
.fifo => .{ .fifo = .read(rdr) },
|
||||||
|
.sock => .{ .sock = .read(rdr) },
|
||||||
|
.ext_dir => .{ .ext_dir = .read(rdr) },
|
||||||
|
.ext_file => .{ .ext_file = .read(alloc, rdr, block_size) },
|
||||||
|
.ext_symlink => .{ .ext_symlink = .read(alloc, rdr) },
|
||||||
|
.ext_block => .{ .ext_block = .read(rdr) },
|
||||||
|
.ext_char => .{ .ext_char = .read(rdr) },
|
||||||
|
.ext_fifo => .{ .ext_fifo = .read(rdr) },
|
||||||
|
.ext_sock => .{ .ext_sock = .read(rdr) },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Types
|
||||||
|
|
||||||
|
pub const Ref = packed struct {
|
||||||
|
block_offset: u16,
|
||||||
|
block_start: u32,
|
||||||
|
_: u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Type = enum(u16) {
|
||||||
|
dir = 1,
|
||||||
|
file,
|
||||||
|
symlink,
|
||||||
|
block,
|
||||||
|
char,
|
||||||
|
fifo,
|
||||||
|
sock,
|
||||||
|
ext_dir,
|
||||||
|
ext_file,
|
||||||
|
ext_symlink,
|
||||||
|
ext_block,
|
||||||
|
ext_char,
|
||||||
|
ext_fifo,
|
||||||
|
ext_sock,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Header = packed struct {
|
||||||
|
inode_type: Type,
|
||||||
|
permission: u16,
|
||||||
|
uid_idx: u16,
|
||||||
|
gid_idx: u16,
|
||||||
|
mod_time: u32,
|
||||||
|
num: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Data = union(Type) {
|
||||||
|
dir: Dir.Dir,
|
||||||
|
file: File.File,
|
||||||
|
symlink: Sym.Symlink,
|
||||||
|
block: Misc.Device,
|
||||||
|
char: Misc.Device,
|
||||||
|
fifo: Misc.Ipc,
|
||||||
|
sock: Misc.Ipc,
|
||||||
|
ext_dir: Dir.ExtDir,
|
||||||
|
ext_file: File.ExtFile,
|
||||||
|
ext_symlink: Sym.ExtSymlink,
|
||||||
|
ext_block: Misc.ExtDevice,
|
||||||
|
ext_char: Misc.ExtDevice,
|
||||||
|
ext_fifo: Misc.ExtIpc,
|
||||||
|
ext_sock: Misc.ExtIpc,
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub const Dir = packed struct {};
|
||||||
|
|
||||||
|
pub const ExtDir = packed struct {};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub const File = struct {};
|
||||||
|
|
||||||
|
pub const ExtFile = struct {};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
pub const Device = packed struct {};
|
||||||
|
|
||||||
|
pub const ExtDevice = packed struct {};
|
||||||
|
|
||||||
|
pub const Ipc = packed struct {};
|
||||||
|
|
||||||
|
pub const ExtIpc = packed struct {};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub const Symlink = struct {};
|
||||||
|
|
||||||
|
pub const ExtSymlink = struct {};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub const Archive = @import("archive.zig");
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const FileReader = std.fs.File.Reader;
|
||||||
|
|
||||||
|
const OffsetFile = @This();
|
||||||
|
|
||||||
|
fil: std.fs.File,
|
||||||
|
offset: u64 = 0,
|
||||||
|
|
||||||
|
pub fn readerAt(self: OffsetFile, offset: u64, buf: []u8) !FileReader {
|
||||||
|
var rdr = self.fil.reader(buf);
|
||||||
|
try rdr.seekTo(self.offset + offset);
|
||||||
|
return rdr;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user