-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
readlink: implement -f #349
readlink: implement -f #349
Conversation
by a quick look, it feels like ftw should be able to do this? |
From 2a19daa37325b26bdb5af0cd1ec4f2f9a3967991 Mon Sep 17 00:00:00 2001
From: fox0 <[email protected]>
Date: Sun, 20 Oct 2024 15:09:38 +0700
Subject: [PATCH] readlink: #[cfg(feature = "full")]
---
tree/readlink.rs | 120 ++++++++++++++++++++++++++---------------------
1 file changed, 66 insertions(+), 54 deletions(-)
diff --git a/tree/readlink.rs b/tree/readlink.rs
index 7a35e74..0544372 100644
--- a/tree/readlink.rs
+++ b/tree/readlink.rs
@@ -13,7 +13,9 @@ use plib::PROJECT_NAME;
use std::error::Error;
use std::fs;
use std::io::{stderr, stdout, ErrorKind, Write};
-use std::path::{Component, Path, PathBuf};
+#[cfg(feature = "full")]
+use std::path::Component;
+use std::path::{Path, PathBuf};
/// readlink — display the contents of a symbolic link
#[derive(Parser)]
@@ -25,6 +27,7 @@ struct Args {
// Not POSIX, but implemented by BusyBox, FreeBSD, GNU Core Utilities, toybox, and others
/// Canonicalize the provided path, resolving symbolic links repeatedly if needed. The absolute path of the resolved file is printed.
+ #[cfg(feature = "full")]
#[arg(short = 'f')]
canonicalize: bool,
@@ -43,12 +46,19 @@ struct Args {
// Behavior of "readlink -f /non-existent-directory/non-existent-file" does not vary
// All implementations: print nothing, exit code 1
fn do_readlink(args: Args) -> Result<String, String> {
+ #[cfg(feature = "full")]
let Args {
no_newline,
canonicalize,
verbose,
pathname,
} = args;
+ #[cfg(not(feature = "full"))]
+ let Args {
+ no_newline,
+ verbose,
+ pathname,
+ } = args;
let pathname_path = pathname.as_path();
@@ -98,10 +108,11 @@ fn do_readlink(args: Args) -> Result<String, String> {
}
};
+ #[cfg(feature = "full")]
if canonicalize {
let recursively_resolved_path_buf = recursive_resolve(pathname_path.to_owned())?;
- match fs::canonicalize(recursively_resolved_path_buf.as_path()) {
+ return match fs::canonicalize(recursively_resolved_path_buf.as_path()) {
Ok(pa) => format_returned_path(pa.as_path()),
Err(er) => {
let mut components = recursively_resolved_path_buf.components();
@@ -140,65 +151,32 @@ fn do_readlink(args: Args) -> Result<String, String> {
map_io_error(&er)
}
}
- }
- } else {
- match fs::symlink_metadata(pathname_path) {
- Ok(me) => {
- if !me.is_symlink() {
- // POSIX says:
- // "If file does not name a symbolic link, readlink shall write a diagnostic message to standard error and exit with non-zero status."
- // However, this is violated by almost all implementations
- return if verbose {
- format_error("Not a symbolic link", None)
- } else {
- Err(String::new())
- };
- }
-
- match fs::read_link(pathname_path) {
- Ok(pa) => format_returned_path(pa.as_path()),
- Err(er) => map_io_error(&er),
- }
- }
- Err(er) => map_io_error(&er),
- }
+ };
}
-}
-
-fn main() -> Result<(), Box<dyn std::error::Error>> {
- // parse command line arguments
- let args = Args::parse();
-
- setlocale(LocaleCategory::LcAll, "");
- textdomain(PROJECT_NAME)?;
- bind_textdomain_codeset(PROJECT_NAME, "UTF-8")?;
-
- let exit_code = match do_readlink(args) {
- Ok(output) => {
- let mut stdout_lock = stdout().lock();
-
- write!(stdout_lock, "{output}").unwrap();
-
- stdout_lock.flush().unwrap();
-
- 0_i32
- }
- Err(error_description) => {
- if !error_description.is_empty() {
- let mut stderr_lock = stderr().lock();
- writeln!(&mut stderr_lock, "readlink: {error_description}").unwrap();
-
- stderr_lock.flush().unwrap();
+ match fs::symlink_metadata(pathname_path) {
+ Ok(me) => {
+ if !me.is_symlink() {
+ // POSIX says:
+ // "If file does not name a symbolic link, readlink shall write a diagnostic message to standard error and exit with non-zero status."
+ // However, this is violated by almost all implementations
+ return if verbose {
+ format_error("Not a symbolic link", None)
+ } else {
+ Err(String::new())
+ };
}
- 1_i32
+ match fs::read_link(pathname_path) {
+ Ok(pa) => format_returned_path(pa.as_path()),
+ Err(er) => map_io_error(&er),
+ }
}
- };
-
- std::process::exit(exit_code);
+ Err(er) => map_io_error(&er),
+ }
}
+#[cfg(feature = "full")]
fn recursive_resolve(starting_path_buf: PathBuf) -> Result<PathBuf, String> {
let mut current_path_buf = starting_path_buf;
@@ -239,3 +217,37 @@ fn recursive_resolve(starting_path_buf: PathBuf) -> Result<PathBuf, String> {
Ok(current_path_buf)
}
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ // parse command line arguments
+ let args = Args::parse();
+
+ setlocale(LocaleCategory::LcAll, "");
+ textdomain(PROJECT_NAME)?;
+ bind_textdomain_codeset(PROJECT_NAME, "UTF-8")?;
+
+ let exit_code = match do_readlink(args) {
+ Ok(output) => {
+ let mut stdout_lock = stdout().lock();
+
+ write!(stdout_lock, "{output}").unwrap();
+
+ stdout_lock.flush().unwrap();
+
+ 0_i32
+ }
+ Err(error_description) => {
+ if !error_description.is_empty() {
+ let mut stderr_lock = stderr().lock();
+
+ writeln!(&mut stderr_lock, "readlink: {error_description}").unwrap();
+
+ stderr_lock.flush().unwrap();
+ }
+
+ 1_i32
+ }
+ };
+
+ std::process::exit(exit_code);
+}
--
2.39.2
|
re @fox0: Making this option configurable is an understandable suggestion. However, in this case, wide support by FreeBSD and Linux suggests this is OK, by virtue of our rule in readme:
This broad OS support of option -f also suggests it may appear in a future POSIX specification. Merging the option without an ifdef (my C lingo for rust cfg) is preferable. We assume here is the option is "popular and common", and accept the cost of option and prefer fewer compile variants to test (with/without cfg). |
5d7f1df
to
eb2d992
Compare
I wasn't familiar with that part of the codebase. Just took at look at this function, which I think may be what you're referring to: Lines 483 to 585 in a08d82d
I'm not sure how much code could be saved by trying to use that abstraction. It doesn't look super promising to me, but I can take another look if this is a concern. |
No description provided.