authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-18 07:38:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:50-07:00
log21e195a1a96100cd5bcd47b6d9565b2141ad13e1
tree30ab776c789eddd447b0a02190d15795734240d5
parent2d7d98da0cd54e9dc12c5d4f97cdf2e7dac36446

std: move some windows path checking logic


4 files changed, 12 insertions(+), 29 deletions(-)

lib/std/fs/Dir.zig+1-1
...@@ -1575,7 +1575,7 @@ pub fn symLink(...@@ -1575,7 +1575,7 @@ pub fn symLink(
1575 // when converting to an NT namespaced path. CreateSymbolicLink in1575 // when converting to an NT namespaced path. CreateSymbolicLink in
1576 // symLinkW will handle the necessary conversion.1576 // symLinkW will handle the necessary conversion.
1577 var target_path_w: windows.PathSpace = undefined;1577 var target_path_w: windows.PathSpace = undefined;
1578 try std.unicode.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data);1578 try windows.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data);
1579 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);1579 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
1580 target_path_w.data[target_path_w.len] = 0;1580 target_path_w.data[target_path_w.len] = 0;
1581 // However, we need to canonicalize any path separators to `\`, since if1581 // However, we need to canonicalize any path separators to `\`, since if
lib/std/os/windows.zig+9
...@@ -5739,3 +5739,12 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {...@@ -5739,3 +5739,12 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
5739 const ppeb: *const PEB = @ptrCast(@alignCast(peb_out.ptr));5739 const ppeb: *const PEB = @ptrCast(@alignCast(peb_out.ptr));
5740 return ppeb.ImageBaseAddress;5740 return ppeb.ImageBaseAddress;
5741}5741}
5742
5743pub fn checkWtf8ToWtf16LeOverflow(wtf8: []const u8, wtf16le: []const u16) error{ BadPathName, NameTooLong }!void {
5744 // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE.
5745 if (wtf16le.len >= wtf8.len) return;
5746 const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch
5747 return error.BadPathName;
5748 if (utf16_len > wtf16le.len)
5749 return error.NameTooLong;
5750}
lib/std/posix.zig+2-2
...@@ -2918,7 +2918,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {...@@ -2918,7 +2918,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
2918 @compileError("WASI does not support os.chdir");2918 @compileError("WASI does not support os.chdir");
2919 } else if (native_os == .windows) {2919 } else if (native_os == .windows) {
2920 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;2920 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
2921 try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path);2921 try windows.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path);
2922 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);2922 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);
2923 return chdirW(wtf16_dir_path[0..len]);2923 return chdirW(wtf16_dir_path[0..len]);
2924 } else {2924 } else {
...@@ -2935,7 +2935,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {...@@ -2935,7 +2935,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {
2935 if (native_os == .windows) {2935 if (native_os == .windows) {
2936 const dir_path_span = mem.span(dir_path);2936 const dir_path_span = mem.span(dir_path);
2937 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;2937 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
2938 try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path);2938 try windows.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path);
2939 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);2939 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);
2940 return chdirW(wtf16_dir_path[0..len]);2940 return chdirW(wtf16_dir_path[0..len]);
2941 } else if (native_os == .wasi and !builtin.link_libc) {2941 } else if (native_os == .wasi and !builtin.link_libc) {
lib/std/unicode.zig-26
...@@ -1809,31 +1809,6 @@ pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{InvalidWtf8}!usize...@@ -1809,31 +1809,6 @@ pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{InvalidWtf8}!usize
1809 return utf8ToUtf16LeImpl(wtf16le, wtf8, .can_encode_surrogate_half);1809 return utf8ToUtf16LeImpl(wtf16le, wtf8, .can_encode_surrogate_half);
1810}1810}
18111811
1812fn checkUtf8ToUtf16LeOverflowImpl(utf8: []const u8, utf16le: []const u16, comptime surrogates: Surrogates) !void {
1813 // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE.
1814 if (utf16le.len >= utf8.len) return;
1815 const utf16_len = calcUtf16LeLenImpl(utf8, surrogates) catch {
1816 return switch (surrogates) {
1817 .cannot_encode_surrogate_half => error.InvalidUtf8,
1818 .can_encode_surrogate_half => error.InvalidWtf8,
1819 };
1820 };
1821 if (utf16_len > utf16le.len)
1822 return error.NameTooLong;
1823}
1824
1825/// Checks if calling `utf8ToUtf16Le` would overflow. Might fail if utf8 is not
1826/// valid UTF-8.
1827pub fn checkUtf8ToUtf16LeOverflow(utf8: []const u8, utf16le: []const u16) error{ InvalidUtf8, NameTooLong }!void {
1828 return checkUtf8ToUtf16LeOverflowImpl(utf8, utf16le, .cannot_encode_surrogate_half);
1829}
1830
1831/// Checks if calling `utf8ToUtf16Le` would overflow. Might fail if wtf8 is not
1832/// valid WTF-8.
1833pub fn checkWtf8ToWtf16LeOverflow(wtf8: []const u8, wtf16le: []const u16) error{ InvalidWtf8, NameTooLong }!void {
1834 return checkUtf8ToUtf16LeOverflowImpl(wtf8, wtf16le, .can_encode_surrogate_half);
1835}
1836
1837/// Surrogate codepoints (U+D800 to U+DFFF) are replaced by the Unicode replacement1812/// Surrogate codepoints (U+D800 to U+DFFF) are replaced by the Unicode replacement
1838/// character (U+FFFD).1813/// character (U+FFFD).
1839/// All surrogate codepoints and the replacement character are encoded as three1814/// All surrogate codepoints and the replacement character are encoded as three
...@@ -2040,7 +2015,6 @@ fn testRoundtripWtf8(wtf8: []const u8) !void {...@@ -2040,7 +2015,6 @@ fn testRoundtripWtf8(wtf8: []const u8) !void {
2040 var wtf16_buf: [32]u16 = undefined;2015 var wtf16_buf: [32]u16 = undefined;
2041 const wtf16_len = try wtf8ToWtf16Le(&wtf16_buf, wtf8);2016 const wtf16_len = try wtf8ToWtf16Le(&wtf16_buf, wtf8);
2042 try testing.expectEqual(wtf16_len, calcWtf16LeLen(wtf8));2017 try testing.expectEqual(wtf16_len, calcWtf16LeLen(wtf8));
2043 try checkWtf8ToWtf16LeOverflow(wtf8, &wtf16_buf);
2044 const wtf16 = wtf16_buf[0..wtf16_len];2018 const wtf16 = wtf16_buf[0..wtf16_len];
20452019
2046 var roundtripped_buf: [32]u8 = undefined;2020 var roundtripped_buf: [32]u8 = undefined;