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