| ... | ... | @@ -3217,22 +3217,48 @@ pub fn isatty(handle: fd_t) bool { |
| 3217 | 3217 | pub fn isCygwinPty(handle: fd_t) bool { |
| 3218 | 3218 | if (builtin.os.tag != .windows) return false; |
| 3219 | 3219 | |
| 3220 | | const size = @sizeOf(windows.FILE_NAME_INFO); |
| 3221 | | var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH); |
| 3220 | // If this is a MSYS2/cygwin pty, then it will be a named pipe with a name in one of these formats: |
| 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 | } |
| 3222 | 3239 | |
| 3223 | | if (windows.kernel32.GetFileInformationByHandleEx( |
| 3224 | | handle, |
| 3225 | | windows.FileNameInfo, |
| 3226 | | @ptrCast(*anyopaque, &name_info_bytes), |
| 3227 | | name_info_bytes.len, |
| 3228 | | ) == 0) { |
| 3229 | | return false; |
| 3240 | const name_bytes_offset = @offsetOf(windows.FILE_NAME_INFO, "FileName"); |
| 3241 | // `NAME_MAX` UTF-16 code units (2 bytes each) |
| 3242 | // Note: This buffer may not be long enough to handle *all* possible paths (PATH_MAX_WIDE would be necessary for that), |
| 3243 | // but because we only care about certain paths and we know they must be within a reasonable length, |
| 3244 | // we can use this smaller buffer and just return false on any error from NtQueryInformationFile. |
| 3245 | const num_name_bytes = windows.MAX_PATH * 2; |
| 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 | } |
| 3231 | 3255 | |
| 3232 | 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 | 3258 | const name_wide = mem.bytesAsSlice(u16, name_bytes); |
| 3235 | | return mem.indexOf(u16, name_wide, &[_]u16{ 'm', 's', 'y', 's', '-' }) != null or |
| 3259 | // 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 | 3262 | mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null; |
| 3237 | 3263 | } |
| 3238 | 3264 | |