Răsfoiți Sursa

Add --octal-permissions argument

Using --octal_permissions will insert another column before the existing
permissions where permissions are encoded using octal values as
requested in #316
Lars Haalck 5 ani în urmă
părinte
comite
16046d57de

+ 5 - 0
src/fs/fields.rs

@@ -87,6 +87,11 @@ pub struct PermissionsPlus {
 }
 
 
+/// The permissions encoded as octal values
+pub struct OctalPermissions {
+    pub permissions: Permissions,
+}
+
 /// A file’s number of hard links on the filesystem.
 ///
 /// Under Unix, a file can exist on the filesystem only once but appear in

+ 4 - 3
src/options/flags.rs

@@ -60,8 +60,9 @@ pub static NO_USER: Arg = Arg { short: None, long: "no-user", takes_value: Takes
 pub static NO_TIME: Arg = Arg { short: None, long: "no-time", takes_value: TakesValue::Forbidden };
 
 // optional feature options
-pub static GIT:       Arg = Arg { short: None,       long: "git",      takes_value: TakesValue::Forbidden };
-pub static EXTENDED:  Arg = Arg { short: Some(b'@'), long: "extended", takes_value: TakesValue::Forbidden };
+pub static GIT:       Arg = Arg { short: None,       long: "git",               takes_value: TakesValue::Forbidden };
+pub static EXTENDED:  Arg = Arg { short: Some(b'@'), long: "extended",          takes_value: TakesValue::Forbidden };
+pub static OCTAL:     Arg = Arg { short: None,       long: "octal-permissions", takes_value: TakesValue::Forbidden };
 
 
 pub static ALL_ARGS: Args = Args(&[
@@ -77,5 +78,5 @@ pub static ALL_ARGS: Args = Args(&[
     &BLOCKS, &TIME, &ACCESSED, &CREATED, &TIME_STYLE,
     &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME,
 
-    &GIT, &EXTENDED,
+    &GIT, &EXTENDED, &OCTAL
 ]);

+ 5 - 2
src/options/help.rs

@@ -56,8 +56,9 @@ LONG VIEW OPTIONS
   --no-user          suppress the user field
   --no-time          suppress the time field"##;
 
-static GIT_HELP:      &str = r##"  --git              list each file's Git status, if tracked or ignored"##;
-static EXTENDED_HELP: &str = r##"  -@, --extended     list each file's extended attributes and sizes"##;
+static GIT_HELP:      &str = r##"  --git               list each file's Git status, if tracked or ignored"##;
+static EXTENDED_HELP: &str = r##"  -@, --extended      list each file's extended attributes and sizes"##;
+static OCTAL_HELP:    &str = r##"  --octal-permissions list each file's permission in octal format"##;
 
 
 /// All the information needed to display the help text, which depends
@@ -119,6 +120,8 @@ impl fmt::Display for HelpString {
             write!(f, "\n{}", EXTENDED_HELP)?;
         }
 
+        write!(f, "\n{}", OCTAL_HELP)?;
+
         Ok(())
     }
 }

+ 2 - 1
src/options/view.rs

@@ -228,12 +228,13 @@ impl Columns {
         let group  = matches.has(&flags::GROUP)?;
         let inode  = matches.has(&flags::INODE)?;
         let links  = matches.has(&flags::LINKS)?;
+        let octal  = matches.has(&flags::OCTAL)?;
 
         let permissions = !matches.has(&flags::NO_PERMISSIONS)?;
         let filesize =    !matches.has(&flags::NO_FILESIZE)?;
         let user =        !matches.has(&flags::NO_USER)?;
 
-        Ok(Columns { time_types, git, blocks, group, inode, links, permissions, filesize, user })
+        Ok(Columns { time_types, git, octal, blocks, group, inode, links, permissions, filesize, user })
     }
 }
 

+ 3 - 0
src/output/render/mod.rs

@@ -28,3 +28,6 @@ pub use self::times::Render as TimeRender;
 
 mod users;
 pub use self::users::Colours as UserColours;
+
+mod octal;
+// octal uses just one colour

+ 116 - 0
src/output/render/octal.rs

@@ -0,0 +1,116 @@
+use ansi_term::Style;
+
+use crate::output::cell::TextCell;
+use crate::fs::fields as f;
+
+impl f::OctalPermissions {
+    fn bits_to_octal(r: bool, w: bool, x: bool) -> u8 {
+        (r  as u8) * 4 + (w as u8) * 2 + (x as u8) * 1
+    }
+
+    pub fn render(&self, style: Style) -> TextCell {
+
+        let perm = &self.permissions;
+        let octal_sticky = Self::bits_to_octal(perm.setuid, perm.setgid, perm.sticky);
+        let octal_owner = Self::bits_to_octal(perm.user_read, perm.user_write, perm.user_execute);
+        let octal_group = Self::bits_to_octal(perm.group_read, perm.group_write, perm.group_execute);
+        let octal_other = Self::bits_to_octal(perm.other_read, perm.other_write, perm.other_execute);
+
+        TextCell::paint(style, format!("{}{}{}{}", octal_sticky, octal_owner, octal_group, octal_other))
+    }
+
+}
+
+#[cfg(test)]
+pub mod test {
+    use crate::output::cell::TextCell;
+    use crate::fs::fields as f;
+
+    use ansi_term::Colour::*;
+
+
+    #[test]
+    fn normal_folder() {
+        let bits = f::Permissions {
+            user_read:  true, user_write:  true,  user_execute:  true, setuid: false,
+            group_read: true, group_write: false, group_execute: true, setgid: false,
+            other_read: true, other_write: false, other_execute: true, sticky: false,
+        };
+
+        let octal = f::OctalPermissions{ permissions: bits };
+
+        let expected = TextCell::paint_str(Purple.bold(), "0755");
+        assert_eq!(expected, octal.render(Purple.bold()).into());
+    }
+
+    #[test]
+    fn normal_file() {
+        let bits = f::Permissions {
+            user_read:  true, user_write:  true,  user_execute:  false, setuid: false,
+            group_read: true, group_write: false, group_execute: false, setgid: false,
+            other_read: true, other_write: false, other_execute: false, sticky: false,
+        };
+
+        let octal = f::OctalPermissions{ permissions: bits };
+
+        let expected = TextCell::paint_str(Purple.bold(), "0644");
+        assert_eq!(expected, octal.render(Purple.bold()).into());
+    }
+
+    #[test]
+    fn secret_file() {
+        let bits = f::Permissions {
+            user_read:  true,  user_write:  true,  user_execute:  false, setuid: false,
+            group_read: false, group_write: false, group_execute: false, setgid: false,
+            other_read: false, other_write: false, other_execute: false, sticky: false,
+        };
+
+        let octal = f::OctalPermissions{ permissions: bits };
+
+        let expected = TextCell::paint_str(Purple.bold(), "0600");
+        assert_eq!(expected, octal.render(Purple.bold()).into());
+    }
+
+    #[test]
+    fn sticky1() {
+        let bits = f::Permissions {
+            user_read:  true, user_write:  true,  user_execute:  true, setuid: true,
+            group_read: true, group_write: true,  group_execute: true, setgid: false,
+            other_read: true, other_write: true,  other_execute: true, sticky: false,
+        };
+
+        let octal = f::OctalPermissions{ permissions: bits };
+
+        let expected = TextCell::paint_str(Purple.bold(), "4777");
+        assert_eq!(expected, octal.render(Purple.bold()).into());
+
+    }
+
+    #[test]
+    fn sticky2() {
+        let bits = f::Permissions {
+            user_read:  true, user_write:  true,  user_execute:  true, setuid: false,
+            group_read: true, group_write: true,  group_execute: true, setgid: true,
+            other_read: true, other_write: true,  other_execute: true, sticky: false,
+        };
+
+        let octal = f::OctalPermissions{ permissions: bits };
+
+        let expected = TextCell::paint_str(Purple.bold(), "2777");
+        assert_eq!(expected, octal.render(Purple.bold()).into());
+    }
+
+    #[test]
+    fn sticky3() {
+        let bits = f::Permissions {
+            user_read:  true, user_write:  true,  user_execute:  true, setuid: false,
+            group_read: true, group_write: true,  group_execute: true, setgid: false,
+            other_read: true, other_write: true,  other_execute: true, sticky: true,
+        };
+
+        let octal = f::OctalPermissions{ permissions: bits };
+
+        let expected = TextCell::paint_str(Purple.bold(), "1777");
+        assert_eq!(expected, octal.render(Purple.bold()).into());
+    }
+}

+ 14 - 0
src/output/table.rs

@@ -49,6 +49,7 @@ pub struct Columns {
     pub blocks: bool,
     pub group: bool,
     pub git: bool,
+    pub octal: bool,
 
     // Defaults to true:
     pub permissions: bool,
@@ -64,6 +65,10 @@ impl Columns {
             columns.push(Column::Inode);
         }
 
+        if self.octal {
+            columns.push(Column::Octal);
+        }
+
         if self.permissions {
             columns.push(Column::Permissions);
         }
@@ -125,6 +130,7 @@ pub enum Column {
     HardLinks,
     Inode,
     GitStatus,
+    Octal,
 }
 
 /// Each column can pick its own **Alignment**. Usually, numbers are
@@ -161,6 +167,7 @@ impl Column {
             Column::HardLinks     => "Links",
             Column::Inode         => "inode",
             Column::GitStatus     => "Git",
+            Column::Octal         => "Octal",
         }
     }
 }
@@ -350,6 +357,12 @@ impl<'a, 'f> Table<'a> {
         }
     }
 
+    fn octal_permissions(&self, file: &File) -> f::OctalPermissions {
+        f::OctalPermissions {
+            permissions: file.permissions(),
+        }
+    }
+
     fn display(&self, file: &File, column: &Column, xattrs: bool) -> TextCell {
         use crate::output::table::TimeType::*;
 
@@ -362,6 +375,7 @@ impl<'a, 'f> Table<'a> {
             Column::User           => file.user().render(self.colours, &*self.env.lock_users()),
             Column::Group          => file.group().render(self.colours, &*self.env.lock_users()),
             Column::GitStatus      => self.git_status(file).render(self.colours),
+            Column::Octal          => self.octal_permissions(file).render(self.colours.octal),
 
             Column::Timestamp(Modified)  => file.modified_time().render(self.colours.date, &self.env.tz, &self.time_format),
             Column::Timestamp(Changed)   => file.changed_time() .render(self.colours.date, &self.env.tz, &self.time_format),

+ 2 - 0
src/style/colours.rs

@@ -23,6 +23,7 @@ pub struct Colours {
     pub inode:        Style,
     pub blocks:       Style,
     pub header:       Style,
+    pub octal:        Style,
 
     pub symlink_path:         Style,
     pub control_char:         Style,
@@ -174,6 +175,7 @@ impl Colours {
             date:         Blue.normal(),
             inode:        Purple.normal(),
             blocks:       Cyan.normal(),
+            octal:        Purple.normal(),
             header:       Style::default().underline(),
 
             symlink_path:         Cyan.normal(),