Initial import of same-file-1.0.6.

Bug: 155309706
Change-Id: Iaa5474ae70e5c8533693d858e824d2c070410571
diff --git a/src/unix.rs b/src/unix.rs
new file mode 100644
index 0000000..fb3d19f
--- /dev/null
+++ b/src/unix.rs
@@ -0,0 +1,112 @@
+use std::fs::{File, OpenOptions};
+use std::hash::{Hash, Hasher};
+use std::io;
+use std::os::unix::fs::MetadataExt;
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::path::Path;
+
+#[derive(Debug)]
+pub struct Handle {
+    file: Option<File>,
+    // If is_std is true, then we don't drop the corresponding File since it
+    // will close the handle.
+    is_std: bool,
+    dev: u64,
+    ino: u64,
+}
+
+impl Drop for Handle {
+    fn drop(&mut self) {
+        if self.is_std {
+            // unwrap() will not panic. Since we were able to open an
+            // std stream successfully, then `file` is guaranteed to be Some()
+            self.file.take().unwrap().into_raw_fd();
+        }
+    }
+}
+
+impl Eq for Handle {}
+
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+        (self.dev, self.ino) == (other.dev, other.ino)
+    }
+}
+
+impl AsRawFd for crate::Handle {
+    fn as_raw_fd(&self) -> RawFd {
+        // unwrap() will not panic. Since we were able to open the
+        // file successfully, then `file` is guaranteed to be Some()
+        self.0.file.as_ref().take().unwrap().as_raw_fd()
+    }
+}
+
+impl IntoRawFd for crate::Handle {
+    fn into_raw_fd(mut self) -> RawFd {
+        // unwrap() will not panic. Since we were able to open the
+        // file successfully, then `file` is guaranteed to be Some()
+        self.0.file.take().unwrap().into_raw_fd()
+    }
+}
+
+impl Hash for Handle {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.dev.hash(state);
+        self.ino.hash(state);
+    }
+}
+
+impl Handle {
+    pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
+        Handle::from_file(OpenOptions::new().read(true).open(p)?)
+    }
+
+    pub fn from_file(file: File) -> io::Result<Handle> {
+        let md = file.metadata()?;
+        Ok(Handle {
+            file: Some(file),
+            is_std: false,
+            dev: md.dev(),
+            ino: md.ino(),
+        })
+    }
+
+    pub fn from_std(file: File) -> io::Result<Handle> {
+        Handle::from_file(file).map(|mut h| {
+            h.is_std = true;
+            h
+        })
+    }
+
+    pub fn stdin() -> io::Result<Handle> {
+        Handle::from_std(unsafe { File::from_raw_fd(0) })
+    }
+
+    pub fn stdout() -> io::Result<Handle> {
+        Handle::from_std(unsafe { File::from_raw_fd(1) })
+    }
+
+    pub fn stderr() -> io::Result<Handle> {
+        Handle::from_std(unsafe { File::from_raw_fd(2) })
+    }
+
+    pub fn as_file(&self) -> &File {
+        // unwrap() will not panic. Since we were able to open the
+        // file successfully, then `file` is guaranteed to be Some()
+        self.file.as_ref().take().unwrap()
+    }
+
+    pub fn as_file_mut(&mut self) -> &mut File {
+        // unwrap() will not panic. Since we were able to open the
+        // file successfully, then `file` is guaranteed to be Some()
+        self.file.as_mut().take().unwrap()
+    }
+
+    pub fn dev(&self) -> u64 {
+        self.dev
+    }
+
+    pub fn ino(&self) -> u64 {
+        self.ino
+    }
+}