Implement std.os.windows.GetPathNameByHandle using NT routines only#5993
Implement std.os.windows.GetPathNameByHandle using NT routines only#5993andrewrk merged 8 commits intoziglang:masterfrom
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! |
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.GetPathNameByHandleroutine which you'd normally link to viakernelbase.dll. In particular, the routine is implemented usingstd.os.windows.ntdll.NtQueryInformationFilewith class flagsFileNormalizedNameInformationandFileVolumeNameInformation. 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 callNtQueryInformationFiletwice. However, there is still one complication in the fact that, by default, NTOS returns NT volume names, e.g.,\Device\HarddiskVolume0which 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.DeviceIoControlsyscall withIOCTL_MOUNTMGR_QUERY_POINTSopcode, with the result ofFileVolumeNameInformationas 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
GetFinalPathNameByHandleWyet, 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, usingNtQueryInformationFilewithFileNormalizedNameInformationseems to agree with what I've reversed engineered using ProcMon on the actualkernelbase.GetFinalPathNameByHandleWon Windows.Anyhow, lemme know what y'all reckon! Comments and suggestions most welcome!