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.
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)

View file

@ -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,8 +231,7 @@ const ScanDir = struct {
}
fn final(self: *Self) void {
if (self.entries.count() == 0) // optimization for the common case
return;
if (self.entries.count() > 0) {
var it = &self.dir.sub;
while (it.*) |e| {
if (self.entries.contains(e)) {
@ -242,6 +241,8 @@ const ScanDir = struct {
it = &e.next;
}
}
self.dir.updateSubErr();
}
fn deinit(self: *Self) void {
self.entries.deinit();
@ -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 };