From 6872bca04b3936720538731f874df7296febdc13 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 10 Jul 2021 22:07:17 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + Cargo.lock | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 +++ src/main.rs | 36 +++++++++ 4 files changed, 272 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f93e3d9 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,225 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cc" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cstr" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11a39d776a3b35896711da8a04dc1835169dcd36f710878187637314e47941b" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "errno" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" +dependencies = [ + "gcc", + "libc", +] + +[[package]] +name = "fs-set-times" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d44f0304c28578c196cb438f08743f66bc675852724b0e1e40fff194a46b06f" +dependencies = [ + "io-lifetimes", + "posish", + "winapi", +] + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "io-lifetimes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78d009010297118b0a443fef912b92e3482e6e6f46ab31e5d60f68b39a553ca9" +dependencies = [ + "libc", + "rustc_version", + "winapi", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "linux-raw-sys" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a0e0375b6446268ee5299c8e92f90030c719b8bb6fcc303a704080da790654" + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "posish" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5d0ebf2e7c5c53b909e46bdb7c1fa696e945b9eab174f44d17a68192b5bc2c" +dependencies = [ + "bitflags", + "cc", + "cstr", + "errno", + "io-lifetimes", + "itoa", + "libc", + "linux-raw-sys", + "once_cell", + "rustc_version", +] + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe" + +[[package]] +name = "symlink-dupes" +version = "0.1.0" +dependencies = [ + "ahash", + "fs-set-times", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3be41ca --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "symlink-dupes" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ahash = "0.7.4" +fs-set-times = "0.5.1" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..41d4ff4 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,36 @@ +use std::{collections::HashMap, env, fs, hash::Hasher, os::unix::fs::symlink, path::PathBuf}; + +use ahash::AHasher; + +fn main() { + let args = env::args_os().collect::>(); + if args.len() != 2 { + println!("usage: ./symlinkDupes "); + return; + } + let dir: PathBuf = PathBuf::from(&args[1]); + let mut filenames = fs::read_dir(&dir).unwrap() + .map(Result::unwrap) + .map(|x| (x.metadata().unwrap().modified().unwrap(), x.file_name())) + .collect::>(); + filenames.sort(); + let mut hashes = HashMap::new(); + let hasher = AHasher::new_with_keys(1234340981, 567840211); + for file in &filenames { + let full_path = dir.join(&file.1); + let content = fs::read(&full_path).unwrap(); + if content.len() > 0 { + let mut hasher = hasher.clone(); + hasher.write(&content); + let hash = hasher.finish(); + let key = (hash, content.len()); + if hashes.contains_key(&key) { + fs::remove_file(&full_path).unwrap(); + symlink(hashes[&key], &full_path).unwrap(); + fs_set_times::set_symlink_times(&full_path, None, Some(file.0.into())).unwrap(); + } else { + hashes.insert(key, &file.1); + } + } + } +}