diff --git a/src/browser.zig b/src/browser.zig index 13e09eb1b13ce90310d87da7adcab626a69aaabc..8ec47656f4ccce7f9453a3282f36aa1b97b5c88a 100644 --- a/src/browser.zig +++ b/src/browser.zig @@ -83,22 +83,22 @@ fn sortLt(_: void, ap: ?*model.Entry, bp: ?*model.Entry) bool { switch (main.config.sort_col) { .name => {}, // name sorting is the fallback .blocks => { - if (sortIntLt(a.blocks, b.blocks)) |r| return r; + if (sortIntLt(a.pack.blocks, b.pack.blocks)) |r| return r; if (sortIntLt(a.size, b.size)) |r| return r; }, .size => { if (sortIntLt(a.size, b.size)) |r| return r; - if (sortIntLt(a.blocks, b.blocks)) |r| return r; + if (sortIntLt(a.pack.blocks, b.pack.blocks)) |r| return r; }, .items => { const ai = if (a.dir()) |d| d.items else 0; const bi = if (b.dir()) |d| d.items else 0; if (sortIntLt(ai, bi)) |r| return r; - if (sortIntLt(a.blocks, b.blocks)) |r| return r; + if (sortIntLt(a.pack.blocks, b.pack.blocks)) |r| return r; if (sortIntLt(a.size, b.size)) |r| return r; }, .mtime => { - if (!a.isext or !b.isext) return a.isext; + if (!a.pack.isext or !b.pack.isext) return a.pack.isext; if (sortIntLt(a.ext().?.mtime, b.ext().?.mtime)) |r| return r; }, } @@ -135,10 +135,10 @@ pub fn loadDir(next_sel: ?*const model.Entry) void { dir_items.append(null) catch unreachable; var it = dir_parent.sub; while (it) |e| { - if (e.blocks > dir_max_blocks) dir_max_blocks = e.blocks; + if (e.pack.blocks > dir_max_blocks) dir_max_blocks = e.pack.blocks; if (e.size > dir_max_size) dir_max_size = e.size; const shown = main.config.show_hidden or blk: { - const excl = if (e.file()) |f| f.excluded else false; + const excl = if (e.file()) |f| f.pack.excluded else false; const name = e.name(); break :blk !excl and name[0] != '.' and name[name.len-1] != '~'; }; @@ -164,14 +164,14 @@ const Row = struct { const item = self.item orelse return; const ch: u7 = ch: { if (item.file()) |f| { - if (f.err) break :ch '!'; - if (f.excluded) break :ch '<'; - if (f.other_fs) break :ch '>'; - if (f.kernfs) break :ch '^'; - if (f.notreg) break :ch '@'; + if (f.pack.err) break :ch '!'; + if (f.pack.excluded) break :ch '<'; + if (f.pack.other_fs) break :ch '>'; + if (f.pack.kernfs) break :ch '^'; + if (f.pack.notreg) break :ch '@'; } else if (item.dir()) |d| { - if (d.err) break :ch '!'; - if (d.suberr) break :ch '.'; + if (d.pack.err) break :ch '!'; + if (d.pack.suberr) break :ch '.'; if (d.sub == null) break :ch 'e'; } else if (item.link()) |_| break :ch 'H'; return; @@ -187,7 +187,7 @@ const Row = struct { width += 2 + width; defer self.col += width; const item = self.item orelse return; - const siz = if (main.config.show_blocks) util.blocksToSize(item.blocks) else item.size; + const siz = if (main.config.show_blocks) util.blocksToSize(item.pack.blocks) else item.size; var shr = if (item.dir()) |d| (if (main.config.show_blocks) util.blocksToSize(d.shared_blocks) else d.shared_size) else 0; if (main.config.show_shared == .unique) shr = siz -| shr; @@ -216,8 +216,8 @@ const Row = struct { if (main.config.show_percent) { self.bg.fg(.num); ui.addprint("{d:>5.1}", .{ 100 * - if (main.config.show_blocks) @intToFloat(f32, item.blocks) / @intToFloat(f32, std.math.max(1, dir_parent.entry.blocks)) - else @intToFloat(f32, item.size) / @intToFloat(f32, std.math.max(1, dir_parent.entry.size)) + if (main.config.show_blocks) @intToFloat(f32, item.pack.blocks) / @intToFloat(f32, std.math.max(1, dir_parent.entry.pack.blocks)) + else @intToFloat(f32, item.size) / @intToFloat(f32, std.math.max(1, dir_parent.entry.size)) }); self.bg.fg(.default); ui.addch('%'); @@ -225,7 +225,7 @@ const Row = struct { if (main.config.show_graph and main.config.show_percent) ui.addch(' '); if (main.config.show_graph) { var max = if (main.config.show_blocks) dir_max_blocks else dir_max_size; - var num = if (main.config.show_blocks) item.blocks else item.size; + var num = if (main.config.show_blocks) item.pack.blocks else item.size; if (max < bar_size) { max *= bar_size; num *= bar_size; @@ -290,7 +290,7 @@ const Row = struct { fn name(self: *Self) void { ui.move(self.row, self.col); if (self.item) |i| { - self.bg.fg(if (i.etype == .dir) .dir else .default); + self.bg.fg(if (i.pack.etype == .dir) .dir else .default); ui.addch(if (i.isDirectory()) '/' else ' '); ui.addstr(ui.shorten(ui.toUtf8(i.name()), ui.cols -| self.col -| 1)); } else { @@ -460,7 +460,7 @@ const info = struct { } else { ui.addstr("Type: "); ui.style(.default); - ui.addstr(if (e.isDirectory()) "Directory" else if (if (e.file()) |f| f.notreg else false) "Other" else "File"); + ui.addstr(if (e.isDirectory()) "Directory" else if (if (e.file()) |f| f.pack.notreg else false) "Other" else "File"); } row.* += 1; @@ -474,7 +474,7 @@ const info = struct { } // Disk usage & Apparent size - drawSize(box, row, " Disk usage: ", util.blocksToSize(e.blocks), if (e.dir()) |d| util.blocksToSize(d.shared_blocks) else 0); + drawSize(box, row, " Disk usage: ", util.blocksToSize(e.pack.blocks), if (e.dir()) |d| util.blocksToSize(d.shared_blocks) else 0); drawSize(box, row, "Apparent size: ", e.size, if (e.dir()) |d| d.shared_size else 0); // Number of items @@ -522,7 +522,7 @@ const info = struct { var row: u32 = 2; // Tabs - if (e.etype == .link) { + if (e.pack.etype == .link) { box.tab(cols-19, tab == .info, 1, "Info"); box.tab(cols-10, tab == .links, 2, "Links"); } @@ -543,7 +543,7 @@ const info = struct { } fn keyInput(ch: i32) bool { - if (entry.?.etype == .link) { + if (entry.?.pack.etype == .link) { switch (ch) { '1', 'h', ui.c.KEY_LEFT => { set(entry, .info); return true; }, '2', 'l', ui.c.KEY_RIGHT => { set(entry, .links); return true; }, @@ -778,7 +778,7 @@ pub fn draw() void { ui.move(ui.rows-1, 1); ui.style(if (main.config.show_blocks) .bold_hd else .hd); ui.addstr("Total disk usage: "); - ui.addsize(.hd, util.blocksToSize(dir_parent.entry.blocks)); + ui.addsize(.hd, util.blocksToSize(dir_parent.entry.pack.blocks)); ui.style(if (main.config.show_blocks) .hd else .bold_hd); ui.addstr(" Apparent size: "); ui.addsize(.hd, dir_parent.entry.size); diff --git a/src/delete.zig b/src/delete.zig index 1f6575c38f2fd7539f02752a7ea7be685df1cba0..d98a2bd888800b504f1180e247ff5f73d5419fd5 100644 --- a/src/delete.zig +++ b/src/delete.zig @@ -100,7 +100,7 @@ fn drawConfirm() void { ui.addstr("Are you sure you want to delete \""); ui.addstr(ui.shorten(ui.toUtf8(entry.name()), 21)); ui.addch('"'); - if (entry.etype != .dir) + if (entry.pack.etype != .dir) ui.addch('?') else { box.move(2, 18); diff --git a/src/model.zig b/src/model.zig index 75cfe3d5223a1de85380a58c4e07dd00b5cbf467..cfd67b54a2be6540caae6dc9760e9d398eb655e8 100644 --- a/src/model.zig +++ b/src/model.zig @@ -17,7 +17,7 @@ const allocator = allocator_state.allocator(); pub const EType = enum(u2) { dir, link, file }; -// Type for the Entry.blocks field. Smaller than a u64 to make room for flags. +// Type for the Entry.Packed.blocks field. Smaller than a u64 to make room for flags. pub const Blocks = u60; // Memory layout: @@ -31,38 +31,40 @@ pub const Blocks = u60; // These are all packed structs and hence do not have any alignment, which is // great for saving memory but perhaps not very great for code size or // performance. -// (TODO: What are the aliassing rules for Zig? There is a 'noalias' keyword, -// but does that mean all unmarked pointers are allowed to alias?) -pub const Entry = packed struct { - etype: EType, - isext: bool, - // Whether or not this entry's size has been counted in its parents. - // Counting of Link entries is deferred until the scan/delete operation has - // completed, so for those entries this flag indicates an intention to be - // counted. - counted: bool, - blocks: Blocks, // 512-byte blocks - size: u64, - next: ?*Entry, +pub const Entry = extern struct { + pack: Packed align(1), + size: u64 align(1), + next: ?*Entry align(1), + + pub const Packed = packed struct(u64) { + etype: EType, + isext: bool, + // Whether or not this entry's size has been counted in its parents. + // Counting of Link entries is deferred until the scan/delete operation has + // completed, so for those entries this flag indicates an intention to be + // counted. + counted: bool, + blocks: Blocks, // 512-byte blocks + }; const Self = @This(); pub fn dir(self: *Self) ?*Dir { - return if (self.etype == .dir) @ptrCast(*Dir, self) else null; + return if (self.pack.etype == .dir) @ptrCast(*Dir, self) else null; } pub fn link(self: *Self) ?*Link { - return if (self.etype == .link) @ptrCast(*Link, self) else null; + return if (self.pack.etype == .link) @ptrCast(*Link, self) else null; } pub fn file(self: *Self) ?*File { - return if (self.etype == .file) @ptrCast(*File, self) else null; + return if (self.pack.etype == .file) @ptrCast(*File, self) else null; } // Whether this entry should be displayed as a "directory". // Some dirs are actually represented in this data model as a File for efficiency. pub fn isDirectory(self: *Self) bool { - return if (self.file()) |f| f.other_fs or f.kernfs else self.etype == .dir; + return if (self.file()) |f| f.pack.other_fs or f.pack.kernfs else self.pack.etype == .dir; } fn nameOffset(etype: EType) usize { @@ -74,12 +76,12 @@ pub const Entry = packed struct { } pub fn name(self: *const Self) [:0]const u8 { - const ptr = @ptrCast([*:0]const u8, self) + nameOffset(self.etype); + const ptr = @ptrCast([*:0]const u8, self) + nameOffset(self.pack.etype); // TODO: ptrCast the 'name' field instead. return std.mem.sliceTo(ptr, 0); } pub fn ext(self: *Self) ?*Ext { - if (!self.isext) return null; + if (!self.pack.isext) return null; return @ptrCast(*Ext, @ptrCast([*]Ext, self) - 1); } @@ -88,7 +90,7 @@ pub const Entry = packed struct { const size = nameOffset(etype) + ename.len + 1 + extsize; var ptr = blk: { while (true) { - if (allocator.allocWithOptions(u8, size, std.math.max(@alignOf(Ext), @alignOf(Entry)), null)) |p| + if (allocator.allocWithOptions(u8, size, 1, null)) |p| break :blk p else |_| {} ui.oom(); @@ -96,8 +98,8 @@ pub const Entry = packed struct { }; std.mem.set(u8, ptr, 0); // kind of ugly, but does the trick var e = @ptrCast(*Entry, ptr.ptr + extsize); - e.etype = etype; - e.isext = isext; + e.pack.etype = etype; + e.pack.isext = isext; var name_ptr = @ptrCast([*]u8, e) + nameOffset(etype); std.mem.copy(u8, name_ptr[0..ename.len], ename); return e; @@ -105,19 +107,19 @@ pub const Entry = packed struct { // Set the 'err' flag on Dirs and Files, propagating 'suberr' to parents. pub fn setErr(self: *Self, parent: *Dir) void { - if (self.dir()) |d| d.err = true - else if (self.file()) |f| f.err = true + if (self.dir()) |d| d.pack.err = true + else if (self.file()) |f| f.pack.err = true else unreachable; var it: ?*Dir = if (&parent.entry == self) parent.parent else parent; while (it) |p| : (it = p.parent) { - if (p.suberr) break; - p.suberr = true; + if (p.pack.suberr) break; + p.pack.suberr = true; } } pub fn addStats(self: *Entry, parent: *Dir, nlink: u31) void { - if (self.counted) return; - self.counted = true; + if (self.pack.counted) return; + self.pack.counted = true; // Add link to the inode map, but don't count its size (yet). if (self.link()) |l| { @@ -125,7 +127,7 @@ pub const Entry = packed struct { var d = inodes.map.getOrPut(l) catch unreachable; if (!d.found_existing) { d.value_ptr.* = .{ .counted = false, .nlink = nlink }; - inodes.total_blocks +|= self.blocks; + inodes.total_blocks +|= self.pack.blocks; l.next = l; } else { inodes.setStats(.{ .key_ptr = d.key_ptr, .value_ptr = d.value_ptr }, false); @@ -144,9 +146,9 @@ pub const Entry = packed struct { if (p.entry.ext()) |pe| if (e.mtime > pe.mtime) { pe.mtime = e.mtime; }; p.items +|= 1; - if (self.etype != .link) { + if (self.pack.etype != .link) { p.entry.size +|= self.size; - p.entry.blocks +|= self.blocks; + p.entry.pack.blocks +|= self.pack.blocks; } } } @@ -165,8 +167,8 @@ pub const Entry = packed struct { // anymore, meaning that delStats() followed by addStats() with the same // data may cause information to be lost. pub fn delStats(self: *Entry, parent: *Dir) void { - if (!self.counted) return; - defer self.counted = false; // defer, to make sure inodes.setStats() still sees it as counted. + if (!self.pack.counted) return; + defer self.pack.counted = false; // defer, to make sure inodes.setStats() still sees it as counted. if (self.link()) |l| { var d = inodes.map.getEntry(l).?; @@ -175,7 +177,7 @@ pub const Entry = packed struct { if (l.next == l) { _ = inodes.map.remove(l); _ = inodes.uncounted.remove(l); - inodes.total_blocks -|= self.blocks; + inodes.total_blocks -|= self.pack.blocks; } else { if (d.key_ptr.* == l) d.key_ptr.* = l.next; @@ -195,9 +197,9 @@ pub const Entry = packed struct { var it: ?*Dir = parent; while(it) |p| : (it = p.parent) { p.items -|= 1; - if (self.etype != .link) { + if (self.pack.etype != .link) { p.entry.size -|= self.size; - p.entry.blocks -|= self.blocks; + p.entry.pack.blocks -|= self.pack.blocks; } } } @@ -212,32 +214,35 @@ pub const Entry = packed struct { } }; -const DevId = u30; // Can be reduced to make room for more flags in Dir. +const DevId = u30; // Can be reduced to make room for more flags in Dir.Packed. -pub const Dir = packed struct { +pub const Dir = extern struct { entry: Entry, - sub: ?*Entry, - parent: ?*Dir, + sub: ?*Entry align(1), + parent: ?*Dir align(1), // entry.{blocks,size}: Total size of all unique files + dirs. Non-shared hardlinks are counted only once. // (i.e. the space you'll need if you created a filesystem with only this dir) // shared_*: Unique hardlinks that still have references outside of this directory. // (i.e. the space you won't reclaim by deleting this dir) // (space reclaimed by deleting a dir =~ entry. - shared_) - shared_blocks: u64, - shared_size: u64, - items: u32, - - // Indexes into the global 'devices.list' array - dev: DevId, + shared_blocks: u64 align(1), + shared_size: u64 align(1), + items: u32 align(1), - err: bool, - suberr: bool, + pack: Packed align(1), // Only used to find the @offsetOff, the name is written at this point as a 0-terminated string. // (Old C habits die hard) - name: u8, + name: [0]u8, + + pub const Packed = packed struct { + // Indexes into the global 'devices.list' array + dev: DevId, + err: bool, + suberr: bool, + }; pub fn fmtPath(self: *const @This(), withRoot: bool, out: *std.ArrayList(u8)) void { if (!withRoot and self.parent == null) return; @@ -259,13 +264,13 @@ pub const Dir = packed struct { }; // File that's been hardlinked (i.e. nlink > 1) -pub const Link = packed struct { +pub const Link = extern struct { entry: Entry, - parent: *Dir, - next: *Link, // Singly circular linked list of all *Link nodes with the same dev,ino. + parent: *Dir align(1), + next: *Link align(1), // Singly circular linked list of all *Link nodes with the same dev,ino. // dev is inherited from the parent Dir - ino: u64, - name: u8, + ino: u64 align(1), + name: [0]u8, // Return value should be freed with main.allocator. pub fn path(self: @This(), withRoot: bool) [:0]const u8 { @@ -278,40 +283,32 @@ pub const Link = packed struct { }; // Anything that's not an (indexed) directory or hardlink. Excluded directories are also "Files". -pub const File = packed struct { +pub const File = extern struct { entry: Entry, - - err: bool, - excluded: bool, - other_fs: bool, - kernfs: bool, - notreg: bool, - _pad: u3, - - name: u8, + pack: Packed, + name: [0]u8, + + pub const Packed = packed struct(u8) { + err: bool = false, + excluded: bool = false, + other_fs: bool = false, + kernfs: bool = false, + notreg: bool = false, + _pad: u3 = 0, // Make this struct "ABI sized" to allow inclusion in an extern struct + }; pub fn resetFlags(f: *@This()) void { - f.err = false; - f.excluded = false; - f.other_fs = false; - f.kernfs = false; - f.notreg = false; + f.pack = .{}; } }; -pub const Ext = packed struct { - mtime: u64 = 0, - uid: u32 = 0, - gid: u32 = 0, - mode: u16 = 0, +pub const Ext = extern struct { + mtime: u64 align(1) = 0, + uid: u32 align(1) = 0, + gid: u32 align(1) = 0, + mode: u16 align(1) = 0, }; -comptime { - std.debug.assert(@bitOffsetOf(Dir, "name") % 8 == 0); - std.debug.assert(@bitOffsetOf(Link, "name") % 8 == 0); - std.debug.assert(@bitOffsetOf(File, "name") % 8 == 0); -} - // List of st_dev entries. Those are typically 64bits, but that's quite a waste // of space when a typical scan won't cover many unique devices. @@ -367,13 +364,13 @@ pub const inodes = struct { const HashContext = struct { pub fn hash(_: @This(), l: *Link) u64 { var h = std.hash.Wyhash.init(0); - h.update(std.mem.asBytes(&@as(u32, l.parent.dev))); + h.update(std.mem.asBytes(&@as(u32, l.parent.pack.dev))); h.update(std.mem.asBytes(&l.ino)); return h.final(); } pub fn eql(_: @This(), a: *Link, b: *Link) bool { - return a.ino == b.ino and a.parent.dev == b.parent.dev; + return a.ino == b.ino and a.parent.pack.dev == b.parent.pack.dev; } }; @@ -399,7 +396,7 @@ pub const inodes = struct { defer dirs.deinit(); var it = entry.key_ptr.*; while (true) { - if (it.entry.counted) { + if (it.entry.pack.counted) { nlink += 1; var parent: ?*Dir = it.parent; while (parent) |p| : (parent = p.parent) { @@ -419,19 +416,19 @@ pub const inodes = struct { var dir_iter = dirs.iterator(); if (add) { while (dir_iter.next()) |de| { - de.key_ptr.*.entry.blocks +|= entry.key_ptr.*.entry.blocks; - de.key_ptr.*.entry.size +|= entry.key_ptr.*.entry.size; + de.key_ptr.*.entry.pack.blocks +|= entry.key_ptr.*.entry.pack.blocks; + de.key_ptr.*.entry.size +|= entry.key_ptr.*.entry.size; if (de.value_ptr.* < nlink) { - de.key_ptr.*.shared_blocks +|= entry.key_ptr.*.entry.blocks; + de.key_ptr.*.shared_blocks +|= entry.key_ptr.*.entry.pack.blocks; de.key_ptr.*.shared_size +|= entry.key_ptr.*.entry.size; } } } else { while (dir_iter.next()) |de| { - de.key_ptr.*.entry.blocks -|= entry.key_ptr.*.entry.blocks; - de.key_ptr.*.entry.size -|= entry.key_ptr.*.entry.size; + de.key_ptr.*.entry.pack.blocks -|= entry.key_ptr.*.entry.pack.blocks; + de.key_ptr.*.entry.size -|= entry.key_ptr.*.entry.size; if (de.value_ptr.* < nlink) { - de.key_ptr.*.shared_blocks -|= entry.key_ptr.*.entry.blocks; + de.key_ptr.*.shared_blocks -|= entry.key_ptr.*.entry.pack.blocks; de.key_ptr.*.shared_size -|= entry.key_ptr.*.entry.size; } } @@ -458,7 +455,7 @@ pub var root: *Dir = undefined; test "entry" { var e = Entry.create(.file, false, "hello"); - try std.testing.expectEqual(e.etype, .file); - try std.testing.expect(!e.isext); + try std.testing.expectEqual(e.pack.etype, .file); + try std.testing.expect(!e.pack.isext); try std.testing.expectEqualStrings(e.name(), "hello"); } diff --git a/src/scan.zig b/src/scan.zig index 74c2ae527c0924460916f48b76880d5d6334b6a0..142857c7475c155317e647ceb0564124b2ba952b 100644 --- a/src/scan.zig +++ b/src/scan.zig @@ -156,11 +156,11 @@ const ScanDir = struct { // in-place conversion to a File entry. That's more efficient, // but also more code. I don't expect this to happen often. var e = entry.key_ptr.*.?; - if (e.etype == .file) { - if (e.size > 0 or e.blocks > 0) { + if (e.pack.etype == .file) { + if (e.size > 0 or e.pack.blocks > 0) { e.delStats(self.dir); e.size = 0; - e.blocks = 0; + e.pack.blocks = 0; e.addStats(self.dir, 0); } e.file().?.resetFlags(); @@ -177,9 +177,9 @@ const ScanDir = struct { var f = e.file().?; switch (t) { .err => e.setErr(self.dir), - .other_fs => f.other_fs = true, - .kernfs => f.kernfs = true, - .excluded => f.excluded = true, + .other_fs => f.pack.other_fs = true, + .kernfs => f.pack.kernfs = true, + .excluded => f.pack.excluded = true, } } @@ -192,9 +192,9 @@ const ScanDir = struct { // XXX: In-place conversion may also be possible here. var e = entry.key_ptr.*.?; // changes of dev/ino affect hard link counting in a way we can't simply merge. - const samedev = if (e.dir()) |d| d.dev == model.devices.getId(stat.dev) else true; + const samedev = if (e.dir()) |d| d.pack.dev == model.devices.getId(stat.dev) else true; const sameino = if (e.link()) |l| l.ino == stat.ino else true; - if (e.etype == etype and samedev and sameino) { + if (e.pack.etype == etype and samedev and sameino) { _ = self.entries.removeAdapted(@as(?*model.Entry,null), HashContext{ .cmp = name }); break :blk e; } else e.delStatsRec(self.dir); @@ -209,18 +209,18 @@ const ScanDir = struct { // entire subtree, which, in turn, would break all shared hardlink // sizes. The current approach may result in incorrect sizes after // refresh, but I expect the difference to be fairly minor. - if (!(e.etype == .dir and e.counted) and (e.blocks != stat.blocks or e.size != stat.size)) { + if (!(e.pack.etype == .dir and e.pack.counted) and (e.pack.blocks != stat.blocks or e.size != stat.size)) { e.delStats(self.dir); - e.blocks = stat.blocks; + e.pack.blocks = stat.blocks; e.size = stat.size; } if (e.dir()) |d| { d.parent = self.dir; - d.dev = model.devices.getId(stat.dev); + d.pack.dev = model.devices.getId(stat.dev); } if (e.file()) |f| { f.resetFlags(); - f.notreg = !stat.dir and !stat.reg; + f.pack.notreg = !stat.dir and !stat.reg; } if (e.link()) |l| l.ino = stat.ino; if (e.ext()) |ext| { @@ -415,11 +415,11 @@ const Context = struct { var e = if (p.items.len == 0) blk: { // Root entry var e = model.Entry.create(.dir, main.config.extended, self.name); - e.blocks = self.stat.blocks; + e.pack.blocks = self.stat.blocks; e.size = self.stat.size; if (e.ext()) |ext| ext.* = self.stat.ext; model.root = e.dir().?; - model.root.dev = model.devices.getId(self.stat.dev); + model.root.pack.dev = model.devices.getId(self.stat.dev); break :blk e; } else p.items[p.items.len-1].addStat(self.name, &self.stat); @@ -552,7 +552,7 @@ pub fn setupRefresh(parent: *model.Dir) void { parent.fmtPath(true, &full_path); active_context.pushPath(full_path.items); active_context.stat.dir = true; - active_context.stat.dev = model.devices.list.items[parent.dev]; + active_context.stat.dev = model.devices.list.items[parent.pack.dev]; } // To be called after setupRefresh() (or from scanRoot()) @@ -1021,7 +1021,7 @@ fn drawBox() void { box.move(2, 30); ui.addstr("size: "); // TODO: Should display the size of the dir-to-be-refreshed on refreshing, not the root. - ui.addsize(.default, util.blocksToSize(model.root.entry.blocks +| model.inodes.total_blocks)); + ui.addsize(.default, util.blocksToSize(model.root.entry.pack.blocks +| model.inodes.total_blocks)); } box.move(3, 2); @@ -1088,7 +1088,7 @@ pub fn draw() void { .{ ui.shorten(active_context.pathZ(), 63), active_context.items_seen } ) catch return; } else { - const r = ui.FmtSize.fmt(util.blocksToSize(model.root.entry.blocks)); + const r = ui.FmtSize.fmt(util.blocksToSize(model.root.entry.pack.blocks)); line = std.fmt.bufPrint(&buf, "\x1b7\x1b[J{s: <51} {d:>9} files / {s}{s}\x1b8", .{ ui.shorten(active_context.pathZ(), 51), active_context.items_seen, r.num(), r.unit } ) catch return;