This PR updates the logic for metadata update after an operation has completed, such that the data displayed in the UI is more consistent with the remote storage situation.
This PR adds a new locking service that keeps track of which local databases are currently in use by the server. If a database is in use due to a running task, immediate calls will now be rejected.
Prior to this change, immediate calls could interfere with the running task, causing a backup to fail abruptly if the user attempted to check the logs or restore.
TempFile.GenerateUniqueName (DEBUG only) builds each name from the caller, a
second-precision timestamp, and the first 8 characters of a Guid, then adds it
to a static tracking dictionary. When many temp files are created within the
same second by the same caller (e.g. BorderTests.Run10kTzstdCompressionAsync,
which writes ~10k blocks), the 8-char Guid prefix can collide, so the generated
name repeats: Dictionary.Add throws "An item with the same key has already been
added", and two TempFiles would otherwise share the same path. Release builds
are unaffected (full Guid, no dictionary).
Append a process-wide atomic counter to the generated name so it is always
unique regardless of timestamp granularity or Guid-prefix collisions. Expose
GenerateUniqueName as internal (Library.Utility already grants InternalsVisibleTo
to the unit-test project) and add a concurrency stress test asserting the
generated names never throw and are all unique.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the CI actions to their latest majors to clear the recurring "Node.js 20
is deprecated" warnings (the pinned actions bundled Node 20, which GitHub is
retiring on runners):
- actions/checkout v4 -> v7
- actions/setup-dotnet v4 -> v5
- actions/upload-artifact v4 -> v7
- actions/setup-node v4 -> v6
- actions/stale v9 -> v10
atomicjar/testcontainers-cloud-setup-action is already on the latest major (v1).
Only the action version tags change. All bumped majors run on Node.js 24 and
require Actions Runner >= v2.327.1, which the GitHub-hosted runners used here
always satisfy. checkout v7's fork-PR checkout block only applies to
pull_request_target/workflow_run (not used here), and setup-node's auto-cache
only triggers with a packageManager field in package.json (not present), so
behavior is unchanged. Validated with actionlint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A backup can have two notions of its local database path: the stored
Backup.DBPath field and a --dbpath advanced option in its settings. The runner
computes an effective path that lets --dbpath override Backup.DBPath, so most
operations honor it. But the "Show log", "Show remote log" and "Delete database"
endpoints read Backup.DBPath directly, so when --dbpath differs they open/delete
the wrong database - "Show log" then fails with "no such table: LogData".
Add a shared Runner.GetEffectiveDBPath(IBackup) helper (same precedence as
Runner.ApplyOptions) and use it in ExecuteGetLog, ExecuteGetRemotelog and
ExecuteDeleteDb so all operations agree on the database file. Adds a unit test
for the precedence.
The database move/update endpoints are intentionally left unchanged, as they
manage the DBPath field itself.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `find` and `list` commands share the same handler. A bare filename is
rewritten to a wildcard filter (e.g. `*/report.txt`), and the handler only
searches every version for a Simple filter or when --all-versions is set, so a
wildcard filter searches only the newest version. The all-versions fallback in
Commands.List only triggers when the newest pass returns zero files, so a file
present only in an older version was silently missed whenever the newest version
still contained a same-named file (and full-path finds behaved differently from
bare-name finds).
Give `find` its own entry point that defaults to all-versions (respecting an
explicit --all-versions/--version/--time), so `find <name>` reliably searches
every backup version. `list` keeps its documented newest-only default. Update the
help text and add a regression test (Issue2287) that a file present only in an
older version is found by `find` but not by `list`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Log the "transaction already completed/disposed" cases as warnings instead of
verbose messages, so they are captured in tests and the underlying issue can be
fixed (per review feedback).
- Replace the fragile message-string matching in IsInactiveTransactionException
with an exception-type check. Microsoft.Data.Sqlite throws InvalidOperationException
("This SqliteTransaction has completed; it is no longer usable.") for an
already-completed transaction; matching the type avoids breaking under
localization or matching unintended messages (verified locally via the Issue5827
test, which catches System.InvalidOperationException).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The new restore engine uses two process-wide static TaskCompletionSources as
synchronization barriers in Restore/FileProcessor.cs: file_processor_continue
(the folder-metadata rendezvous) and priority_files_completed. Their counters
are reset at the start of each restore, but the TaskCompletionSources were only
created once at field initialization and were never reset.
After the first restore in a process completes the folder-metadata rendezvous,
its TaskCompletionSource stays completed, so on the second and later restores in
the same process the rendezvous "await" returns immediately and no longer waits
for all file content to be restored before folder metadata (including Windows
ACLs) is applied. This lost ordering guarantee (introduced by #6079) causes
intermittent folder metadata/permission restore failures, observed as the flaky
Issue6068FileAndFolderAttributesAndPermissions unit test on the Windows CI runner.
Reset both TaskCompletionSources in RestoreHandler before the FileLister/
FileProcessor tasks are started (so there is no race), alongside the existing
counter reset. file_processor_continue is the demonstrated root cause;
priority_files_completed has the identical never-reset pattern and is reset
defensively.
Verified locally on .NET 10: before the reset, file_processor_continue is already
completed on the 2nd+ restore in a process; the Issue6068 suite passes repeatedly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This addresses a logic issue in the previous check for TLS certs introduced with the option to ignore CRL failures. Since the call would end up calling `.Verify()` on the certificate, even toggling for soft-fail CRL issues, the certificate would be rejected.
With the new logic we manually verify the chain. This is only done if the user has requested specific certificates should be validated as we otherwise rely on the OS cert validation.
The macOS DiskImage unit tests intermittently failed in CI with:
System.InvalidOperationException : Process diskutil with arguments
eject /dev/rdiskN exited with code 1: Volume failed to eject
ReAttach() and CleanupDisk() called `diskutil eject` directly while a
volume could still be busy right after writing, so the eject transiently
failed (e.g. Test_GPT_FAT32_FAT32_FAT32_Async). This is test-infrastructure
only; no product code is affected.
Add a shared EjectDisk() helper that flushes buffers (sync), force-unmounts
all volumes first, then ejects with exponential backoff (reusing
Utility.GetRetryDelay), falling back to a forced `hdiutil detach` of the
image-backed device. Also make Unmount() force-unmount and return on success.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This ensures all in-flight backend requests are completed before the compact handler continues.
Prior to this, particular situations could cause the compact to throw an exception before actually removing files.
If the user has not specified any overrides, use the OS default validator.
Prior to this PR all certs were validated by the .NET default chain validator, which is more strict with regards to revocation checks. With this PR, the OS default is now used to validate certificates.
A failing test reveals that in some cases, files may be read-only which causes failures when attempting to set metadata. This PR updates the logic to ensure we clear the read-only attributes before attempting to apply metadata.