Skip to content

Instantly share code, notes, and snippets.

@mre
Created March 9, 2018 01:15
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mre/91ebb841c34df69671bd117ead621a8b to your computer and use it in GitHub Desktop.
Save mre/91ebb841c34df69671bd117ead621a8b to your computer and use it in GitHub Desktop.
A simple clone of `ls -l` in Rust
extern crate chrono;
extern crate libc;
#[macro_use]
extern crate structopt;
use std::fs;
use std::path::PathBuf;
use std::error::Error;
use std::process;
use std::os::unix::fs::PermissionsExt;
use libc::{S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};
use structopt::StructOpt;
use chrono::{DateTime, Local};
#[derive(StructOpt, Debug)]
struct Opt {
/// Output file
#[structopt(default_value = ".", parse(from_os_str))]
path: PathBuf,
}
fn parse_permissions(mode: u16) -> String {
let user = triplet(mode, S_IRUSR, S_IWUSR, S_IXUSR);
let group = triplet(mode, S_IRGRP, S_IWGRP, S_IXGRP);
let other = triplet(mode, S_IROTH, S_IWOTH, S_IXOTH);
[user, group, other].join("")
}
fn triplet(mode: u16, read: u16, write: u16, execute: u16) -> String {
match (mode & read, mode & write, mode & execute) {
(0, 0, 0) => "---",
(_, 0, 0) => "r--",
(0, _, 0) => "-w-",
(0, 0, _) => "--x",
(_, 0, _) => "r-x",
(_, _, 0) => "rw-",
(0, _, _) => "-wx",
(_, _, _) => "rwx",
}.to_string()
}
fn main() {
let opt = Opt::from_args();
if let Err(ref e) = run(&opt.path) {
println!("{}", e);
process::exit(1);
}
}
fn run(dir: &PathBuf) -> Result<(), Box<Error>> {
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let metadata = entry.metadata()?;
let file_name = entry
.file_name()
.into_string()
.or_else(|f| Err(format!("Invalid entry: {:?}", f)))?;
let size = metadata.len();
let modified: DateTime<Local> = DateTime::from(metadata.modified()?);
let mode = metadata.permissions().mode();
println!(
"{} {:>5} {} {}",
parse_permissions(mode as u16),
size,
modified.format("%_d %b %H:%M").to_string(),
file_name
);
}
}
Ok(())
}
@matthewboman
Copy link

Lines 24-26 cause this error expected u16, found u32 on Linux Mint 17.3 but this works when everything is changed to u32

@thamognya
Copy link

Here is the fixed version

extern crate chrono;
extern crate libc;
#[macro_use]
extern crate structopt;

use std::fs;
use std::path::PathBuf;
use std::error::Error;
use std::process;
use std::os::unix::fs::PermissionsExt;
use libc::{S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};

use structopt::StructOpt;
use chrono::{DateTime, Local};

#[derive(StructOpt, Debug)]
struct Opt {
    /// Output file
    #[structopt(default_value = ".", parse(from_os_str))]
    path: PathBuf,
}

fn parse_permissions(mode: u32) -> String {
    let user = triplet(mode, S_IRUSR, S_IWUSR, S_IXUSR);
    let group = triplet(mode, S_IRGRP, S_IWGRP, S_IXGRP);
    let other = triplet(mode, S_IROTH, S_IWOTH, S_IXOTH);
    [user, group, other].join("")
}

fn triplet(mode: u32, read: u32, write: u32, execute: u32) -> String {
    match (mode & read, mode & write, mode & execute) {
        (0, 0, 0) => "---",
        (_, 0, 0) => "r--",
        (0, _, 0) => "-w-",
        (0, 0, _) => "--x",
        (_, 0, _) => "r-x",
        (_, _, 0) => "rw-",
        (0, _, _) => "-wx",
        (_, _, _) => "rwx",
    }.to_string()
}

fn main() {
    let opt = Opt::from_args();
    if let Err(ref e) = run(&opt.path) {
        println!("{}", e);
        process::exit(1);
    }
}

fn run(dir: &PathBuf) -> Result<(), Box<dyn Error>> {
    if dir.is_dir() {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let metadata = entry.metadata()?;
            let file_name = entry
                .file_name()
                .into_string()
                .or_else(|f| Err(format!("Invalid entry: {:?}", f)))?;

            let size = metadata.len();
            let modified: DateTime<Local> = DateTime::from(metadata.modified()?);
            let mode = metadata.permissions().mode();

            println!(
                "{} {:>5} {} {}",
                parse_permissions(mode as u32),
                size,
                modified.format("%_d %b %H:%M").to_string(),
                file_name
            );
        }
    }
    Ok(())
}

@mre
Copy link
Author

mre commented Jun 29, 2022

Thanks a lot for providing a fix @thamognya. 👍

@thamognya
Copy link

thamognya commented Jul 1, 2022

you're welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment