strmode/
lib.rs

1//! An implementation of BSD strmode(3).
2
3/// Returns a `String` describing the file permissions contained in a `u32`,
4/// as in the`st_mode` bit field of `struct stat`. It is formatted in the usual
5/// UNIX convention, eg `-rw-r--r--`.
6///
7/// # Examples
8///
9/// ```
10/// use std::fs;
11/// use std::os::unix::fs::PermissionsExt;
12/// use strmode::strmode;
13///
14/// fn main() -> std::io::Result<()> {
15///     let metadata = fs::metadata("/dev/null")?;
16///     let permissions = metadata.permissions();
17///     let mode = permissions.mode();
18///
19///     assert_eq!(strmode(mode), "crw-rw-rw-");
20///
21///     Ok(())
22/// }
23/// ```
24pub fn strmode(mode: u32) -> String {
25    let mut flags = ['-'; 10];
26
27    let perms = [
28        (0o000400, 'r'), (0o000200, 'w'), (0o000100, 'x'), // user
29        (0o000040, 'r'), (0o000020, 'w'), (0o000010, 'x'), // group
30        (0o000004, 'r'), (0o000002, 'w'), (0o000001, 'x'), // other
31    ];
32
33    // Permissions
34    let s = &mut flags[1..];
35    for i in 0..9 {
36        if mode & perms[i].0 == perms[i].0 {
37            s[i] = perms[i].1;
38        }
39    }
40
41    // File type
42    match mode & 0o170000 {
43        0o010000    => { flags[0] = 'p' },  // fifo
44        0o020000    => { flags[0] = 'c' },  // character special
45        0o040000    => { flags[0] = 'd' },  // directory
46        0o060000    => { flags[0] = 'b' },  // block special
47        0o100000    => { },                 // regular file
48        0o120000    => { flags[0] = 'l' },  // symbolic link
49        0o140000    => { flags[0] = 's' },  // socket
50        _           => { flags[0] = '?' },  // unknown
51    }
52
53    // setuid
54    let xusr_setuid = mode & (0o000100 | 0o004000);
55    if xusr_setuid == 0o004000 {
56        flags[3] = 'S';
57    } else if xusr_setuid == (0o000100 | 0o004000) {
58         flags[3] = 's';
59    }
60
61    // setgid
62    let xgrp_setgid = mode & (0o000010 | 0o002000);
63    if xgrp_setgid == 0o002000 {
64        flags[6] = 'S';
65    } else if xgrp_setgid == (0o000010 | 0o002000) {
66        flags[6] = 's';
67    }
68
69    // sticky
70    let xoth_sticky = mode & (0o000001 | 0o001000);
71    if xoth_sticky == 0o001000 {
72        flags[9] = 'T';
73    } else if xoth_sticky == (0o000001 | 0o001000) {
74        flags[9] = 't';
75    }
76
77    return flags.into_iter().collect();
78}
79
80#[test]
81fn test_strmode() {
82    let tests = [
83        (0o100644, "-rw-r--r--", "file, 644"),
84        (0o100600, "-rw-------", "file, 600"),
85        (0o100777, "-rwxrwxrwx", "file, 777"),
86        (0o040755, "drwxr-xr-x", "directory, 755"),
87        (0o040711, "drwx--x--x", "directory, 711"),
88        (0o020660, "crw-rw----", "character special, 660"),
89        (0o060660, "brw-rw----", "block special, 660"),
90        (0o120777, "lrwxrwxrwx", "symbolic link, 777"),
91        (0o010600, "prw-------", "fifo, 600"),
92        (0o140755, "srwxr-xr-x", "socket ,755"),
93        (0o104555, "-r-sr-xr-x", "file, 755 with setuid"),
94        (0o104644, "-rwSr--r--", "file, 644 with setuid"),
95        (0o044755, "drwsr-xr-x", "directory, 755 with setuid"),
96        (0o044666, "drwSrw-rw-", "directory, 666 with setuid"),
97        (0o102755, "-rwxr-sr-x", "file, 755 with setgid"),
98        (0o102644, "-rw-r-Sr--", "file, 644 with setgid"),
99        (0o042755, "drwxr-sr-x", "directory, 755 with setgid"),
100        (0o042644, "drw-r-Sr--", "directory, 644 with setgid"),
101        (0o041755, "drwxr-xr-t", "directory, 755 with sticky"),
102        (0o041644, "drw-r--r-T", "directory, 644 with sticky"),
103        (0o104471, "-r-Srwx--x", "file, 471 with setuid"),
104        (0o106471, "-r-Srws--x", "file, 471 with setuid and setgid"),
105        (0o044471, "dr-Srwx--x", "directory, 471 with setuid"),
106        (0o046471, "dr-Srws--x", "directory, 471 with setuid and setgid"),
107        (0o045471, "dr-Srwx--t", "directory, 471 with setuid and sticky"),
108        (0o047471, "dr-Srws--t", "directory, 471 with setuid, setgid, and sticky"),
109        (0o047470, "dr-Srws--T", "directory, 470 with setuid, setgid, and sticky"),
110    ];
111
112    for t in &tests {
113        assert_eq!(t.1, strmode(t.0), "{}: {:o}", t.2, t.0);
114    }
115}