]> git.proxmox.com Git - proxmox-backup.git/commitdiff
catalog: shell: Improve output of stat command.
authorChristian Ebner <c.ebner@proxmox.com>
Wed, 26 Feb 2020 16:14:19 +0000 (17:14 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 27 Feb 2020 05:53:17 +0000 (06:53 +0100)
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
src/backup/catalog_shell.rs

index 0d467cb86a999e863ed42852ecc0b97652afe3b0..a59446a3010ec81c0d39a118d414b24919794ce5 100644 (file)
@@ -1,11 +1,14 @@
 use std::cell::RefCell;
 use std::collections::HashMap;
+use std::convert::TryFrom;
 use std::ffi::{CString, OsStr};
 use std::io::Write;
 use std::os::unix::ffi::OsStrExt;
 use std::path::Path;
 
+use chrono::{Utc, offset::TimeZone};
 use failure::*;
+use nix::sys::stat::{Mode, SFlag};
 
 use proxmox::api::{cli::*, *};
 use proxmox::sys::linux::tty;
@@ -313,21 +316,92 @@ fn stat_command(path: String) -> Result<(), Error> {
         let path = ctx.canonical_path(&path)?;
         let item = ctx.lookup(&path)?;
         let mut out = std::io::stdout();
-        out.write_all(b"File: ")?;
+        out.write_all(b"  File:\t")?;
         out.write_all(item.filename.as_bytes())?;
-        out.write_all(&[b'\n'])?;
-        out.write_all(format!("Size: {}\n", item.size).as_bytes())?;
-        out.write_all(b"Type: ")?;
-        match item.entry.mode as u32 & libc::S_IFMT {
-            libc::S_IFDIR => out.write_all(b"directory\n")?,
-            libc::S_IFREG => out.write_all(b"regular file\n")?,
-            libc::S_IFLNK => out.write_all(b"symbolic link\n")?,
-            libc::S_IFBLK => out.write_all(b"block special file\n")?,
-            libc::S_IFCHR => out.write_all(b"character special file\n")?,
+        out.write_all(b"\n")?;
+        out.write_all(format!("  Size:\t{}\t\t", item.size).as_bytes())?;
+        out.write_all(b"Type:\t")?;
+
+        let mut mode_out = vec![b'-'; 10];
+        match SFlag::from_bits_truncate(item.entry.mode as u32) {
+            SFlag::S_IFDIR => {
+                mode_out[0] = b'd';
+                out.write_all(b"directory\n")?;
+            }
+            SFlag::S_IFREG => {
+                mode_out[0] = b'-';
+                out.write_all(b"regular file\n")?;
+            }
+            SFlag::S_IFLNK => {
+                mode_out[0] = b'l';
+                out.write_all(b"symbolic link\n")?;
+            }
+            SFlag::S_IFBLK => {
+                mode_out[0] = b'b';
+                out.write_all(b"block special file\n")?;
+            }
+            SFlag::S_IFCHR => {
+                mode_out[0] = b'c';
+                out.write_all(b"character special file\n")?;
+            }
             _ => out.write_all(b"unknown\n")?,
         };
-        out.write_all(format!("Uid: {}\n", item.entry.uid).as_bytes())?;
-        out.write_all(format!("Gid: {}\n", item.entry.gid).as_bytes())?;
+
+        let mode = Mode::from_bits_truncate(item.entry.mode as u32);
+        if mode.contains(Mode::S_IRUSR) {
+            mode_out[1] = b'r';
+        }
+        if mode.contains(Mode::S_IWUSR) {
+            mode_out[2] = b'w';
+        }
+        match (mode.contains(Mode::S_IXUSR), mode.contains(Mode::S_ISUID)) {
+            (false, false) => mode_out[3] = b'-',
+            (true, false) => mode_out[3] = b'x',
+            (false, true) => mode_out[3] = b'S',
+            (true, true) => mode_out[3] = b's',
+        }
+
+        if mode.contains(Mode::S_IRGRP) {
+            mode_out[4] = b'r';
+        }
+        if mode.contains(Mode::S_IWGRP) {
+            mode_out[5] = b'w';
+        }
+        match (mode.contains(Mode::S_IXGRP), mode.contains(Mode::S_ISGID)) {
+            (false, false) => mode_out[6] = b'-',
+            (true, false) => mode_out[6] = b'x',
+            (false, true) => mode_out[6] = b'S',
+            (true, true) => mode_out[6] = b's',
+        }
+
+        if mode.contains(Mode::S_IROTH) {
+            mode_out[7] = b'r';
+        }
+        if mode.contains(Mode::S_IWOTH) {
+            mode_out[8] = b'w';
+        }
+        match (mode.contains(Mode::S_IXOTH), mode.contains(Mode::S_ISVTX)) {
+            (false, false) => mode_out[9] = b'-',
+            (true, false) => mode_out[9] = b'x',
+            (false, true) => mode_out[9] = b'T',
+            (true, true) => mode_out[9] = b't',
+        }
+
+        if !item.xattr.xattrs.is_empty() {
+            mode_out.push(b'+');
+        }
+
+        out.write_all(b"Access:\t")?;
+        out.write_all(&mode_out)?;
+        out.write_all(b"\t")?;
+        out.write_all(format!(" Uid:\t{}\t", item.entry.uid).as_bytes())?;
+        out.write_all(format!("Gid:\t{}\n", item.entry.gid).as_bytes())?;
+
+        let time = i64::try_from(item.entry.mtime)?;
+        let sec = time / 1_000_000_000;
+        let nsec = u32::try_from(time % 1_000_000_000)?;
+        let dt = Utc.timestamp(sec, nsec);
+        out.write_all(format!("Modify:\t{}\n", dt.to_rfc2822()).as_bytes())?;
         out.flush()?;
         Ok(())
     })