]>
git.proxmox.com Git - rustc.git/blob - src/vendor/same-file/src/lib.rs
2 This crate provides a safe and simple **cross platform** way to determine
3 whether two file paths refer to the same file or directory.
5 Most uses of this crate should be limited to the top-level `is_same_file`
6 function, which takes two file paths and returns true if they refer to the
7 same file or directory:
10 # fn example() -> ::std::io::Result<()> {
11 use same_file::is_same_file;
13 assert!(try!(is_same_file("/bin/sh", "/usr/bin/sh")));
14 # Ok(()) } example().unwrap();
17 Additionally, this crate provides a `Handle` type that permits a more efficient
18 equality check depending on your access pattern. For example, if one wanted to
19 checked whether any path in a list of paths corresponded to the process' stdout
20 handle, then one could build a handle once for stdout. The equality check for
21 each file in the list then only requires one stat call instead of two. The code
25 # fn example() -> ::std::io::Result<()> {
26 use same_file::Handle;
29 "examples/is_same_file.rs",
30 "examples/is_stderr.rs",
33 let stdout_handle = try!(Handle::stdout());
34 for candidate in candidates {
35 let handle = try!(Handle::from_path(candidate));
36 if stdout_handle == handle {
37 println!("{:?} is stdout!", candidate);
39 println!("{:?} is NOT stdout!", candidate);
42 # Ok(()) } example().unwrap();
45 See `examples/is_stderr.rs` for a runnable example. Compare the output of
46 `cargo run is_stderr 2> examples/stderr` and `cargo run is_stderr`.
49 #![deny(missing_docs)]
52 extern crate kernel32
;
60 #[cfg(any(target_os = "redox", unix))]
65 #[cfg(any(target_os = "redox", unix))]
70 /// A handle to a file that can be tested for equality with other handles.
72 /// If two files are the same, then any two handles of those files will compare
73 /// equal. If two files are not the same, then any two handles of those files
74 /// will compare not-equal.
76 /// A handle consumes an open file resource as long as it exists.
78 /// Note that it's possible for comparing two handles to produce a false
79 /// positive on some platforms. Namely, two handles can compare equal even if
80 /// the two handles *don't* point to the same file.
81 #[derive(Debug, Eq, PartialEq)]
82 pub struct Handle(imp
::Handle
);
85 /// Construct a handle from a path.
87 /// Note that the underlying `File` is opened in read-only mode on all
89 pub fn from_path
<P
: AsRef
<Path
>>(p
: P
) -> io
::Result
<Handle
> {
90 imp
::Handle
::from_path(p
).map(Handle
)
93 /// Construct a handle from a file.
94 pub fn from_file(file
: File
) -> io
::Result
<Handle
> {
95 imp
::Handle
::from_file(file
).map(Handle
)
98 /// Construct a handle from stdin.
99 pub fn stdin() -> io
::Result
<Handle
> {
100 imp
::Handle
::stdin().map(Handle
)
103 /// Construct a handle from stdout.
104 pub fn stdout() -> io
::Result
<Handle
> {
105 imp
::Handle
::stdout().map(Handle
)
108 /// Construct a handle from stderr.
109 pub fn stderr() -> io
::Result
<Handle
> {
110 imp
::Handle
::stderr().map(Handle
)
113 /// Return a reference to the underlying file.
114 pub fn as_file(&self) -> &File
{
118 /// Return a mutable reference to the underlying file.
119 pub fn as_file_mut(&mut self) -> &mut File
{
123 /// Return the underlying device number of this handle.
124 #[cfg(any(target_os = "redox", unix))]
125 pub fn dev(&self) -> u64 {
129 /// Return the underlying inode number of this handle.
130 #[cfg(any(target_os = "redox", unix))]
131 pub fn ino(&self) -> u64 {
136 /// Returns true if the two file paths may correspond to the same file.
138 /// If there was a problem accessing either file path, then an error is
141 /// Note that it's possible for this to produce a false positive on some
142 /// platforms. Namely, this can return true even if the two file paths *don't*
143 /// resolve to the same file.
148 /// use same_file::is_same_file;
150 /// assert!(is_same_file("./foo", "././foo").unwrap_or(false));
152 pub fn is_same_file
<P
, Q
>(
155 ) -> io
::Result
<bool
> where P
: AsRef
<Path
>, Q
: AsRef
<Path
> {
156 Ok(try
!(Handle
::from_path(path1
)) == try
!(Handle
::from_path(path2
)))
164 use std
::fs
::{self, File}
;
166 use std
::path
::{Path, PathBuf}
;
170 use super::is_same_file
;
172 struct TempDir(PathBuf
);
175 fn path
<'a
>(&'a
self) -> &'a Path
{
180 impl Drop
for TempDir
{
182 fs
::remove_dir_all(&self.0).unwrap();
186 fn tmpdir() -> TempDir
{
187 let p
= env
::temp_dir();
188 let mut r
= self::rand
::thread_rng();
189 let ret
= p
.join(&format
!("rust-{}", r
.next_u32()));
190 fs
::create_dir(&ret
).unwrap();
195 pub fn soft_link_dir
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(
198 ) -> io
::Result
<()> {
199 use std
::os
::unix
::fs
::symlink
;
204 pub fn soft_link_file
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(
207 ) -> io
::Result
<()> {
208 soft_link_dir(src
, dst
)
212 pub fn soft_link_dir
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(
215 ) -> io
::Result
<()> {
216 use std
::os
::windows
::fs
::symlink_dir
;
217 symlink_dir(src
, dst
)
221 pub fn soft_link_file
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(
224 ) -> io
::Result
<()> {
225 use std
::os
::windows
::fs
::symlink_file
;
226 symlink_file(src
, dst
)
229 // These tests are rather uninteresting. The really interesting tests
230 // would stress the edge cases. On Unix, this might be comparing two files
231 // on different mount points with the same inode number. On Windows, this
232 // might be comparing two files whose file indices are the same on file
233 // systems where such things aren't guaranteed to be unique.
235 // Alas, I don't know how to create those environmental conditions. ---AG
238 fn same_file_trivial() {
240 let dir
= tdir
.path();
242 File
::create(dir
.join("a")).unwrap();
243 assert
!(is_same_file(dir
.join("a"), dir
.join("a")).unwrap());
247 fn same_dir_trivial() {
249 let dir
= tdir
.path();
251 fs
::create_dir(dir
.join("a")).unwrap();
252 assert
!(is_same_file(dir
.join("a"), dir
.join("a")).unwrap());
256 fn not_same_file_trivial() {
258 let dir
= tdir
.path();
260 File
::create(dir
.join("a")).unwrap();
261 File
::create(dir
.join("b")).unwrap();
262 assert
!(!is_same_file(dir
.join("a"), dir
.join("b")).unwrap());
266 fn not_same_dir_trivial() {
268 let dir
= tdir
.path();
270 fs
::create_dir(dir
.join("a")).unwrap();
271 fs
::create_dir(dir
.join("b")).unwrap();
272 assert
!(!is_same_file(dir
.join("a"), dir
.join("b")).unwrap());
276 fn same_file_hard() {
278 let dir
= tdir
.path();
280 File
::create(dir
.join("a")).unwrap();
281 fs
::hard_link(dir
.join("a"), dir
.join("alink")).unwrap();
282 assert
!(is_same_file(dir
.join("a"), dir
.join("alink")).unwrap());
286 fn same_file_soft() {
288 let dir
= tdir
.path();
290 File
::create(dir
.join("a")).unwrap();
291 soft_link_file(dir
.join("a"), dir
.join("alink")).unwrap();
292 assert
!(is_same_file(dir
.join("a"), dir
.join("alink")).unwrap());
298 let dir
= tdir
.path();
300 fs
::create_dir(dir
.join("a")).unwrap();
301 soft_link_dir(dir
.join("a"), dir
.join("alink")).unwrap();
302 assert
!(is_same_file(dir
.join("a"), dir
.join("alink")).unwrap());