mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
Merge pull request #895 from tarka/ls-uname-group
Add username and groupname lookup to `ls`
This commit is contained in:
commit
2713758b52
1 changed files with 83 additions and 33 deletions
116
src/ls/ls.rs
116
src/ls/ls.rs
|
@ -8,37 +8,41 @@
|
||||||
* For the full copyright and license information, please view the LICENSE file
|
* For the full copyright and license information, please view the LICENSE file
|
||||||
* that was distributed with this source code.
|
* that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate pretty_bytes;
|
extern crate pretty_bytes;
|
||||||
use pretty_bytes::converter::convert;
|
use pretty_bytes::converter::convert;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
use self::libc::c_char;
|
||||||
|
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::{ReadDir, DirEntry, FileType, Metadata};
|
use std::fs::{ReadDir, DirEntry, FileType, Metadata};
|
||||||
use std::ffi::{OsString};
|
use std::ffi::{OsString,CStr};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
Help,
|
Help,
|
||||||
Version,
|
Version,
|
||||||
List
|
List
|
||||||
}
|
}
|
||||||
|
|
||||||
static NAME: &'static str = "ls";
|
static NAME: &'static str = "ls";
|
||||||
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
pub fn uumain(args: Vec<String>) -> i32 {
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
let mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
|
|
||||||
opts.optflag("", "help", "display this help and exit");
|
opts.optflag("", "help", "display this help and exit");
|
||||||
opts.optflag("", "version", "output version information 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", "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("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='.*~'.");
|
opts.optflag("B", "ignore-backups", "Ignore files that end with ~. Equivalent to using `--ignore='*~'` or `--ignore='.*~'.");
|
||||||
|
@ -53,7 +57,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
panic!()
|
panic!()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mode = if matches.opt_present("version") {
|
let mode = if matches.opt_present("version") {
|
||||||
Mode::Version
|
Mode::Version
|
||||||
} else if matches.opt_present("help") {
|
} else if matches.opt_present("help") {
|
||||||
|
@ -61,20 +65,20 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
} else {
|
} else {
|
||||||
Mode::List
|
Mode::List
|
||||||
};
|
};
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
Mode::Version => version(),
|
Mode::Version => version(),
|
||||||
Mode::Help => help(),
|
Mode::Help => help(),
|
||||||
Mode::List => list(matches)
|
Mode::List => list(matches)
|
||||||
}
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version() {
|
fn version() {
|
||||||
println!("{} {}", NAME, VERSION);
|
println!("{} {}", NAME, VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help() {
|
fn help() {
|
||||||
let msg = format!("{0} {1}\n\n\
|
let msg = format!("{0} {1}\n\n\
|
||||||
Usage: {0} [OPTION]... DIRECTORY \n \
|
Usage: {0} [OPTION]... DIRECTORY \n \
|
||||||
|
@ -93,15 +97,15 @@ fn list(options: getopts::Matches) {
|
||||||
} else {
|
} else {
|
||||||
options.free.iter().cloned().collect()
|
options.free.iter().cloned().collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
for loc in locs {
|
for loc in locs {
|
||||||
let p = Path::new(&loc);
|
let p = Path::new(&loc);
|
||||||
|
|
||||||
if !p.exists() {
|
if !p.exists() {
|
||||||
show_error!("Cannot find path '{}' because it does not exist.", loc);
|
show_error!("Cannot find path '{}' because it does not exist.", loc);
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.is_dir() {
|
if p.is_dir() {
|
||||||
match fs::read_dir(p) {
|
match fs::read_dir(p) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -110,8 +114,8 @@ fn list(options: getopts::Matches) {
|
||||||
},
|
},
|
||||||
Ok(entries) => enter_directory(entries, &options),
|
Ok(entries) => enter_directory(entries, &options),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.is_file() {
|
if p.is_file() {
|
||||||
display_item(Path::new(p), &options)
|
display_item(Path::new(p), &options)
|
||||||
}
|
}
|
||||||
|
@ -127,31 +131,78 @@ fn enter_directory(contents: ReadDir, options: &getopts::Matches) {
|
||||||
},
|
},
|
||||||
Ok(en) => en
|
Ok(en) => en
|
||||||
};
|
};
|
||||||
|
|
||||||
// Currently have a DirEntry that we can believe in.
|
// Currently have a DirEntry that we can believe in.
|
||||||
display_dir_entry(entry, options);
|
display_dir_entry(entry, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) {
|
fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) {
|
||||||
let md = match entry.metadata() {
|
let md = match entry.metadata() {
|
||||||
Err(e) => {
|
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);
|
display_file_name(entry.file_name()), e);
|
||||||
panic!();
|
panic!();
|
||||||
},
|
},
|
||||||
Ok(md) => md
|
Ok(md) => md
|
||||||
};
|
};
|
||||||
|
|
||||||
println!(" {}{} {} somebody somegroup {: >9} {}",
|
println!(" {}{} {} {} {} {: >9} {}",
|
||||||
display_file_type(entry.file_type()),
|
display_file_type(entry.file_type()),
|
||||||
display_permissions(&md),
|
display_permissions(&md),
|
||||||
display_symlink_count(&md),
|
display_symlink_count(&md),
|
||||||
|
display_uname(&md),
|
||||||
|
display_group(&md),
|
||||||
display_file_size(&md, options),
|
display_file_size(&md, options),
|
||||||
display_file_name(entry.file_name())
|
display_file_name(entry.file_name())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cstr2string(cstr: *const c_char) -> String {
|
||||||
|
unsafe { String::from_utf8_lossy(CStr::from_ptr(cstr).to_bytes()).to_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;
|
||||||
|
|
||||||
|
let pw = unsafe { getpwuid(metadata.uid()) };
|
||||||
|
if !pw.is_null() {
|
||||||
|
cstr2string(unsafe { ptr::read(pw).pw_name })
|
||||||
|
} else {
|
||||||
|
metadata.uid().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "linux")]
|
||||||
|
fn display_group(metadata: &Metadata) -> String {
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
let ent = unsafe { getgrgid(metadata.gid()) };
|
||||||
|
if !ent.is_null() {
|
||||||
|
cstr2string(unsafe { ptr::read(ent).gr_name })
|
||||||
|
} else {
|
||||||
|
metadata.gid().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "linux"))]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn display_uname(metadata: &Metadata) -> String {
|
||||||
|
"somebody".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "linux"))]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn display_group(metadata: &Metadata) -> String {
|
||||||
|
"somegroup".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String {
|
fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String {
|
||||||
if options.opt_present("human-readable") {
|
if options.opt_present("human-readable") {
|
||||||
convert(metadata.len() as f64)
|
convert(metadata.len() as f64)
|
||||||
|
@ -166,9 +217,9 @@ fn display_file_type(file_type: Result<FileType, std::io::Error>) -> String {
|
||||||
show_error!("{}", e);
|
show_error!("{}", e);
|
||||||
panic!()
|
panic!()
|
||||||
},
|
},
|
||||||
Ok(ft) => ft
|
Ok(ft) => ft
|
||||||
};
|
};
|
||||||
|
|
||||||
if file_type.is_dir() {
|
if file_type.is_dir() {
|
||||||
"d".to_string()
|
"d".to_string()
|
||||||
} else if file_type.is_symlink() {
|
} else if file_type.is_symlink() {
|
||||||
|
@ -193,7 +244,6 @@ fn display_symlink_count(metadata: &Metadata) -> String {
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
fn display_symlink_count(metadata: &Metadata) -> String {
|
fn display_symlink_count(metadata: &Metadata) -> String {
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
metadata.nlink().to_string()
|
metadata.nlink().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +254,7 @@ fn display_permissions(metadata: &Metadata) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
|
|
||||||
fn display_permissions(_metadata: &Metadata) -> String {
|
fn display_permissions(_metadata: &Metadata) -> String {
|
||||||
//use std::os::unix::fs::PermissionsExt;
|
//use std::os::unix::fs::PermissionsExt;
|
||||||
"xxxxxxxxx".to_string()
|
"xxxxxxxxx".to_string()
|
||||||
|
@ -213,15 +263,15 @@ fn display_permissions(_metadata: &Metadata) -> String {
|
||||||
fn display_item(item: &Path, options: &getopts::Matches) {
|
fn display_item(item: &Path, options: &getopts::Matches) {
|
||||||
// let fileType = item.file
|
// let fileType = item.file
|
||||||
// let mut fileMeta = String::new();
|
// let mut fileMeta = String::new();
|
||||||
|
|
||||||
// fileMeta = fileMeta + if item.is_dir() {
|
// fileMeta = fileMeta + if item.is_dir() {
|
||||||
// "d"
|
// "d"
|
||||||
// } else if item.sy
|
// } else if item.sy
|
||||||
// } else {
|
// } else {
|
||||||
// "-"
|
// "-"
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// println!("{}{}", displayString, item.display());
|
// println!("{}{}", displayString, item.display());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue