summaryrefslogtreecommitdiff
path: root/test/test_stat.rs
blob: 3d7541cc91c99db5fb42cbd026a7e93c51b0acd2 (plain)
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use std::fs;
use std::str;

use libc::consts::os::posix88;

use nix::sys::stat::{stat, fstat, lstat};

use nix::fcntl::open;
use nix::unistd::{close, unlink};
use nix::fcntl::{O_CREAT, O_RDONLY};
use nix::sys::stat::{FileStat, S_IWUSR, S_IRUSR};
use nix::Result;

fn assert_stat_results(stat_result: Result<FileStat>) {
    match stat_result {
        Ok(stats) => {
            assert!(stats.st_dev > 0);      // must be positive integer, exact number machine dependent
            assert!(stats.st_ino > 0);      // inode is positive integer, exact number machine dependent
            assert!(stats.st_mode > 0);     // must be positive integer
            assert!(stats.st_nlink == 1);   // there links created, must be 1
            // uid could be 0 for the `root` user. This quite possible when
            // the tests are being run on a rooted Android device.
            assert!(stats.st_uid >= 0);      // must be positive integer
            assert!(stats.st_gid >= 0);      // must be positive integer
            assert!(stats.st_rdev == 0);    // no special device
            assert!(stats.st_size == 0);    // size is 0 because we did not write anything to the file
            assert!(stats.st_blksize > 0);  // must be positive integer, exact number machine dependent
            assert!(stats.st_blocks <= 16);  // Up to 16 blocks can be allocated for a blank file
        }
        Err(_) => panic!("stat call failed") // if stats system call fails, something is seriously wrong on that machine
    }
}

fn assert_lstat_results(stat_result: Result<FileStat>) {
    match stat_result {
        Ok(stats) => {
            assert!(stats.st_dev > 0);      // must be positive integer, exact number machine dependent
            assert!(stats.st_ino > 0);      // inode is positive integer, exact number machine dependent
            assert!(stats.st_mode > 0);     // must be positive integer

            // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t
            // (u16 on Android), and that will be a compile error.
            // On other platforms they are the same (either both are u16 or u32).
            assert!((stats.st_mode as usize) & (posix88::S_IFMT as usize)
                    == posix88::S_IFLNK as usize); // should be a link
            assert!(stats.st_nlink == 1);   // there links created, must be 1
            // uid could be 0 for the `root` user. This quite possible when
            // the tests are being run on a rooted Android device.
            assert!(stats.st_uid >= 0);      // must be positive integer
            assert!(stats.st_gid >= 0);      // must be positive integer
            assert!(stats.st_rdev == 0);    // no special device
            assert!(stats.st_size > 0);    // size is > 0 because it points to another file
            assert!(stats.st_blksize > 0);  // must be positive integer, exact number machine dependent

            // st_blocks depends on whether the machine's file system uses fast
            // or slow symlinks, so just make sure it's not negative
            // (Android's st_blocks is ulonglong which is always non-negative.)
            assert!(stats.st_blocks >= 0);
        }
        Err(_) => panic!("stat call failed") // if stats system call fails, something is seriously wrong on that machine
    }
}

#[test]
fn test_stat_and_fstat() {
    let filename = b"target/foo.txt".as_ref();
    let fd = open(filename, O_CREAT, S_IWUSR).unwrap();  // create empty file

    let stat_result = stat(filename);
    assert_stat_results(stat_result);

    let fstat_result = fstat(fd);
    assert_stat_results(fstat_result);

    close(fd).unwrap();
    unlink(filename).unwrap();
}

#[test]
fn test_stat_fstat_lstat() {
    let filename = b"target/bar.txt".as_ref();
    let linkname = b"target/barlink".as_ref();

    open(filename, O_CREAT, S_IWUSR | S_IRUSR).unwrap();  // create empty file
    fs::soft_link("bar.txt", str::from_utf8(linkname).unwrap()).unwrap();
    let fd = open(linkname, O_RDONLY, S_IRUSR).unwrap();

    // should be the same result as calling stat,
    // since it's a regular file
    let stat_result = lstat(filename);
    assert_stat_results(stat_result);

    let lstat_result = lstat(linkname);
    assert_lstat_results(lstat_result);

    let fstat_result = fstat(fd);
    assert_stat_results(fstat_result);

    close(fd).unwrap();
    unlink(linkname).unwrap();
    unlink(filename).unwrap();
}