summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2023-10-07 13:56:41 +0200
committerAnton Khirnov <anton@khirnov.net>2023-10-07 19:09:04 +0200
commit80d204cc94f3514dc46387534eb9f8e4d72719ff (patch)
treed2a0b612dc3afcf13c5bf179a4dd7986c18fa614
parent71f9452cca49bcd9da0ddda3047c2e18e58b9083 (diff)
Preserve setuid bits cleared by chown.
-rwxr-xr-xperm_offset.py20
1 files changed, 16 insertions, 4 deletions
diff --git a/perm_offset.py b/perm_offset.py
index 4e13eb3..3f23ab1 100755
--- a/perm_offset.py
+++ b/perm_offset.py
@@ -3,6 +3,7 @@
import argparse
import logging
import os
+from stat import S_IMODE, S_ISLNK
import sys
def remap_file(fpath, src, dst, count, dry_run):
@@ -15,10 +16,21 @@ def remap_file(fpath, src, dst, count, dry_run):
if gid >= src and gid < src + count:
gid += dst - src
- logging.debug('chown(%s, %d->%d, %d->%d)' % (fpath, stat.st_uid, uid,
- stat.st_gid, gid))
- if not dry_run:
- os.chown(fpath, uid, gid, follow_symlinks = False)
+ mode = S_IMODE(stat.st_mode)
+
+ logging.debug('chown(%s, mode=%o %d->%d, %d->%d)' %
+ (fpath, mode, stat.st_uid, uid, stat.st_gid, gid))
+ if dry_run:
+ return
+
+ if S_ISLNK(stat.st_mode) and not os.chown in os.supports_follow_symlinks:
+ return
+ os.chown(fpath, uid, gid, follow_symlinks = False)
+
+ # chown may clear setuid bits, so make sure to preserve them
+ if S_ISLNK(stat.st_mode) and not os.chmod in os.supports_follow_symlinks:
+ return
+ os.chmod(fpath, mode, follow_symlinks = False)
parser = argparse.ArgumentParser(
description = "Remap UIDs/GIDs in a directory tree from one range to another"