Commit Graph
14338 Commits
Author SHA1 Message Date
Kenneth Skovhede 2f65cdee22 Fix database inconsistent after metadata delete
In the case of an interrupted upload, Duplicati will remove files that did not make it to the destination and then cleanup the database.

In the special case where multiple files were sharing exact metadata, the cleanup step could sometimes remove metadata that was needed. This would be detected and the repair rolled back, but the backup would fail to run.

With the fix the criteria for removing metadata has been narrowed to the correct subset.
2026-07-13 13:45:36 +02:00
Kenneth SkovhedeandGitHub 2238bb89e3 Merge pull request #7051 from duplicati/feature/delay-start-from-msi
Make the Service delay-start
2026-07-13 11:50:41 +02:00
Kenneth Skovhede f58900bcd5 Fix uninstall issue 2026-07-13 10:23:34 +02:00
Kenneth Skovhede 3860aa8963 Make the Service delay-start
When installing a service from the MSI, make sure the service is delay-started.

This is a follow-up to #7045
2026-07-13 08:48:32 +02:00
Kenneth SkovhedeandGitHub 4f3fa3ef74 Merge pull request #7045 from JamBalaya56562/fix/windows-service-delayed-start
Delay Windows service startup to avoid boot timeout
2026-07-13 08:41:26 +02:00
Kenneth SkovhedeandGitHub 97594608bc Merge pull request #7030 from duplicati/feature/lock-down-permissions-on-data-folder
Lock permissions on datafolder
2026-07-13 08:38:17 +02:00
Kenneth SkovhedeandGitHub 6aeaed8305 Merge pull request #7020 from JamBalaya56562/feature/add-par2-parity
Add pluggable parity module with PAR2 error-correction for remote volumes
2026-07-13 08:37:57 +02:00
Kenneth SkovhedeandGitHub cb3f600ed2 Merge pull request #7044 from duplicati/feature/support-machine-id-override
Allow machine-id override
2026-07-12 19:28:14 +02:00
Kenneth Skovhede 445297dfc0 Avoid default parameters and make the agent load delayed as well 2026-07-12 19:27:46 +02:00
Kenneth SkovhedeandGitHub c1acc6f3ff Merge pull request #7038 from TowyTowy/fix/retention-policy-invalid-value-crash
Validate --retention-policy format instead of crashing on a missing colon
2026-07-12 19:20:08 +02:00
Kenneth SkovhedeandGitHub c3204f833c Merge branch 'master' into feature/add-par2-parity 2026-07-12 19:19:15 +02:00
JamBalaya56562 1a62332f19 Delay Windows service startup 2026-07-12 21:38:36 +09:00
Kenneth Skovhede e64e1456d1 Allow machine-id override
This fixes an issue where the machineId could be set in the global advanced options, but would not be applied when connecting to the console.

Setting the option would cause the machine to have one id for the connection and another id for the backup reports.

This also fixes an incorrectly reported default value for the machineId. Previously it would report `InstallId` but actually use `MachineId` for the default value.
2026-07-12 12:16:58 +02:00
Kenneth Skovhede d4e4ed9a13 Set insecure env var for testing 2026-07-12 11:59:20 +02:00
Kenneth SkovhedeandGitHub 3f95c222d0 Merge branch 'master' into feature/lock-down-permissions-on-data-folder 2026-07-12 11:56:14 +02:00
Kenneth SkovhedeandGitHub fe9cdcd67c Merge pull request #7043 from JamBalaya56562/fix/windows-zip-fallback-db-lock
Stabilize ZipFallback database cleanup on Windows
2026-07-12 11:52:46 +02:00
Kenneth Skovhede ec2c6e8b4b Nit: Make exception string localizable 2026-07-12 11:50:21 +02:00
Kenneth Skovhede 094579b352 Nit: Explicitly pass flag indicating if parity repair is allowed 2026-07-12 11:47:26 +02:00
Kenneth SkovhedeandGitHub 577d0634e6 Merge pull request #7042 from JamBalaya56562/fix/known-warning-no-stacktrace
Do not attach stack traces to known-problem path warnings (#6426)
2026-07-12 11:42:43 +02:00
Kenneth SkovhedeandGitHub 9a8863216d Merge pull request #7040 from JamBalaya56562/fix/recreate-empty-destination-cleanup
Delete the incomplete recreate database when recreate fails (#6205)
2026-07-12 11:40:11 +02:00
Kenneth SkovhedeandGitHub 75ccb33db1 Merge pull request #7039 from JamBalaya56562/fix/remove-restore-cancel-button
Remove redundant cancel button from restore progress
2026-07-12 11:37:09 +02:00
JamBalaya56562andClaude Opus 4.8 aafc94fb69 Delete the incomplete recreate database when the remote is empty (#6205)
When all files are deleted from the remote destination and the user runs repair
(which recreates the local database), the recreate fails because the destination
is empty. Previously the partial/empty database that had just been created was
left on disk, which blocked every subsequent operation: a fresh backup could not
run, and even retrying the repair failed because the recreate refuses to run when
the database file already exists.

RecreateDatabaseHandler.RunAsync now removes the database it created when the
recreate fails because the remote destination is empty (UserInformationException
with help id EmptyRemoteLocation / EmptyRemoteLocationWithPrefix), so the next run
starts cleanly. The database connection is disposed before the cleanup runs, so the
file is not locked, and the cleanup is best-effort and never masks the original error.

The cleanup is deliberately scoped to the empty-destination case. Other recreate
failures - in particular a database with missing blocks / broken filelists (help id
DatabaseIsBrokenConsiderPurge) - intentionally keep the recreated database so the
user can run list-broken-files / purge-broken-files against it.

Adds an Issue6205 regression test.

Fixes #6205

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 12:32:06 +09:00
JamBalaya56562 de48174842 Stabilize ZipFallback database cleanup on Windows 2026-07-12 12:11:26 +09:00
JamBalaya56562andClaude Opus 4.8 1d4642acdf Do not attach stack traces to known-problem path warnings (#6426)
During a backup, LogExceptionHelper.LogCommonWarning is the shared helper used
to log "excluding path" warnings from many enumeration/metadata steps. For known,
expected problems (permission denied, locked file, path not found, path too long)
it passed the exception to WriteWarningMessage, so the file log, console and
report modules rendered the full stack trace (via LogEntry.AsString(true)) for
every such path — bloating the logs with no diagnostic value.

The known-category branches now log without attaching the exception, so no stack
trace is stored; the self-describing warning message (e.g. "Excluding path due to
permission denied: <path>") remains. The fallback branch keeps the exception so
genuinely unexpected failures are still fully debuggable.

Adds Issue6426 tests asserting known-problem warnings carry no exception while
unknown errors keep it.

Fixes #6426

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 06:56:54 +09:00
JamBalaya56562 214480e8e6 Remove redundant cancel button from restore progress
The legacy ngax restore progress showed a "Cancel" button inside the
`wait-area` (restore.html) in addition to the existing stop control in the
top navigation bar. Restore cancellation already works via the top control
(StateController.stopDialog, which posts /task/{id}/stop or /abort); the extra
button called a separate /task/{id}/stop that was not handled by the restore
flow, so it was redundant and confusing.

Remove the redundant button and its dedicated handler:
- restore.html: drop `allow-cancel="true"` from the wait-area.
- waitarea.html: remove the Cancel button block.
- waitArea.js: remove the `allowCancel` binding, `cancelTask()`, and the now
  unused `AppService` dependency.

Legacy ngax UI only; the new ngclient UI does not have this button. No backend,
API, cancellation, or restore behavior is changed.

Fixes #4453
2026-07-12 04:58:55 +09:00
Kenneth SkovhedeandGitHub b45298a91d Merge pull request #7037 from JamBalaya56562/fix/test-filters-parameters-file-sources
Fix test-filters ignoring --source from a parameters file (#4812)
2026-07-11 16:16:44 +02:00
TowyTowyandClaude Fable 5 d073d16089 Validate retention-policy format instead of crashing on missing colon
RetentionPolicyValue.CreateFromString split each --retention-policy entry
on ':' and unconditionally read periodInterval[1]. A malformed entry
without a colon (e.g. a typo like --retention-policy=1W) therefore threw
an IndexOutOfRangeException during the retention phase of a backup, and an
entry with extra colons (e.g. 7D:1D:5h) silently discarded the trailing
segment, applying a different policy than the user intended.

Guard the split length and raise a clear UserInformationException that
names the offending value and the expected <timeframe>:<interval> format.
Valid entries are parsed exactly as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 16:02:42 +02:00
Kenneth SkovhedeandGitHub 033d150da0 Merge pull request #7035 from duplicati/feature/server-db-lock
Server database lock
2026-07-11 14:55:02 +02:00
Kenneth SkovhedeandGitHub 06aeb13dea Merge pull request #7036 from duplicati/feature/improve-metadata-update
Improve metadata update
2026-07-11 14:54:17 +02:00
JamBalaya56562andClaude Opus 4.8 e0d9848d0e Fix test-filters ignoring --source from a parameters file (#4812)
When running `test-filters --parameters-file=...`, the parameters file's
--source entries were dropped and its --target was injected as the (only)
positional path, so filter testing ran against the backend URL instead of the
real source paths. The parameters-file handling only appended --source for the
`backup` command and always treated the first positional argument as a target.

test-filters/test-filter take source paths as positional arguments and have no
target, so the handling now appends --source for those commands (as it does for
backup) and does not inject --target (reported at verbose level, consistent with
how a --source on a non-backup command is already handled).

Adds an Issue4812 regression test driving Program.RunCommandLine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 21:50:01 +09:00
Kenneth Skovhede 824fc76c72 Switched to pragma for busy_timeout. 2026-07-11 12:22:28 +02:00
Kenneth Skovhede 36da653eb2 Improve metadata update
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.
2026-07-11 12:17:42 +02:00
Kenneth SkovhedeandGitHub 8b0575b987 Merge pull request #7034 from JamBalaya56562/fix/tempfile-unique-name-collision
Fix flaky temp-file name collision in debug builds
2026-07-11 12:13:42 +02:00
Kenneth SkovhedeandGitHub 98133c07a2 Merge pull request #7017 from JamBalaya56562/fix/repair-transaction-cleanup
Avoid secondary transaction errors after repair failure
2026-07-11 12:12:38 +02:00
Kenneth SkovhedeandGitHub 9e59e51159 Merge pull request #7031 from duplicati/feature/dont-use-power-management-in-ci
Prevent tests toggling powermode
2026-07-11 12:12:22 +02:00
Kenneth SkovhedeandGitHub 3c1374b911 Merge pull request #7033 from JamBalaya56562/chore/update-github-actions
Update GitHub Actions to current major versions
2026-07-11 12:11:57 +02:00
Kenneth Skovhede f690297d1b Server database lock
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.
2026-07-11 12:11:30 +02:00
JamBalaya56562andClaude Opus 4.8 e772a800d4 Fix flaky temp-file name collision in debug builds
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>
2026-07-11 07:31:05 +09:00
JamBalaya56562andClaude Opus 4.8 7e31cd5cba Update GitHub Actions to current major versions
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>
2026-07-11 06:47:01 +09:00
JamBalaya56562andClaude Opus 4.8 1470b05a4b Address PR review: async parity API, opt-in module, per-operation instance, tests
Responds to the review on #7020:
- IParity Create/Verify/Repair are now async (CancellationToken); the par2
  runner uses WaitForExitAsync and awaits the output reads directly.
- Removed ParityBase; Par2Parity implements IParity directly.
- parity-redundancy-level is parsed via Utility.ParseIntOption and validated as
  positive, and moved into the par2 module's own options. no-parity removed;
  parity-module now defaults to empty (opt-in) and is the sole toggle.
- The availability probe and "not found" warning are per-instance; BackendManager
  holds one shared parity instance per operation (SharedParityProvider), disposed
  with the manager, instead of constructing one per volume.
- The download repair path guards on Blocks/Files volume type; a successful parity
  repair now logs a warning; the test/verification flow disables repair
  (allowParityRepair=false) so damage is reported rather than masked.
- Added a full backup -> corrupt -> detect -> restore/recover integration test.
- Fix: par2cmdline 0.8.1 aborts on single-character protected filenames, so the
  working-copy base name is now "data" instead of "d". Verified end-to-end against
  real par2 in a Linux container (all parity tests pass).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 00:57:54 +09:00
Kenneth SkovhedeandGitHub c7a455f823 Merge pull request #7032 from JamBalaya56562/fix/dbpath-consistency-showlog
Use effective dbpath for show-log and delete-db endpoints (fixes #1698)
2026-07-10 17:14:31 +02:00
Kenneth Skovhede 53a768f47b Removed source check as it failed cross-os 2026-07-10 16:35:33 +02:00
Kenneth SkovhedeandGitHub 59e52d31ee Merge pull request #7029 from JamBalaya56562/fix/find-search-all-versions
Make CLI `find` search all backup versions by default (fixes #2287)
2026-07-10 16:28:38 +02:00
JamBalaya56562andClaude Opus 4.8 68dedaa320 Use effective dbpath for show-log and delete-db endpoints (fixes #1698)
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>
2026-07-10 22:28:27 +09:00
Kenneth Skovhede d4e1efc137 Tried a bit more specific capture 2026-07-10 15:26:41 +02:00
Kenneth SkovhedeandGitHub 3289de9af1 Merge pull request #7026 from duplicati/feature/improve-tls-cert-validation
Improve TLS cert validation
2026-07-10 15:10:05 +02:00
Kenneth Skovhede cf10b8274a Also disable snapshots on MacOS 2026-07-10 15:08:41 +02:00
Kenneth Skovhede e72bf15050 Prevent tests toggling powermode
This PR disables sleep prevention in tests.
This replaces #7028
2026-07-10 15:07:58 +02:00
Kenneth Skovhede a7ef8e42f2 Lock permissions on datafolder
This PR is a security hardning change and will break some setups.

The hardning is done to ensure the datafolder is not compromised and particularly that it is not maliciously seeded.

The changes now **requires** that the datafolder is locked down with exact permissions, or Duplicati will refuse to use it. This is a change to prior functionality where the folder would simply be locked down if it was not already locked.

Previously, a file named `insecure-permissions.txt` could be placed in the folder to instruct Duplicati not to set permissions. With this change that file is no longer supported.

The only way to opt-out of the permission check is to supply `--allow-insecure-datafolder` or the environment variable `DUPLICATI__ALLOW_INSECURE_DATAFOLDER`. Once either of those are set, Duplicati will no longer check permissions and accept folders with other permissions.

The setting can be applied to `preload.json`, but the file needs to be in a trusted location, which is either the directory with the binaries or the file pointed to by `DUPLICATI_PRELOAD_SETTINGS`. The setting cannot be placed in a `preload.json` file that is in an insecure folder as the folder is not read if the permissions are not correct.

The previous paths `/usr/local/share/Duplicati/preload.json` and `C:\ProgramData\Duplicati\preload.json` are no longer supported as they cannot be guaranteed to be locked down.

A `preload.json` in the datafolder is still supported, provided the folder passes the permission check (or the `--allow-insecure-datafolder` is passed to the executable).

For most users, this should not cause any problems as Duplicati has been locking down the folders, so they should be correctly locked down already.

The configuretool has been updated with a `secure-datafolder` command that can be used to force the correct permissions on a folder, in case the folder did not have the correct permissions.

For some Docker setups it may not be possible to set the permissions and the check will fail. These setup will need to apply `DUPLICATI__ALLOW_INSECURE_DATAFOLDER=true` in the image to run without the protections.
2026-07-10 15:03:32 +02:00
JamBalaya56562andClaude Opus 4.8 c091b3e6fc Make CLI find search all backup versions by default (fixes #2287)
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>
2026-07-10 21:56:03 +09:00