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 {...@@ -643,10 +643,19 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
643 // symlink, not the path that the symlink points to. We want the path643 // symlink, not the path that the symlink points to. We want the path
644 // that the symlink points to, though, so we need to get the realpath.644 // that the symlink points to, though, so we need to get the realpath.
645 const pathname_w = try windows.wToPrefixedFileW(null, image_path_name);645 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) {
647 error.InvalidWtf8 => unreachable,649 error.InvalidWtf8 => unreachable,
648 else => |e| return e,650 else => |e| return e,
649 };651 };
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];
650 },659 },
651 else => @compileError("std.fs.selfExePath not supported for this target"),660 else => @compileError("std.fs.selfExePath not supported for this target"),
652 }661 }
lib/std/fs/Dir.zig+23-11
...@@ -1370,7 +1370,16 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError...@@ -1370,7 +1370,16 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError
1370 }1370 }
1371 if (native_os == .windows) {1371 if (native_os == .windows) {
1372 const pathname_w = try windows.sliceToPrefixedFileW(self.fd, pathname);1372 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];
1374 }1383 }
1375 const pathname_c = try posix.toPosixPath(pathname);1384 const pathname_c = try posix.toPosixPath(pathname);
1376 return self.realpathZ(&pathname_c, out_buffer);1385 return self.realpathZ(&pathname_c, out_buffer);
...@@ -1381,7 +1390,16 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError...@@ -1381,7 +1390,16 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError
1381pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 {1390pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 {
1382 if (native_os == .windows) {1391 if (native_os == .windows) {
1383 const pathname_w = try windows.cStrToPrefixedFileW(self.fd, pathname);1392 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];
1385 }1403 }
13861404
1387 var flags: posix.O = .{};1405 var flags: posix.O = .{};
...@@ -1411,9 +1429,9 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE...@@ -1411,9 +1429,9 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE
1411}1429}
14121430
1413/// Windows-only. Same as `Dir.realpath` except `pathname` is WTF16 LE encoded.1431/// 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.
1415/// See also `Dir.realpath`, `realpathW`.1433/// 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 {
1417 const w = windows;1435 const w = windows;
14181436
1419 const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;1437 const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
...@@ -1434,13 +1452,7 @@ pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathErr...@@ -1434,13 +1452,7 @@ pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathErr
1434 };1452 };
1435 defer w.CloseHandle(h_file);1453 defer w.CloseHandle(h_file);
14361454
1437 var wide_buf: [w.PATH_MAX_WIDE]u16 = undefined;1455 return w.GetFinalPathNameByHandle(h_file, .{}, out_buffer);
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];
1444}1456}
14451457
1446pub const RealPathAllocError = RealPathError || Allocator.Error;1458pub const RealPathAllocError = RealPathError || Allocator.Error;
lib/std/posix.zig+15-26
...@@ -5676,7 +5676,12 @@ pub const RealPathError = error{...@@ -5676,7 +5676,12 @@ pub const RealPathError = error{
5676pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {5676pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {
5677 if (native_os == .windows) {5677 if (native_os == .windows) {
5678 const pathname_w = try windows.sliceToPrefixedFileW(null, pathname);5678 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];
5680 } else if (native_os == .wasi and !builtin.link_libc) {5685 } else if (native_os == .wasi and !builtin.link_libc) {
5681 @compileError("WASI does not support os.realpath");5686 @compileError("WASI does not support os.realpath");
5682 }5687 }
...@@ -5690,7 +5695,12 @@ pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathE...@@ -5690,7 +5695,12 @@ pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathE
5690pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {5695pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {
5691 if (native_os == .windows) {5696 if (native_os == .windows) {
5692 const pathname_w = try windows.cStrToPrefixedFileW(null, pathname);5697 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];
5694 } else if (native_os == .wasi and !builtin.link_libc) {5704 } else if (native_os == .wasi and !builtin.link_libc) {
5695 return realpath(mem.sliceTo(pathname, 0), out_buffer);5705 return realpath(mem.sliceTo(pathname, 0), out_buffer);
5696 }5706 }
...@@ -5736,32 +5746,11 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealP...@@ -5736,32 +5746,11 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealP
57365746
5737/// Same as `realpath` except `pathname` is WTF16LE-encoded.5747/// Same as `realpath` except `pathname` is WTF16LE-encoded.
5738///5748///
5739/// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).5749/// The result is encoded as WTF16LE.
5740///5750///
5741/// Calling this function is usually a bug.5751/// Calling this function is usually a bug.
5742pub fn realpathW(pathname: []const u16, out_buffer: *[max_path_bytes]u8) RealPathError![]u8 {5752pub fn realpathW(pathname: []const u16, out_buffer: *[max_path_bytes]u16) RealPathError![]u16 {
5743 const w = windows;5753 return fs.cwd().realpathW(pathname, out_buffer);
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);
5765}5754}
57665755
5767/// Spurious wakeups are possible and no precision of timing is guaranteed.5756/// Spurious wakeups are possible and no precision of timing is guaranteed.