Commit e233971e4f

Ryan Liptak <squeek502@hotmail.com>
2024-03-01 00:54:46
Fix symLink's handling of `/` path separators on Windows
Symlink targets require canonicalized path separators on Windows
1 parent 147beec
Changed files (2)
lib
lib/std/fs/Dir.zig
@@ -1705,6 +1705,15 @@ pub fn symLink(
         var target_path_w: std.os.windows.PathSpace = undefined;
         target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
         target_path_w.data[target_path_w.len] = 0;
+        // However, we need to canonicalize any path separators to `\`, since if
+        // the target path is relative, then it must use `\` as the path separator.
+        mem.replaceScalar(
+            u16,
+            target_path_w.data[0..target_path_w.len],
+            mem.nativeToLittle(u16, '/'),
+            mem.nativeToLittle(u16, '\\'),
+        );
+
         const sym_link_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sym_link_path);
         return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
     }
@@ -1744,6 +1753,7 @@ pub fn symLinkW(
     self: Dir,
     /// WTF-16, does not need to be NT-prefixed. The NT-prefixing
     /// of this path is handled by CreateSymbolicLink.
+    /// Any path separators must be `\`, not `/`.
     target_path_w: [:0]const u16,
     /// WTF-16, must be NT-prefixed or relative
     sym_link_path_w: []const u16,
lib/std/fs/test.zig
@@ -178,6 +178,19 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void
     try testing.expectEqualStrings(target_path, given);
 }
 
+test "Dir.symLink with relative target that has a / path separator" {
+    var tmp = testing.tmpDir(.{});
+    defer tmp.cleanup();
+
+    try tmp.dir.makePath("a");
+    try tmp.dir.writeFile("a/file", "");
+    try tmp.dir.symLink("a/file", "symlink", .{});
+
+    const stat = try tmp.dir.statFile("symlink");
+    // statFile follows symlinks
+    try testing.expectEqual(File.Kind.file, stat.kind);
+}
+
 test "File.stat on a File that is a symlink returns Kind.sym_link" {
     // This test requires getting a file descriptor of a symlink which
     // is not possible on all targets