Almost there?
This commit is contained in:
@@ -17,6 +17,7 @@ pub const DecompressType = enum(u16) {
|
|||||||
|
|
||||||
pub fn decompress(self: DecompressType, alloc: std.mem.Allocator, rdr: io.AnyReader) !std.ArrayList(u8) {
|
pub fn decompress(self: DecompressType, alloc: std.mem.Allocator, rdr: io.AnyReader) !std.ArrayList(u8) {
|
||||||
var out = std.ArrayList(u8).init(alloc);
|
var out = std.ArrayList(u8).init(alloc);
|
||||||
|
errdefer out.deinit();
|
||||||
switch (self) {
|
switch (self) {
|
||||||
.zlib => try compress.zlib.decompress(rdr, out.writer()),
|
.zlib => try compress.zlib.decompress(rdr, out.writer()),
|
||||||
.lzma => {
|
.lzma => {
|
||||||
|
|||||||
+60
-3
@@ -1,5 +1,62 @@
|
|||||||
pub const DirHeader = packed struct {};
|
const std = @import("std");
|
||||||
|
const io = std.io;
|
||||||
|
|
||||||
pub const RawDirEntry = struct {};
|
const InodeType = @import("inode/inode.zig").InodeType;
|
||||||
|
|
||||||
pub const DirEntry = struct {};
|
const DirHeader = packed struct {
|
||||||
|
count: u32,
|
||||||
|
inode_block_start: u32,
|
||||||
|
inode_num: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RawDirEntryStart = packed struct {
|
||||||
|
inode_block_offset: u16,
|
||||||
|
/// Difference from the current DirHeader inode_num
|
||||||
|
inode_num_difference: i16,
|
||||||
|
/// Extended inodes will be their basic type.
|
||||||
|
inode_type: InodeType,
|
||||||
|
name_size: u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DirEntry = struct {
|
||||||
|
block_start: u32,
|
||||||
|
offset: u16,
|
||||||
|
inode_num: u32,
|
||||||
|
name: []const u8,
|
||||||
|
|
||||||
|
fn init(alloc: std.mem.Allocator, hdr: DirHeader, rdr: io.AnyReader) !DirEntry {
|
||||||
|
const raw = try rdr.readStruct(RawDirEntryStart);
|
||||||
|
const name = try alloc.alloc(u8, raw.name_size + 1);
|
||||||
|
_ = try rdr.read(name);
|
||||||
|
return .{
|
||||||
|
.block_start = hdr.inode_block_start,
|
||||||
|
.offset = raw.inode_block_offset,
|
||||||
|
.inode_num = if (raw.inode_num_difference > 0)
|
||||||
|
hdr.inode_num + @abs(raw.inode_num_difference)
|
||||||
|
else
|
||||||
|
hdr.inode_num - @abs(raw.inode_num_difference),
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: DirEntry, alloc: std.mem.Allocator) void {
|
||||||
|
alloc.free(self.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn readDirectory(alloc: std.mem.Allocator, rdr: io.AnyReader, size: u64) !std.StringHashMap(DirEntry) {
|
||||||
|
var out: std.StringHashMap(DirEntry) = .init(alloc);
|
||||||
|
errdefer out.deinit();
|
||||||
|
var red_size: u64 = 3;
|
||||||
|
var hdr: DirHeader = try rdr.readStruct(DirHeader);
|
||||||
|
while (red_size < size) : (hdr = try rdr.readStruct(DirHeader)) {
|
||||||
|
var i: u32 = 0;
|
||||||
|
while (i <= hdr.count) : (i += 1) {
|
||||||
|
var tmp: DirEntry = try .init(alloc, hdr, rdr);
|
||||||
|
errdefer tmp.deinit(alloc);
|
||||||
|
try out.put(tmp.name, tmp);
|
||||||
|
red_size += 8 + tmp.name.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|||||||
+87
-8
@@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const io = std.io;
|
const io = std.io;
|
||||||
|
|
||||||
const inode = @import("inode/inode.zig");
|
const inode = @import("inode/inode.zig");
|
||||||
|
const directory = @import("directory.zig");
|
||||||
|
|
||||||
const Reader = @import("reader.zig").Reader;
|
const Reader = @import("reader.zig").Reader;
|
||||||
const DirEntry = @import("directory.zig").DirEntry;
|
const DirEntry = @import("directory.zig").DirEntry;
|
||||||
@@ -11,24 +12,55 @@ const FileError = error{
|
|||||||
NotDirectory,
|
NotDirectory,
|
||||||
NotNormalFile,
|
NotNormalFile,
|
||||||
NotSymlink,
|
NotSymlink,
|
||||||
|
NotFound,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const File = struct {
|
pub const File = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
inode: inode.Inode,
|
inode: inode.Inode,
|
||||||
|
dirEntries: std.StringHashMap(DirEntry) = undefined,
|
||||||
|
hasEntries: bool = false,
|
||||||
|
|
||||||
// pub fn fromDirEntry(read: Reader, ent: DirEntry) !File {}
|
pub fn deinit(self: *File, alloc: std.mem.Allocator) void {
|
||||||
|
self.inode.deinit();
|
||||||
pub fn open(self: File, reader: *Reader, path: []const u8) !File {
|
alloc.free(self.name);
|
||||||
if (path.len == 0 || std.mem.eql(u8, path, ".")) {
|
if (self.hasEntries) {
|
||||||
return self;
|
var iter = self.dirEntries.iterator();
|
||||||
|
while (iter.next()) |ent| {
|
||||||
|
ent.value_ptr.deinit(alloc);
|
||||||
}
|
}
|
||||||
switch (inode.InodeHeader.inode_type) {
|
self.dirEntries.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(self: *File, reader: *Reader, path: []const u8) !File {
|
||||||
|
return self.realOpen(reader, path, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn realOpen(self: *File, reader: *Reader, path: []const u8, first: bool) !File {
|
||||||
|
const clean_path: []const u8 = std.mem.trimLeft(u8, path, "/");
|
||||||
|
if (clean_path.len == 0) {
|
||||||
|
return self.*;
|
||||||
|
}
|
||||||
|
if (!first) {
|
||||||
|
defer reader.alloc.free(path);
|
||||||
|
defer self.deinit(reader.alloc);
|
||||||
|
}
|
||||||
|
switch (self.inode.header.inode_type) {
|
||||||
.dir, .ext_dir => {},
|
.dir, .ext_dir => {},
|
||||||
else => return FileError.NotDirectory,
|
else => return FileError.NotDirectory,
|
||||||
}
|
}
|
||||||
_ = reader;
|
if (!self.hasEntries) {
|
||||||
//TODO: read dir entries and find correct inode and file
|
try self.readDirEntries(reader);
|
||||||
|
}
|
||||||
|
const split_idx = std.mem.indexOf(u8, clean_path, "/") orelse clean_path.len;
|
||||||
|
const name = clean_path[0..split_idx];
|
||||||
|
const ent = self.dirEntries.get(name);
|
||||||
|
if (ent == null) {
|
||||||
|
return FileError.NotFound;
|
||||||
|
}
|
||||||
|
var fil = try fileFromDirEntry(reader, ent.?);
|
||||||
|
return fil.realOpen(reader, clean_path[split_idx..], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symPath(self: File) ![]const u8 {
|
pub fn symPath(self: File) ![]const u8 {
|
||||||
@@ -38,4 +70,51 @@ pub const File = struct {
|
|||||||
else => FileError.NotSymlink,
|
else => FileError.NotSymlink,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn readDirEntries(self: *File, reader: *Reader) !void {
|
||||||
|
var block_start: u32 = 0;
|
||||||
|
var offset: u16 = 0;
|
||||||
|
var size: u32 = 0;
|
||||||
|
switch (self.inode.data) {
|
||||||
|
.dir => |d| {
|
||||||
|
block_start = d.block_start;
|
||||||
|
offset = d.offset;
|
||||||
|
size = d.size;
|
||||||
|
},
|
||||||
|
.ext_dir => |d| {
|
||||||
|
block_start = d.block_start;
|
||||||
|
offset = d.offset;
|
||||||
|
size = d.size;
|
||||||
|
},
|
||||||
|
else => return FileError.NotDirectory,
|
||||||
|
}
|
||||||
|
var offset_rdr = reader.holder.readerAt(reader.super.dir_table_start + block_start);
|
||||||
|
var meta_rdr: MetadataReader = try .init(
|
||||||
|
reader.alloc,
|
||||||
|
offset_rdr.any(),
|
||||||
|
reader.super.decomp,
|
||||||
|
);
|
||||||
|
defer meta_rdr.deinit();
|
||||||
|
self.dirEntries = try directory.readDirectory(reader.alloc, meta_rdr.any(), size);
|
||||||
|
self.hasEntries = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn fileFromDirEntry(read: *Reader, ent: DirEntry) !File {
|
||||||
|
var offset_rdr = read.holder.readerAt(ent.block_start + read.super.inode_table_start);
|
||||||
|
var meta_rdr: MetadataReader = try .init(
|
||||||
|
read.alloc,
|
||||||
|
offset_rdr.any(),
|
||||||
|
read.super.decomp,
|
||||||
|
);
|
||||||
|
defer meta_rdr.deinit();
|
||||||
|
try meta_rdr.skip(ent.offset);
|
||||||
|
return .{
|
||||||
|
.name = ent.name,
|
||||||
|
.inode = try .init(
|
||||||
|
read.alloc,
|
||||||
|
meta_rdr.any(),
|
||||||
|
read.super.block_size,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ pub const InodeRef = packed struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const InodeType = enum(u16) {
|
pub const InodeType = enum(u16) {
|
||||||
dir,
|
dir = 1,
|
||||||
file,
|
file,
|
||||||
sym,
|
sym,
|
||||||
block,
|
block,
|
||||||
|
|||||||
+14
-9
@@ -6,9 +6,10 @@ const FileHolder = @import("readers/file_holder.zig").FileHolder;
|
|||||||
const Superblock = @import("superblock.zig").Superblock;
|
const Superblock = @import("superblock.zig").Superblock;
|
||||||
const File = @import("file.zig").File;
|
const File = @import("file.zig").File;
|
||||||
const MetadataReader = @import("readers/metadata.zig").MetadataReader;
|
const MetadataReader = @import("readers/metadata.zig").MetadataReader;
|
||||||
|
const DirEntry = @import("directory.zig").DirEntry;
|
||||||
|
|
||||||
pub const Reader = struct {
|
pub const Reader = struct {
|
||||||
arena: std.heap.ArenaAllocator,
|
alloc: std.mem.Allocator,
|
||||||
holder: FileHolder,
|
holder: FileHolder,
|
||||||
super: Superblock,
|
super: Superblock,
|
||||||
root: File,
|
root: File,
|
||||||
@@ -17,9 +18,8 @@ pub const Reader = struct {
|
|||||||
var holder: FileHolder = try .init(filepath, offset);
|
var holder: FileHolder = try .init(filepath, offset);
|
||||||
const super: Superblock = try holder.reader().readStruct(Superblock);
|
const super: Superblock = try holder.reader().readStruct(Superblock);
|
||||||
try super.validate();
|
try super.validate();
|
||||||
const arena: std.heap.ArenaAllocator = .init(alloc);
|
|
||||||
var out: Reader = .{
|
var out: Reader = .{
|
||||||
.arena = arena,
|
.alloc = alloc,
|
||||||
.holder = holder,
|
.holder = holder,
|
||||||
.super = super,
|
.super = super,
|
||||||
.root = undefined,
|
.root = undefined,
|
||||||
@@ -28,14 +28,14 @@ pub const Reader = struct {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *Reader) void {
|
pub fn deinit(self: *Reader) void {
|
||||||
self.arena.deinit();
|
self.root.deinit(self.alloc);
|
||||||
self.holder.deinit();
|
self.holder.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fileFromRef(self: *Reader, ref: inode.InodeRef, name: []const u8) !File {
|
fn fileFromRef(self: *Reader, ref: inode.InodeRef, name: []const u8) !File {
|
||||||
var offset_rdr = self.holder.readerAt(ref.block_start + self.super.inode_table_start);
|
var offset_rdr = self.holder.readerAt(ref.block_start + self.super.inode_table_start);
|
||||||
var meta_rdr: MetadataReader = try .init(
|
var meta_rdr: MetadataReader = try .init(
|
||||||
self.arena.allocator(),
|
self.alloc,
|
||||||
offset_rdr.any(),
|
offset_rdr.any(),
|
||||||
self.super.decomp,
|
self.super.decomp,
|
||||||
);
|
);
|
||||||
@@ -44,7 +44,7 @@ pub const Reader = struct {
|
|||||||
return .{
|
return .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.inode = try .init(
|
.inode = try .init(
|
||||||
self.arena.allocator(),
|
self.alloc,
|
||||||
meta_rdr.any(),
|
meta_rdr.any(),
|
||||||
self.super.block_size,
|
self.super.block_size,
|
||||||
),
|
),
|
||||||
@@ -53,8 +53,13 @@ pub const Reader = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "reader" {
|
test "reader" {
|
||||||
const test_file_path = "testing/LinuxPATest.sfs";
|
const test_sfs_path = "testing/LinuxPATest.sfs";
|
||||||
var rdr: Reader = try .init(std.testing.allocator, test_file_path, 0);
|
const test_file_path = "PortableApps/PortableApps.com/Data/PortableAppsMenu.ini";
|
||||||
|
|
||||||
|
var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0);
|
||||||
defer rdr.deinit();
|
defer rdr.deinit();
|
||||||
std.debug.print("{}\n", .{rdr.root});
|
var fil = try rdr.root.open(&rdr, test_file_path);
|
||||||
|
defer fil.deinit(rdr.alloc);
|
||||||
|
|
||||||
|
std.debug.print("{}\n", .{fil});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user