]>
Commit | Line | Data |
---|---|---|
7cac9316 | 1 | use std::fs::{File, OpenOptions}; |
0531ce1d | 2 | use std::hash::{Hash, Hasher}; |
7cac9316 XL |
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 { | |
19 | fn drop(&mut self) { | |
20 | if self.is_std { | |
0531ce1d XL |
21 | // unwrap() will not panic. Since we were able to open an |
22 | // std stream successfully, then `file` is guaranteed to be Some() | |
7cac9316 XL |
23 | self.file.take().unwrap().into_raw_fd(); |
24 | } | |
25 | } | |
26 | } | |
27 | ||
28 | impl Eq for Handle {} | |
29 | ||
30 | impl PartialEq for Handle { | |
31 | fn eq(&self, other: &Handle) -> bool { | |
32 | (self.dev, self.ino) == (other.dev, other.ino) | |
33 | } | |
34 | } | |
35 | ||
36 | impl AsRawFd for ::Handle { | |
37 | fn as_raw_fd(&self) -> RawFd { | |
0531ce1d XL |
38 | // unwrap() will not panic. Since we were able to open the |
39 | // file successfully, then `file` is guaranteed to be Some() | |
7cac9316 XL |
40 | self.0.file.as_ref().take().unwrap().as_raw_fd() |
41 | } | |
42 | } | |
43 | ||
44 | impl IntoRawFd for ::Handle { | |
45 | fn into_raw_fd(mut self) -> RawFd { | |
0531ce1d XL |
46 | // unwrap() will not panic. Since we were able to open the |
47 | // file successfully, then `file` is guaranteed to be Some() | |
7cac9316 XL |
48 | self.0.file.take().unwrap().into_raw_fd() |
49 | } | |
50 | } | |
51 | ||
0531ce1d XL |
52 | impl Hash for Handle { |
53 | fn hash<H: Hasher>(&self, state: &mut H) { | |
54 | self.dev.hash(state); | |
55 | self.ino.hash(state); | |
56 | } | |
57 | } | |
58 | ||
7cac9316 XL |
59 | impl Handle { |
60 | pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> { | |
0531ce1d | 61 | Handle::from_file(OpenOptions::new().read(true).open(p)?) |
7cac9316 XL |
62 | } |
63 | ||
64 | pub fn from_file(file: File) -> io::Result<Handle> { | |
0531ce1d | 65 | let md = file.metadata()?; |
7cac9316 XL |
66 | Ok(Handle { |
67 | file: Some(file), | |
68 | is_std: false, | |
69 | dev: md.dev(), | |
70 | ino: md.ino(), | |
71 | }) | |
72 | } | |
73 | ||
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 | ||
81 | pub fn stdin() -> io::Result<Handle> { | |
82 | Handle::from_std(unsafe { File::from_raw_fd(0) }) | |
83 | } | |
84 | ||
85 | pub fn stdout() -> io::Result<Handle> { | |
86 | Handle::from_std(unsafe { File::from_raw_fd(1) }) | |
87 | } | |
88 | ||
89 | pub fn stderr() -> io::Result<Handle> { | |
90 | Handle::from_std(unsafe { File::from_raw_fd(2) }) | |
91 | } | |
92 | ||
93 | pub fn as_file(&self) -> &File { | |
0531ce1d XL |
94 | // unwrap() will not panic. Since we were able to open the |
95 | // file successfully, then `file` is guaranteed to be Some() | |
7cac9316 XL |
96 | self.file.as_ref().take().unwrap() |
97 | } | |
98 | ||
99 | pub fn as_file_mut(&mut self) -> &mut File { | |
0531ce1d XL |
100 | // unwrap() will not panic. Since we were able to open the |
101 | // file successfully, then `file` is guaranteed to be Some() | |
7cac9316 XL |
102 | self.file.as_mut().take().unwrap() |
103 | } | |
104 | ||
105 | pub fn dev(&self) -> u64 { | |
106 | self.dev | |
107 | } | |
108 | ||
109 | pub fn ino(&self) -> u64 { | |
110 | self.ino | |
111 | } | |
112 | } |