authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2023-03-08 01:18:33-08:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2023-03-08 04:26:50-08:00
log93b35c69998398e962bff84f3e5006afa122fbde
treeb88a6096e8aa0f8602523eadd8d0b2d092458287
parent6d74c0d1b41b52bca3d66092a48660f2ee4ae4f8

os.isCygwinPty: Fix a bug, replace kernel32 call, and optimize

- Fixes the first few code units of the name being omitted (it was using `@sizeOf(FILE_NAME_INFO)` as the start of the name bytes, but that includes the length of the dummy [1]u16 field and padding; instead the start should be the offset of the dummy [1]u16 field) - Replaces kernel32.GetFileInformationByHandleEx call with ntdll.NtQueryInformationFile + Contributes towards #1840 - Checks that the handle is a named pipe first before querying and checking the name, which is a much faster call than NtQueryInformationFile (this was about a 10x speedup in my probably-not-so-good/take-it-with-a-grain-of-salt benchmarking)

3 files changed, 69 insertions(+), 11 deletions(-)

lib/std/os.zig+37-11
...@@ -3217,22 +3217,48 @@ pub fn isatty(handle: fd_t) bool {...@@ -3217,22 +3217,48 @@ pub fn isatty(handle: fd_t) bool {
3217pub fn isCygwinPty(handle: fd_t) bool {3217pub fn isCygwinPty(handle: fd_t) bool {
3218 if (builtin.os.tag != .windows) return false;3218 if (builtin.os.tag != .windows) return false;
32193219
3220 const size = @sizeOf(windows.FILE_NAME_INFO);3220 // If this is a MSYS2/cygwin pty, then it will be a named pipe with a name in one of these formats:
3221 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH);3221 // msys-[...]-ptyN-[...]
3222 // cygwin-[...]-ptyN-[...]
3223 //
3224 // Example: msys-1888ae32e00d56aa-pty0-to-master
3225
3226 // First, just check that the handle is a named pipe.
3227 // This allows us to avoid the more costly NtQueryInformationFile call
3228 // for handles that aren't named pipes.
3229 {
3230 var io_status: windows.IO_STATUS_BLOCK = undefined;
3231 var device_info: windows.FILE_FS_DEVICE_INFORMATION = undefined;
3232 const rc = windows.ntdll.NtQueryVolumeInformationFile(handle, &io_status, &device_info, @sizeOf(windows.FILE_FS_DEVICE_INFORMATION), .FileFsDeviceInformation);
3233 switch (rc) {
3234 .SUCCESS => {},
3235 else => return false,
3236 }
3237 if (device_info.DeviceType != windows.FILE_DEVICE_NAMED_PIPE) return false;
3238 }
32223239
3223 if (windows.kernel32.GetFileInformationByHandleEx(3240 const name_bytes_offset = @offsetOf(windows.FILE_NAME_INFO, "FileName");
3224 handle,3241 // `NAME_MAX` UTF-16 code units (2 bytes each)
3225 windows.FileNameInfo,3242 // Note: This buffer may not be long enough to handle *all* possible paths (PATH_MAX_WIDE would be necessary for that),
3226 @ptrCast(*anyopaque, &name_info_bytes),3243 // but because we only care about certain paths and we know they must be within a reasonable length,
3227 name_info_bytes.len,3244 // we can use this smaller buffer and just return false on any error from NtQueryInformationFile.
3228 ) == 0) {3245 const num_name_bytes = windows.MAX_PATH * 2;
3229 return false;3246 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (name_bytes_offset + num_name_bytes);
3247
3248 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
3249 const rc = windows.ntdll.NtQueryInformationFile(handle, &io_status_block, &name_info_bytes, @intCast(u32, name_info_bytes.len), .FileNameInformation);
3250 switch (rc) {
3251 .SUCCESS => {},
3252 .INVALID_PARAMETER => unreachable,
3253 else => return false,
3230 }3254 }
32313255
3232 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);3256 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
3233 const name_bytes = name_info_bytes[size .. size + @as(usize, name_info.FileNameLength)];3257 const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + @as(usize, name_info.FileNameLength)];
3234 const name_wide = mem.bytesAsSlice(u16, name_bytes);3258 const name_wide = mem.bytesAsSlice(u16, name_bytes);
3235 return mem.indexOf(u16, name_wide, &[_]u16{ 'm', 's', 'y', 's', '-' }) != null or3259 // Note: The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master
3260 return (mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'm', 's', 'y', 's', '-' }) or
3261 mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'c', 'y', 'g', 'w', 'i', 'n', '-' })) and
3236 mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null;3262 mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null;
3237}3263}
32383264
lib/std/os/windows.zig+23
...@@ -2472,6 +2472,29 @@ pub const FILE_INFORMATION_CLASS = enum(c_int) {...@@ -2472,6 +2472,29 @@ pub const FILE_INFORMATION_CLASS = enum(c_int) {
2472 FileMaximumInformation,2472 FileMaximumInformation,
2473};2473};
24742474
2475pub const FILE_FS_DEVICE_INFORMATION = extern struct {
2476 DeviceType: DEVICE_TYPE,
2477 Characteristics: ULONG,
2478};
2479
2480pub const FS_INFORMATION_CLASS = enum(c_int) {
2481 FileFsVolumeInformation = 1,
2482 FileFsLabelInformation,
2483 FileFsSizeInformation,
2484 FileFsDeviceInformation,
2485 FileFsAttributeInformation,
2486 FileFsControlInformation,
2487 FileFsFullSizeInformation,
2488 FileFsObjectIdInformation,
2489 FileFsDriverPathInformation,
2490 FileFsVolumeFlagsInformation,
2491 FileFsSectorSizeInformation,
2492 FileFsDataCopyInformation,
2493 FileFsMetadataSizeInformation,
2494 FileFsFullSizeInformationEx,
2495 FileFsMaximumInformation,
2496};
2497
2475pub const OVERLAPPED = extern struct {2498pub const OVERLAPPED = extern struct {
2476 Internal: ULONG_PTR,2499 Internal: ULONG_PTR,
2477 InternalHigh: ULONG_PTR,2500 InternalHigh: ULONG_PTR,
lib/std/os/windows/ntdll.zig+9
...@@ -18,6 +18,7 @@ const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK;...@@ -18,6 +18,7 @@ const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK;
18const LARGE_INTEGER = windows.LARGE_INTEGER;18const LARGE_INTEGER = windows.LARGE_INTEGER;
19const OBJECT_INFORMATION_CLASS = windows.OBJECT_INFORMATION_CLASS;19const OBJECT_INFORMATION_CLASS = windows.OBJECT_INFORMATION_CLASS;
20const FILE_INFORMATION_CLASS = windows.FILE_INFORMATION_CLASS;20const FILE_INFORMATION_CLASS = windows.FILE_INFORMATION_CLASS;
21const FS_INFORMATION_CLASS = windows.FS_INFORMATION_CLASS;
21const UNICODE_STRING = windows.UNICODE_STRING;22const UNICODE_STRING = windows.UNICODE_STRING;
22const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;23const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;
23const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;24const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
...@@ -232,6 +233,14 @@ pub extern "ntdll" fn NtQueryObject(...@@ -232,6 +233,14 @@ pub extern "ntdll" fn NtQueryObject(
232 ReturnLength: ?*ULONG,233 ReturnLength: ?*ULONG,
233) callconv(WINAPI) NTSTATUS;234) callconv(WINAPI) NTSTATUS;
234235
236pub extern "ntdll" fn NtQueryVolumeInformationFile(
237 FileHandle: HANDLE,
238 IoStatusBlock: *IO_STATUS_BLOCK,
239 FsInformation: *anyopaque,
240 Length: ULONG,
241 FsInformationClass: FS_INFORMATION_CLASS,
242) callconv(WINAPI) NTSTATUS;
243
235pub extern "ntdll" fn RtlWakeAddressAll(244pub extern "ntdll" fn RtlWakeAddressAll(
236 Address: ?*const anyopaque,245 Address: ?*const anyopaque,
237) callconv(WINAPI) void;246) callconv(WINAPI) void;