Skip to content

Commit 6feccbd

Browse files
committed
introduce std.os.windows.QueryObjectName
1 parent 61fcef4 commit 6feccbd

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

lib/std/os/windows.zig

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,51 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
955955
return @bitCast(u64, result);
956956
}
957957

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+
9581003
pub const GetFinalPathNameByHandleError = error {
9591004
BadPathName,
9601005
FileNotFound,

lib/std/os/windows/bits.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub const SIZE_T = usize;
6565
pub const TCHAR = if (UNICODE) WCHAR else u8;
6666
pub const UINT = c_uint;
6767
pub const ULONG_PTR = usize;
68+
pub const PULONG = *ULONG;
6869
pub const LONG_PTR = isize;
6970
pub const DWORD_PTR = ULONG_PTR;
7071
pub const UNICODE = false;
@@ -1606,3 +1607,18 @@ pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008;
16061607
pub const SD_RECEIVE = 0;
16071608
pub const SD_SEND = 1;
16081609
pub const SD_BOTH = 2;
1610+
1611+
pub const OBJECT_INFORMATION_CLASS = extern enum {
1612+
ObjectBasicInformation = 0,
1613+
ObjectNameInformation = 1,
1614+
ObjectTypeInformation = 2,
1615+
ObjectTypesInformation = 3,
1616+
ObjectHandleFlagInformation = 4,
1617+
ObjectSessionInformation = 5,
1618+
MaxObjectInfoClass,
1619+
};
1620+
1621+
pub const OBJECT_NAME_INFORMATION = extern struct {
1622+
Name: UNICODE_STRING,
1623+
};
1624+
pub const POBJECT_NAME_INFORMATION = *OBJECT_NAME_INFORMATION;

lib/std/os/windows/ntdll.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,11 @@ pub extern "NtDll" fn NtWaitForKeyedEvent(
113113
) callconv(WINAPI) NTSTATUS;
114114

115115
pub extern "NtDll" fn RtlSetCurrentDirectory_U(PathName: *UNICODE_STRING) callconv(WINAPI) NTSTATUS;
116+
117+
pub extern "NtDll" fn NtQueryObject(
118+
Handle: HANDLE,
119+
ObjectInformationClass: OBJECT_INFORMATION_CLASS,
120+
ObjectInformation: PVOID,
121+
ObjectInformationLength: ULONG,
122+
ReturnLength: ?PULONG,
123+
) callconv(WINAPI) NTSTATUS;

0 commit comments

Comments
 (0)