main.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
  2. // All rights reserved. This file is part of core-utils, distributed under the
  3. // GPL v3 license. For full terms please see the LICENSE file.
  4. #![crate_type = "bin"]
  5. #![crate_name = "ln"]
  6. #![feature(path_ext,collections)]
  7. static VERS: &'static str = "0.1.0";
  8. static PROG: &'static str = "ln";
  9. extern crate getopts;
  10. extern crate util;
  11. use getopts::{Options};
  12. use util::{Status};
  13. use std::env;
  14. use std::fs;
  15. use std::os;
  16. use std::path::{PathBuf};
  17. use std::fs::{PathExt};
  18. fn unix_symlink(from: &PathBuf, to: &PathBuf, verbose: bool) {
  19. match os::unix::fs::symlink(from, to) {
  20. Ok(_) => {
  21. if verbose {
  22. println!("{} -> {}", from.display(), to.display());
  23. }
  24. },
  25. Err(e) => {
  26. util::err(PROG, Status::Error, e.to_string());
  27. }
  28. };
  29. }
  30. fn sym_link_files(files: Vec<String>, to: &PathBuf, force: bool, verbose: bool) {
  31. for item in files.iter() {
  32. if !to.is_dir() {
  33. util::err(PROG, Status::Error, String::from(String::from(
  34. to.to_str().unwrap()) + " is not a directory"));
  35. } else {
  36. soft_link(&PathBuf::from(item), &to.join(PathBuf::from(item)), force, verbose);
  37. }
  38. }
  39. }
  40. fn hard_link_files(files: Vec<String>, to: &PathBuf, force: bool, verbose: bool) {
  41. for item in files.iter() {
  42. if !to.is_dir() {
  43. util::err(PROG, Status::Error, String::from(String::from(
  44. to.to_str().unwrap()) + " is not a directory"));
  45. } else {
  46. let to_path = PathBuf::from(item);
  47. hard_link(&to_path, &to.join(&to_path), force, verbose);
  48. }
  49. }
  50. }
  51. fn soft_link(from: &PathBuf, to: &PathBuf, force: bool, verbose: bool) {
  52. if !force {
  53. if cfg!(target_family = "unix") {
  54. unix_symlink(from, to, verbose);
  55. }
  56. } else {
  57. if PathBuf::from(to).exists() {
  58. fs::remove_file(to).ok();
  59. if cfg!(target_family = "unix") {
  60. unix_symlink(from, to, verbose);
  61. }
  62. }
  63. }
  64. }
  65. fn hard_link(from: &PathBuf, to: &PathBuf, force: bool, verbose: bool) {
  66. if !force {
  67. match fs::hard_link(from, to) {
  68. Ok(_) => {
  69. if verbose {
  70. println!("{} -> {}", from.display(), to.display());
  71. }
  72. },
  73. Err(e) => {
  74. util::err(PROG, Status::Error, e.to_string());
  75. }
  76. };
  77. } else {
  78. if PathBuf::from(to).exists() {
  79. fs::remove_file(to).ok();
  80. match fs::hard_link(from, to) {
  81. Ok(_) => { },
  82. Err(e) => {
  83. util::err(PROG, Status::Error, e.to_string());
  84. }
  85. };
  86. }
  87. }
  88. }
  89. fn print_usage(prog: &str, opts: Options) {
  90. let breif = format!("Usage: {} [OPTION] TARGET LINK_NAME\nCreate links between files", prog);
  91. print!("{}", opts.usage(&breif));
  92. util::exit(Status::Ok);
  93. }
  94. fn main() {
  95. let args: Vec<String> = env::args().collect();
  96. let mut opts = Options::new();
  97. opts.optflag("h", "help", "Print the help menu");
  98. opts.optflag("", "version", "Print the version");
  99. opts.optflag("v", "verbose", "Verbose print the operation");
  100. opts.optflag("f", "force", "Force operation. Removes existsing target files");
  101. opts.optflag("s", "soft", "Create a symbolic link");
  102. opts.optflag("p", "physical", "Create a hard link");
  103. let matches = match opts.parse(&args[1..]) {
  104. Ok(m) => { m },
  105. Err(f) => {
  106. util::err(PROG, Status::OptError, f.to_string());
  107. panic!(f.to_string());
  108. }
  109. };
  110. if matches.opt_present("h") {
  111. print_usage(PROG, opts);
  112. } else if matches.opt_present("version") {
  113. util::copyright(PROG, VERS, "2015", vec!["Alberto Corona"]);
  114. } else {
  115. let verb = matches.opt_present("v");
  116. let force = matches.opt_present("f");
  117. let src = match matches.free.first() {
  118. Some(s) => { PathBuf::from(s) },
  119. None => {
  120. util::err(PROG, Status::Error, String::from(" no arguments given"));
  121. panic!();
  122. },
  123. };
  124. let dest = PathBuf::from(matches.free.last().unwrap());
  125. if matches.free.len() == 1 {
  126. println!("{}: no link name for {}", PROG, src.display());
  127. util::exit(Status::Error);
  128. }
  129. if matches.opt_present("s") {
  130. if matches.free.len() > 2 {
  131. sym_link_files(matches.free.init().to_vec(), &dest, force, verb);
  132. } else {
  133. soft_link(&src, &PathBuf::from(&matches.free[1]), force, verb);
  134. }
  135. } else if matches.opt_present("p") {
  136. if matches.free.len() > 2 {
  137. hard_link_files(matches.free.init().to_vec(), &dest, force, verb);
  138. } else {
  139. hard_link(&src, &PathBuf::from(&matches.free[1]), force, verb);
  140. }
  141. }
  142. }
  143. }