Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions src/borg/platform/linux.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ BSD_TO_LINUX_FLAGS = {
stat.UF_NODUMP: FS_NODUMP_FL,
stat.UF_IMMUTABLE: FS_IMMUTABLE_FL,
stat.UF_APPEND: FS_APPEND_FL,
stat.UF_COMPRESSED: FS_COMPR_FL,
}
# must be a bitwise OR of all values in BSD_TO_LINUX_FLAGS.
LINUX_MASK = FS_NODUMP_FL | FS_IMMUTABLE_FL | FS_APPEND_FL


def set_flags(path, bsd_flags, fd=None):
Expand All @@ -136,17 +137,34 @@ def set_flags(path, bsd_flags, fd=None):
if stat.S_ISBLK(st.st_mode) or stat.S_ISCHR(st.st_mode) or stat.S_ISLNK(st.st_mode):
# see comment in get_flags()
return
cdef int flags = 0
cdef int flags
cdef int mask = LINUX_MASK # 1 at positions we want to influence
cdef int new_flags = 0
for bsd_flag, linux_flag in BSD_TO_LINUX_FLAGS.items():
if bsd_flags & bsd_flag:
flags |= linux_flag
new_flags |= linux_flag

open_fd = fd is None
if open_fd:
fd = os.open(path, os.O_RDONLY|os.O_NONBLOCK|os.O_NOFOLLOW)
try:
# Get current flags.
if ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1:
# If this fails, give up because it is either not supported by the fs
# or maybe not permitted? If we can't determine the current flags,
# we better not risk corrupting them by setflags, see the comment below.
return # give up silently

# Replace only the bits we actually want to influence, keep others.
# We can't just set all flags to the archived value, because we might
# reset flags that are not controllable from userspace, see #9039.
flags = (flags & ~mask) | (new_flags & mask)

if ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1:
error_number = errno.errno
if error_number != errno.EOPNOTSUPP:
# Usually we would only catch EOPNOTSUPP here, but Linux Kernel 6.17
# has a bug where it returns ENOTTY instead of EOPNOTSUPP.
if error_number not in (errno.EOPNOTSUPP, errno.ENOTTY):
raise OSError(error_number, strerror(error_number).decode(), path)
finally:
if open_fd:
Expand Down
Loading