@@ -955,6 +955,51 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
955
955
return @bitCast (u64 , result );
956
956
}
957
957
958
+ pub fn QueryObjectName (
959
+ handle : HANDLE ,
960
+ out_buffer : []u16 ,
961
+ ) ! []u16 {
962
+ var full_buffer : [@sizeOf (OBJECT_NAME_INFORMATION ) + PATH_MAX_WIDE * 2 ]u8 align (@alignOf (OBJECT_NAME_INFORMATION )) = undefined ;
963
+ var info = @ptrCast (* OBJECT_NAME_INFORMATION , & full_buffer );
964
+ //buffer size is specified in bytes
965
+ const full_buffer_length = @intCast (ULONG , @sizeOf (OBJECT_NAME_INFORMATION ) + std .math .min (PATH_MAX_WIDE , (out_buffer .len + 1 ) * 2 ));
966
+ //last argument would return the length required for full_buffer, not exposed here
967
+ const rc = ntdll .NtQueryObject (handle , .ObjectNameInformation , full_buffer [0.. ], full_buffer_length , null );
968
+ return switch (rc ) {
969
+ .SUCCESS = > if (@ptrCast (? [* ]WCHAR , info .Name .Buffer )) | buffer | blk : {
970
+ //resulting string length is specified in bytes
971
+ const path_length_unterminated = @divExact (info .Name .Length , 2 );
972
+ if (out_buffer .len < path_length_unterminated ) {
973
+ return error .NameTooLong ;
974
+ }
975
+ std .mem .copy (WCHAR , out_buffer [0.. path_length_unterminated ], buffer [0.. path_length_unterminated :0 ]);
976
+ break :blk out_buffer [0.. path_length_unterminated ];
977
+ } else error .Unexpected ,
978
+ .ACCESS_DENIED = > error .AccessDenied ,
979
+ .INVALID_HANDLE = > error .InvalidHandle ,
980
+ .BUFFER_OVERFLOW , .BUFFER_TOO_SMALL = > error .NameTooLong ,
981
+ //name_buffer.len >= @sizeOf(OBJECT_NAME_INFORMATION) holds statically
982
+ .INFO_LENGTH_MISMATCH = > unreachable ,
983
+ else = > | e | unexpectedStatus (e ),
984
+ };
985
+ }
986
+ test "QueryObjectName" {
987
+ if (comptime builtin .os .tag != .windows )
988
+ return ;
989
+
990
+ //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths.
991
+ const file = try std .fs .openSelfExe (.{});
992
+ defer file .close ();
993
+ //make this large enough for the test runner exe path
994
+ var out_buffer align (16 ) = std .mem .zeroes ([1 << 10 ]u16 );
995
+
996
+ var result_path = try QueryObjectName (file .handle , out_buffer [0.. ]);
997
+ //insufficient size
998
+ std .testing .expectError (error .NameTooLong , QueryObjectName (file .handle , out_buffer [0 .. result_path .len - 1 ]));
999
+ //exactly-sufficient size
1000
+ _ = try QueryObjectName (file .handle , out_buffer [0.. result_path .len ]);
1001
+ }
1002
+
958
1003
pub const GetFinalPathNameByHandleError = error {
959
1004
BadPathName ,
960
1005
FileNotFound ,
0 commit comments