mirror of
https://github.com/borgbackup/borg.git
synced 2026-02-19 02:29:19 -05:00
Merge pull request #9128 from ThomasWaldmann/port/9116-to-master
extract: fs flags: use get/set to influence only specific flags, #9039, FreeBSD only (master)
This commit is contained in:
commit
47b3611bcb
3 changed files with 72 additions and 3 deletions
|
|
@ -24,7 +24,8 @@ elif is_freebsd: # pragma: freebsd only
|
|||
from .freebsd import API_VERSION as OS_API_VERSION
|
||||
from .freebsd import listxattr, getxattr, setxattr
|
||||
from .freebsd import acl_get, acl_set
|
||||
from .base import set_flags, get_flags
|
||||
from .freebsd import set_flags
|
||||
from .base import get_flags
|
||||
from .base import SyncFile
|
||||
from .posix import process_alive, local_pid_alive
|
||||
from .posix import swidth
|
||||
|
|
|
|||
|
|
@ -225,3 +225,71 @@ def acl_set(path, item, numeric_ids=False, fd=None):
|
|||
if ret == 1:
|
||||
_set_acl(path, ACL_TYPE_ACCESS, item, 'acl_access', numeric_ids, fd=fd)
|
||||
_set_acl(path, ACL_TYPE_DEFAULT, item, 'acl_default', numeric_ids, fd=fd)
|
||||
|
||||
|
||||
cdef extern from "sys/stat.h":
|
||||
int chflags(const char *path, unsigned long flags)
|
||||
int lchflags(const char *path, unsigned long flags)
|
||||
int fchflags(int fd, unsigned long flags)
|
||||
|
||||
# ----------------------------
|
||||
# BSD file flags (FreeBSD)
|
||||
# ----------------------------
|
||||
# Only influence flags that are known to be settable and leave system-managed/read-only flags untouched.
|
||||
# We express the mask in terms of names to avoid hard failures if a constant does
|
||||
# not exist on a given FreeBSD version; missing names simply contribute 0.
|
||||
import stat as stat_mod
|
||||
|
||||
SETTABLE_FLAG_NAMES = (
|
||||
# Owner-settable (UF_*)
|
||||
'UF_NODUMP',
|
||||
'UF_IMMUTABLE',
|
||||
'UF_APPEND',
|
||||
'UF_OPAQUE',
|
||||
'UF_NOUNLINK',
|
||||
'UF_HIDDEN',
|
||||
# Super-user-only (SF_*)
|
||||
'SF_ARCHIVED',
|
||||
'SF_IMMUTABLE',
|
||||
'SF_APPEND',
|
||||
'SF_NOUNLINK',
|
||||
)
|
||||
|
||||
cdef unsigned long SETTABLE_FLAGS_MASK = 0
|
||||
for _name in SETTABLE_FLAG_NAMES:
|
||||
# getattr(..., 0) keeps this importable when flags are missing on some FreeBSD versions
|
||||
SETTABLE_FLAGS_MASK |= <unsigned long> getattr(stat_mod, _name, 0)
|
||||
|
||||
|
||||
def set_flags(path, bsd_flags, fd=None):
|
||||
"""Set a subset of BSD file flags on FreeBSD without disturbing other bits.
|
||||
|
||||
Only flags that are known to be settable are influenced. All other flag bits are preserved as-is.
|
||||
"""
|
||||
# Determine current flags.
|
||||
try:
|
||||
if fd is not None:
|
||||
st = os.fstat(fd)
|
||||
else:
|
||||
st = os.lstat(path)
|
||||
current = st.st_flags
|
||||
except (OSError, AttributeError):
|
||||
# We can't determine the current flags, so better give up than corrupting anything.
|
||||
return
|
||||
|
||||
new_flags = (current & ~SETTABLE_FLAGS_MASK) | (bsd_flags & SETTABLE_FLAGS_MASK)
|
||||
|
||||
cdef unsigned long c_flags = <unsigned long> new_flags
|
||||
if fd is not None:
|
||||
if fchflags(fd, c_flags) == -1:
|
||||
err = errno.errno
|
||||
# Some filesystems may not support flags; ignore EOPNOTSUPP quietly.
|
||||
if err != errno.EOPNOTSUPP:
|
||||
# Keep error signature consistent with other platforms; st may not exist here.
|
||||
raise OSError(err, os.strerror(err), path)
|
||||
else:
|
||||
path_bytes = os.fsencode(path)
|
||||
if lchflags(path_bytes, c_flags) == -1:
|
||||
err = errno.errno
|
||||
if err != errno.EOPNOTSUPP:
|
||||
raise OSError(err, os.strerror(err), os.fsdecode(path_bytes))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from ...helpers import flags_noatime, flags_normal
|
|||
from .. import changedir, same_ts_ns
|
||||
from .. import are_symlinks_supported, are_hardlinks_supported, is_utime_fully_supported, is_birthtime_fully_supported
|
||||
from ...platform import get_birthtime_ns
|
||||
from ...platformflags import is_darwin, is_win32
|
||||
from ...platformflags import is_darwin, is_freebsd, is_win32
|
||||
from . import (
|
||||
RK_ENCRYPTION,
|
||||
requires_hardlinks,
|
||||
|
|
@ -608,7 +608,7 @@ def test_extract_xattrs_resourcefork(archivers, request):
|
|||
# assert atime_extracted == atime_expected # still broken, but not really important.
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_darwin, reason="only for macOS")
|
||||
@pytest.mark.skipif(not (is_darwin or is_freebsd), reason="only for macOS or FreeBSD")
|
||||
def test_extract_restores_append_flag(archivers, request):
|
||||
archiver = request.getfixturevalue(archivers)
|
||||
# create a file and set the append flag on it
|
||||
|
|
|
|||
Loading…
Reference in a new issue