authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2024-02-29 15:54:46-08:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2024-02-29 16:12:24-08:00
loge233971e4fe19953ce8af63860a0791f5ca1268e
treef101253289a65aa2fa19ebe305e915daa2775171
parent147beec7da5f3eb3a858037b806ad8b1b66bfffc

Fix symLink's handling of `/` path separators on Windows

Symlink targets require canonicalized path separators on Windows

2 files changed, 23 insertions(+), 0 deletions(-)

lib/std/fs/Dir.zig+10
...@@ -1705,6 +1705,15 @@ pub fn symLink(...@@ -1705,6 +1705,15 @@ pub fn symLink(
1705 var target_path_w: std.os.windows.PathSpace = undefined;1705 var target_path_w: std.os.windows.PathSpace = undefined;
1706 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);1706 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
1707 target_path_w.data[target_path_w.len] = 0;1707 target_path_w.data[target_path_w.len] = 0;
1708 // However, we need to canonicalize any path separators to `\`, since if
1709 // the target path is relative, then it must use `\` as the path separator.
1710 mem.replaceScalar(
1711 u16,
1712 target_path_w.data[0..target_path_w.len],
1713 mem.nativeToLittle(u16, '/'),
1714 mem.nativeToLittle(u16, '\\'),
1715 );
1716
1708 const sym_link_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sym_link_path);1717 const sym_link_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sym_link_path);
1709 return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);1718 return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
1710 }1719 }
...@@ -1744,6 +1753,7 @@ pub fn symLinkW(...@@ -1744,6 +1753,7 @@ pub fn symLinkW(
1744 self: Dir,1753 self: Dir,
1745 /// WTF-16, does not need to be NT-prefixed. The NT-prefixing1754 /// WTF-16, does not need to be NT-prefixed. The NT-prefixing
1746 /// of this path is handled by CreateSymbolicLink.1755 /// of this path is handled by CreateSymbolicLink.
1756 /// Any path separators must be `\`, not `/`.
1747 target_path_w: [:0]const u16,1757 target_path_w: [:0]const u16,
1748 /// WTF-16, must be NT-prefixed or relative1758 /// WTF-16, must be NT-prefixed or relative
1749 sym_link_path_w: []const u16,1759 sym_link_path_w: []const u16,
lib/std/fs/test.zig+13
...@@ -178,6 +178,19 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void...@@ -178,6 +178,19 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void
178 try testing.expectEqualStrings(target_path, given);178 try testing.expectEqualStrings(target_path, given);
179}179}
180180
181test "Dir.symLink with relative target that has a / path separator" {
182 var tmp = testing.tmpDir(.{});
183 defer tmp.cleanup();
184
185 try tmp.dir.makePath("a");
186 try tmp.dir.writeFile("a/file", "");
187 try tmp.dir.symLink("a/file", "symlink", .{});
188
189 const stat = try tmp.dir.statFile("symlink");
190 // statFile follows symlinks
191 try testing.expectEqual(File.Kind.file, stat.kind);
192}
193
181test "File.stat on a File that is a symlink returns Kind.sym_link" {194test "File.stat on a File that is a symlink returns Kind.sym_link" {
182 // This test requires getting a file descriptor of a symlink which195 // This test requires getting a file descriptor of a symlink which
183 // is not possible on all targets196 // is not possible on all targets