From 58e89c09811258fcae0d4ec536d7bf7940f0ac9b Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Sun, 11 May 2025 09:39:24 -0500 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ README.md | 3 +++ inode.zig | 50 +++++++++++++++++++++++++++++++++++++++ inode_types.zig | 60 +++++++++++++++++++++++++++++++++++++++++++++++ squashfs.zig | 17 ++++++++++++++ superblock.zig | 52 ++++++++++++++++++++++++++++++++++++++++ test_squashfs.zig | 15 ++++++++++++ 7 files changed, 199 insertions(+) create mode 100644 README.md create mode 100644 inode.zig create mode 100644 inode_types.zig create mode 100644 squashfs.zig create mode 100644 superblock.zig create mode 100644 test_squashfs.zig diff --git a/.gitignore b/.gitignore index 3389c86..3400e46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +testing/ + .zig-cache/ zig-out/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf72099 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# zig-squashfs + +Messing around with zig via making a squashfs library. May amount to something. Or not. diff --git a/inode.zig b/inode.zig new file mode 100644 index 0000000..9fb4d12 --- /dev/null +++ b/inode.zig @@ -0,0 +1,50 @@ +pub const InodeRef = packed struct { + _: u16, + block_start: u32, + offset: u16, +}; + +const InodeType = enum(u16) { + dir = 1, + file, + symlink, + block_device, + char_device, + fifo, + socket, + ext_dir, + ext_file, + ext_symlink, + ext_block_device, + ext_char_device, + ext_fifo, + ext_socket, +}; + +pub const InodeHeader = packed struct { + inode_type: InodeType, + perm: u16, + uid_index: u16, + gid_index: u16, + mod_time: u32, + inode_num: u32, +}; + +const itypes = @import("inode_types.zig"); + +const InodeData = union(enum) { + dir: itypes.DirInode, + file: itypes.FileInode, + symlink: itypes.SymlinkInode, + block_device: itypes.DeviceInode, + char_device: itypes.DeviceInode, + fifo: itypes.FifoInode, + socket: itypes.FifoInode, + ext_dir: itypes.ExtDirInode, + ext_file: itypes.ExtFileInode, + ext_symlink: itypes.ExtSymlinkInode, + ext_block_device: itypes.ExtDeviceInode, + ext_char_device: itypes.ExtDeviceInode, + ext_fifo: itypes.ExtFifoInode, + ext_socket: itypes.ExtFifoInode, +}; diff --git a/inode_types.zig b/inode_types.zig new file mode 100644 index 0000000..f1bbaac --- /dev/null +++ b/inode_types.zig @@ -0,0 +1,60 @@ +pub const DirInode = packed struct { + dir_block_start: u32, + hard_links: u32, + dir_table_size: u16, + dir_block_offset: u16, + parent_inode_num: u32, +}; + +pub const DirIndexStart = packed struct { + dir_header_offset: u32, + dir_table_offset: u32, + name_size: u32, +}; + +pub const DirIndex = struct { + start: DirIndexStart, + name: []const u8, +}; + +pub const ExtDirInodeStart = packed struct { + hard_links: u32, + dir_table_size: u32, + dir_block_start: u32, + parent_inode_num: u32, + dir_index_count: u16, + dir_block_offset: u16, + xattr_index: u32, +}; + +pub const ExtDirInode = struct { + start: ExtDirInodeStart, + indexes: []const u8, +}; + +pub const FileInodeStart = packed struct { + start: u32, + frag_index: u32, + frag_block_offset: u32, + size: u32, +}; + +pub const FileInode = struct { + start: FileInodeStart, + block_sizes: []const u32, +}; + +pub const ExtFileInodeStart = packed struct { + start: u64, + size: u64, + sparse: u64, + hard_links: u32, + frag_index: u32, + frag_block_offset: u32, + xattr_index: u32, +}; + +pub const ExtFileInode = struct { + start: ExtFileInodeStart, + block_sizes: []const u32, +}; diff --git a/squashfs.zig b/squashfs.zig new file mode 100644 index 0000000..2399282 --- /dev/null +++ b/squashfs.zig @@ -0,0 +1,17 @@ +const std = @import("std"); +const io = std.io; +const Superblock = @import("superblock.zig").Superblock; + +pub const Reader = struct { + super: Superblock, + rdr: io.AnyReader, +}; + +pub fn newReader(rdr: io.AnyReader) !Reader { + const super = try rdr.readStruct(Superblock); + try super.valid(); + return Reader{ + .super = super, + .rdr = rdr, + }; +} \ No newline at end of file diff --git a/superblock.zig b/superblock.zig new file mode 100644 index 0000000..2d6173b --- /dev/null +++ b/superblock.zig @@ -0,0 +1,52 @@ +const std = @import("std"); + +pub const SuperblockError = error{ + InvalidMagic, + InvalidLog, + InvalidVersion, +}; + +pub const Superblock = packed struct { + magic: u32, + count: u32, + mod_time: u32, + block_size: u32, + frags: u32, + comp: u16, + block_log: u16, + flags: packed struct { + inode_uncomp: bool, + data_uncomp: bool, + _unused: bool, + frag_uncomp: bool, + frag_always: bool, + data_dedupe: bool, + export_table: bool, + xattr_uncomp: bool, + no_xattr: bool, + comp_options: bool, + id_uncomp: bool, + _padding: u5, + }, + id_count: u16, + ver_maj: u16, + ver_min: u16, + root_inode: @import("inode.zig").InodeRef, + size: u64, + id_table: u64, + xattr_table: u64, + inode_table: u64, + dir_table: u64, + frag_table: u64, + export_table: u64, + + pub fn valid(self: Superblock) SuperblockError!void { + if (self.magic != 0x73717368) { + return SuperblockError.InvalidMagic; + } else if (self.block_log != std.math.log2(self.block_size)) { + return SuperblockError.InvalidLog; + } else if (self.ver_maj != 4 or self.ver_min != 0) { + return SuperblockError.InvalidVersion; + } + } +}; diff --git a/test_squashfs.zig b/test_squashfs.zig new file mode 100644 index 0000000..0128133 --- /dev/null +++ b/test_squashfs.zig @@ -0,0 +1,15 @@ +const std = @import("std"); +const debug = std.debug; +const squashfs = @import("squashfs.zig"); + +const testFileName = "testing/LinuxPATest.sfs"; + +test "open test file" { + const testFile = try std.fs.cwd().openFile( + testFileName, + .{}, + ); + defer testFile.close(); + const reader = try squashfs.newReader(testFile.reader().any()); + _ = reader; +}