-
Notifications
You must be signed in to change notification settings - Fork 286
/
Copy pathfile_descriptor.rs
100 lines (85 loc) · 2.72 KB
/
file_descriptor.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::{
fs, io,
os::unix::io::{IntoRawFd, RawFd},
};
use libc::size_t;
use crate::{ErrorKind, Result};
use std::io::stdin;
use std::path::Path;
/// A file descriptor wrapper.
///
/// It allows to retrieve raw file descriptor, write to the file descriptor and
/// mainly it closes the file descriptor once dropped.
#[derive(Debug)]
pub struct FileDesc {
fd: RawFd,
close_on_drop: bool,
}
impl FileDesc {
/// Constructs a new `FileDesc` with the given `RawFd`.
///
/// # Arguments
///
/// * `fd` - raw file descriptor
/// * `close_on_drop` - specify if the raw file descriptor should be closed once the `FileDesc` is dropped
pub fn new(fd: RawFd, close_on_drop: bool) -> FileDesc {
FileDesc { fd, close_on_drop }
}
pub fn read(&self, buffer: &mut [u8], size: usize) -> Result<usize> {
let result = unsafe {
libc::read(
self.fd,
buffer.as_mut_ptr() as *mut libc::c_void,
size as size_t,
) as isize
};
if result < 0 {
Err(ErrorKind::IoError(io::Error::last_os_error()))
} else {
Ok(result as usize)
}
}
/// Returns the underlying file descriptor.
pub fn raw_fd(&self) -> RawFd {
self.fd
}
}
impl Drop for FileDesc {
fn drop(&mut self) {
if self.close_on_drop {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// opened after we closed ours.
let _ = unsafe { libc::close(self.fd) };
}
}
}
/// Creates a file descriptor pointing to the standard input or `/dev/tty`.
pub fn tty_fd(close_on_drop: bool) -> Result<FileDesc> {
use crate::tty::IsTty;
let fd = match open_rw("/dev/tty") {
Ok(tty) => {
println!("Can open");
tty
}
Err(e) => {
println!("Can not open");
if stdin().is_tty() {
libc::STDIN_FILENO
} else {
return Err(ErrorKind::IoError(io::Error::new(io::ErrorKind::Other, "Failed to initialize input source. Crossterm first tried to open `/dev/tty` wereafter `libc::STDIN_FILENO`, but both could not be used.")));
}
}
};
Ok(FileDesc::new(fd, close_on_drop))
}
fn open_rw<P: AsRef<Path>>(path: P) -> io::Result<RawFd> {
use std::fs::OpenOptions;
let file = OpenOptions::new()
.read(true)
.write(true)
.open(path)?;
Ok(file.into_raw_fd())
}