Merge pull request #6944 from duplicati/feature/fix-locking-on-windows

Fix remote file locking on Windows
This commit is contained in:
Kenneth Skovhede
2026-06-03 17:42:17 +02:00
committed by GitHub
4 changed files with 29 additions and 9 deletions
@@ -54,6 +54,23 @@ namespace Duplicati.Library.Main.Database
return dbnew;
}
/// <summary>
/// Creates a new instance of the <see cref="LocalLockDatabase"/> class.
/// </summary>
/// <param name="database">The database to create the new instance on.</param>
/// <param name="token">A cancellation token to cancel the operation.</param>
/// <returns>The <see cref="LocalLockDatabase"/> instance</returns>
public static async Task<LocalLockDatabase> CreateAsync(LocalDatabase database, CancellationToken token)
{
var db = (LocalLockDatabase)await LocalDatabase.CreateLocalDatabaseAsync(
database,
new LocalLockDatabase(),
token
).ConfigureAwait(false);
db.ShouldCloseConnection = false;
return db;
}
/// <summary>
/// Updates the lock expiration time for a remote volume.
/// </summary>
@@ -604,9 +604,10 @@ namespace Duplicati.Library.Main.Operation
return;
}
m_result.LockResults = new SetLockResults(m_result);
using var lockDb = await LocalLockDatabase.CreateAsync(m_database, m_taskReader.StopToken);
m_result.LockResults ??= new SetLockResults();
await new SetLocksHandler(m_options, (SetLockResults)m_result.LockResults)
.RunAsync(backendManager, versionTimestamps)
.RunAsync(backendManager, lockDb, versionTimestamps)
.ConfigureAwait(false);
}
@@ -73,14 +73,14 @@ namespace Duplicati.Library.Main.Operation
if (!backendManager.SupportsObjectLocking)
throw new UserInformationException("Backend does not support object locking", "BackendDoesNotSupportLocking");
if (!File.Exists(m_options.Dbpath))
var ownsDatabase = databaseOverride is null;
if (ownsDatabase && !File.Exists(m_options.Dbpath))
throw new UserInformationException(string.Format("Database file does not exist: {0}", m_options.Dbpath), "DatabaseFileDoesNotExist");
m_result.OperationProgressUpdater.UpdatePhase(OperationPhase.ReadLockInfo_Running);
var ownsDatabase = databaseOverride is null;
await using var db = ownsDatabase
? await LocalLockDatabase.CreateAsync(m_options.Dbpath, null, m_result.TaskControl.ProgressToken).ConfigureAwait(false)
? await LocalLockDatabase.CreateAsync(m_options.Dbpath!, null, m_result.TaskControl.ProgressToken).ConfigureAwait(false)
: null;
var database = databaseOverride ?? db!;
@@ -118,6 +118,7 @@ namespace Duplicati.Library.Main.Operation
m_result.VolumesRead = readCount;
m_result.VolumesUpdated = updatedCount;
m_result.EndTime = DateTime.UtcNow;
if (updatedCount > 0 || errorCount > 0)
Log.WriteInformationMessage(LOGTAG, "ReadLockInfoComplete", "Read lock info complete: {0} updated, {1} errors", updatedCount, errorCount);
@@ -50,7 +50,7 @@ namespace Duplicati.Library.Main.Operation
public Task RunAsync(IBackendManager backendManager, IEnumerable<DateTime>? versionTimestamps = null)
=> RunAsync(backendManager, null, versionTimestamps);
internal async Task RunAsync(IBackendManager backendManager, Database.LocalLockDatabase? databaseOverride, IEnumerable<DateTime>? versionTimestamps = null)
public async Task RunAsync(IBackendManager backendManager, Database.LocalLockDatabase? databaseOverride, IEnumerable<DateTime>? versionTimestamps = null)
{
if (m_options.RemoteFileLockDuration is null)
throw new UserInformationException("No lock duration specified", "MissingLockDuration");
@@ -61,16 +61,16 @@ namespace Duplicati.Library.Main.Operation
if (!backendManager.SupportsObjectLocking)
throw new UserInformationException("Backend does not support object locking", "BackendDoesNotSupportLocking");
if (!File.Exists(m_options.Dbpath))
var ownsDatabase = databaseOverride is null;
if (ownsDatabase && !File.Exists(m_options.Dbpath))
throw new Exception(string.Format("Database file does not exist: {0}", m_options.Dbpath));
var effectiveVersionTimestamps = versionTimestamps ?? m_versionTimestamps;
m_result.OperationProgressUpdater.UpdatePhase(OperationPhase.Backup_Lock);
var ownsDatabase = databaseOverride is null;
await using var db = ownsDatabase
? await LocalLockDatabase.CreateAsync(m_options.Dbpath, null, m_result.TaskControl.ProgressToken).ConfigureAwait(false)
? await LocalLockDatabase.CreateAsync(m_options.Dbpath!, null, m_result.TaskControl.ProgressToken).ConfigureAwait(false)
: null;
var database = databaseOverride ?? db!;
@@ -123,6 +123,7 @@ namespace Duplicati.Library.Main.Operation
m_result.VolumesRead = readCount;
m_result.VolumesUpdated = updatedCount;
m_result.EndTime = DateTime.UtcNow;
}
private async Task<List<long>> ResolveFilesetIdsAsync(Database.LocalListDatabase db, IEnumerable<DateTime>? suppliedVersions)