mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-12 17:08:39 -09:00
Track which extended mode fields we have + bugfixes
This prevents displaying invalid zero values or writing such values out in JSON/bin exports. Very old issue, actually, but with the new binfmt experiments it's finally started annoying me.
This commit is contained in:
parent
6b7983b2f5
commit
c30699f93b
9 changed files with 104 additions and 49 deletions
|
|
@ -111,6 +111,7 @@ pub const Thread = struct {
|
|||
if (expected_len > t.buf.len) ui.die("Error writing data: path too long.\n", .{});
|
||||
|
||||
if (block.len > 0) {
|
||||
if (global.file_off >= (1<<40)) ui.die("Export data file has grown too large, please report a bug.\n", .{});
|
||||
global.index.items[4..][t.block_num*8..][0..8].* = bigu64((global.file_off << 24) + block.len);
|
||||
global.file_off += block.len;
|
||||
global.fd.writeAll(block) catch |e|
|
||||
|
|
@ -120,6 +121,7 @@ pub const Thread = struct {
|
|||
t.off = 0;
|
||||
t.block_num = @intCast((global.index.items.len - 4) / 8);
|
||||
global.index.appendSlice(&[1]u8{0}**8) catch unreachable;
|
||||
if (global.index.items.len + 12 >= (1<<28)) ui.die("Too many data blocks, please report a bug.\n", .{});
|
||||
}
|
||||
|
||||
fn cborHead(t: *Thread, major: CborMajor, arg: u64) void {
|
||||
|
|
@ -184,14 +186,22 @@ pub const Thread = struct {
|
|||
|
||||
fn itemExt(t: *Thread, stat: *const sink.Stat) void {
|
||||
if (!main.config.extended) return;
|
||||
t.itemKey(.uid);
|
||||
t.cborHead(.pos, stat.ext.uid);
|
||||
t.itemKey(.gid);
|
||||
t.cborHead(.pos, stat.ext.gid);
|
||||
t.itemKey(.mode);
|
||||
t.cborHead(.pos, stat.ext.mode);
|
||||
t.itemKey(.mtime);
|
||||
t.cborHead(.pos, stat.ext.mtime);
|
||||
if (stat.ext.pack.hasuid) {
|
||||
t.itemKey(.uid);
|
||||
t.cborHead(.pos, stat.ext.uid);
|
||||
}
|
||||
if (stat.ext.pack.hasgid) {
|
||||
t.itemKey(.gid);
|
||||
t.cborHead(.pos, stat.ext.gid);
|
||||
}
|
||||
if (stat.ext.pack.hasmode) {
|
||||
t.itemKey(.mode);
|
||||
t.cborHead(.pos, stat.ext.mode);
|
||||
}
|
||||
if (stat.ext.pack.hasmtime) {
|
||||
t.itemKey(.mtime);
|
||||
t.cborHead(.pos, stat.ext.mtime);
|
||||
}
|
||||
}
|
||||
|
||||
fn itemEnd(t: *Thread) void {
|
||||
|
|
|
|||
|
|
@ -387,10 +387,10 @@ const Import = struct {
|
|||
.sub => ctx.fields.sub = kv.val.itemref(ref),
|
||||
.ino => ctx.stat.ino = kv.val.int(u64),
|
||||
.nlink => ctx.stat.nlink = kv.val.int(u31),
|
||||
.uid => ctx.stat.ext.uid = kv.val.int(u32),
|
||||
.gid => ctx.stat.ext.gid = kv.val.int(u32),
|
||||
.mode => ctx.stat.ext.mode = kv.val.int(u16),
|
||||
.mtime => ctx.stat.ext.mtime = kv.val.int(u64),
|
||||
.uid => { ctx.stat.ext.uid = kv.val.int(u32); ctx.stat.ext.pack.hasuid = true; },
|
||||
.gid => { ctx.stat.ext.gid = kv.val.int(u32); ctx.stat.ext.pack.hasgid = true; },
|
||||
.mode => { ctx.stat.ext.mode = kv.val.int(u16); ctx.stat.ext.pack.hasmode = true; },
|
||||
.mtime => { ctx.stat.ext.mtime = kv.val.int(u64); ctx.stat.ext.pack.hasmtime = true; },
|
||||
else => kv.val.skip(),
|
||||
};
|
||||
|
||||
|
|
@ -439,20 +439,25 @@ pub fn get(ref: u64, alloc: std.mem.Allocator) *model.Entry {
|
|||
var etype: ?model.EType = null;
|
||||
var name: []const u8 = "";
|
||||
var p = parser;
|
||||
var ext = model.Ext{};
|
||||
while (p.next()) |kv| {
|
||||
switch (kv.key) {
|
||||
.type => etype = kv.val.etype(),
|
||||
.name => name = kv.val.bytes(),
|
||||
.uid => { ext.uid = kv.val.int(u32); ext.pack.hasuid = true; },
|
||||
.gid => { ext.gid = kv.val.int(u32); ext.pack.hasgid = true; },
|
||||
.mode => { ext.mode = kv.val.int(u16); ext.pack.hasmode = true; },
|
||||
.mtime => { ext.mtime = kv.val.int(u64); ext.pack.hasmtime = true; },
|
||||
else => kv.val.skip(),
|
||||
}
|
||||
if (etype != null and name.len != 0) break;
|
||||
}
|
||||
if (etype == null or name.len == 0) die();
|
||||
|
||||
// XXX: 'extended' should really depend on whether the info is in the file.
|
||||
var entry = model.Entry.create(alloc, etype.?, main.config.extended, name);
|
||||
var entry = model.Entry.create(alloc, etype.?, main.config.extended and !ext.isEmpty(), name);
|
||||
entry.next = .{ .ref = std.math.maxInt(u64) };
|
||||
if (entry.ext()) |e| e.* = ext;
|
||||
if (entry.dir()) |d| d.sub = .{ .ref = std.math.maxInt(u64) };
|
||||
p = parser;
|
||||
while (p.next()) |kv| switch (kv.key) {
|
||||
.prev => entry.next = .{ .ref = kv.val.itemref(ref) },
|
||||
.asize => { if (entry.pack.etype != .dir) entry.size = kv.val.int(u64); },
|
||||
|
|
@ -472,11 +477,6 @@ pub fn get(ref: u64, alloc: std.mem.Allocator) *model.Entry {
|
|||
|
||||
.ino => { if (entry.link()) |l| l.ino = kv.val.int(u64); },
|
||||
.nlink => { if (entry.link()) |l| l.pack.nlink = kv.val.int(u31); },
|
||||
|
||||
.uid => { if (entry.ext()) |e| e.uid = kv.val.int(u32); },
|
||||
.gid => { if (entry.ext()) |e| e.gid = kv.val.int(u32); },
|
||||
.mode => { if (entry.ext()) |e| e.mode = kv.val.int(u16); },
|
||||
.mtime => { if (entry.ext()) |e| e.mtime = kv.val.int(u64); },
|
||||
else => kv.val.skip(),
|
||||
};
|
||||
return entry;
|
||||
|
|
|
|||
|
|
@ -363,8 +363,13 @@ const Row = struct {
|
|||
defer self.col += 27;
|
||||
ui.move(self.row, self.col+1);
|
||||
const ext = if (self.item) |e| e.ext() else dir_parent.entry.ext();
|
||||
if (ext) |e| ui.addts(self.bg, e.mtime)
|
||||
else ui.addstr(" no mtime");
|
||||
if (ext) |e| {
|
||||
if (e.pack.hasmtime) {
|
||||
ui.addts(self.bg, e.mtime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ui.addstr(" no mtime");
|
||||
}
|
||||
|
||||
fn name(self: *Self) void {
|
||||
|
|
@ -526,18 +531,24 @@ const info = struct {
|
|||
box.move(row.*, 3);
|
||||
ui.style(.bold);
|
||||
if (e.ext()) |ext| {
|
||||
ui.addstr("Mode: ");
|
||||
ui.style(.default);
|
||||
ui.addmode(ext.mode);
|
||||
var buf: [32]u8 = undefined;
|
||||
ui.style(.bold);
|
||||
ui.addstr(" UID: ");
|
||||
ui.style(.default);
|
||||
ui.addstr(std.fmt.bufPrintZ(&buf, "{d:<6}", .{ ext.uid }) catch unreachable);
|
||||
ui.style(.bold);
|
||||
ui.addstr(" GID: ");
|
||||
ui.style(.default);
|
||||
ui.addstr(std.fmt.bufPrintZ(&buf, "{d:<6}", .{ ext.gid }) catch unreachable);
|
||||
if (ext.pack.hasmode) {
|
||||
ui.addstr("Mode: ");
|
||||
ui.style(.default);
|
||||
ui.addmode(ext.mode);
|
||||
ui.style(.bold);
|
||||
}
|
||||
if (ext.pack.hasuid) {
|
||||
ui.addstr(" UID: ");
|
||||
ui.style(.default);
|
||||
ui.addstr(std.fmt.bufPrintZ(&buf, "{d:<6}", .{ ext.uid }) catch unreachable);
|
||||
ui.style(.bold);
|
||||
}
|
||||
if (ext.pack.hasgid) {
|
||||
ui.addstr(" GID: ");
|
||||
ui.style(.default);
|
||||
ui.addstr(std.fmt.bufPrintZ(&buf, "{d:<6}", .{ ext.gid }) catch unreachable);
|
||||
}
|
||||
} else {
|
||||
ui.addstr("Type: ");
|
||||
ui.style(.default);
|
||||
|
|
@ -552,11 +563,13 @@ const info = struct {
|
|||
|
||||
// Last modified
|
||||
if (e.ext()) |ext| {
|
||||
box.move(row.*, 3);
|
||||
ui.style(.bold);
|
||||
ui.addstr("Last modified: ");
|
||||
ui.addts(.default, ext.mtime);
|
||||
row.* += 1;
|
||||
if (ext.pack.hasmtime) {
|
||||
box.move(row.*, 3);
|
||||
ui.style(.bold);
|
||||
ui.addstr("Last modified: ");
|
||||
ui.addts(.default, ext.mtime);
|
||||
row.* += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Disk usage & Apparent size
|
||||
|
|
|
|||
|
|
@ -151,14 +151,22 @@ pub const Writer = struct {
|
|||
}
|
||||
if (stat.etype == .nonreg) ctx.write(",\"notreg\":true");
|
||||
if (main.config.extended) {
|
||||
ctx.write(",\"uid\":");
|
||||
ctx.writeUint(stat.ext.uid);
|
||||
ctx.write(",\"gid\":");
|
||||
ctx.writeUint(stat.ext.gid);
|
||||
ctx.write(",\"mode\":");
|
||||
ctx.writeUint(stat.ext.mode);
|
||||
ctx.write(",\"mtime\":");
|
||||
ctx.writeUint(stat.ext.mtime);
|
||||
if (stat.ext.pack.hasuid) {
|
||||
ctx.write(",\"uid\":");
|
||||
ctx.writeUint(stat.ext.uid);
|
||||
}
|
||||
if (stat.ext.pack.hasgid) {
|
||||
ctx.write(",\"gid\":");
|
||||
ctx.writeUint(stat.ext.gid);
|
||||
}
|
||||
if (stat.ext.pack.hasmode) {
|
||||
ctx.write(",\"mode\":");
|
||||
ctx.writeUint(stat.ext.mode);
|
||||
}
|
||||
if (stat.ext.pack.hasmtime) {
|
||||
ctx.write(",\"mtime\":");
|
||||
ctx.writeUint(stat.ext.mtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@ fn itemkey(ctx: *Ctx, key: []const u8) void {
|
|||
'g' => {
|
||||
if (eq(u8, key, "gid")) {
|
||||
ctx.stat.ext.gid = ctx.p.uint(u32);
|
||||
ctx.stat.ext.pack.hasgid = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
|
@ -365,10 +366,12 @@ fn itemkey(ctx: *Ctx, key: []const u8) void {
|
|||
'm' => {
|
||||
if (eq(u8, key, "mode")) {
|
||||
ctx.stat.ext.mode = ctx.p.uint(u16);
|
||||
ctx.stat.ext.pack.hasmode = true;
|
||||
return;
|
||||
}
|
||||
if (eq(u8, key, "mtime")) {
|
||||
ctx.stat.ext.mtime = ctx.p.uint(u64);
|
||||
ctx.stat.ext.pack.hasmtime = true;
|
||||
// Accept decimal numbers, but discard the fractional part because our data model doesn't support it.
|
||||
switch (ctx.p.nextByte()) {
|
||||
'.' =>
|
||||
|
|
@ -410,6 +413,7 @@ fn itemkey(ctx: *Ctx, key: []const u8) void {
|
|||
'u' => {
|
||||
if (eq(u8, key, "uid")) {
|
||||
ctx.stat.ext.uid = ctx.p.uint(u32);
|
||||
ctx.stat.ext.pack.hasuid = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -578,7 +578,7 @@ pub fn main() void {
|
|||
if (import_file) |f| {
|
||||
readImport(f) catch |e| ui.die("Error reading file '{s}': {s}.\n", .{f, ui.errorString(e)});
|
||||
config.imported = true;
|
||||
if (config.binreader and export_json != null or export_bin != null)
|
||||
if (config.binreader and (export_json != null or export_bin != null))
|
||||
bin_reader.import();
|
||||
} else {
|
||||
var buf = [_]u8{0} ** (std.fs.MAX_PATH_BYTES+1);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ pub const Dir = struct {
|
|||
}
|
||||
}
|
||||
|
||||
const e = self.getEntry(t, stat.etype, main.config.extended, name);
|
||||
const e = self.getEntry(t, stat.etype, main.config.extended and !stat.ext.isEmpty(), name);
|
||||
e.pack.blocks = stat.blocks;
|
||||
e.size = stat.size;
|
||||
if (e.dir()) |d| {
|
||||
|
|
@ -172,7 +172,7 @@ pub const Dir = struct {
|
|||
|
||||
pub fn createRoot(path: []const u8, stat: *const sink.Stat) Dir {
|
||||
const p = global.root orelse blk: {
|
||||
model.root = model.Entry.create(main.allocator, .dir, main.config.extended, path).dir().?;
|
||||
model.root = model.Entry.create(main.allocator, .dir, main.config.extended and !stat.ext.isEmpty(), path).dir().?;
|
||||
break :blk model.root;
|
||||
};
|
||||
sink.global.state = .zeroing;
|
||||
|
|
@ -185,6 +185,7 @@ pub fn createRoot(path: []const u8, stat: *const sink.Stat) Dir {
|
|||
p.entry.pack.blocks = stat.blocks;
|
||||
p.entry.size = stat.size;
|
||||
p.pack.dev = model.devices.getId(stat.dev);
|
||||
if (p.entry.ext()) |e| e.* = stat.ext;
|
||||
return Dir.init(p);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -325,10 +325,23 @@ pub const File = extern struct {
|
|||
};
|
||||
|
||||
pub const Ext = extern struct {
|
||||
pack: Pack = .{},
|
||||
mtime: u64 align(1) = 0,
|
||||
uid: u32 align(1) = 0,
|
||||
gid: u32 align(1) = 0,
|
||||
mode: u16 align(1) = 0,
|
||||
|
||||
pub const Pack = packed struct(u8) {
|
||||
hasmtime: bool = false,
|
||||
hasuid: bool = false,
|
||||
hasgid: bool = false,
|
||||
hasmode: bool = false,
|
||||
_pad: u4 = 0,
|
||||
};
|
||||
|
||||
pub fn isEmpty(e: *const Ext) bool {
|
||||
return !e.pack.hasmtime and !e.pack.hasuid and !e.pack.hasgid and !e.pack.hasmode;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ fn statAt(parent: std.fs.Dir, name: [:0]const u8, follow: bool, symlink: *bool)
|
|||
.ino = truncate(sink.Stat, .ino, stat.ino),
|
||||
.nlink = clamp(sink.Stat, .nlink, stat.nlink),
|
||||
.ext = .{
|
||||
.pack = .{
|
||||
.hasmtime = true,
|
||||
.hasuid = true,
|
||||
.hasgid = true,
|
||||
.hasmode = true,
|
||||
},
|
||||
.mtime = clamp(model.Ext, .mtime, stat.mtime().tv_sec),
|
||||
.uid = truncate(model.Ext, .uid, stat.uid),
|
||||
.gid = truncate(model.Ext, .gid, stat.gid),
|
||||
|
|
|
|||
Loading…
Reference in a new issue