windows.ReadLink: handle NOT_A_REPARSE_POINT and add test

This commit is contained in:
Ryan Liptak 2025-12-10 18:59:15 -08:00
parent ea7512084b
commit 36cb5ea5f4
2 changed files with 28 additions and 0 deletions

View file

@ -218,6 +218,32 @@ test "Dir.readLink" {
}.impl);
}
test "Dir.readLink on non-symlinks" {
try testWithAllSupportedPathTypes(struct {
fn impl(ctx: *TestContext) !void {
const file_path = try ctx.transformPath("file.txt");
try ctx.dir.writeFile(.{ .sub_path = file_path, .data = "nonsense" });
const dir_path = try ctx.transformPath("subdir");
try ctx.dir.makeDir(dir_path);
// file
var buffer: [fs.max_path_bytes]u8 = undefined;
try std.testing.expectError(error.NotLink, ctx.dir.readLink(file_path, &buffer));
if (builtin.os.tag == .windows) {
var file_path_w = try std.os.windows.sliceToPrefixedFileW(ctx.dir.fd, file_path);
try std.testing.expectError(error.NotLink, ctx.dir.readLinkW(file_path_w.span(), &file_path_w.data));
}
// dir
try std.testing.expectError(error.NotLink, ctx.dir.readLink(dir_path, &buffer));
if (builtin.os.tag == .windows) {
var dir_path_w = try std.os.windows.sliceToPrefixedFileW(ctx.dir.fd, dir_path);
try std.testing.expectError(error.NotLink, ctx.dir.readLinkW(dir_path_w.span(), &dir_path_w.data));
}
}
}.impl);
}
fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
var buffer: [fs.max_path_bytes]u8 = undefined;
const actual = try dir.readLink(symlink_path, buffer[0..]);

View file

@ -3125,6 +3125,7 @@ pub const ReadLinkError = error{
BadPathName,
AntivirusInterference,
UnsupportedReparsePointType,
NotLink,
};
/// `sub_path_w` will never be accessed after `out_buffer` has been written to, so it
@ -3155,6 +3156,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u16) ReadLi
const rc = DeviceIoControl(result_handle, FSCTL.GET_REPARSE_POINT, .{ .out = reparse_buf[0..] });
switch (rc) {
.SUCCESS => {},
.NOT_A_REPARSE_POINT => return error.NotLink,
else => return unexpectedStatus(rc),
}