Skip to content

Commit 52ddc15

Browse files
committed
introduce std.os.windows.QueryObjectName
1 parent 0337278 commit 52ddc15

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

lib/std/os/windows.zig

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,46 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
952952
return @bitCast(u64, result);
953953
}
954954

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+
955995
pub const GetFinalPathNameByHandleError = error {
956996
BadPathName,
957997
FileNotFound,
@@ -963,7 +1003,9 @@ pub const GetFinalPathNameByHandleError = error {
9631003
else
9641004
error {
9651005
AccessDenied,
966-
SystemResources,
1006+
BufferTooSmall,
1007+
InvalidHandle,
1008+
Unnamed,
9671009
};
9681010

9691011
/// Specifies how to format volume path in the result of `GetFinalPathNameByHandle`.
@@ -1147,7 +1189,7 @@ test "GetFinalPathNameByHandle" {
11471189

11481190
const selfExeFile: std.fs.File = try std.fs.openSelfExe(.{}); //any file would do
11491191

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
11511193

11521194
//check with sufficient size
11531195
const dos_length = try S.check(selfExeFile, buffer[0..], .{.volume_name = .Dos});

lib/std/os/windows/bits.zig

Lines changed: 17 additions & 1 deletion
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;
@@ -1178,7 +1179,7 @@ pub const OBJ_VALID_ATTRIBUTES = 0x000003F2;
11781179
pub const UNICODE_STRING = extern struct {
11791180
Length: c_ushort,
11801181
MaximumLength: c_ushort,
1181-
Buffer: [*]WCHAR,
1182+
Buffer: ?[*]WCHAR,
11821183
};
11831184

11841185
const ACTIVATION_CONTEXT_DATA = opaque {};
@@ -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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,10 @@ 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) NTSTATUS;

0 commit comments

Comments
 (0)