authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-11-24 07:17:30-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-11-24 07:17:30-08:00
log289f2f0d3455d2bdefb84af84075602c53a730bd
tree8567386bb404156dfbbf0a432e7656fd6aa2f00b
parent66fe584eade01f5f71e565ba2fbf036436c4bf5a
parentd48faf1a3246c1b5c0f7de04233982f464796f1b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #17541 from moosichu/fix/wine-get-final-path-name-by-handle

Windows: Deal with NT namespaced paths in GetFinalPathNameByHandle

1 files changed, 21 insertions(+), 8 deletions(-)

lib/std/os/windows.zig+21-8
...@@ -1392,16 +1392,29 @@ pub fn GetFinalPathNameByHandle(...@@ -1392,16 +1392,29 @@ pub fn GetFinalPathNameByHandle(
1392 },1392 },
1393 .Dos => {1393 .Dos => {
1394 // parse the string to separate volume path from file path1394 // parse the string to separate volume path from file path
1395 const expected_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");1395 const device_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");
13961396
1397 // TODO find out if a path can start with something besides `\Device\<volume name>`,1397 // We aren't entirely sure of the structure of the path returned by
1398 // and if we need to handle it differently1398 // QueryObjectName in all contexts/environments.
1399 // (i.e. how to determine the start and end of the volume name in that case)1399 // This code is written to cover the various cases that have
1400 if (!mem.eql(u16, expected_prefix, final_path[0..expected_prefix.len])) return error.Unexpected;1400 // been encountered and solved appropriately. But note that there's
1401 // no easy way to verify that they have all been tackled!
1402 // (Unless you, the reader knows of one then please do action that!)
1403 if (!mem.startsWith(u16, final_path, device_prefix)) {
1404 // Wine seems to return NT namespaced paths starting with \??\ from QueryObjectName
1405 // (e.g. `\??\Z:\some\path\to\a\file.txt`), in which case we can just strip the
1406 // prefix to turn it into an absolute path.
1407 // https://github.com/ziglang/zig/issues/26029
1408 // https://bugs.winehq.org/show_bug.cgi?id=39569
1409 return ntToWin32Namespace(final_path, out_buffer) catch |err| switch (err) {
1410 error.NotNtPath => return error.Unexpected,
1411 error.NameTooLong => |e| return e,
1412 };
1413 }
14011414
1402 const file_path_begin_index = mem.indexOfPos(u16, final_path, expected_prefix.len, &[_]u16{'\\'}) orelse unreachable;1415 const file_path_begin_index = mem.indexOfPos(u16, final_path, device_prefix.len, &[_]u16{'\\'}) orelse unreachable;
1403 const volume_name_u16 = final_path[0..file_path_begin_index];1416 const volume_name_u16 = final_path[0..file_path_begin_index];
1404 const device_name_u16 = volume_name_u16[expected_prefix.len..];1417 const device_name_u16 = volume_name_u16[device_prefix.len..];
1405 const file_name_u16 = final_path[file_path_begin_index..];1418 const file_name_u16 = final_path[file_path_begin_index..];
14061419
1407 // MUP is Multiple UNC Provider, and indicates that the path is a UNC1420 // MUP is Multiple UNC Provider, and indicates that the path is a UNC