#![doc(html_root_url = "https://docs.rs/same-file/1.0.0")]
#![deny(missing_docs)]
#[cfg(windows)]
extern crate winapi;
use std::fs::File;
use std::io;
use std::path::Path;
#[cfg(any(target_os = "redox", unix))]
use unix as imp;
#[cfg(windows)]
use win as imp;
#[cfg(any(target_os = "redox", unix))]
mod unix;
#[cfg(windows)]
mod win;
#[derive(Debug, Eq, PartialEq)]
pub struct Handle(imp::Handle);
impl Handle {
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
imp::Handle::from_path(p).map(Handle)
}
pub fn from_file(file: File) -> io::Result<Handle> {
imp::Handle::from_file(file).map(Handle)
}
pub fn stdin() -> io::Result<Handle> {
imp::Handle::stdin().map(Handle)
}
pub fn stdout() -> io::Result<Handle> {
imp::Handle::stdout().map(Handle)
}
pub fn stderr() -> io::Result<Handle> {
imp::Handle::stderr().map(Handle)
}
pub fn as_file(&self) -> &File {
self.0.as_file()
}
pub fn as_file_mut(&mut self) -> &mut File {
self.0.as_file_mut()
}
#[cfg(any(target_os = "redox", unix))]
pub fn dev(&self) -> u64 {
self.0.dev()
}
#[cfg(any(target_os = "redox", unix))]
pub fn ino(&self) -> u64 {
self.0.ino()
}
}
pub fn is_same_file<P, Q>(
path1: P,
path2: Q,
) -> io::Result<bool> where P: AsRef<Path>, Q: AsRef<Path> {
Ok(Handle::from_path(path1)? == Handle::from_path(path2)?)
}
#[cfg(test)]
mod tests {
extern crate rand;
use std::env;
use std::fs::{self, File};
use std::io;
use std::path::{Path, PathBuf};
use self::rand::Rng;
use super::is_same_file;
struct TempDir(PathBuf);
impl TempDir {
fn path<'a>(&'a self) -> &'a Path {
&self.0
}
}
impl Drop for TempDir {
fn drop(&mut self) {
fs::remove_dir_all(&self.0).unwrap();
}
}
fn tmpdir() -> TempDir {
let p = env::temp_dir();
let mut r = self::rand::thread_rng();
let ret = p.join(&format!("rust-{}", r.next_u32()));
fs::create_dir(&ret).unwrap();
TempDir(ret)
}
#[cfg(unix)]
pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
use std::os::unix::fs::symlink;
symlink(src, dst)
}
#[cfg(unix)]
pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
soft_link_dir(src, dst)
}
#[cfg(windows)]
pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
use std::os::windows::fs::symlink_dir;
symlink_dir(src, dst)
}
#[cfg(windows)]
pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
use std::os::windows::fs::symlink_file;
symlink_file(src, dst)
}
#[test]
fn same_file_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap());
}
#[test]
fn same_dir_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
fs::create_dir(dir.join("a")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap());
}
#[test]
fn not_same_file_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
File::create(dir.join("b")).unwrap();
assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap());
}
#[test]
fn not_same_dir_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
fs::create_dir(dir.join("a")).unwrap();
fs::create_dir(dir.join("b")).unwrap();
assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap());
}
#[test]
fn same_file_hard() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
fs::hard_link(dir.join("a"), dir.join("alink")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
}
#[test]
fn same_file_soft() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
soft_link_file(dir.join("a"), dir.join("alink")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
}
#[test]
fn same_dir_soft() {
let tdir = tmpdir();
let dir = tdir.path();
fs::create_dir(dir.join("a")).unwrap();
soft_link_dir(dir.join("a"), dir.join("alink")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<super::Handle>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<super::Handle>();
}
}