#![allow(dead_code)] #![allow(unused_imports)] extern crate sha2; use std::fs::{File}; use std::fs; use std::path::{Path, PathBuf}; use std::io::prelude::*; use sha2::{Sha256}; mod hash; mod traverse; mod pool; mod rotating_list; fn funcall(w: T) { w(); } const THREADS: usize = 3; //const OUTPUT_DIR: &'static str = "./output"; //const INPUT_DIR: &'static str = "./target"; macro_rules! join_path { ($($path:expr),*) => { { let mut buf = std::path::PathBuf::new(); $( buf.push($path); )+ buf } } } fn output_path(input_dir: &str, output_dir: &str, path: &Path) -> Result { let mut buf = PathBuf::new(); buf.push(output_dir); if let Some(path) = path.to_str() { buf.push(&path[input_dir.len()+1..]); Ok(buf) } else { Err("Bad pathspec") } } fn main() { let args: Vec = std::env::args().collect(); if args.len() < 3 { println!("hashlink - generate recursive file hashtable to coerce duplicate files to hardlinks.\n"); println!("Usage: {} ", args[0]); return; } let input_dir = &args[1]; let output_dir = &args[2]; let root = traverse::DirectoryIterator::begin(input_dir).unwrap(); let mut pools = create_pools!(THREADS); if !Path::new(output_dir).exists() { if let Err(err) = fs::create_dir(output_dir) { println!("Could not create output directory: {}", err); return; } } let hardlink_dir = join_path!(output_dir, ".hashlink"); if !hardlink_dir.exists() { if let Err(err) = fs::create_dir(hardlink_dir.as_path()) { println!("Could not create .hashlink directory: {}", err); return; } } for dir in root { let hardlink_dir = hardlink_dir.to_path_buf(); let input_dir = input_dir.to_string(); let output_dir = output_dir.to_string(); send!(pools.get(), move || { if let Ok(mut file) = File::open(&dir) { if let Ok(hash) = hash::FileHash::create(&mut file) { let hlpath = join_path!(hardlink_dir, hash.to_string()); if let Ok(dst) = output_path(&input_dir, &output_dir, Path::new(&dir)) { if let Some(parent) = dst.parent() { if !parent.exists() { if let Err(_) = fs::create_dir(parent) { return; } } } if !hlpath.exists() { if let Err(_) = std::fs::copy(&dir, &hlpath) { return; } } match fs::hard_link(hlpath, dst) { Ok(_) => println!("{} -> {}", dir, hash), Err(err) => println!("E: {} failed: {}", dir, err), } } } } }); } }