Only write if something changed
MODIFY
WalletWasabi/Helpers/IoHelpers.cs
WalletWasabi/Helpers/IoHelpers.cs
@@ -275,6 +275,11 @@ namespace System.IO
public static byte[] GetHashFile(string filePath)
{
var bytes = File.ReadAllBytes(filePath);
+ return GetHash(bytes);
+ }
+
+ public static byte[] GetHash(byte[] bytes)
+ {
using (var sha = new SHA256Managed())
{
return sha.ComputeHash(bytes, 0, bytes.Length);

MODIFY
WalletWasabi/Stores/IndexStore.cs
WalletWasabi/Stores/IndexStore.cs
@@ -106,7 +106,7 @@ namespace WalletWasabi.Stores
Index.Add(filter);
await IndexFileManager.WrapInMutexAsync(async () =>
{
- await IndexFileManager.AppendAllLinesAsync(new[] { filter.ToHeightlessLine() });
+ await IndexFileManager.WriteAllLinesAsync(Index.Select(x => x.ToHeightlessLine()));
});
}
finally

MODIFY
WalletWasabi/Stores/IoManager.cs
WalletWasabi/Stores/IoManager.cs
@@ -2,9 +2,11 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Helpers;
+using WalletWasabi.Logging;
namespace WalletWasabi.Stores
{
@@ -16,6 +18,7 @@ namespace WalletWasabi.Stores
public string OriginalFilePath { get; }
public string OldFilePath { get; }
public string NewFilePath { get; }
+ public string DigestFilePath { get; }
public string FileName { get; }
public string FileNameWithoutExtension { get; }
@@ -23,12 +26,14 @@ namespace WalletWasabi.Stores
private const string OldExtension = ".old";
private const string NewExtension = ".new";
+ private const string DigestExtension = ".dig";
public IoManager(string filePath)
{
OriginalFilePath = Guard.NotNullOrEmptyOrWhitespace(nameof(filePath), filePath, trim: true);
OldFilePath = $"{OriginalFilePath}{OldExtension}";
NewFilePath = $"{OriginalFilePath}{NewExtension}";
+ DigestFilePath = $"{OriginalFilePath}{DigestExtension}";
FileName = Path.GetFileName(OriginalFilePath);
FileNameWithoutExtension = Path.GetFileNameWithoutExtension(OriginalFilePath);
@@ -218,22 +223,54 @@ namespace WalletWasabi.Stores
public async Task WriteAllLinesAsync(IEnumerable<string> contents, CancellationToken cancellationToken = default)
{
+ byte[] hash = null;
+ try
+ {
+ IEnumerable<byte[]> arrays = contents.Select(x => Encoding.ASCII.GetBytes(x));
+ byte[] bytes = ByteHelpers.Combine(arrays);
+ hash = IoHelpers.GetHash(bytes);
+ if (File.Exists(DigestFilePath))
+ {
+ var digest = await File.ReadAllBytesAsync(DigestFilePath, cancellationToken);
+ if (ByteHelpers.CompareFastUnsafe(hash, digest))
+ {
+ return;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogWarning<IoManager>("Failed to read digest.");
+ Logger.LogInfo<IoManager>(ex);
+ }
+
await File.WriteAllLinesAsync(NewFilePath, contents, cancellationToken);
SafeMoveNewToOriginal();
- }
- public async Task AppendAllLinesAsync(IEnumerable<string> contents, CancellationToken cancellationToken = default)
+ try
{
- // Make sure the NewFilePath exists.
- if (TryGetSafestFileVersion(out string safestFilePath) && safestFilePath != NewFilePath)
+ await File.WriteAllBytesAsync(DigestFilePath, hash);
+ }
+ catch (Exception ex)
{
- File.Copy(safestFilePath, NewFilePath, overwrite: true);
+ Logger.LogWarning<IoManager>("Failed to create digest.");
+ Logger.LogInfo<IoManager>(ex);
}
-
- await File.AppendAllLinesAsync(NewFilePath, contents, cancellationToken);
- SafeMoveNewToOriginal();
}
+ // Can't compute hash for append.
+ //public async Task AppendAllLinesAsync(IEnumerable<string> contents, CancellationToken cancellationToken = default)
+ //{
+ // // Make sure the NewFilePath exists.
+ // if (TryGetSafestFileVersion(out string safestFilePath) && safestFilePath != NewFilePath)
+ // {
+ // File.Copy(safestFilePath, NewFilePath, overwrite: true);
+ // }
+
+ // await File.AppendAllLinesAsync(NewFilePath, contents, cancellationToken);
+ // SafeMoveNewToOriginal();
+ //}
+
public async Task<string[]> ReadAllLinesAsync(CancellationToken cancellationToken = default)
{
var filePath = OriginalFilePath;

Only write if something changed