using System; using System.Threading; using System.Threading.Tasks; using Duplicati.Library.Interface; namespace Duplicati.Library.Main.Backend; #nullable enable partial class BackendManager { /// /// Represents a pending object lock operation /// private class SetObjectLockOperation : PendingOperation { /// /// The log tag for this class /// private static readonly string LOGTAG = Logging.Log.LogTagFromType(); /// /// The remote filename that should be locked /// public override string RemoteFilename { get; } /// /// The desired lock expiration time in UTC /// public DateTime LockUntilUtc { get; } /// /// The operation type /// public override BackendActionType Operation => BackendActionType.SetObjectLock; /// /// Creates a new SetObjectLockOperation /// /// The remote file name to lock /// The UTC timestamp to lock the file until /// The execution context /// The cancellation token public SetObjectLockOperation(string remoteName, DateTime lockUntilUtc, ExecuteContext context, CancellationToken cancelToken) : base(context, true, cancelToken) { RemoteFilename = remoteName; LockUntilUtc = lockUntilUtc; } /// public override async Task ExecuteAsync(IBackend backend, CancellationToken cancelToken) { if (backend is not ILockingBackend lockingBackend) throw new NotSupportedException("Backend does not support object locking operations"); Context.Statwriter.SendEvent(BackendActionType.SetObjectLock, BackendEventType.Started, RemoteFilename, 0); try { await lockingBackend.SetObjectLockUntilAsync(RemoteFilename, LockUntilUtc, cancelToken).ConfigureAwait(false); } catch (Exception ex) { Logging.Log.WriteWarningMessage(LOGTAG, "SetObjectLockFailed", ex, "Failed to apply object lock for {0}: {1}", RemoteFilename, ex.Message); throw; } finally { Context.Statwriter.SendEvent(BackendActionType.SetObjectLock, BackendEventType.Completed, RemoteFilename, 0); } return true; } } }