diff --git a/coreutils/src/commands/ln.rs b/coreutils/src/commands/ln.rs index b09b757..b851c3e 100644 --- a/coreutils/src/commands/ln.rs +++ b/coreutils/src/commands/ln.rs @@ -1,7 +1,6 @@ use boxutils::args::ArgParser; use boxutils::commands::Command; use std::fs; -use std::path::Path; pub struct Ln; @@ -17,6 +16,7 @@ impl Command for Ln { .add_option("-S") .parse_args("ln"); + let mut dereference = true; let help = args.get_normal_args().len() != 2 || args.get_flag("--help"); if help { println!("Usage: ln [-sfnbtv] [-S SUF] TARGET LINK"); @@ -31,7 +31,7 @@ impl Command for Ln { } if args.get_flag("-f") { - if fs::metadata(&destination).is_ok() { + if fs::exists(&destination).unwrap() { if fs::metadata(&destination).unwrap().is_dir() { fs::remove_dir_all(&destination).unwrap(); } else { @@ -41,10 +41,7 @@ impl Command for Ln { } if args.get_flag("-n") { - if Path::new(&destination).exists() { - println!("ln: {} exists, stopping...", destination); - return; - } + dereference = false; } if args.get_flag("-b") { @@ -54,13 +51,13 @@ impl Command for Ln { } if args.get_flag("-s") { - let symlink_result = boxutils::cross::fs::symlink(to_be_linked, destination); + let symlink_result = boxutils::cross::fs::symlink(to_be_linked, destination, dereference); if let Err(e) = symlink_result { eprintln!("ln: failed to create symlink: {}", e); } } else { - if let Err(e) = boxutils::cross::fs::hard_link(to_be_linked, destination) { + if let Err(e) = boxutils::cross::fs::hard_link(to_be_linked, destination, dereference) { eprintln!("ln: failed to create hard link: {}", e); } } diff --git a/utils/src/cross/fs.rs b/utils/src/cross/fs.rs index af15cd7..9660231 100644 --- a/utils/src/cross/fs.rs +++ b/utils/src/cross/fs.rs @@ -5,24 +5,56 @@ use std::os::unix::fs::symlink as unix_symlink; #[cfg(windows)] use std::os::windows::fs::{symlink_dir, symlink_file}; +fn deref(to_be_dereferenced: String) -> String { + let mut metadata = fs::metadata(&to_be_dereferenced).unwrap(); + let file = &to_be_dereferenced; + let mut new_file = file.clone(); + while metadata.is_symlink() { + new_file = String::from(fs::read_link(new_file.to_string()).unwrap().into_os_string().into_string().unwrap()); + metadata = fs::metadata(&new_file).unwrap() + } + + new_file +} + #[cfg(windows)] -pub fn symlink(to_be_linked: String, destination: String) -> std::io::Result<()> { - let target_metadata = fs::metadata(&to_be_linked)?; - if target_metadata.is_dir() { - symlink_dir(&to_be_linked, &destination) +pub fn symlink(to_be_linked: String, destination: String, dereference: bool) -> std::io::Result<()> { + if !dereference { + let target_metadata = fs::metadata(&to_be_linked)?; + if target_metadata.is_dir() { + symlink_dir(&to_be_linked, &destination) + } else { + symlink_file(&to_be_linked, &destination) + }?; } else { - symlink_file(&to_be_linked, &destination) - }?; + let dereferenced = deref(to_be_linked.clone()); + let deref_metadata = fs::metadata(&dereferenced)?; + if deref_metadata.is_dir() { + symlink_dir(&dereferenced, &destination) + } else { + symlink_file(&dereferenced, &destination) + }?; + } Ok(()) } #[cfg(unix)] -pub fn symlink(to_be_linked: String, destination: String) -> std::io::Result<()> { - unix_symlink(to_be_linked, destination)?; +pub fn symlink(to_be_linked: String, destination: String, dereference: bool) -> std::io::Result<()> { + if !dereference { + unix_symlink(to_be_linked, destination)?; + } else { + let dereferenced = deref(to_be_linked); + unix_symlink(dereferenced, destination)?; + } Ok(()) } -pub fn hard_link(to_be_linked: String, destination: String) -> std::io::Result<()> { - fs::hard_link(to_be_linked, destination)?; +pub fn hard_link(to_be_linked: String, destination: String, dereference: bool) -> std::io::Result<()> { + if !dereference { + fs::hard_link(to_be_linked, destination)?; + } else { + let dereferenced = deref(to_be_linked); + fs::hard_link(dereferenced, destination)?; + } Ok(()) }