Skip to content

Commit d15a70d

Browse files
committed
Ensure no access violations happen in case of bidirectional synchronisation of binary files
1 parent 38a83f8 commit d15a70d

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

Program.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ internal static class Global
4141

4242

4343

44+
internal static readonly AsyncLockQueueDictionary BinaryFileOperationLocks = new AsyncLockQueueDictionary();
4445
internal static readonly AsyncLockQueueDictionary FileOperationLocks = new AsyncLockQueueDictionary();
4546
//internal static readonly AsyncLock FileOperationAsyncLock = new AsyncLock();
4647
}
@@ -772,15 +773,28 @@ public static async Task SaveFileModifications(string fullName, byte[] fileData,
772773
|| !FileExtensions.BinaryEqual(otherFileData, fileData)
773774
)
774775
{
775-
await DeleteFile(otherFullName, context);
776+
var filenames = new List<string>()
777+
{
778+
fullName,
779+
otherFullName
780+
};
776781

777-
Directory.CreateDirectory(Path.GetDirectoryName(otherFullName));
782+
//NB! in order to avoid deadlocks, always take the locks in deterministic order
783+
filenames.Sort(StringComparer.InvariantCultureIgnoreCase);
778784

779-
//@"\\?\" prefix is needed for writing to long paths: https://stackoverflow.com/questions/44888844/directorynotfoundexception-when-using-long-paths-in-net-4-7
780-
await FileExtensions.WriteAllBytesAsync(@"\\?\" + otherFullName, fileData, context.Token);
785+
using (await Global.BinaryFileOperationLocks.LockAsync(filenames[0], context.Token))
786+
using (await Global.BinaryFileOperationLocks.LockAsync(filenames[1], context.Token))
787+
{
788+
await DeleteFile(otherFullName, context);
781789

782-
var now = DateTime.UtcNow; //NB! compute now after saving the file
783-
ConverterSavedFileDates[otherFullName] = now;
790+
Directory.CreateDirectory(Path.GetDirectoryName(otherFullName));
791+
792+
//@"\\?\" prefix is needed for writing to long paths: https://stackoverflow.com/questions/44888844/directorynotfoundexception-when-using-long-paths-in-net-4-7
793+
await FileExtensions.WriteAllBytesAsync(@"\\?\" + otherFullName, fileData, context.Token);
794+
795+
var now = DateTime.UtcNow; //NB! compute now after saving the file
796+
ConverterSavedFileDates[otherFullName] = now;
797+
}
784798

785799

786800
await AddMessage(ConsoleColor.Magenta, $"Synchronised updates from file {fullName}", context);

0 commit comments

Comments
 (0)