Extraction Finished-ish
This commit is contained in:
+2
-2
@@ -119,8 +119,8 @@ pub fn root(self: *Archive) !SfsFile {
|
|||||||
var rdr = try self.fil.readerAt(self.super.root_ref.block_start + self.super.inode_start, &[0]u8{});
|
var rdr = try self.fil.readerAt(self.super.root_ref.block_start + self.super.inode_start, &[0]u8{});
|
||||||
var meta: MetadataReader = .init(self.allocator(), &rdr.interface, &self.decomp);
|
var meta: MetadataReader = .init(self.allocator(), &rdr.interface, &self.decomp);
|
||||||
try meta.interface.discardAll(self.super.root_ref.block_offset);
|
try meta.interface.discardAll(self.super.root_ref.block_offset);
|
||||||
const inode: Inode = try .read(self.allocator(), &meta.interface, self.super.block_size);
|
const in: Inode = try .read(self.allocator(), &meta.interface, self.super.block_size);
|
||||||
return .init(self, inode, "");
|
return .init(self, in, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(self: *Archive, path: []const u8) !SfsFile {
|
pub fn open(self: *Archive, path: []const u8) !SfsFile {
|
||||||
|
|||||||
+143
-31
@@ -7,6 +7,8 @@ const Archive = @import("archive.zig");
|
|||||||
const DirEntry = @import("dir_entry.zig");
|
const DirEntry = @import("dir_entry.zig");
|
||||||
const ExtractionOptions = @import("options.zig");
|
const ExtractionOptions = @import("options.zig");
|
||||||
const Inode = @import("inode.zig");
|
const Inode = @import("inode.zig");
|
||||||
|
const BlockSize = @import("inode_data/file.zig").BlockSize;
|
||||||
|
const DataReader = @import("util/data.zig");
|
||||||
const MetadataReader = @import("util/metadata.zig");
|
const MetadataReader = @import("util/metadata.zig");
|
||||||
|
|
||||||
const FileError = error{
|
const FileError = error{
|
||||||
@@ -15,7 +17,7 @@ const FileError = error{
|
|||||||
NotSymlink,
|
NotSymlink,
|
||||||
NotDevice,
|
NotDevice,
|
||||||
NotFound,
|
NotFound,
|
||||||
InvalidExtractionPath,
|
ExtractionPathExists,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SfsFile = @This();
|
const SfsFile = @This();
|
||||||
@@ -88,6 +90,44 @@ pub fn permissions(self: SfsFile) u16 {
|
|||||||
return self.inode.hdr.permissions;
|
return self.inode.hdr.permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isRegular(self: SfsFile) bool {
|
||||||
|
return switch (self.inode.hdr.inode_type) {
|
||||||
|
.file, .ext_file => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// The returned DataReader will no longer work if the File's deinit function is called
|
||||||
|
/// or, more specifically, it's inode's deinit function is called.
|
||||||
|
pub fn dataReader(self: SfsFile) !DataReader {
|
||||||
|
if (!self.isRegular()) return FileError.NotRegularFile;
|
||||||
|
var frag_idx: u32 = undefined;
|
||||||
|
var frag_offset: u32 = undefined;
|
||||||
|
var size: u64 = undefined;
|
||||||
|
var blocks: []BlockSize = undefined;
|
||||||
|
var start: u64 = undefined;
|
||||||
|
switch (self.inode.data) {
|
||||||
|
.file => |f| {
|
||||||
|
frag_idx = f.frag_idx;
|
||||||
|
frag_offset = f.frag_block_offset;
|
||||||
|
size = f.size;
|
||||||
|
blocks = f.block_sizes;
|
||||||
|
start = f.block_start;
|
||||||
|
},
|
||||||
|
.ext_file => |f| {
|
||||||
|
frag_idx = f.frag_idx;
|
||||||
|
frag_offset = f.frag_block_offset;
|
||||||
|
size = f.size;
|
||||||
|
blocks = f.block_sizes;
|
||||||
|
start = f.block_start;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
var out: DataReader = .init(self.archive, blocks, start, size);
|
||||||
|
if (frag_idx != 0xFFFFFFFF)
|
||||||
|
out.addFragment(try self.archive.frag(frag_idx), frag_offset);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn isDir(self: SfsFile) bool {
|
pub fn isDir(self: SfsFile) bool {
|
||||||
return switch (self.inode.hdr.inode_type) {
|
return switch (self.inode.hdr.inode_type) {
|
||||||
.dir, .ext_dir => true,
|
.dir, .ext_dir => true,
|
||||||
@@ -101,7 +141,7 @@ pub fn iterate(self: SfsFile) !Iterator {
|
|||||||
.archive = self.archive,
|
.archive = self.archive,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/// Open a file/folder within a directory at the given path.
|
/// Open a sub-file/folder within a directory at the given path.
|
||||||
/// If path is ".", "/", or "./", this File is returned.
|
/// If path is ".", "/", or "./", this File is returned.
|
||||||
pub fn open(self: SfsFile, path: []const u8) !SfsFile {
|
pub fn open(self: SfsFile, path: []const u8) !SfsFile {
|
||||||
if (!self.isDir()) return FileError.NotDirectory;
|
if (!self.isDir()) return FileError.NotDirectory;
|
||||||
@@ -142,7 +182,7 @@ pub fn isSymlink(self: SfsFile) bool {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn symlinkPath(self: SfsFile) ![]const u8 {
|
pub fn symlinkPath(self: SfsFile) ![]const u8 {
|
||||||
if (!self.isSymlink()) FileError.NotSymlink;
|
if (!self.isSymlink()) return FileError.NotSymlink;
|
||||||
return switch (self.inode.data) {
|
return switch (self.inode.data) {
|
||||||
.symlink => |s| s.target,
|
.symlink => |s| s.target,
|
||||||
.ext_symlink => |s| s.target,
|
.ext_symlink => |s| s.target,
|
||||||
@@ -170,9 +210,6 @@ pub fn dev(self: SfsFile) !u32 {
|
|||||||
/// Extract the given File to the path. If File is a regular file, the path must be a directory or not exist.
|
/// Extract the given File to the path. If File is a regular file, the path must be a directory or not exist.
|
||||||
/// If the gievn path is a folder, the File's contents will be extracted within.
|
/// If the gievn path is a folder, the File's contents will be extracted within.
|
||||||
pub fn extract(self: *SfsFile, path: []const u8, options: ExtractionOptions) !void {
|
pub fn extract(self: *SfsFile, path: []const u8, options: ExtractionOptions) !void {
|
||||||
std.Options = .{
|
|
||||||
.log_level = options.log_level,
|
|
||||||
};
|
|
||||||
var alloc = self.archive.allocator();
|
var alloc = self.archive.allocator();
|
||||||
var ext_path: []u8 = undefined;
|
var ext_path: []u8 = undefined;
|
||||||
if (std.fs.cwd().statFile(path)) |stat| {
|
if (std.fs.cwd().statFile(path)) |stat| {
|
||||||
@@ -183,24 +220,24 @@ pub fn extract(self: *SfsFile, path: []const u8, options: ExtractionOptions) !vo
|
|||||||
path.len + self.name.len
|
path.len + self.name.len
|
||||||
else
|
else
|
||||||
path.len + self.name.len + 1;
|
path.len + self.name.len + 1;
|
||||||
ext_path = alloc.alloc(u8, alloc_size);
|
ext_path = try alloc.alloc(u8, alloc_size);
|
||||||
@memcpy(ext_path[0..path.len], path);
|
@memcpy(ext_path[0..path.len], path);
|
||||||
@memcpy(ext_path[ext_path.len - self.name.len ..], self.name);
|
@memcpy(ext_path[ext_path.len - self.name.len ..], self.name);
|
||||||
if (!has_end_sep) ext_path[path.len] = '/';
|
if (!has_end_sep) ext_path[path.len] = '/';
|
||||||
} else {
|
} else {
|
||||||
ext_path = path;
|
ext_path = @constCast(path);
|
||||||
}
|
}
|
||||||
} else return FileError.InvalidExtractionPath;
|
} else return FileError.ExtractionPathExists;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
if (err == .FileNotFound) {
|
if (err == error.FileNotFound) {
|
||||||
ext_path = path;
|
ext_path = @constCast(path);
|
||||||
} else {
|
} else {
|
||||||
std.log.err("Error stat-ing extraction path {s}: {}\n", .{ path, err });
|
std.log.err("Error stat-ing extraction path {s}: {}\n", .{ path, err });
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer if (ext_path.len > path.len) alloc.free(ext_path);
|
defer if (ext_path.len > path.len) alloc.free(ext_path);
|
||||||
var pool: std.Thread.Pool = .{};
|
var pool: std.Thread.Pool = undefined;
|
||||||
try pool.init(.{ .allocator = alloc });
|
try pool.init(.{ .allocator = alloc });
|
||||||
var wg: WaitGroup = .{};
|
var wg: WaitGroup = .{};
|
||||||
defer pool.deinit();
|
defer pool.deinit();
|
||||||
@@ -220,16 +257,15 @@ const ParentInfo = struct {
|
|||||||
options: ExtractionOptions,
|
options: ExtractionOptions,
|
||||||
err: *?anyerror,
|
err: *?anyerror,
|
||||||
|
|
||||||
fn finish(self: *ParentInfo) void {
|
fn finish(self: *const ParentInfo) void {
|
||||||
{
|
self.mut.lock();
|
||||||
self.mut.lock();
|
if (!self.dir_wg.isDone()) {
|
||||||
defer self.mut.unlock();
|
self.mut.unlock();
|
||||||
self.dir_wg.finish();
|
return;
|
||||||
if (!self.dir_wg.isDone()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.mut.unlock();
|
||||||
self.sfs_fil.archive.allocator().destroy(self.mut);
|
self.sfs_fil.archive.allocator().destroy(self.mut);
|
||||||
|
self.sfs_fil.archive.allocator().destroy(self.dir_wg);
|
||||||
defer self.parent_wg.finish();
|
defer self.parent_wg.finish();
|
||||||
var fil = std.fs.cwd().openFile(self.path, .{}) catch |err| {
|
var fil = std.fs.cwd().openFile(self.path, .{}) catch |err| {
|
||||||
std.log.err("Error opening folder {s} to set permissions: {}\n", .{ self.path, err });
|
std.log.err("Error opening folder {s} to set permissions: {}\n", .{ self.path, err });
|
||||||
@@ -267,33 +303,110 @@ fn extractReal(self: SfsFile, path: []const u8, options: ExtractionOptions, pol:
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
defer fil.close();
|
defer fil.close();
|
||||||
//TODO:
|
var dat_rdr = self.dataReader() catch |err| {
|
||||||
|
std.log.err("Error getting data reader for {s} (inode {}): {}\n", .{ self.name, self.inode.hdr.num, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
defer dat_rdr.deinit();
|
||||||
|
var wrt = fil.writer(&[0]u8{});
|
||||||
|
_ = dat_rdr.interface.streamRemaining(&wrt.interface) catch |err| {
|
||||||
|
std.log.err("Error writing data for {s} (inode {}) to {s}: {}\n", .{ self.name, self.inode.hdr.num, path, err });
|
||||||
|
out_err.* = wrt.err orelse err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
wrt.interface.flush() catch |err| {
|
||||||
|
std.log.err("Error flushing data for {s} (inode {}) to {s}: {}\n", .{ self.name, self.inode.hdr.num, path, err });
|
||||||
|
out_err.* = wrt.err orelse err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
self.setPerm(fil, options) catch |err| {
|
self.setPerm(fil, options) catch |err| {
|
||||||
std.log.err("Error setting permissions for {s}: {}\n", .{ path, err });
|
std.log.err("Error setting permissions/owner for {s}: {}\n", .{ path, err });
|
||||||
out_err.* = err;
|
out_err.* = err;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
.symlink, .ext_symlink => {},
|
.symlink, .ext_symlink => {
|
||||||
|
//TODO: deal with dereference symlink options
|
||||||
|
const target_path = self.symlinkPath() catch |err| {
|
||||||
|
std.log.err("Error getting symlink target path for {s} (inode {}): {}\n", .{ self.name, self.inode.hdr.num, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
std.fs.cwd().symLink(target_path, path, .{}) catch |err| {
|
||||||
|
std.log.err("Error creating {s}: {}\n", .{ path, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
// self.setPerm(fil, options) catch |err| {
|
||||||
|
// std.log.err("Error setting permissions/owner for {s}: {}\n", .{ path, err });
|
||||||
|
// out_err.* = err;
|
||||||
|
// return;
|
||||||
|
// };
|
||||||
|
},
|
||||||
.block_dev,
|
.block_dev,
|
||||||
.char_dev,
|
.char_dev,
|
||||||
.fifo,
|
.fifo,
|
||||||
.ext_block_dev,
|
.ext_block_dev,
|
||||||
.ext_char_dev,
|
.ext_char_dev,
|
||||||
.ext_fifo,
|
.ext_fifo,
|
||||||
=> {},
|
=> {
|
||||||
|
var mode: u32 = undefined;
|
||||||
|
var fil_dev: u32 = 0;
|
||||||
|
switch (self.inode.hdr.inode_type) {
|
||||||
|
.block_dev, .ext_block_dev => {
|
||||||
|
mode = std.posix.DT.BLK;
|
||||||
|
fil_dev = self.dev() catch |err| {
|
||||||
|
std.log.err("Error getting device number for {s} (inode {}): {}\n", .{ self.name, self.inode.hdr.num, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.char_dev, .ext_char_dev => {
|
||||||
|
mode = std.posix.DT.CHR;
|
||||||
|
fil_dev = self.dev() catch |err| {
|
||||||
|
std.log.err("Error getting device number for {s} (inode {}): {}\n", .{ self.name, self.inode.hdr.num, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => mode = std.posix.DT.FIFO,
|
||||||
|
}
|
||||||
|
const res = std.os.linux.mknod(@ptrCast(path), mode, fil_dev);
|
||||||
|
if (res != 0) {
|
||||||
|
std.log.err("Error creating device file at {s} with code {}\n", .{ path, res });
|
||||||
|
out_err.* = error.MknodError;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fil = std.fs.cwd().openFile(path, .{}) catch |err| {
|
||||||
|
std.log.err("Error openning {s} to set permissions: {}\n", .{ path, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
defer fil.close();
|
||||||
|
self.setPerm(fil, options) catch |err| {
|
||||||
|
std.log.err("Error setting permissions/owner for {s}: {}\n", .{ path, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
},
|
||||||
.dir, .ext_dir => {
|
.dir, .ext_dir => {
|
||||||
_ = std.fs.cwd().statFile(path) catch |err| {
|
_ = std.fs.cwd().statFile(path) catch |err| {
|
||||||
if (err == .NotFound) {}
|
if (err == error.FileNotFound) {}
|
||||||
};
|
};
|
||||||
var dir_wg: *WaitGroup = self.archive.allocator().create(WaitGroup) catch |err| {
|
var dir_wg: *WaitGroup = self.archive.allocator().create(WaitGroup) catch |err| {
|
||||||
std.log.err("Error allocating mutex for {s} (inode {}): {}\n", .{ path, self.inode.hdr.num, err });
|
std.log.err("Error allocating waitgroup for {s} (inode {}): {}\n", .{ path, self.inode.hdr.num, err });
|
||||||
out_err.* = err;
|
out_err.* = err;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const parent_info: ParentInfo = .{
|
const parent_info: ParentInfo = .{
|
||||||
.fil = self,
|
.sfs_fil = self,
|
||||||
.path = path,
|
.path = path,
|
||||||
|
.mut = self.archive.allocator().create(Mutex) catch |err| {
|
||||||
|
std.log.err("Error allocating mutex for {s} (inode {}): {}\n", .{ path, self.inode.hdr.num, err });
|
||||||
|
out_err.* = err;
|
||||||
|
return;
|
||||||
|
},
|
||||||
.dir_wg = dir_wg,
|
.dir_wg = dir_wg,
|
||||||
.parent_wg = wg,
|
.parent_wg = wg,
|
||||||
.options = options,
|
.options = options,
|
||||||
@@ -313,9 +426,9 @@ fn extractReal(self: SfsFile, path: []const u8, options: ExtractionOptions, pol:
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (iter_fil == null) break;
|
if (iter_fil == null) break;
|
||||||
var fil = iter_fil.?;
|
const fil = iter_fil.?;
|
||||||
dir_wg.start();
|
dir_wg.start();
|
||||||
const path_len = path.len + fil.name.len;
|
var path_len = path.len + fil.name.len;
|
||||||
if (!path_has_end_sep) path_len += 1;
|
if (!path_has_end_sep) path_len += 1;
|
||||||
var new_path = self.archive.allocator().alloc(u8, path_len) catch |err| {
|
var new_path = self.archive.allocator().alloc(u8, path_len) catch |err| {
|
||||||
std.log.err("Error allocating subpath for {s} (inode {}): {}\n", .{ path, self.inode.hdr.num, err });
|
std.log.err("Error allocating subpath for {s} (inode {}): {}\n", .{ path, self.inode.hdr.num, err });
|
||||||
@@ -324,7 +437,7 @@ fn extractReal(self: SfsFile, path: []const u8, options: ExtractionOptions, pol:
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
@memcpy(new_path[0..path.len], path);
|
@memcpy(new_path[0..path.len], path);
|
||||||
@memcpy(new_path[new_path.len - fil.name.len ..], fil.name.len);
|
@memcpy(new_path[new_path.len - fil.name.len ..], fil.name);
|
||||||
if (!path_has_end_sep) new_path[path.len] = '/';
|
if (!path_has_end_sep) new_path[path.len] = '/';
|
||||||
pol.spawn(extractReal, .{
|
pol.spawn(extractReal, .{
|
||||||
fil,
|
fil,
|
||||||
@@ -340,7 +453,6 @@ fn extractReal(self: SfsFile, path: []const u8, options: ExtractionOptions, pol:
|
|||||||
dir_wg.finish();
|
dir_wg.finish();
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
fil.extractReal;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.socket, .ext_socket => {
|
.socket, .ext_socket => {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub const File = struct {
|
|||||||
|
|
||||||
pub fn read(alloc: std.mem.Allocator, rdr: *Reader, block_size: u32) !File {
|
pub fn read(alloc: std.mem.Allocator, rdr: *Reader, block_size: u32) !File {
|
||||||
var start: [16]u8 = undefined;
|
var start: [16]u8 = undefined;
|
||||||
try rdr.readSliceAll(u8, &start, .little);
|
try rdr.readSliceAll(&start);
|
||||||
const frag_idx: u32 = std.mem.readInt(u32, start[4..8], .little);
|
const frag_idx: u32 = std.mem.readInt(u32, start[4..8], .little);
|
||||||
const size: u32 = std.mem.readInt(u32, start[12..16], .little);
|
const size: u32 = std.mem.readInt(u32, start[12..16], .little);
|
||||||
var num_blocks: u32 = size / block_size;
|
var num_blocks: u32 = size / block_size;
|
||||||
@@ -50,7 +50,7 @@ pub const ExtFile = struct {
|
|||||||
|
|
||||||
pub fn read(alloc: std.mem.Allocator, rdr: *Reader, block_size: u32) !ExtFile {
|
pub fn read(alloc: std.mem.Allocator, rdr: *Reader, block_size: u32) !ExtFile {
|
||||||
var start: [40]u8 = undefined;
|
var start: [40]u8 = undefined;
|
||||||
try rdr.readSliceAll(u8, &start, .little);
|
try rdr.readSliceAll(&start);
|
||||||
const frag_idx: u32 = std.mem.readInt(u32, start[28..32], .little);
|
const frag_idx: u32 = std.mem.readInt(u32, start[28..32], .little);
|
||||||
const size: u64 = std.mem.readInt(u64, start[8..16], .little);
|
const size: u64 = std.mem.readInt(u64, start[8..16], .little);
|
||||||
var num_blocks: u32 = @truncate(size / block_size);
|
var num_blocks: u32 = @truncate(size / block_size);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub const Symlink = struct {
|
|||||||
|
|
||||||
pub fn read(alloc: std.mem.Allocator, rdr: *Reader) !Symlink {
|
pub fn read(alloc: std.mem.Allocator, rdr: *Reader) !Symlink {
|
||||||
var start: [8]u8 = undefined;
|
var start: [8]u8 = undefined;
|
||||||
try rdr.readSliceAll(u8, &start, .little);
|
try rdr.readSliceAll(&start);
|
||||||
const target_size = std.mem.readInt(u32, start[4..8], .little);
|
const target_size = std.mem.readInt(u32, start[4..8], .little);
|
||||||
const target = try alloc.alloc(u8, target_size + 1);
|
const target = try alloc.alloc(u8, target_size + 1);
|
||||||
errdefer alloc.free(target);
|
errdefer alloc.free(target);
|
||||||
@@ -30,7 +30,7 @@ pub const ExtSymlink = struct {
|
|||||||
|
|
||||||
pub fn read(alloc: std.mem.Allocator, rdr: *Reader) !ExtSymlink {
|
pub fn read(alloc: std.mem.Allocator, rdr: *Reader) !ExtSymlink {
|
||||||
var start: [8]u8 = undefined;
|
var start: [8]u8 = undefined;
|
||||||
try rdr.readSliceAll(u8, &start, .little);
|
try rdr.readSliceAll(&start);
|
||||||
const target_size = std.mem.readInt(u32, start[4..8], .little);
|
const target_size = std.mem.readInt(u32, start[4..8], .little);
|
||||||
const target = try alloc.alloc(u8, target_size + 1);
|
const target = try alloc.alloc(u8, target_size + 1);
|
||||||
errdefer alloc.free(target);
|
errdefer alloc.free(target);
|
||||||
|
|||||||
+1
-1
@@ -15,4 +15,4 @@ log_level: std.log.Level = .err,
|
|||||||
// verboseWriter: ?*Writer = null,
|
// verboseWriter: ?*Writer = null,
|
||||||
|
|
||||||
pub const Default: ExtractionOptions = .{};
|
pub const Default: ExtractionOptions = .{};
|
||||||
pub const VerboseDefault: ExtractionOptions = .{ .verbose = true };
|
pub const VerboseDefault: ExtractionOptions = .{ .log_level = .debug };
|
||||||
|
|||||||
+4
-4
@@ -62,12 +62,12 @@ pub fn Table(T: anytype) type {
|
|||||||
}
|
}
|
||||||
const is_last = (self.values - 1) / VALS_PER_BLOCK == block_num;
|
const is_last = (self.values - 1) / VALS_PER_BLOCK == block_num;
|
||||||
const slice_size = if (is_last) self.values - (block_num * VALS_PER_BLOCK) else VALS_PER_BLOCK;
|
const slice_size = if (is_last) self.values - (block_num * VALS_PER_BLOCK) else VALS_PER_BLOCK;
|
||||||
const slice = try self.alloc.alloc(slice_size);
|
const slice = try self.alloc.alloc(T, slice_size);
|
||||||
var rdr = try self.fil.readerAt(self.tab_start + (8 * block_num), &[0]u8{});
|
var rdr = try self.fil.readerAt(self.tab_start + (8 * block_num), &[0]u8{});
|
||||||
const offset: u64 = 0;
|
var offset: u64 = 0;
|
||||||
try rdr.interface.readSliceEndian(u64, @ptrCast(&idx_offset), .little);
|
try rdr.interface.readSliceEndian(u64, @ptrCast(&offset), .little);
|
||||||
rdr = try self.fil.readerAt(offset, &[0]u8{});
|
rdr = try self.fil.readerAt(offset, &[0]u8{});
|
||||||
var meta: MetadataReader = .init(&rdr.interface, self.decomp);
|
var meta: MetadataReader = .init(self.alloc, &rdr.interface, self.decomp);
|
||||||
try meta.interface.readSliceEndian(T, @ptrCast(slice), .little);
|
try meta.interface.readSliceEndian(T, @ptrCast(slice), .little);
|
||||||
try self.tab.put(block_num, slice);
|
try self.tab.put(block_num, slice);
|
||||||
return slice[idx_offset];
|
return slice[idx_offset];
|
||||||
|
|||||||
+49
-24
@@ -18,7 +18,7 @@ block_size: u32,
|
|||||||
|
|
||||||
blocks: []BlockSize,
|
blocks: []BlockSize,
|
||||||
|
|
||||||
frag: ?FragEntry, // TODO: do something better?
|
frag: ?FragEntry = null, // TODO: do something better?
|
||||||
frag_offset: u32 = 0,
|
frag_offset: u32 = 0,
|
||||||
size: u64,
|
size: u64,
|
||||||
|
|
||||||
@@ -49,7 +49,9 @@ pub fn init(archive: *Archive, blocks: []BlockSize, start: u64, size: u64) DataR
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *DataReader) void {
|
pub fn deinit(self: *DataReader) void {
|
||||||
self.alloc.free(self.inteface.buffer);
|
self.alloc.free(self.interface.buffer);
|
||||||
|
self.interface.end = 0;
|
||||||
|
self.interface.seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addFragment(self: *DataReader, entry: FragEntry, frag_offset: u32) void {
|
pub fn addFragment(self: *DataReader, entry: FragEntry, frag_offset: u32) void {
|
||||||
@@ -57,21 +59,29 @@ pub fn addFragment(self: *DataReader, entry: FragEntry, frag_offset: u32) void {
|
|||||||
self.frag_offset = frag_offset;
|
self.frag_offset = frag_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blockNum(self: DataReader) u32 {
|
fn numBlocks(self: DataReader) usize {
|
||||||
var res = self.blocks.len;
|
var res = self.blocks.len;
|
||||||
if (self.frag != null) res += 1;
|
if (self.frag != null) res += 1;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn advance(self: *DataReader) !void {
|
fn advance(self: *DataReader) !void {
|
||||||
if (self.block_idx > self.blocks.len or (self.block_idx == self.blocks.len and self.frag == null)) return Reader.Error.EndOfStream;
|
if (self.block_idx > self.blocks.len or (self.block_idx == self.blocks.len and self.frag == null)) {
|
||||||
|
if (self.interface.buffer.len > 0) {
|
||||||
|
self.alloc.free(self.interface.buffer);
|
||||||
|
self.interface.buffer = &[0]u8{};
|
||||||
|
self.interface.end = 0;
|
||||||
|
self.interface.seek = 0;
|
||||||
|
}
|
||||||
|
return Reader.Error.EndOfStream;
|
||||||
|
}
|
||||||
defer self.block_idx += 1;
|
defer self.block_idx += 1;
|
||||||
|
const cur_block_size = if (self.block_idx == self.numBlocks() - 1) self.size % self.block_size else self.block_size;
|
||||||
|
try self.resizeBuffer(cur_block_size);
|
||||||
self.interface.seek = 0;
|
self.interface.seek = 0;
|
||||||
self.alloc.free(self.interface.buffer);
|
self.interface.end = cur_block_size;
|
||||||
if (self.block_idx == self.blocks.len) { // fragment
|
if (self.block_idx == self.blocks.len) { // fragment
|
||||||
var rdr = try self.fil.readerAt(self.frag.?.start + self.frag_offset, &[0]u8);
|
var rdr = try self.fil.readerAt(self.frag.?.start, &[0]u8{});
|
||||||
self.interface.buffer = try rdr.interface.readAlloc(self.alloc, self.size % self.block_size);
|
|
||||||
self.interface.end = self.interface.buffer.len;
|
|
||||||
if (self.frag.?.size.uncompressed) {
|
if (self.frag.?.size.uncompressed) {
|
||||||
try rdr.interface.discardAll(self.frag_offset);
|
try rdr.interface.discardAll(self.frag_offset);
|
||||||
try rdr.interface.readSliceAll(self.interface.buffer);
|
try rdr.interface.readSliceAll(self.interface.buffer);
|
||||||
@@ -79,30 +89,45 @@ fn advance(self: *DataReader) !void {
|
|||||||
}
|
}
|
||||||
const tmp_buf = try self.alloc.alloc(u8, self.frag.?.size.size);
|
const tmp_buf = try self.alloc.alloc(u8, self.frag.?.size.size);
|
||||||
defer self.alloc.free(tmp_buf);
|
defer self.alloc.free(tmp_buf);
|
||||||
var limit_rdr = Reader.limited(&rdr.interface, self.frag.?.size.size, tmp_buf);
|
var limit_rdr = Reader.limited(&rdr.interface, @enumFromInt(self.frag.?.size.size), tmp_buf);
|
||||||
const needed_block = try self.alloc.alloc(u8, self.frag_offset + self.interface.buffer.len);
|
const needed_block = try self.alloc.alloc(u8, self.frag_offset + cur_block_size);
|
||||||
defer self.alloc.free(needed_block);
|
defer self.alloc.free(needed_block);
|
||||||
_ = try self.decomp.decompReader(&limit_rdr.interface, needed_block);
|
_ = try self.decomp.decompReader(&limit_rdr.interface, needed_block);
|
||||||
@memcpy(self.interface.buffer, needed_block[self.frag_offset..]);
|
@memcpy(self.interface.buffer, needed_block[self.frag_offset..]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const cur_block_size = if (self.block_idx == self.blockNum() - 1) self.size % self.block_size else self.block_size;
|
|
||||||
const block = self.blocks[self.block_idx];
|
const block = self.blocks[self.block_idx];
|
||||||
var rdr = try self.fil.readerAt(self.cur_offset, &[0]u8);
|
if (block.size == 0) {
|
||||||
self.interface.end = cur_block_size;
|
@memset(self.interface.buffer, 0);
|
||||||
if (block.uncompressed) {
|
|
||||||
self.interface.buffer = try rdr.interface.readAlloc(self.alloc, cur_block_size);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var buf: [8192]u8 = undefined;
|
var rdr = try self.fil.readerAt(self.cur_offset, &[0]u8{});
|
||||||
var limit_rdr = Reader.limited(&rdr.interface, block.size, &buf);
|
if (block.uncompressed) {
|
||||||
|
try rdr.interface.readSliceAll(self.interface.buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var buf: [8192]u8 = undefined; //TODO: possibly change for better performance/memory usage. Might need to be a full block in size.
|
||||||
|
var limit_rdr = Reader.limited(&rdr.interface, @enumFromInt(block.size), &buf);
|
||||||
_ = try self.decomp.decompReader(&limit_rdr.interface, self.interface.buffer);
|
_ = try self.decomp.decompReader(&limit_rdr.interface, self.interface.buffer);
|
||||||
}
|
}
|
||||||
|
/// Does not guarentee that data currently in the buffer is retained.
|
||||||
|
fn resizeBuffer(self: *DataReader, size: usize) !void {
|
||||||
|
if (self.interface.buffer.len == size) return;
|
||||||
|
if (!self.alloc.resize(self.interface.buffer, size)) {
|
||||||
|
self.alloc.free(self.interface.buffer);
|
||||||
|
self.interface.buffer = self.alloc.alloc(u8, size) catch |err| {
|
||||||
|
self.interface.buffer = &[0]u8{};
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.interface.buffer.len = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn stream(rdr: *Reader, wrt: *Writer, limit: Limit) Reader.StreamError!usize {
|
fn stream(rdr: *Reader, wrt: *Writer, limit: Limit) Reader.StreamError!usize {
|
||||||
var self: *DataReader = @fieldParentPtr("interface", rdr);
|
var self: *DataReader = @alignCast(@fieldParentPtr("interface", rdr));
|
||||||
if (rdr.seek >= rdr.end) self.advance() catch |err| {
|
if (rdr.seek >= rdr.end) self.advance() catch |err| {
|
||||||
if (err == .EndOfStream) return err;
|
if (err == error.EndOfStream) return error.EndOfStream;
|
||||||
std.log.err("Error advancing data reader: {}\n", .{err});
|
std.log.err("Error advancing data reader: {}\n", .{err});
|
||||||
return Reader.Error.ReadFailed;
|
return Reader.Error.ReadFailed;
|
||||||
};
|
};
|
||||||
@@ -114,9 +139,9 @@ fn stream(rdr: *Reader, wrt: *Writer, limit: Limit) Reader.StreamError!usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn discard(rdr: *Reader, limit: Limit) Reader.Error!usize {
|
fn discard(rdr: *Reader, limit: Limit) Reader.Error!usize {
|
||||||
var self: *DataReader = @fieldParentPtr("interface", rdr);
|
var self: *DataReader = @alignCast(@fieldParentPtr("interface", rdr));
|
||||||
if (rdr.seek >= rdr.end) self.advance() catch |err| {
|
if (rdr.seek >= rdr.end) self.advance() catch |err| {
|
||||||
if (err == .EndOfStream) return err;
|
if (err == error.EndOfStream) return error.EndOfStream;
|
||||||
std.log.err("Error advancing data reader: {}\n", .{err});
|
std.log.err("Error advancing data reader: {}\n", .{err});
|
||||||
return Reader.Error.ReadFailed;
|
return Reader.Error.ReadFailed;
|
||||||
};
|
};
|
||||||
@@ -127,16 +152,16 @@ fn discard(rdr: *Reader, limit: Limit) Reader.Error!usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn readVec(rdr: *Reader, vec: [][]u8) Reader.Error!usize {
|
fn readVec(rdr: *Reader, vec: [][]u8) Reader.Error!usize {
|
||||||
var self: *DataReader = @fieldParentPtr("interface", rdr);
|
var self: *DataReader = @alignCast(@fieldParentPtr("interface", rdr));
|
||||||
if (rdr.seek >= rdr.end) self.advance() catch |err| {
|
if (rdr.seek >= rdr.end) self.advance() catch |err| {
|
||||||
if (err == .EndOfStream) return err;
|
if (err == error.EndOfStream) return error.EndOfStream;
|
||||||
std.log.err("Error advancing data reader: {}\n", .{err});
|
std.log.err("Error advancing data reader: {}\n", .{err});
|
||||||
return Reader.Error.ReadFailed;
|
return Reader.Error.ReadFailed;
|
||||||
};
|
};
|
||||||
var cur_red: usize = 0;
|
var cur_red: usize = 0;
|
||||||
for (vec) |s| {
|
for (vec) |s| {
|
||||||
const to_copy: usize = @min(rdr.end - rdr.seek, s.len);
|
const to_copy: usize = @min(rdr.end - rdr.seek, s.len);
|
||||||
@memcpy(s[0..to_copy], self.buf[rdr.seek .. rdr.seek + to_copy]);
|
@memcpy(s[0..to_copy], rdr.buffer[rdr.seek .. rdr.seek + to_copy]);
|
||||||
rdr.seek += to_copy;
|
rdr.seek += to_copy;
|
||||||
cur_red += to_copy;
|
cur_red += to_copy;
|
||||||
if (rdr.end == rdr.seek) break;
|
if (rdr.end == rdr.seek) break;
|
||||||
|
|||||||
Reference in New Issue
Block a user