-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Implement std.os.windows.GetPathNameByHandle using NT routines only #5993
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@andrewrk we can finally get rid of the
EDIT2: I've found a bug in my implementation and patched it up, so the CI should be green now on all platforms. In your hands @andrewrk and @daurnimator. |
This commit proposes an initial draft of `GetPathNameByHandle` function which wraps NT syscalls and strives to emulate (currently only partially) the `kernel32.GetFinalPathNameByHandleW` function.
Favour newer API which uses `NtQueryInformationFile` with class flags `FileNormalizedNameInformation` and `FileVolumeNameInformation` instead of lower-level `NtQueryObject`. `NtQueryObject` is still used as a fallback in case the former are unavailable.
a93b0cb
to
2f82d23
Compare
This commit reimagines `std.os.windows.GetFinalPathNameByHandle` using `DeviceIoControl` to query the OS mount manager for the DOS (symlink) paths for the given NT volume name. In particular, it uses `IOCTL_MOUNTMGR_QUERY_POINTS` ioctl opcode to query the manager for the available moount points.
2f82d23
to
bdda8fa
Compare
"incorrect alignment" is a safety check that is triggered for It's possible this PR has uncovered an unrelated bug. I'll dive in here and try to help figure out what's going on. |
Related: #5996
|
Oh I see it :) Looks like it was a True Positive: var path_buffer: [@sizeOf(FILE_NAME_INFORMATION) + PATH_MAX_WIDE * 2 + 2]u8 = undefined;
var volume_buffer: [MAX_PATH]u8 = undefined;
// ...
const file_name = @ptrCast(*const FILE_NAME_INFORMATION, @alignCast(@alignOf(FILE_NAME_INFORMATION), &path_buffer[0]));
const volume_name = @ptrCast(*const FILE_NAME_INFORMATION, @alignCast(@alignOf(FILE_NAME_INFORMATION), &volume_buffer[0])); Those var volume_buffer: [MAX_PATH]u8 align(@alignOf(FILE_NAME_INFORMATION)) = undefined; |
Oh nice one, thanks for looking into the issue here @andrewrk. I’ll make the necessary changes and run the release-safe tests again. |
All green now! Thanks again @andrewrk for an alignment fix! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kubkon nice work, merge at will
Agreed! To make sure we catch situations like these, a panic would be preferable here, so lemme tweak that! |
And some other minor refactors which address more review comments.
bb8b24f
to
73b9f65
Compare
Awesome suggestion, thanks! Incorporated in 73b9f65. |
Unless you've got more comments you'd like me to address @daurnimator, I'm gonna go ahead and merge this in when the CI is green. Let me know what you reckon! |
go for it! |
Random note: with this merged, it's no longer possible to build Zig on Windows 7.
I know Zig does not intend to support Windows 7, but before this, there wasn't anything Windows 8+ specific in the build process. Just ran into this error and thought it was worth noting. |
@squeek502 that was by design on my part. However, if there is a feeling we should have wider support with |
No worries; Zig is officially incompatible with Windows 7. Just thought I'd make a note of where it actually stopped working. |
This PR is part of #1840.
This PR proposes an in-house implementation of
std.os.windows.GetPathNameByHandle
routine which you'd normally link to viakernelbase.dll
. In particular, the routine is implemented usingstd.os.windows.ntdll.NtQueryInformationFile
with class flagsFileNormalizedNameInformation
andFileVolumeNameInformation
. The former allows us to get the normalized (canonical) path to the resource, however, the volume name is not prepended. This is what we use the latter for. Hence, in effect we callNtQueryInformationFile
twice. However, there is still one complication in the fact that, by default, NTOS returns NT volume names, e.g.,\Device\HarddiskVolume0
which needs to be converted to the more familiar DOS volume name such asC:
or whatnot (an interesting fact,C:
and\DosDevices\C:
are simply symbolic link objects to\Device\HarddiskVolume0
). To convert the NT volume name into DOS volume name, we issuestd.os.windows.DeviceIoControl
syscall withIOCTL_MOUNTMGR_QUERY_POINTS
opcode, with the result ofFileVolumeNameInformation
as the input. Then, the mount manager returns all symbolic link objects that point at that volume, and we select the first available from the result pool as our DOS drive letter.This PR took me quite a while to figure out as most of the API is not very well documented. The things got even more complicated since ReactOS doesn't provide
GetFinalPathNameByHandleW
yet, and Wine uses a slightly different (may I say dated approach?) plus Wine it seems somehow manages to obtain DOS drive letter upfront: link for the interested. Finally, usingNtQueryInformationFile
withFileNormalizedNameInformation
seems to agree with what I've reversed engineered using ProcMon on the actualkernelbase.GetFinalPathNameByHandleW
on Windows.Anyhow, lemme know what y'all reckon! Comments and suggestions most welcome!