public static void Main(string[] args) { Console.WriteLine("Findup.exe v1.0 - use -help for usage information. Created in 2010 by James Gentile."); Console.WriteLine(" "); string[] paths = new string[0]; System.Boolean recurse = false; System.Boolean delete = false; System.Boolean noprompt = false; System.Boolean b4b = false; List <FileInfoExt> fs = new List <FileInfoExt>(); long bytesInDupes = 0; // bytes in all the duplicates long numOfDupes = 0; // number of duplicate files found. long bytesRec = 0; // number of bytes recovered. long delFiles = 0; // number of files deleted. int c = 0; int i = 0; string deleteConfirm; for (i = 0; i < args.Length; i++) { if ((System.String.Compare(args[i], "-help", true) == 0) || (System.String.Compare(args[i], "-h", true) == 0)) { Console.WriteLine("Usage: findup.exe <file/directory #1> <file/directory #2> ... <file/directory #N> [-recurse] [-delete] [-noprompt]"); Console.WriteLine(" "); Console.WriteLine("Options: -help - displays this help infomration."); Console.WriteLine(" -recurse - recurses through subdirectories."); Console.WriteLine(" -delete - deletes duplicates with confirmation prompt."); Console.WriteLine(" -noprompt - when used with -delete option, deletes files without confirmation prompt."); Console.WriteLine(" -b4b - do a byte-for-byte comparison, instead of SHA-512 hashing. Might be much slower, but most secure."); Console.WriteLine(" "); Console.WriteLine("Examples: findup.exe c:\\finances -recurse"); Console.WriteLine(" findup.exe c:\\users\\alice\\plan.txt d:\\data -recurse -delete -noprompt"); Console.WriteLine(" findup.exe c:\\data .\\*.txt c:\\reports\\quarter.doc -recurse -b4b"); Console.WriteLine(" "); return; } if (System.String.Compare(args[i], "-recurse", true) == 0) { recurse = true; continue; } if (System.String.Compare(args[i], "-delete", true) == 0) { delete = true; continue; } if (System.String.Compare(args[i], "-noprompt", true) == 0) { noprompt = true; continue; } if (System.String.Compare(args[i], "-b4b", true) == 0) { b4b = true; continue; } Array.Resize(ref paths, paths.Length + 1); paths[c] = args[i]; c++; } if (paths.Length == 0) { Console.WriteLine("No files specified, try findup.exe -help"); return; } Recurse recurseMe = new Recurse(); recurseMe.Recursive(paths, "*.*", recurse, fs); if (fs.Count < 2) { Console.WriteLine("Findup.exe needs at least 2 files to compare. try findup.exe -help"); return; } RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(randomNumber); // get 512-bit SHA-512 salt. for (i = 0; i < fs.Count; i++) { if (fs[i].Checked == true) // If file was already matched, then skip to next. { continue; } for (c = i + 1; c < fs.Count; c++) { if (fs[c].Checked == true) // skip already matched inner loop files. { continue; } if (fs[i].FI.Length != fs[c].FI.Length) // If file size matches, then check hash. { continue; } if (System.String.Compare(fs[i].FI.FullName, fs[c].FI.FullName, true) == 0) // don't count the same file as a match. { continue; } if (fs[i].SHA512_1st1K == null) // check/hash first 1K first. { fs[i].SHA512_1st1K = Compute1KHash(fs[i].FI.FullName); } if (fs[c].SHA512_1st1K == null) { fs[c].SHA512_1st1K = Compute1KHash(fs[c].FI.FullName); } if (CompareHash(fs[i].SHA512_1st1K, fs[c].SHA512_1st1K) == false) // if the 1st 1K has the same hash.. { continue; } if (fs[i].SHA512_1st1K == null) // if hash error, then skip to next file. { continue; } if (b4b == true) // byte for byte comparison specified? { if (B4b(fs[i].FI.FullName, fs[c].FI.FullName) == false) // call the byte for byte comparison function { continue; } } else if (fs[i].FI.Length > 1024) // skip hashing the file again if < 1024 bytes. { if (fs[i].SHA512_All == null) // check/hash the rest of the files. { fs[i].SHA512_All = ComputeFullHash(fs[i].FI.FullName); } if (fs[c].SHA512_All == null) { fs[c].SHA512_All = ComputeFullHash(fs[c].FI.FullName); } if (CompareHash(fs[i].SHA512_All, fs[c].SHA512_All) == false) { continue; } if (fs[i].SHA512_All == null) // check for hash fail before declaring a duplicate. { continue; } } Console.WriteLine("Match : " + fs[i].FI.FullName); Console.WriteLine("with : " + fs[c].FI.FullName); fs[c].Checked = true; // do not check or match against this file again. numOfDupes++; // increase count of matches. bytesInDupes += fs[c].FI.Length; // accumulate number of bytes in duplicates. if (delete != true) // if delete is specified, try to delete the duplicate file. { continue; } if (noprompt == false) { Console.Write("Delete the duplicate file <Y/n>?"); deleteConfirm = Console.ReadLine(); if ((deleteConfirm[0] != 'Y') && (deleteConfirm[0] != 'y')) { continue; } } try { File.Delete(fs[c].FI.FullName); Console.WriteLine("Deleted: " + fs[c].FI.FullName); bytesRec += fs[c].FI.Length; delFiles++; } catch (Exception e) { Console.WriteLine("File delete error: " + e.Message); } } } Console.WriteLine(" "); Console.WriteLine("Files checked : {0:N0}", fs.Count); Console.WriteLine("Duplicate files : {0:N0}", numOfDupes); Console.WriteLine("Duplicate bytes : {0:N0}", bytesInDupes); Console.WriteLine("Duplicates deleted : {0:N0}", delFiles); Console.WriteLine("Recovered bytes : {0:N0}", bytesRec); return; }