@@ -952,6 +952,46 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
952
952
return @bitCast (u64 , result );
953
953
}
954
954
955
+ pub fn QueryObjectName (
956
+ Handle : HANDLE ,
957
+ out_buffer : []u16 ,
958
+ ReturnLength : ? PULONG , //returned in bytes
959
+ ) ! [:0 ]u16 {
960
+ const alignment = @alignOf (OBJECT_NAME_INFORMATION );
961
+ const begin_addr = @ptrToInt (out_buffer .ptr );
962
+ const aligned_begin_addr = std .mem .alignForward (begin_addr , alignment );
963
+ const alignment_step = aligned_begin_addr - begin_addr ;
964
+ const aligned_raw_buffer = @alignCast (alignment , std .mem .sliceAsBytes (out_buffer )[alignment_step .. out_buffer .len * @sizeOf (u16 )]);
965
+ if (aligned_raw_buffer .len < @sizeOf (OBJECT_NAME_INFORMATION )) return error .BufferTooSmall ; //this would result in .INFO_LENGTH_MISMATCH
966
+
967
+ var info = @ptrCast (* OBJECT_NAME_INFORMATION , aligned_raw_buffer );
968
+ info .* = undefined ; //all of the fields we read will be overwritten, and the result string is placed in the same buffer after the struct
969
+ const out_buffer_length = std .math .cast (ULONG , aligned_raw_buffer .len ) catch | e | std .math .maxInt (u32 ); //we'll just use as much of it as we can
970
+ const rc = ntdll .NtQueryObject (Handle , .ObjectNameInformation , out_buffer .ptr , out_buffer_length , ReturnLength ); //buffer size is specified in u16...
971
+ switch (rc ){
972
+ .SUCCESS = > if (info .Name .Buffer ) | buffer | return buffer [0.. @divExact (info .Name .Length , 2 ):0 ] //... but result length is specified in u8
973
+ else return error .Unnamed ,
974
+ .ACCESS_DENIED = > return error .AccessDenied ,
975
+ .INVALID_HANDLE = > return error .InvalidHandle ,
976
+ .BUFFER_OVERFLOW , .BUFFER_TOO_SMALL = > return error .NameTooLong ,
977
+ .INFO_LENGTH_MISMATCH = > unreachable , //aligned_raw_buffer.len < @sizeOf(OBJECT_NAME_INFORMATION) already checked previously
978
+ else = > | e | return unexpectedStatus (e ),
979
+ }
980
+ }
981
+ test "QueryObjectName" {
982
+ const file : std.fs.File = try std .fs .openSelfExe (.{}); //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths.
983
+ defer file .close ();
984
+ var out_buffer align (16 ) = std .mem .zeroes ([1 << 10 ]u16 ); //make this big enough for the test runner exe path
985
+ var required_length : ULONG = undefined ;
986
+
987
+ _ = try QueryObjectName (file .handle , out_buffer [0.. ], & required_length );
988
+ required_length = @divExact (required_length , 2 );
989
+ _ = try QueryObjectName (file .handle , out_buffer [0.. required_length ], null );
990
+ std .testing .expect (null == QueryObjectName (file .handle , out_buffer [0.. required_length -1 ], null )
991
+ catch | e | switch (e ) {error .NameTooLong = > null , else = > unreachable });
992
+ _ = try QueryObjectName (file .handle , out_buffer [0.. required_length + 1 ], null );
993
+ }
994
+
955
995
pub const GetFinalPathNameByHandleError = error {
956
996
BadPathName ,
957
997
FileNotFound ,
@@ -963,7 +1003,9 @@ pub const GetFinalPathNameByHandleError = error {
963
1003
else
964
1004
error {
965
1005
AccessDenied ,
966
- SystemResources ,
1006
+ BufferTooSmall ,
1007
+ InvalidHandle ,
1008
+ Unnamed ,
967
1009
};
968
1010
969
1011
/// Specifies how to format volume path in the result of `GetFinalPathNameByHandle`.
@@ -1147,7 +1189,7 @@ test "GetFinalPathNameByHandle" {
1147
1189
1148
1190
const selfExeFile : std.fs.File = try std .fs .openSelfExe (.{}); //any file would do
1149
1191
1150
- var buffer = std .mem .zeroes ([1 << 10 ]u16 ); //make this big enough for the current directory
1192
+ var buffer = std .mem .zeroes ([1 << 10 ]u16 ); //make this big enough for the test runner exe path
1151
1193
1152
1194
//check with sufficient size
1153
1195
const dos_length = try S .check (selfExeFile , buffer [0.. ], .{.volume_name = .Dos });
0 commit comments