diff --git a/src/model.zig b/src/model.zig index aadac4f..feb589a 100644 --- a/src/model.zig +++ b/src/model.zig @@ -109,16 +109,11 @@ pub const Entry = extern 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.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.pack.suberr) break; - p.pack.suberr = true; - } + fn hasErr(self: *Self) bool { + return + if (self.file()) |f| f.pack.err + else if (self.dir()) |d| d.pack.err or d.pack.suberr + else false; } pub fn addStats(self: *Entry, parent: *Dir, nlink: u31) void { @@ -265,6 +260,19 @@ pub const Dir = extern struct { i -= 1; } } + + // Only updates the suberr of this Dir, assumes child dirs have already + // been updated and does not propagate to parents. + pub fn updateSubErr(self: *@This()) void { + self.pack.suberr = false; + var sub = self.sub; + while (sub) |e| : (sub = e.next) { + if (e.hasErr()) { + self.pack.suberr = true; + break; + } + } + } }; // File that's been hardlinked (i.e. nlink > 1) diff --git a/src/scan.zig b/src/scan.zig index 40e94bd..4608a4f 100644 --- a/src/scan.zig +++ b/src/scan.zig @@ -176,7 +176,7 @@ const ScanDir = struct { }; var f = e.file().?; switch (t) { - .err => e.setErr(self.dir), + .err => f.pack.err = true, .other_fs => f.pack.other_fs = true, .kernfs => f.pack.kernfs = true, .excluded => f.pack.excluded = true, @@ -231,16 +231,17 @@ const ScanDir = struct { } fn final(self: *Self) void { - if (self.entries.count() == 0) // optimization for the common case - return; - var it = &self.dir.sub; - while (it.*) |e| { - if (self.entries.contains(e)) { - e.delStatsRec(self.dir); - it.* = e.next; - } else - it = &e.next; + if (self.entries.count() > 0) { + var it = &self.dir.sub; + while (it.*) |e| { + if (self.entries.contains(e)) { + e.delStatsRec(self.dir); + it.* = e.next; + } else + it = &e.next; + } } + self.dir.updateSubErr(); } fn deinit(self: *Self) void { @@ -261,6 +262,7 @@ const ScanDir = struct { const Context = struct { // When scanning to RAM parents: ?std.ArrayList(ScanDir) = null, + refreshing: ?*model.Dir = null, // When scanning to a file wr: ?*Writer = null, @@ -300,7 +302,10 @@ const Context = struct { fn initMem(dir: ?*model.Dir) *Self { var self = main.allocator.create(Self) catch unreachable; - self.* = .{ .parents = std.ArrayList(ScanDir).init(main.allocator) }; + self.* = .{ + .parents = std.ArrayList(ScanDir).init(main.allocator), + .refreshing = dir, + }; if (dir) |d| self.parents.?.append(ScanDir.init(d)) catch unreachable; return self; } @@ -311,6 +316,8 @@ const Context = struct { defer counting_hardlinks = false; main.handleEvent(false, true); model.inodes.addAllStats(); + var p = self.refreshing; + while (p) |d| : (p = d.parent) d.updateSubErr(); } if (self.wr) |wr| { wr.writer().writeByte(']') catch |e| writeErr(e); @@ -353,7 +360,7 @@ const Context = struct { // Set a flag to indicate that there was an error listing file entries in the current directory. // (Such errors are silently ignored when exporting to a file, as the directory metadata has already been written) fn setDirlistError(self: *Self) void { - if (self.parents) |*p| p.items[p.items.len-1].dir.entry.setErr(p.items[p.items.len-1].dir); + if (self.parents) |*p| p.items[p.items.len-1].dir.pack.err = true; } const Special = enum { err, other_fs, kernfs, excluded };