From 6179b89bcc9e9d4603c557d8976ba0c96072913d Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 4 Jun 2016 14:50:52 +0100 Subject: [PATCH 1/6] Add conversion of UID to username for `ls` --- src/ls/ls.rs | 89 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 33 deletions(-) diff --git a/src/ls/ls.rs b/src/ls/ls.rs index 3c7c4e58f..775f61277 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -8,37 +8,40 @@ * For the full copyright and license information, please view the LICENSE file * that was distributed with this source code. */ - + extern crate getopts; extern crate pretty_bytes; use pretty_bytes::converter::convert; - + #[macro_use] extern crate uucore; - + use getopts::Options; use std::fs; use std::fs::{ReadDir, DirEntry, FileType, Metadata}; -use std::ffi::{OsString}; +use std::ffi::{OsString,CStr}; use std::path::Path; use std::io::Write; - +use std::ptr; +use uucore::c_types::getpwuid; + + #[derive(Copy, Clone, PartialEq)] enum Mode { Help, Version, List } - + static NAME: &'static str = "ls"; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); - + pub fn uumain(args: Vec) -> i32 { let mut opts = Options::new(); - + opts.optflag("", "help", "display this help and exit"); opts.optflag("", "version", "output version information and exit"); - + opts.optflag("a", "all", "Do not ignore hidden files (files with names that start with '.')."); opts.optflag("A", "almost-all", "In a directory, do not ignore all file names that start with '.', only ignore '.' and '..'."); opts.optflag("B", "ignore-backups", "Ignore files that end with ~. Equivalent to using `--ignore='*~'` or `--ignore='.*~'."); @@ -53,7 +56,7 @@ pub fn uumain(args: Vec) -> i32 { panic!() }, }; - + let mode = if matches.opt_present("version") { Mode::Version } else if matches.opt_present("help") { @@ -61,20 +64,20 @@ pub fn uumain(args: Vec) -> i32 { } else { Mode::List }; - + match mode { Mode::Version => version(), Mode::Help => help(), Mode::List => list(matches) } - + 0 } - + fn version() { println!("{} {}", NAME, VERSION); } - + fn help() { let msg = format!("{0} {1}\n\n\ Usage: {0} [OPTION]... DIRECTORY \n \ @@ -93,15 +96,15 @@ fn list(options: getopts::Matches) { } else { options.free.iter().cloned().collect() }; - + for loc in locs { let p = Path::new(&loc); - + if !p.exists() { show_error!("Cannot find path '{}' because it does not exist.", loc); panic!(); } - + if p.is_dir() { match fs::read_dir(p) { Err(e) => { @@ -110,8 +113,8 @@ fn list(options: getopts::Matches) { }, Ok(entries) => enter_directory(entries, &options), }; - } - + } + if p.is_file() { display_item(Path::new(p), &options) } @@ -127,31 +130,52 @@ fn enter_directory(contents: ReadDir, options: &getopts::Matches) { }, Ok(en) => en }; - + // Currently have a DirEntry that we can believe in. display_dir_entry(entry, options); - } + } } fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) { let md = match entry.metadata() { Err(e) => { - show_error!("Unable to retrieve metadata for {}. \n Error: {}", + show_error!("Unable to retrieve metadata for {}. \n Error: {}", display_file_name(entry.file_name()), e); panic!(); }, Ok(md) => md }; - - println!(" {}{} {} somebody somegroup {: >9} {}", + + println!(" {}{} {} {} {} {: >9} {}", display_file_type(entry.file_type()), display_permissions(&md), display_symlink_count(&md), + display_uname(&md), + display_group(&md), display_file_size(&md, options), display_file_name(entry.file_name()) ); } +fn display_uname(metadata: &Metadata) -> String { + use std::os::unix::fs::MetadataExt; + + let pw = unsafe { getpwuid(metadata.uid()) }; + if !pw.is_null() { + let pw_name = unsafe { + String::from_utf8_lossy(CStr::from_ptr(ptr::read(pw).pw_name).to_bytes()).to_string() + }; + pw_name + } else { + metadata.uid().to_string() + } +} + +fn display_group(metadata: &Metadata) -> String { + use std::os::unix::fs::MetadataExt; + metadata.gid().to_string() +} + fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String { if options.opt_present("human-readable") { convert(metadata.len() as f64) @@ -166,9 +190,9 @@ fn display_file_type(file_type: Result) -> String { show_error!("{}", e); panic!() }, - Ok(ft) => ft + Ok(ft) => ft }; - + if file_type.is_dir() { "d".to_string() } else if file_type.is_symlink() { @@ -193,7 +217,6 @@ fn display_symlink_count(metadata: &Metadata) -> String { #[cfg(target_family = "unix")] fn display_symlink_count(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; - metadata.nlink().to_string() } @@ -204,7 +227,7 @@ fn display_permissions(metadata: &Metadata) -> String { } #[cfg(target_family = "unix")] - + fn display_permissions(_metadata: &Metadata) -> String { //use std::os::unix::fs::PermissionsExt; "xxxxxxxxx".to_string() @@ -213,15 +236,15 @@ fn display_permissions(_metadata: &Metadata) -> String { fn display_item(item: &Path, options: &getopts::Matches) { // let fileType = item.file // let mut fileMeta = String::new(); - + // fileMeta = fileMeta + if item.is_dir() { // "d" // } else if item.sy // } else { // "-" // }; - - - + + + // println!("{}{}", displayString, item.display()); -} \ No newline at end of file +} From 04522760f1b3e6aa7f6404e005fde73dcd687eb2 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 4 Jun 2016 15:12:40 +0100 Subject: [PATCH 2/6] Break cstring->String conversion out into function --- src/ls/ls.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ls/ls.rs b/src/ls/ls.rs index 775f61277..a2f04d3a9 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -16,6 +16,9 @@ use pretty_bytes::converter::convert; #[macro_use] extern crate uucore; +extern crate libc; +use self::libc::c_char; + use getopts::Options; use std::fs; use std::fs::{ReadDir, DirEntry, FileType, Metadata}; @@ -23,7 +26,7 @@ use std::ffi::{OsString,CStr}; use std::path::Path; use std::io::Write; use std::ptr; -use uucore::c_types::getpwuid; +use uucore::c_types::{getpwuid, getgrgid}; #[derive(Copy, Clone, PartialEq)] @@ -157,15 +160,16 @@ fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) { ); } +fn cstr2string(cstr: *const c_char) -> String { + unsafe { String::from_utf8_lossy(CStr::from_ptr(cstr).to_bytes()).to_string() } +} + fn display_uname(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; let pw = unsafe { getpwuid(metadata.uid()) }; if !pw.is_null() { - let pw_name = unsafe { - String::from_utf8_lossy(CStr::from_ptr(ptr::read(pw).pw_name).to_bytes()).to_string() - }; - pw_name + cstr2string(unsafe { ptr::read(pw).pw_name }) } else { metadata.uid().to_string() } @@ -173,7 +177,7 @@ fn display_uname(metadata: &Metadata) -> String { fn display_group(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; - metadata.gid().to_string() + metadata.uid().to_string() } fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String { From ce7f23bcc45aa311fb579f7bf2e47c5c9ffd4eb3 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 4 Jun 2016 15:14:59 +0100 Subject: [PATCH 3/6] Fill in group name for `ls` --- src/ls/ls.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ls/ls.rs b/src/ls/ls.rs index a2f04d3a9..d414a1ac8 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -177,7 +177,13 @@ fn display_uname(metadata: &Metadata) -> String { fn display_group(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; - metadata.uid().to_string() + + let ent = unsafe { getgrgid(metadata.gid()) }; + if !ent.is_null() { + cstr2string(unsafe { ptr::read(ent).gr_name }) + } else { + metadata.gid().to_string() + } } fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String { From 8161bb7fe185c25f73aa767481fa5096d0fa0ec3 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 4 Jun 2016 15:30:39 +0100 Subject: [PATCH 4/6] Flag uname/group functions as unix-specific and add NO-OP Windows versions. --- src/ls/ls.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ls/ls.rs b/src/ls/ls.rs index d414a1ac8..c3803cbfc 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -164,6 +164,7 @@ fn cstr2string(cstr: *const c_char) -> String { unsafe { String::from_utf8_lossy(CStr::from_ptr(cstr).to_bytes()).to_string() } } +#[cfg(target_family = "unix")] fn display_uname(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; @@ -175,6 +176,7 @@ fn display_uname(metadata: &Metadata) -> String { } } +#[cfg(target_family = "unix")] fn display_group(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; @@ -186,6 +188,18 @@ fn display_group(metadata: &Metadata) -> String { } } +#[cfg(target_family = "windows")] +#[allow(unused_variables)] +fn display_uname(metadata: &Metadata) -> String { + "somebody".to_string() +} + +#[cfg(target_family = "windows")] +#[allow(unused_variables)] +fn display_group(metadata: &Metadata) -> String { + "somegroup".to_string() +} + fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String { if options.opt_present("human-readable") { convert(metadata.len() as f64) From 1606770a3e85dc8342acc7e3e4cc48363be3adea Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 5 Jun 2016 11:07:28 +0100 Subject: [PATCH 5/6] getpwuid is `linux` platform only currently. --- src/ls/ls.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ls/ls.rs b/src/ls/ls.rs index c3803cbfc..cebc60156 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -164,7 +164,9 @@ fn cstr2string(cstr: *const c_char) -> String { unsafe { String::from_utf8_lossy(CStr::from_ptr(cstr).to_bytes()).to_string() } } -#[cfg(target_family = "unix")] +// Currently getpwuid is `linux` target only. If it's broken out into +// a posix-compliant attribute this can be updated... +#[cfg(target_family = "linux")] fn display_uname(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; @@ -176,7 +178,7 @@ fn display_uname(metadata: &Metadata) -> String { } } -#[cfg(target_family = "unix")] +#[cfg(target_family = "linux")] fn display_group(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt; @@ -188,13 +190,13 @@ fn display_group(metadata: &Metadata) -> String { } } -#[cfg(target_family = "windows")] +#[cfg(not(target_family = "linux"))] #[allow(unused_variables)] fn display_uname(metadata: &Metadata) -> String { "somebody".to_string() } -#[cfg(target_family = "windows")] +#[cfg(not(target_family = "linux"))] #[allow(unused_variables)] fn display_group(metadata: &Metadata) -> String { "somegroup".to_string() From 7a3ba3242a179304fb8a4add99504e91967816f4 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 5 Jun 2016 11:45:44 +0100 Subject: [PATCH 6/6] Need to make the `use` Linux-only too. --- src/ls/ls.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ls/ls.rs b/src/ls/ls.rs index cebc60156..a6fef41a6 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -26,8 +26,6 @@ use std::ffi::{OsString,CStr}; use std::path::Path; use std::io::Write; use std::ptr; -use uucore::c_types::{getpwuid, getgrgid}; - #[derive(Copy, Clone, PartialEq)] enum Mode { @@ -166,6 +164,9 @@ fn cstr2string(cstr: *const c_char) -> String { // Currently getpwuid is `linux` target only. If it's broken out into // a posix-compliant attribute this can be updated... +#[cfg(target_family = "linux")] +use uucore::c_types::{getpwuid, getgrgid}; + #[cfg(target_family = "linux")] fn display_uname(metadata: &Metadata) -> String { use std::os::unix::fs::MetadataExt;