Skip to content

Commit 3ffb925

Browse files
committed
tty: support printing msys2 tty path
1 parent 5316f58 commit 3ffb925

3 files changed

Lines changed: 57 additions & 5 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/tty/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ fluent = { workspace = true }
2727
[target.'cfg(unix)'.dependencies]
2828
rustix = { workspace = true, features = ["fs", "termios"] }
2929

30+
[target.'cfg(windows)'.dependencies]
31+
windows-sys = { workspace = true, features = [
32+
"Win32_Storage_FileSystem",
33+
"Win32_Foundation",
34+
] }
35+
3036
[[bin]]
3137
name = "tty"
3238
path = "src/main.rs"

src/uu/tty/src/tty.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
5858
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
5959
};
6060
#[cfg(target_os = "windows")]
61-
let write_result = if std::io::stdin().is_terminal() {
62-
writeln!(stdout, r"\\.\CON")
63-
} else {
64-
set_exit_code(1);
65-
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
61+
let write_result = {
62+
use std::os::windows::io::AsHandle;
63+
let stdin = std::io::stdin();
64+
let stdin_handle = stdin.as_handle();
65+
if stdin_handle.is_terminal() {
66+
if let Some(name) = file_name(stdin_handle) {
67+
writeln!(stdout, "{name}")
68+
} else {
69+
writeln!(stdout, r"\\.\CON")
70+
}
71+
} else {
72+
set_exit_code(1);
73+
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
74+
}
6675
};
6776

6877
if write_result.is_err() || stdout.flush().is_err() {
@@ -74,6 +83,42 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
7483
Ok(())
7584
}
7685

86+
#[cfg(target_os = "windows")]
87+
fn file_name(handle: std::os::windows::io::BorrowedHandle) -> Option<String> {
88+
use std::mem::MaybeUninit;
89+
use std::os::windows::io::AsRawHandle;
90+
use windows_sys::Win32::Foundation::MAX_PATH;
91+
use windows_sys::Win32::Storage::FileSystem::{FileNameInfo, GetFileInformationByHandleEx};
92+
// Manually define FILE_NAME_INFO so we can more easily construct a stack buffer.
93+
#[repr(C)]
94+
#[allow(non_snake_case)]
95+
struct FILE_NAME_INFO {
96+
FileNameLength: u32,
97+
FileName: [MaybeUninit<u16>; MAX_PATH as usize],
98+
}
99+
let mut name = FILE_NAME_INFO {
100+
FileNameLength: 0,
101+
FileName: [MaybeUninit::uninit(); _],
102+
};
103+
unsafe {
104+
let result = GetFileInformationByHandleEx(
105+
handle.as_raw_handle(),
106+
FileNameInfo,
107+
(&raw mut name).cast(),
108+
size_of::<FILE_NAME_INFO>() as u32,
109+
);
110+
if result == 0 {
111+
None
112+
} else {
113+
let name = name.FileName.get(..name.FileNameLength as usize / 2)?;
114+
// SAFETY: all elements up to FileNameLength have been initialized
115+
let name: &[u16] = &*(std::ptr::from_ref::<[MaybeUninit<u16>]>(name) as *const [u16]);
116+
// This should never fail for a valid msys terminal because they use ASCII names.
117+
String::from_utf16(name).ok()
118+
}
119+
}
120+
}
121+
77122
pub fn uu_app() -> Command {
78123
let cmd = Command::new("tty")
79124
.version(uucore::crate_version!())

0 commit comments

Comments
 (0)