summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/pane.zig23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index 30530c3b..de7f7cd4 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -845,6 +845,9 @@ fn nameFault(name: []const u8) ?[]const u8 {
}
if (name[0] == ' ') return e_name_char ++ ": a blank at its start";
if (name[name.len - 1] == ' ') return e_name_char ++ ": a blank at its end";
+ // No file system takes a longer one (NAME_MAX): a Save would only fail.
+ var parts = std.mem.splitScalar(u8, name, '/');
+ while (parts.next()) |part| if (part.len > 255) return "invalid file name: a component over 255 bytes";
return null;
}
@@ -1364,6 +1367,26 @@ test "a write of two lines to name is refused EINVAL, on a held open or not" {
try testing.expectEqualStrings("/tmp/pardes-a", nameOf(p, p.panes[p.paneBySerial(serial).?].?));
}
+test "a name with a component over 255 bytes is refused, and a long path's failed Save keeps its reason" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const refused = wr(p, Node.of(serial, .name), "/tmp/" ++ "c" ** 256 ++ "/f.txt\n");
+ try testing.expectEqual(E.INVAL, refused.errno());
+ try testing.expectEqualStrings("invalid file name: a component over 255 bytes", refused.reply.ename);
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .name), "/tmp/" ++ "c" ** 255 ++ "\n").reply.status);
+ // A Save of a 3000-byte path the host refuses: the waiting write's
+ // reason is at the end, the path giving up its middle.
+ const long = "/nonexistent-pardes-root/" ++ ("d" ** 200 ++ "/") ** 15 ++ "f.txt";
+ const id = p.paneBySerial(serial).?;
+ try nameBuffer(p, id, long, false);
+ p.fs.late_failure_len = 0;
+ p.saveFailed(@intCast(id), long, error.AccessDenied);
+ const late = p.fs.late_failure[0..p.fs.late_failure_len];
+ try testing.expect(std.mem.startsWith(u8, late, "Save /nonexistent-pardes-root/"));
+ try testing.expect(std.mem.endsWith(u8, late, "/f.txt: no such directory"));
+}
+
test "a name cut across writes is one name, applied once at its newline or its close" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();