Commit graph

3398 commits

Author SHA1 Message Date
TW
079aebb26c
Merge pull request #9331 from ThomasWaldmann/fix-cockpit-commandline
Some checks are pending
Lint / lint (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / asan_ubsan (push) Blocked by required conditions
CI / native_tests (push) Blocked by required conditions
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Blocked by required conditions
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Blocked by required conditions
CI / vm_tests (OmniOS, false, omnios, r151056) (push) Blocked by required conditions
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Blocked by required conditions
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Blocked by required conditions
CI / windows_tests (push) Blocked by required conditions
CodeQL / Analyze (push) Waiting to run
cockpit: fix subprocess invocation in frozen binaries
2026-02-14 22:06:34 +01:00
Thomas Waldmann
054194f4cb
cockpit: fix subprocess invocation in frozen binaries
When running as a Pyinstaller-made binary, sys.executable points to the
borg binary itself. Invoking it with "-m borg" resulted in an incorrect
command line (e.g., "borg -m borg ..."), which confused the argument
parser in the subprocess.

This change checks sys.frozen to determine the correct invocation:
- If frozen: [sys.executable, ...args]
- If not frozen: [sys.executable, "-m", "borg", ...args]
2026-02-14 21:22:30 +01:00
Thomas Waldmann
391252476d
remove API_VERSION check
we now have better build tools and these exceptions have
not been seen since long.
2026-02-14 20:45:09 +01:00
Thomas Waldmann
013edcd558 cleanup: remove check_python() compatibility shim
The check_python() function verified that the Python runtime supported
'follow_symlinks' for os.stat, os.utime, and os.chown. This check is no
longer necessary because:

1. Borg now requires Python >= 3.10.
2. On POSIX systems (Linux, macOS, *BSD, Haiku, OmniOS), support for these
   operations relies on the *at syscalls (fstatat, etc.), which have been
   implemented in standard libc for well over a decade (e.g., FreeBSD 8.0+,
   NetBSD 6.0+, Solaris 11+).
3. On Windows (MSYS2/MinGW), Python has supported follow_symlinks for
   os.stat since Python 3.2. The removed check specifically inspected only
   os.stat on Windows, avoiding the problematic os.utime/os.chown checks.

Any platform capable of running Python 3.10 will inherently support these
standard file operations.
2026-02-14 20:25:56 +01:00
trxvorr
6430564adb Fix #9279: normalize drive letters on Windows 2026-02-14 20:22:42 +05:30
Thomas Waldmann
2b5bca41aa
cygwin: skip ~root base dir test 2026-02-13 15:58:40 +01:00
Thomas Waldmann
e8f867072c
CI: fix tmpdir check on netbsd 2026-02-13 08:08:11 +01:00
Mrityunjay Raj
ffe360a2ec fix typos found by codespell
- backupped → backed-up (docs/faq.rst)
- splitted → expected (src/borg/testsuite/xattr_test.py)
- uptodate → up-to-date (docs/development.rst, src/borg/repository.py)

Closes #9295
2026-02-13 00:16:54 +05:30
TW
8da5de3670
Merge pull request #9288 from ThomasWaldmann/directory-extraction-master
Some checks are pending
Lint / lint (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / asan_ubsan (push) Blocked by required conditions
CI / native_tests (push) Blocked by required conditions
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Blocked by required conditions
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Blocked by required conditions
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Blocked by required conditions
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Blocked by required conditions
CI / windows_tests (push) Blocked by required conditions
CodeQL / Analyze (push) Waiting to run
extract: do not delete existing directory if possible, fixes #4233
2026-02-11 13:57:53 +01:00
Thomas Waldmann
b85ad47fda
extract --continue: optimize processing of already existing dirs
if an already existing fs directory has the correct (as archived) mtime,
we have already extracted it in a previous borg extract run and we do not
need and should not call restore_attrs for it again.

if the directory exists, but does not have the correct mtime, restore_attrs
will be called and its attributes will be extracted (and mtime set to
correct value).
2026-02-11 12:11:26 +01:00
Aiman
e19a2213a3 testsuite: remove deprecated manual cleanup in create_cmd_test 2026-02-11 16:10:21 +05:30
TW
b802cfd496
Merge pull request #9292 from ThomasWaldmann/list-fingerprint-master
Some checks are pending
Lint / lint (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / asan_ubsan (push) Blocked by required conditions
CI / native_tests (push) Blocked by required conditions
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Blocked by required conditions
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Blocked by required conditions
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Blocked by required conditions
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Blocked by required conditions
CI / windows_tests (push) Blocked by required conditions
CodeQL / Analyze (push) Waiting to run
list --format: add fingerprint placeholder
2026-02-11 09:12:55 +01:00
TW
26bde193b6
Merge pull request #9290 from MultisampledNight/fix-padme-ui
Some checks are pending
Lint / lint (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / asan_ubsan (push) Blocked by required conditions
CI / native_tests (push) Blocked by required conditions
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Blocked by required conditions
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Blocked by required conditions
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Blocked by required conditions
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Blocked by required conditions
CI / windows_tests (push) Blocked by required conditions
CodeQL / Analyze (push) Waiting to run
Fix padme UI
2026-02-10 08:55:05 +01:00
Thomas Waldmann
baed0bc5d0
list --format: add fingerprint placeholder
This allows users to compare file content efficiently without reading the
full file data, by exposing a hash of the chunk IDs and the relevant
conditions for valid comparisons, like chunker params, chunker seed/key,
id key, key type, etc.

This is based on PR #5167 by @hrehfeld, code + discussion, with some changes:
- the conditions hash now includes more relevant input params
- returning a single value that is composed of 2 parts
- tests (including new buzhash64)

Example output (different files in same archive):

1e88bfb02d0a5320-a539587200c33b857f9827d01fcb7dabacf30501c83929e7308668d43f4a6302 file1
1e88bfb02d0a5320-9ed78a4c14d0506d9ae75d914cca90db64655ddea22647dd1c89f19e2fc080ae file2

The fingerprint has 2 parts:

First part: same hash, indicates same chunking / chunk id generation params,
            meaning that the second part is valid to be compared.

Second part: different hash, because file content is different.
             same hash here would mean same content.
2026-02-10 08:45:42 +01:00
MultisampledNight
245a46842d
test(compress): roundtrip through UI parsing 2026-02-09 23:59:38 +01:00
MultisampledNight
74f5faba96
compress: expose Padmé size obfuscation via UI
Fixes #9286.
Tested manually via:

 = export BORG_REPO=repo
 = alias b='python -m borg'
 = echo meow > file
 = b create ::test ./file -C obfuscate,250,none
 = b info
Archive name: ::test
Archive fingerprint: 2c67ba6c04faa6d911b5dd02b99593ea2cf6ebe7c38e2e6fca90afad47a7095e
[...]
Command line: /home/user/c/d0/software/backup/borg/src/borg/__main__.py create ::test ./file -C obfuscate,250,none
[...]
Number of files: 1
Original size: 40 B
 = rm file
 = b list ::test
-rw-r--r-- user   users         5 Mon, 2026-02-09 22:41:54 +0100 file
 = b extract ::test file
 = cat file
meow
 = # Yup, all good. Let's go for something nontrivial to make sure it's stripped accordingly.
 = dd if=/dev/urandom of=file bs=1M count=4
 = b create ::test ./file -C obfuscate,250,zstd
 = mv file original
 = b info
Archive name: ::test
Archive fingerprint: 2c67ba6c04faa6d911b5dd02b99593ea2cf6ebe7c38e2e6fca90afad47a7095e
[...]
Command line: /home/user/c/d0/software/backup/borg/src/borg/__main__.py create ::test ./file -C obfuscate,250,none
Working Directory: /home/user/l/bug/borg
Number of files: 1
Original size: 40 B

Archive name: ::test
Archive fingerprint: 01014345dd1187f014f19ac59a2313a4e6d644532b287d806fe87882ca47ea0d
[...]
Command line: /home/user/c/d0/software/backup/borg/src/borg/__main__.py create ::test ./file -C obfuscate,250,zstd
Working Directory: /home/user/l/bug/borg
Number of files: 1
Original size: 4.19 MB
 = b extract aid:01014345dd1187f014f19ac59a2313a4e6d644532b287d806fe87882ca47ea0d 
 = sha256sum file original
d74be01406764ef11f5aa3ee27033bdced2c9573c0b3ed980fcfb2116c7d84de  file
d74be01406764ef11f5aa3ee27033bdced2c9573c0b3ed980fcfb2116c7d84de  original
 =
2026-02-09 23:23:29 +01:00
Thomas Waldmann
98d189d088
extract: do not delete existing directory if possible, fixes #4233
A pre-existing directory might be a btrfs subvolume that was created by
the user ahead of time when restoring several nested subvolumes from a
single archive.

If the archive item to be extracted is a directory and there is already
a directory at the destination path, do not remove (and recreate) it,
but just use it.

That way, btrfs subvolumes (which look like directories) are not deleted.

Fix originally contributed by @intelfx in #7866, but needed more work,
so I thought more about the implications and added a test.

Note:

In the past, we first removed (empty) directories, then created a fresh
one, then called restore_attrs for that. That produced correct metadata,
but only for the case of an EMPTY exisiting directory. If the existing
directory was not empty, the simply os.rmdir we tried did not work
anyway and did not remove the existing directory.

Usually we extract to an empty base directory, thus encountering this
edge case is mostly limited to continuing a previous extraction.
In that case, calling restore_attrs again on a directory that already has
existing attrs should be harmless, because they are identical.
2026-02-09 22:27:42 +01:00
Thomas Waldmann
37fbe3f40b
swidth: use cross platform implementation, fixes #7493
This implementation should be good enough for our usecase (paths) and has no external dependencies.

There is also a wcwidth library which might be even better, but would add another dependency.
2026-02-09 22:01:49 +01:00
Thomas Waldmann
50f4e54462
map_chars: deal invalid chars in paths on windows 2026-02-09 21:32:08 +01:00
Thomas Waldmann
88581d1bb8
Improve Windows path handling with forward slash standardization
This commit implements a comprehensive approach to Windows path compatibility
by standardizing on forward slashes (/) for all internal path representations
while maintaining cross-platform archive compatibility.

Core Strategy:
- All internal paths now use forward slashes as separators on all platforms
- Boundary normalization: backslashes converted to forward slashes at entry
  points on Windows (filesystem paths only, not user patterns)
- Literal backslashes from POSIX archives replaced with % on Windows extraction

Key Changes:

Path Handling (helpers/fs.py):
- Added slashify(): converts backslashes to forward slashes on Windows
- Added percentify(): replaces backslashes with % for POSIX-to-Windows extraction
- Updated make_path_safe() to check for Windows-style .. patterns
- Changed get_strip_prefix() to use posixpath.normpath instead of os.path.normpath
- Updated remove_dotdot_prefixes() to use forward slashes consistently

Pattern Matching (patterns.py):
- Replaced os.path with posixpath throughout for consistent separator handling
- Updated PathFullPattern, PathPrefixPattern, FnmatchPattern, ShellPattern
- All pattern matching now uses / as separator regardless of platform
- Removed platform-specific os.sep usage

Archive Operations (archive.py, item.pyx):
- Applied slashify() to paths during archive creation on Windows
- Added percentify/slashify encoding/decoding for symlink targets
- Ensures archived paths always use forward slashes

Command Line (archiver/create_cmd.py, extract_cmd.py):
- Replaced os.path.join/normpath with posixpath equivalents
- Added slashify() for stdin-provided paths on Windows
- Updated strip_components to use / separator
- Changed PathSpec to FilesystemPathSpec for proper path handling

Repository (repository.py, legacyrepository.py):
- Replaced custom _local_abspath_to_file_url() with Path.as_uri()

Documentation (archiver/help_cmd.py):
- Clarified that all archived paths use forward slashes
- Added note about Windows absolute paths in archives (e.g., C/Windows/System32)
- Documented backslash-to-percent replacement for POSIX archives on Windows

Impact:
- Windows users can now create and extract archives with consistent path handling
- Cross-platform archives remain compatible
- Pattern matching works identically on all platforms
2026-02-09 20:02:21 +01:00
Thomas Waldmann
ae4b9521f8
fix issues found by linter 2026-02-09 20:02:13 +01:00
Thomas Waldmann
f646d2c4d0
docs: consolidate key backup info in borg key export, fixes #6204
Consolidate key backup documentation into `borg key export` and reference
it from Quickstart and FAQ to avoid duplication and inconsistency.

Clarify that while `repokey` or `authenticated` mode stores the key in the
repo, a separate backup is still recommended to protect against repository
corruption or data loss.
2026-02-08 11:50:31 +01:00
Thomas Waldmann
dfa9308dca
cockpit: start the Borg runner after all widgets are mounted 2026-01-29 17:43:48 +01:00
Thomas Waldmann
4073bb263f
fix S3 url description, fixes #9249
- profile also must be followed by @
- in URL specs, it is "scheme", not "schema"
- note that the scheme is usually https
2026-01-28 12:12:26 +01:00
Thomas Waldmann
618a401b48
fix or skip tests on windows 2026-01-27 22:09:25 +01:00
Thomas Waldmann
9eaf7df3f0
fix file: URL parsing for windows
Linux: /abs/path -> file:///abs/path
Windows: c:/abs/path -> file:///c:/abs/path
2026-01-27 22:09:24 +01:00
Thomas Waldmann
0f0566ea63
correctly construct file: URL on windows 2026-01-27 22:09:22 +01:00
Thomas Waldmann
3bddee22d4
Version: do not access private attributes, fixes #9263
DeprecationWarning: Version._version is private and will be removed soon
2026-01-22 17:23:45 +01:00
MartinKurtz
4827521f9c
mount: warn about symlinks pointing outside of the mountpoint, see #9254
Some checks failed
Lint / lint (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / security (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
CI / asan_ubsan (push) Has been cancelled
CI / native_tests (push) Has been cancelled
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Has been cancelled
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Has been cancelled
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Has been cancelled
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Has been cancelled
CI / windows_tests (push) Has been cancelled
2026-01-20 03:21:34 +01:00
Thomas Waldmann
e671234942
fix mismatch in xattr test, fixes #9238 2025-12-24 02:17:07 +01:00
Thomas Waldmann
fef9d63111
pyinstaller missing module workaround 2025-12-23 18:53:15 +01:00
Thomas Waldmann
ee2fcefcb8
hlfuse: fix getxattr, raise ENOATTR 2025-12-23 16:13:49 +01:00
Thomas Waldmann
7278a1d5fc
ENOATTR import cleanups 2025-12-23 16:13:47 +01:00
Thomas Waldmann
c9ebeba933
make mypy happy 2025-12-23 16:13:46 +01:00
Thomas Waldmann
334f73df08
use hlfuse similar to llfuse, move import 2025-12-20 19:47:30 +01:00
Thomas Waldmann
cc18e3f171
rename fuse2 -> hlfuse
fuse2 was a bit misleading. it meant "our 2nd fuse implementation",
but could be misunderstood to refer to fuse v2.

hlfuse.py now means highlevel fuse, as opposed to the lowlevel fuse in fuse.py.
2025-12-20 19:46:29 +01:00
Thomas Waldmann
2e567d9785
fuse_impl.ENOATTR (import from borg.platform) 2025-12-20 19:46:04 +01:00
Thomas Waldmann
562bb27368
fix hardlink inode issue 2025-12-20 19:31:55 +01:00
Thomas Waldmann
7590d1eed4
add has_any_fuse flag 2025-12-20 19:31:54 +01:00
Thomas Waldmann
3e676e95c1
pytest report header: report llfuse/pyfuse3/mfusepy 2025-12-20 19:31:53 +01:00
Thomas Waldmann
176dec80f3
integrate mount2_cmds_test into mount_cmds_test
Updated mount_cmds_test.py to work with both llfuse/pyfuse3 and mfusepy
by checking for either implementation in skip conditions.

mfusepy: 2 test fails due to hardlink implementation differences
2025-12-20 19:31:50 +01:00
Thomas Waldmann
ead93b6d12
integrate mount2/umount2 into mount/umount, use BORG_FUSE_IMPL 2025-12-20 19:31:49 +01:00
Thomas Waldmann
71416d76f4
fuse2: getattr: prefer fh lookup if possible 2025-12-20 19:31:47 +01:00
Thomas Waldmann
0aa7c16749
fuse2: improve comments 2025-12-20 19:31:46 +01:00
Thomas Waldmann
3393c0f2b7
fuse2: implement lazy children dict allocation for DirEntry 2025-12-20 19:31:45 +01:00
Thomas Waldmann
8eb676b047
fuse2: remove path from packed inodes to save memory 2025-12-20 19:31:43 +01:00
Thomas Waldmann
a842234843
fuse2: add __slots__ to DirEntry for memory optimization 2025-12-20 19:31:42 +01:00
Thomas Waldmann
72befa1bcf
fuse2: rename Node -> DirEntry, inode_count -> current_ino 2025-12-20 19:31:41 +01:00
Thomas Waldmann
9651b083df
Optimize fuse2 memory usage with centralized packed item storage 2025-12-20 19:31:39 +01:00
Thomas Waldmann
6632b1187a
fuse2: remove unused fuse_main 2025-12-20 19:31:38 +01:00