53 lines
1.7 KiB
C#
53 lines
1.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace StellaOps.Concelier.Exporter.Json;
|
|
|
|
public static class ExportDigestCalculator
|
|
{
|
|
public static string ComputeTreeDigest(JsonExportResult result)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(result);
|
|
|
|
using var sha256 = SHA256.Create();
|
|
var buffer = new byte[128 * 1024];
|
|
|
|
foreach (var file in result.FilePaths.OrderBy(static path => path, StringComparer.Ordinal))
|
|
{
|
|
var normalized = file.Replace("\\", "/");
|
|
var pathBytes = Encoding.UTF8.GetBytes(normalized);
|
|
_ = sha256.TransformBlock(pathBytes, 0, pathBytes.Length, null, 0);
|
|
|
|
var fullPath = ResolveFullPath(result.ExportDirectory, normalized);
|
|
using var stream = File.OpenRead(fullPath);
|
|
int read;
|
|
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
|
|
{
|
|
_ = sha256.TransformBlock(buffer, 0, read, null, 0);
|
|
}
|
|
}
|
|
|
|
_ = sha256.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
|
|
var hash = sha256.Hash ?? Array.Empty<byte>();
|
|
var hex = Convert.ToHexString(hash).ToLowerInvariant();
|
|
return $"sha256:{hex}";
|
|
}
|
|
|
|
private static string ResolveFullPath(string root, string normalizedRelativePath)
|
|
{
|
|
var segments = normalizedRelativePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
|
var parts = new string[segments.Length + 1];
|
|
parts[0] = root;
|
|
for (var i = 0; i < segments.Length; i++)
|
|
{
|
|
parts[i + 1] = segments[i];
|
|
}
|
|
|
|
return Path.Combine(parts);
|
|
}
|
|
}
|