authorgravatar for michael@pfaff.devMichael Pfaff <michael@pfaff.dev> 2025-04-26 09:05:26-04:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-10-08 17:07:38-07:00
logf2227ae6776112f952f7db1c0a0eb2a0a27cf576
tree3d6ce48d8015bd19a541e7a4d289507367fbda1e
parent328ae41468f3514251ac1b0726c41eca9fbc3fb5

Return WTF16LE encoded path from realpathW


3 files changed, 48 insertions(+), 38 deletions(-)

lib/std/fs.zig+10-1
......@@ -643,10 +643,19 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
643643 // symlink, not the path that the symlink points to. We want the path
644644 // that the symlink points to, though, so we need to get the realpath.
645645 const pathname_w = try windows.wToPrefixedFileW(null, image_path_name);
646 return std.fs.cwd().realpathW(pathname_w.span(), out_buffer) catch |err| switch (err) {
646
647 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
648 const wide_slice = std.fs.cwd().realpathW(pathname_w.span(), &wide_buf) catch |err| switch (err) {
647649 error.InvalidWtf8 => unreachable,
648650 else => |e| return e,
649651 };
652
653 const len = std.unicode.calcWtf8Len(wide_slice);
654 if (len > out_buffer.len)
655 return error.NameTooLong;
656
657 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
658 return out_buffer[0..end_index];
650659 },
651660 else => @compileError("std.fs.selfExePath not supported for this target"),
652661 }
lib/std/fs/Dir.zig+23-11
......@@ -1370,7 +1370,16 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError
13701370 }
13711371 if (native_os == .windows) {
13721372 const pathname_w = try windows.sliceToPrefixedFileW(self.fd, pathname);
1373 return self.realpathW(pathname_w.span(), out_buffer);
1373
1374 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
1375 const wide_slice = try self.realpathW(pathname_w.span(), &wide_buf);
1376
1377 const len = std.unicode.calcWtf8Len(wide_slice);
1378 if (len > out_buffer.len)
1379 return error.NameTooLong;
1380
1381 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
1382 return out_buffer[0..end_index];
13741383 }
13751384 const pathname_c = try posix.toPosixPath(pathname);
13761385 return self.realpathZ(&pathname_c, out_buffer);
......@@ -1381,7 +1390,16 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError
13811390pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 {
13821391 if (native_os == .windows) {
13831392 const pathname_w = try windows.cStrToPrefixedFileW(self.fd, pathname);
1384 return self.realpathW(pathname_w.span(), out_buffer);
1393
1394 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
1395 const wide_slice = try self.realpathW(pathname_w.span(), &wide_buf);
1396
1397 const len = std.unicode.calcWtf8Len(wide_slice);
1398 if (len > out_buffer.len)
1399 return error.NameTooLong;
1400
1401 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
1402 return out_buffer[0..end_index];
13851403 }
13861404
13871405 var flags: posix.O = .{};
......@@ -1411,9 +1429,9 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE
14111429}
14121430
14131431/// Windows-only. Same as `Dir.realpath` except `pathname` is WTF16 LE encoded.
1414/// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
1432/// The result is encoded as WTF16 LE.
14151433/// See also `Dir.realpath`, `realpathW`.
1416pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathError![]u8 {
1434pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u16) RealPathError![]u16 {
14171435 const w = windows;
14181436
14191437 const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
......@@ -1434,13 +1452,7 @@ pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathErr
14341452 };
14351453 defer w.CloseHandle(h_file);
14361454
1437 var wide_buf: [w.PATH_MAX_WIDE]u16 = undefined;
1438 const wide_slice = try w.GetFinalPathNameByHandle(h_file, .{}, &wide_buf);
1439 const len = std.unicode.calcWtf8Len(wide_slice);
1440 if (len > out_buffer.len)
1441 return error.NameTooLong;
1442 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
1443 return out_buffer[0..end_index];
1455 return w.GetFinalPathNameByHandle(h_file, .{}, out_buffer);
14441456}
14451457
14461458pub const RealPathAllocError = RealPathError || Allocator.Error;
lib/std/posix.zig+15-26
......@@ -5676,7 +5676,12 @@ pub const RealPathError = error{
56765676pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {
56775677 if (native_os == .windows) {
56785678 const pathname_w = try windows.sliceToPrefixedFileW(null, pathname);
5679 return realpathW(pathname_w.span(), out_buffer);
5679
5680 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
5681 const wide_slice = try realpathW(pathname_w.span(), &wide_buf);
5682
5683 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
5684 return out_buffer[0..end_index];
56805685 } else if (native_os == .wasi and !builtin.link_libc) {
56815686 @compileError("WASI does not support os.realpath");
56825687 }
......@@ -5690,7 +5695,12 @@ pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathE
56905695pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {
56915696 if (native_os == .windows) {
56925697 const pathname_w = try windows.cStrToPrefixedFileW(null, pathname);
5693 return realpathW(pathname_w.span(), out_buffer);
5698
5699 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
5700 const wide_slice = try realpathW(pathname_w.span(), &wide_buf);
5701
5702 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
5703 return out_buffer[0..end_index];
56945704 } else if (native_os == .wasi and !builtin.link_libc) {
56955705 return realpath(mem.sliceTo(pathname, 0), out_buffer);
56965706 }
......@@ -5736,32 +5746,11 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealP
57365746
57375747/// Same as `realpath` except `pathname` is WTF16LE-encoded.
57385748///
5739/// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
5749/// The result is encoded as WTF16LE.
57405750///
57415751/// Calling this function is usually a bug.
5742pub fn realpathW(pathname: []const u16, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {
5743 const w = windows;
5744
5745 const dir = fs.cwd().fd;
5746 const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
5747 const share_access = w.FILE_SHARE_READ | w.FILE_SHARE_WRITE | w.FILE_SHARE_DELETE;
5748 const creation = w.FILE_OPEN;
5749 const h_file = blk: {
5750 const res = w.OpenFile(pathname, .{
5751 .dir = dir,
5752 .access_mask = access_mask,
5753 .share_access = share_access,
5754 .creation = creation,
5755 .filter = .any,
5756 }) catch |err| switch (err) {
5757 error.WouldBlock => unreachable,
5758 else => |e| return e,
5759 };
5760 break :blk res;
5761 };
5762 defer w.CloseHandle(h_file);
5763
5764 return std.os.getFdPath(h_file, out_buffer);
5752pub fn realpathW(pathname: []const u16, out_buffer: *[max_path_bytes]u16) RealPathError![]u16 {
5753 return fs.cwd().realpathW(pathname, out_buffer);
57655754}
57665755
57675756/// Spurious wakeups are possible and no precision of timing is guaranteed.