Update parent dir suberr on refresh

Fixes #233
This commit is contained in:
Yorhel 2023-12-05 12:03:39 +01:00
parent c83159f076
commit a2eb84e7d3
2 changed files with 37 additions and 22 deletions

View file

@ -109,16 +109,11 @@ pub const Entry = extern struct {
}; };
} }
// Set the 'err' flag on Dirs and Files, propagating 'suberr' to parents. fn hasErr(self: *Self) bool {
pub fn setErr(self: *Self, parent: *Dir) void { return
if (self.dir()) |d| d.pack.err = true if (self.file()) |f| f.pack.err
else if (self.file()) |f| f.pack.err = true else if (self.dir()) |d| d.pack.err or d.pack.suberr
else unreachable; else false;
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;
}
} }
pub fn addStats(self: *Entry, parent: *Dir, nlink: u31) void { pub fn addStats(self: *Entry, parent: *Dir, nlink: u31) void {
@ -265,6 +260,19 @@ pub const Dir = extern struct {
i -= 1; 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) // File that's been hardlinked (i.e. nlink > 1)

View file

@ -176,7 +176,7 @@ const ScanDir = struct {
}; };
var f = e.file().?; var f = e.file().?;
switch (t) { switch (t) {
.err => e.setErr(self.dir), .err => f.pack.err = true,
.other_fs => f.pack.other_fs = true, .other_fs => f.pack.other_fs = true,
.kernfs => f.pack.kernfs = true, .kernfs => f.pack.kernfs = true,
.excluded => f.pack.excluded = true, .excluded => f.pack.excluded = true,
@ -231,16 +231,17 @@ const ScanDir = struct {
} }
fn final(self: *Self) void { fn final(self: *Self) void {
if (self.entries.count() == 0) // optimization for the common case if (self.entries.count() > 0) {
return; var it = &self.dir.sub;
var it = &self.dir.sub; while (it.*) |e| {
while (it.*) |e| { if (self.entries.contains(e)) {
if (self.entries.contains(e)) { e.delStatsRec(self.dir);
e.delStatsRec(self.dir); it.* = e.next;
it.* = e.next; } else
} else it = &e.next;
it = &e.next; }
} }
self.dir.updateSubErr();
} }
fn deinit(self: *Self) void { fn deinit(self: *Self) void {
@ -261,6 +262,7 @@ const ScanDir = struct {
const Context = struct { const Context = struct {
// When scanning to RAM // When scanning to RAM
parents: ?std.ArrayList(ScanDir) = null, parents: ?std.ArrayList(ScanDir) = null,
refreshing: ?*model.Dir = null,
// When scanning to a file // When scanning to a file
wr: ?*Writer = null, wr: ?*Writer = null,
@ -300,7 +302,10 @@ const Context = struct {
fn initMem(dir: ?*model.Dir) *Self { fn initMem(dir: ?*model.Dir) *Self {
var self = main.allocator.create(Self) catch unreachable; 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; if (dir) |d| self.parents.?.append(ScanDir.init(d)) catch unreachable;
return self; return self;
} }
@ -311,6 +316,8 @@ const Context = struct {
defer counting_hardlinks = false; defer counting_hardlinks = false;
main.handleEvent(false, true); main.handleEvent(false, true);
model.inodes.addAllStats(); model.inodes.addAllStats();
var p = self.refreshing;
while (p) |d| : (p = d.parent) d.updateSubErr();
} }
if (self.wr) |wr| { if (self.wr) |wr| {
wr.writer().writeByte(']') catch |e| writeErr(e); 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. // 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) // (Such errors are silently ignored when exporting to a file, as the directory metadata has already been written)
fn setDirlistError(self: *Self) void { 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 }; const Special = enum { err, other_fs, kernfs, excluded };