1
0
mirror of https://github.com/oliverbooth/fdup.git synced 2024-11-14 04:15:41 +00:00

Compare commits

..

No commits in common. "801dfe09cb005256b157348dd470142edb59804e" and "16eb21e8794cf7d578eda69eb4620fb9ba1c14af" have entirely different histories.

7 changed files with 14 additions and 105 deletions

View File

@ -1,26 +0,0 @@
using System.ComponentModel;
using Humanizer;
using Spectre.Console;
using Spectre.Console.Cli;
namespace FindDuplicates;
[Description("Display a list of usable hashing algorithms.")]
internal sealed class AlgListCommand : Command
{
public override int Execute(CommandContext context)
{
AnsiConsole.WriteLine("The default algorithm fdup uses is SHA512.");
AnsiConsole.MarkupLine("To specify a different one, use the [cyan]-a[/] or [cyan]--algorithm[/] flag, and pass one of the values below:");
var table = new Table();
table.AddColumn("Algorithm");
table.AddColumn("Value");
foreach (Algorithm algorithm in Enum.GetValues<Algorithm>())
table.AddRow($"{algorithm.Humanize()}", $"{algorithm.ToString().ToLower()}");
AnsiConsole.Write(table);
return 0;
}
}

View File

@ -1,15 +0,0 @@
using System.ComponentModel;
namespace FindDuplicates;
internal enum Algorithm
{
[Description("SHA512")] Sha512,
[Description("SHA384")] Sha384,
[Description("SHA256")] Sha256,
[Description("SHA3-512")] Sha3512,
[Description("SHA3-384")] Sha3384,
[Description("SHA3-256")] Sha3256,
[Description("SHA1")] Sha1,
[Description("MD5")] Md5
}

View File

@ -1,42 +0,0 @@
using System.Security.Cryptography;
namespace FindDuplicates;
internal static class AlgorithmExtensions
{
public static int GetByteCount(this Algorithm algorithm)
{
return algorithm switch
{
Algorithm.Sha512 => SHA512.HashSizeInBytes,
Algorithm.Sha384 => SHA384.HashSizeInBytes,
Algorithm.Sha256 => SHA256.HashSizeInBytes,
Algorithm.Sha3512 => SHA3_512.HashSizeInBytes,
Algorithm.Sha3384 => SHA3_384.HashSizeInBytes,
Algorithm.Sha3256 => SHA3_256.HashSizeInBytes,
Algorithm.Sha1 => SHA1.HashSizeInBytes,
Algorithm.Md5 => MD5.HashSizeInBytes,
_ => 0
};
}
public static int HashData(this Algorithm algorithm, Stream source, Span<byte> destination)
{
// I'd love to use a dictionary to cache the function map, but you can't use Span<> as a type argument,
// probably due to the fact that a lambda heap allocs, and we can't have that for ref structs, oh no (!)
// so enjoy this absolutely cursed switch expression which checks each algorithm separately. I hate it too.
return algorithm switch
{
Algorithm.Sha512 => SHA512.HashData(source, destination),
Algorithm.Sha384 => SHA384.HashData(source, destination),
Algorithm.Sha256 => SHA256.HashData(source, destination),
Algorithm.Sha3512 => SHA3_512.HashData(source, destination),
Algorithm.Sha3384 => SHA3_384.HashData(source, destination),
Algorithm.Sha3256 => SHA3_256.HashData(source, destination),
Algorithm.Sha1 => SHA1.HashData(source, destination),
Algorithm.Md5 => MD5.HashData(source, destination),
_ => -1
};
}
}

View File

@ -33,7 +33,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Spectre.Console.Cli" Version="0.48.0"/> <PackageReference Include="Spectre.Console.Cli" Version="0.48.0"/>
</ItemGroup> </ItemGroup>

View File

@ -1,6 +1,6 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Security.Cryptography;
using System.Text; using System.Text;
using Humanizer;
using Spectre.Console; using Spectre.Console;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -21,7 +21,6 @@ internal sealed class ListCommand : AsyncCommand<ListSettings>
AnsiConsole.MarkupLineInterpolated($"Searching [cyan]{inputDirectory.FullName}[/]"); AnsiConsole.MarkupLineInterpolated($"Searching [cyan]{inputDirectory.FullName}[/]");
AnsiConsole.MarkupLine($"Recursive mode is {(settings.Recursive ? "[green]ON" : "[red]OFF")}[/]"); AnsiConsole.MarkupLine($"Recursive mode is {(settings.Recursive ? "[green]ON" : "[red]OFF")}[/]");
AnsiConsole.MarkupLine($"Using hash algorithm [cyan]{settings.Algorithm.Humanize()}[/]");
await AnsiConsole.Status() await AnsiConsole.Status()
.StartAsync("Waiting to hash files...", DoHashWaitAsync) .StartAsync("Waiting to hash files...", DoHashWaitAsync)
@ -34,18 +33,18 @@ internal sealed class ListCommand : AsyncCommand<ListSettings>
{ {
int fileCount = files.Count; int fileCount = files.Count;
if (fileCount <= 1) if (fileCount > 1)
continue; {
duplicates += fileCount; duplicates += fileCount;
AnsiConsole.MarkupLineInterpolated($"Found [cyan]{fileCount}[/] identical files"); AnsiConsole.MarkupLineInterpolated($"Found [cyan]{fileCount}[/] identical files");
AnsiConsole.MarkupLineInterpolated($"{settings.Algorithm.Humanize()} [green]{hash}[/]:"); AnsiConsole.MarkupLineInterpolated($"SHA512 [green]{hash}[/]:");
foreach (FileInfo file in files) foreach (FileInfo file in files)
AnsiConsole.MarkupLineInterpolated($"- {file.FullName}"); AnsiConsole.MarkupLineInterpolated($"- {file.FullName}");
AnsiConsole.WriteLine(); AnsiConsole.WriteLine();
} }
}
if (duplicates == 0) if (duplicates == 0)
AnsiConsole.MarkupLine("[green]No duplicates found![/]"); AnsiConsole.MarkupLine("[green]No duplicates found![/]");
@ -110,12 +109,12 @@ internal sealed class ListCommand : AsyncCommand<ListSettings>
private void ProcessFile(FileInfo file, ListSettings settings) private void ProcessFile(FileInfo file, ListSettings settings)
{ {
Span<byte> buffer = stackalloc byte[settings.Algorithm.GetByteCount()]; Span<byte> buffer = stackalloc byte[64];
try try
{ {
using FileStream stream = file.OpenRead(); using FileStream stream = file.OpenRead();
using BufferedStream bufferedStream = new BufferedStream(stream, 1048576 /* 1MB */); using BufferedStream bufferedStream = new BufferedStream(stream, 1048576 /* 1MB */);
settings.Algorithm.HashData(bufferedStream, buffer); SHA512.HashData(bufferedStream, buffer);
string hash = ByteSpanToString(buffer); string hash = ByteSpanToString(buffer);
if (settings.Verbose) if (settings.Verbose)
AnsiConsole.WriteLine($"{file.FullName} ->\n {hash}"); AnsiConsole.WriteLine($"{file.FullName} ->\n {hash}");
@ -147,7 +146,7 @@ internal sealed class ListCommand : AsyncCommand<ListSettings>
private static string ByteSpanToString(ReadOnlySpan<byte> buffer) private static string ByteSpanToString(ReadOnlySpan<byte> buffer)
{ {
var builder = new StringBuilder(buffer.Length * 2); var builder = new StringBuilder();
foreach (byte b in buffer) foreach (byte b in buffer)
builder.Append($"{b:X2}"); builder.Append($"{b:X2}");

View File

@ -10,13 +10,8 @@ internal sealed class ListSettings : CommandSettings
[DefaultValue(".")] [DefaultValue(".")]
public string InputPath { get; set; } = "."; public string InputPath { get; set; } = ".";
[CommandOption("-a|--algorithm <algorithm>")]
[Description("The hash algorithm used for comparison. Defaults to SHA512. For a list of all available algorithms, run fdup alglist")]
[DefaultValue(Algorithm.Sha512)]
public Algorithm Algorithm { get; set; } = Algorithm.Sha512;
[CommandOption("-r|--recursive")] [CommandOption("-r|--recursive")]
[Description("Scans the directory recursively. This may increase run time and is not advised to use when at high order directories such as C: or /")] [Description("When this flag is set, the directory will be scanned recursively. This may take longer.")]
[DefaultValue(false)] [DefaultValue(false)]
public bool Recursive { get; set; } = false; public bool Recursive { get; set; } = false;

View File

@ -2,5 +2,4 @@ using FindDuplicates;
using Spectre.Console.Cli; using Spectre.Console.Cli;
var app = new CommandApp<ListCommand>(); var app = new CommandApp<ListCommand>();
app.Configure(cfg => cfg.AddCommand<AlgListCommand>("alglist"));
await app.RunAsync(args).ConfigureAwait(false); await app.RunAsync(args).ConfigureAwait(false);