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