Skip to content

Commit d52f9b7

Browse files
moosichusqueek502
authored andcommitted
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 <[email protected]>
1 parent c96f9a0 commit d52f9b7

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

lib/std/os/windows.zig

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,16 +1291,33 @@ pub fn GetFinalPathNameByHandle(
12911291
},
12921292
.Dos => {
12931293
// parse the string to separate volume path from file path
1294-
const expected_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");
1295-
1296-
// TODO find out if a path can start with something besides `\Device\<volume name>`,
1297-
// and if we need to handle it differently
1298-
// (i.e. how to determine the start and end of the volume name in that case)
1299-
if (!mem.eql(u16, expected_prefix, final_path[0..expected_prefix.len])) return error.Unexpected;
1294+
const device_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");
1295+
1296+
// We aren't entirely sure of the structure of the path returned by
1297+
// QueryObjectName in all contexts/environments.
1298+
// This code is written to cover the various cases that have
1299+
// been encountered and solved appropriately. But note that there's
1300+
// no easy way to verify that they have all been tackled!
1301+
// (Unless you, the reader knows of one then please do action that!)
1302+
if (!mem.eql(u16, device_prefix, final_path[0..device_prefix.len])) {
1303+
// Wine seems to return NT namespaced paths from QueryObjectName
1304+
// (e.g. `\??\Z:\some\path\to\a\file.txt`), in which case we can just strip the
1305+
// prefix to turn it into an absolute paths
1306+
const namespace_prefix = getNamespacePrefix(u16, final_path);
1307+
if (namespace_prefix == .nt) {
1308+
const unprefixed_path = final_path[NamespacePrefix.len..];
1309+
// TODO: Handle other possible path types, only drive absolute has been observed so far
1310+
if (getUnprefixedPathType(u16, unprefixed_path) != .drive_absolute) {
1311+
return error.Unexpected;
1312+
}
1313+
return unprefixed_path;
1314+
}
1315+
return error.Unexpected;
1316+
}
13001317

1301-
const file_path_begin_index = mem.indexOfPos(u16, final_path, expected_prefix.len, &[_]u16{'\\'}) orelse unreachable;
1318+
const file_path_begin_index = mem.indexOfPos(u16, final_path, device_prefix.len, &[_]u16{'\\'}) orelse unreachable;
13021319
const volume_name_u16 = final_path[0..file_path_begin_index];
1303-
const device_name_u16 = volume_name_u16[expected_prefix.len..];
1320+
const device_name_u16 = volume_name_u16[device_prefix.len..];
13041321
const file_name_u16 = final_path[file_path_begin_index..];
13051322

13061323
// MUP is Multiple UNC Provider, and indicates that the path is a UNC
@@ -2558,6 +2575,9 @@ pub const NamespacePrefix = enum {
25582575
fake_verbatim,
25592576
/// `\??\`
25602577
nt,
2578+
2579+
// The length of all the prefixes (except `none`)
2580+
pub const len: usize = 4;
25612581
};
25622582

25632583
/// If `T` is `u16`, then `path` should be encoded as WTF-16LE.

0 commit comments

Comments
 (0)