Skip to content
3 changes: 2 additions & 1 deletion LiteDB/Client/Shared/SharedEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
using LiteDB.Client.Shared;
using LiteDB.Vector;
#if NETFRAMEWORK
using System.Security.AccessControl;
Expand All @@ -22,7 +23,7 @@ public SharedEngine(EngineSettings settings)
{
_settings = settings;

var name = Path.GetFullPath(settings.Filename).ToLower().Sha1();
var name = SharedMutexNameFactory.Create(settings.Filename, settings.SharedMutexNameStrategy);

try
{
Expand Down
38 changes: 38 additions & 0 deletions LiteDB/Client/Shared/SharedMutexNameFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using LiteDB.Engine;

namespace LiteDB.Client.Shared;

internal static class SharedMutexNameFactory
{
internal static string Create(string fileName, SharedMutexNameStrategy strategy)
{
return strategy switch
{
SharedMutexNameStrategy.UriEscape or SharedMutexNameStrategy.Default => Uri.EscapeDataString(Path.GetFullPath(fileName).ToLowerInvariant()),
SharedMutexNameStrategy.Sha1Hash => Sha1(fileName),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize path before SHA1 mutex naming

The Sha1Hash branch no longer normalizes the file path the way the legacy code did. The previous implementation hashed Path.GetFullPath(settings.Filename).ToLower() so the mutex name was identical regardless of relative versus absolute paths or path casing. Here the raw fileName is hashed, so two processes that point at the same file with different path representations will compute different mutex names and both acquire their own mutexes, effectively removing mutual exclusion and defeating the purpose of the compatibility switch.

Useful? React with 👍 / 👎.

_ => throw new ArgumentOutOfRangeException(nameof(strategy), strategy, null)
};
}

internal static string Sha1(string value)
{
var data = Encoding.UTF8.GetBytes(value);

using (var sha = SHA1.Create())
{
var hashData = sha.ComputeHash(data);
var hash = new StringBuilder();

foreach (var b in hashData)
{
hash.Append(b.ToString("X2"));
}

return hash.ToString();
}
}
}
5 changes: 5 additions & 0 deletions LiteDB/Engine/EngineSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public class EngineSettings
/// Is used to transform a <see cref="BsonValue"/> from the database on read. This can be used to upgrade data from older versions.
/// </summary>
public Func<string, BsonValue, BsonValue> ReadTransform { get; set; }

/// <summary>
/// Determines how the mutex name is generated.
/// </summary>
public SharedMutexNameStrategy SharedMutexNameStrategy { get; set; }

/// <summary>
/// Create new IStreamFactory for datafile
Expand Down
9 changes: 9 additions & 0 deletions LiteDB/Engine/SharedMutexNameStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

namespace LiteDB.Engine;

public enum SharedMutexNameStrategy
{
Default,
UriEscape,
Sha1Hash
}
18 changes: 0 additions & 18 deletions LiteDB/Utils/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,6 @@ public static bool IsWord(this string str)
return true;
}

public static string Sha1(this string value)
{
var data = Encoding.UTF8.GetBytes(value);

using (var sha = SHA1.Create())
{
var hashData = sha.ComputeHash(data);
var hash = new StringBuilder();

foreach (var b in hashData)
{
hash.Append(b.ToString("X2"));
}

return hash.ToString();
}
}

/// <summary>
/// Implement SqlLike in C# string - based on
/// https://stackoverflow.com/a/8583383/3286260
Expand Down
Loading