1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Copyright (c) 2021 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by General Public License that can be found
// in the LICENSE file.

use std::path::Path;

use crate::error::Error;

/// Check whether two files refere to same file in filesystem.
pub fn same_file<P: AsRef<Path>>(file1: P, file2: P) -> Result<bool, Error> {
    let fd1 = nc::openat(nc::AT_FDCWD, file1.as_ref(), nc::O_RDONLY, 0)?;
    let fd2 = nc::openat(nc::AT_FDCWD, file2.as_ref(), nc::O_RDONLY, 0)?;
    let is_same = same_file_fd(fd1, fd2)?;
    nc::close(fd1)?;
    nc::close(fd2)?;
    Ok(is_same)
}

/// Check whether two file descriptors refere to same file in filesystem.
pub fn same_file_fd(fd1: i32, fd2: i32) -> Result<bool, Error> {
    let mut stat1 = nc::stat_t::default();
    nc::fstat(fd1, &mut stat1)?;
    let mut stat2 = nc::stat_t::default();
    nc::fstat(fd2, &mut stat2)?;
    Ok(stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_same_file() {
        assert_eq!(same_file("/etc/passwd", "/etc/passwd"), Ok(true));
    }
}