authorgravatar for readcuttingt@gmail.comTom Read Cutting <readcuttingt@gmail.com> 2023-10-15 20:08:18+01:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-11-21 01:52:50-08:00
log689032d571ace146a78c5286125822dfd02970b2
treed25d7a8143fcf6abb339bf6164171423314262de
parent534370c4dede07c692ced0c5526a5370f233b4d3

Deal with NT paths in GetFinalPathNameByHandle

When calling QueryObjectName, NT namespaced paths can be returned. This change appropriately strips the prefix to turn it into an absolute path. (The above behaviour was observed at least in Wine so far) Co-authored-by: Ryan Liptak <squeek502@hotmail.com>

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

lib/std/os/windows.zig+19-8
...@@ -1298,16 +1298,27 @@ pub fn GetFinalPathNameByHandle(...@@ -1298,16 +1298,27 @@ pub fn GetFinalPathNameByHandle(
1298 },1298 },
1299 .Dos => {1299 .Dos => {
1300 // parse the string to separate volume path from file path1300 // parse the string to separate volume path from file path
1301 const expected_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");1301 const device_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");
13021302
1303 // TODO find out if a path can start with something besides `\Device\<volume name>`,1303 // We aren't entirely sure of the structure of the path returned by
1304 // and if we need to handle it differently1304 // QueryObjectName in all contexts/environments.
1305 // (i.e. how to determine the start and end of the volume name in that case)1305 // This code is written to cover the various cases that have
1306 if (!mem.eql(u16, expected_prefix, final_path[0..expected_prefix.len])) return error.Unexpected;1306 // been encountered and solved appropriately. But note that there's
1307 // no easy way to verify that they have all been tackled!
1308 // (Unless you, the reader knows of one then please do action that!)
1309 if (!mem.startsWith(u16, final_path, device_prefix)) {
1310 // Wine seems to return NT namespaced paths starting with \??\ from QueryObjectName
1311 // (e.g. `\??\Z:\some\path\to\a\file.txt`), in which case we can just strip the
1312 // prefix to turn it into an absolute path.
1313 return ntToWin32Namespace(final_path, out_buffer) catch |err| switch (err) {
1314 error.NotNtPath => return error.Unexpected,
1315 error.NameTooLong => |e| return e,
1316 };
1317 }
13071318
1308 const file_path_begin_index = mem.indexOfPos(u16, final_path, expected_prefix.len, &[_]u16{'\\'}) orelse unreachable;1319 const file_path_begin_index = mem.indexOfPos(u16, final_path, device_prefix.len, &[_]u16{'\\'}) orelse unreachable;
1309 const volume_name_u16 = final_path[0..file_path_begin_index];1320 const volume_name_u16 = final_path[0..file_path_begin_index];
1310 const device_name_u16 = volume_name_u16[expected_prefix.len..];1321 const device_name_u16 = volume_name_u16[device_prefix.len..];
1311 const file_name_u16 = final_path[file_path_begin_index..];1322 const file_name_u16 = final_path[file_path_begin_index..];
13121323
1313 // MUP is Multiple UNC Provider, and indicates that the path is a UNC1324 // MUP is Multiple UNC Provider, and indicates that the path is a UNC