1 use std::fs::{File, OpenOptions};
2 use std::hash::{Hash, Hasher};
3 use std::io;
4 use std::os::unix::fs::MetadataExt;
5 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
6 use std::path::Path;
7 
8 #[derive(Debug)]
9 pub struct Handle {
10     file: Option<File>,
11     // If is_std is true, then we don't drop the corresponding File since it
12     // will close the handle.
13     is_std: bool,
14     dev: u64,
15     ino: u64,
16 }
17 
18 impl Drop for Handle {
drop(&mut self)19     fn drop(&mut self) {
20         if self.is_std {
21             // unwrap() will not panic. Since we were able to open an
22             // std stream successfully, then `file` is guaranteed to be Some()
23             self.file.take().unwrap().into_raw_fd();
24         }
25     }
26 }
27 
28 impl Eq for Handle {}
29 
30 impl PartialEq for Handle {
eq(&self, other: &Handle) -> bool31     fn eq(&self, other: &Handle) -> bool {
32         (self.dev, self.ino) == (other.dev, other.ino)
33     }
34 }
35 
36 impl AsRawFd for crate::Handle {
as_raw_fd(&self) -> RawFd37     fn as_raw_fd(&self) -> RawFd {
38         // unwrap() will not panic. Since we were able to open the
39         // file successfully, then `file` is guaranteed to be Some()
40         self.0.file.as_ref().take().unwrap().as_raw_fd()
41     }
42 }
43 
44 impl IntoRawFd for crate::Handle {
into_raw_fd(mut self) -> RawFd45     fn into_raw_fd(mut self) -> RawFd {
46         // unwrap() will not panic. Since we were able to open the
47         // file successfully, then `file` is guaranteed to be Some()
48         self.0.file.take().unwrap().into_raw_fd()
49     }
50 }
51 
52 impl Hash for Handle {
hash<H: Hasher>(&self, state: &mut H)53     fn hash<H: Hasher>(&self, state: &mut H) {
54         self.dev.hash(state);
55         self.ino.hash(state);
56     }
57 }
58 
59 impl Handle {
from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle>60     pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
61         Handle::from_file(OpenOptions::new().read(true).open(p)?)
62     }
63 
from_file(file: File) -> io::Result<Handle>64     pub fn from_file(file: File) -> io::Result<Handle> {
65         let md = file.metadata()?;
66         Ok(Handle {
67             file: Some(file),
68             is_std: false,
69             dev: md.dev(),
70             ino: md.ino(),
71         })
72     }
73 
from_std(file: File) -> io::Result<Handle>74     pub fn from_std(file: File) -> io::Result<Handle> {
75         Handle::from_file(file).map(|mut h| {
76             h.is_std = true;
77             h
78         })
79     }
80 
stdin() -> io::Result<Handle>81     pub fn stdin() -> io::Result<Handle> {
82         Handle::from_std(unsafe { File::from_raw_fd(0) })
83     }
84 
stdout() -> io::Result<Handle>85     pub fn stdout() -> io::Result<Handle> {
86         Handle::from_std(unsafe { File::from_raw_fd(1) })
87     }
88 
stderr() -> io::Result<Handle>89     pub fn stderr() -> io::Result<Handle> {
90         Handle::from_std(unsafe { File::from_raw_fd(2) })
91     }
92 
as_file(&self) -> &File93     pub fn as_file(&self) -> &File {
94         // unwrap() will not panic. Since we were able to open the
95         // file successfully, then `file` is guaranteed to be Some()
96         self.file.as_ref().take().unwrap()
97     }
98 
as_file_mut(&mut self) -> &mut File99     pub fn as_file_mut(&mut self) -> &mut File {
100         // unwrap() will not panic. Since we were able to open the
101         // file successfully, then `file` is guaranteed to be Some()
102         self.file.as_mut().take().unwrap()
103     }
104 
dev(&self) -> u64105     pub fn dev(&self) -> u64 {
106         self.dev
107     }
108 
ino(&self) -> u64109     pub fn ino(&self) -> u64 {
110         self.ino
111     }
112 }
113