summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 23:13:57 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit90530f893236c665deb9f5bddc925ee1fe51cca5 (patch)
treef9fb5a34731eab09fddae5751d3cc8450c796853 /src/ninep
parent8b2a55f31169ede82e11a573ab655e72e7831fe7 (diff)
downloadpardes-90530f893236c665deb9f5bddc925ee1fe51cca5.tar.gz
pardes-90530f893236c665deb9f5bddc925ee1fe51cca5.zip
A failed Dump or a Restore of no dump fails its write, before any warning
A Dump into a DumpDir it could not write, or a Restore of a file that is not a dump, answered a ctl write with rc 0 and only a message, and the Restore warned about unsaved panes before it ever looked at the file. The hosts' dump write now fails the waiting 9P write with EIO (the late failure a Save uses), naming the path and the reason in the log, and Restore parses the file before its unsaved-panes refusal, failing with `not a pardes dump`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/ctl.zig27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index e62ff605..caf8914f 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1237,3 +1237,30 @@ test "a look after Newcol fills the empty column the keyboard is on" {
try testing.expectEqual(@as(usize, 1), p.col_n[p.ncol - 1]);
try testing.expectEqual(p.active, p.col_panes[p.ncol - 1][0]);
}
+
+test "a Restore of a file that is no dump fails the write before any warning, and a failed Dump fails its write" {
+ if (comptime !pardes.hosted) return error.SkipZigTest;
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const f = pane_files.fileOf(p.panes[0].?).?;
+ f.content = try p.gpa.realloc(f.content, 3);
+ @memcpy(f.content, "yy\n");
+ f.revision +%= 1; // unsaved: a Restore would warn about it first
+ var tmp = testing.tmpDir(.{});
+ defer tmp.cleanup();
+ try tmp.dir.writeFile(testing.io, .{ .sub_path = "notes.txt", .data = "just notes\n" });
+ var dir_buf: [4096]u8 = undefined;
+ const dir = dir_buf[0..try tmp.dir.realPath(testing.io, &dir_buf)];
+ var line_buf: [4200]u8 = undefined;
+ const line = try std.fmt.bufPrint(&line_buf, "Restore {s}/notes.txt\n", .{dir});
+ const root_ctl = @intFromEnum(tree.TopFile.ctl);
+ const refused = wr(p, root_ctl, line);
+ try testing.expectEqual(E.IO, refused.errno());
+ try testing.expect(std.mem.indexOf(u8, refused.reply.ename, "not a pardes dump") != null);
+ try testing.expect(p.restore_req == null);
+ try testing.expect(p.panes[0].?.discard_warned == null);
+
+ p.fs.late_failure_len = 0;
+ p.dumpFailed("/nowhere/pardes.dump.zon", error.FileNotFound);
+ try testing.expectEqualStrings("Dump /nowhere/pardes.dump.zon: FileNotFound", p.fs.late_failure[0..p.fs.late_failure_len]);
+}