Merge pull request #9093 from ThomasWaldmann/port/master-9089-set_flags
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 / posix_tests (push) Has been cancelled
CI / windows_tests (push) Has been cancelled

extract: misc. fixes for restoring linux fs flags, port to master
This commit is contained in:
TW 2025-10-25 03:32:56 +02:00 committed by GitHub
commit ca706652d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -124,8 +124,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):
@ -134,17 +135,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: