Skip to content

Instantly share code, notes, and snippets.

@entrity
Last active March 29, 2018 04:08
Show Gist options
  • Save entrity/a5f9c7b2cd6b9e9c772d51e5fd4a59e0 to your computer and use it in GitHub Desktop.
Save entrity/a5f9c7b2cd6b9e9c772d51e5fd4a59e0 to your computer and use it in GitHub Desktop.
Toggle whether the "immutable" flag is set on a file. (Works only on EXT file systems.)
#!/usr/bin/python2
# Toggle the "immutable" flag on a file. This flag will prevent you from
# removing or rewriting a file, even if you have permissions or or root.
# Usage:
# $0 <filepath> [on|off]
# $0 <dirpath> [on|off]
# If the argument is a file and no second argument (on/off) is given, then
# the script will read the current ext file flags and toggle the immutable flag.
# If the argument is a directory, the script runs on all of the files in
# the file tree beneath the directory. The operation is set to "on" automatically.
import fcntl
import os
import struct
import sys
# Taken from ext2fs/ext2_fs.h.
EXT2_IMMUTABLE_FL = 0x00000010
if struct.calcsize('P') == 8:
EXT2_IOC_SETFLAGS = 0x40086602 # This is the 64-bit code
EXT2_IOC_GETFLAGS = 0x80086601 # This is the 64-bit code
else:
EXT2_IOC_SETFLAGS = 0x40046602 # this is the 32-bit code
EXT2_IOC_GETFLAGS = 0x80046601 # This is the 32-bit code
FORCE_ON = 'on' in sys.argv[1:]
FORCE_OFF = 'off' in sys.argv[1:]
QUIET = 'q' in sys.argv[1:]
def log(text):
if not QUIET:
print(text)
def do_file(fpath):
fd = os.open(fpath, os.O_RDONLY)
rec = struct.pack('L', 0)
x = fcntl.ioctl(fd, EXT2_IOC_GETFLAGS, rec)
flags = struct.unpack('L',x)[0]
was_immutable = flags & EXT2_IMMUTABLE_FL
if FORCE_ON:
do_immutable = True
elif FORCE_OFF:
do_immutable = False
elif was_immutable:
do_immutable = False
else:
do_immutable = True
if (FORCE_ON and was_immutable) or (FORCE_OFF and not was_immutable):
log('skipping %s' % fpath)
else:
if do_immutable:
flags = flags | EXT2_IMMUTABLE_FL
else:
flags = flags & ~EXT2_IMMUTABLE_FL
log('toggling immutable %5s %s' % ('__ON_' if flags & EXT2_IMMUTABLE_FL else '_OFF_', fpath))
f = struct.pack('i', flags)
fcntl.ioctl(fd, EXT2_IOC_SETFLAGS, f);
os.close(fd)
# Traverse file tree beneath this dir and call do_file on all files
def do_dir(dpath):
if len(sys.argv) == 2:
global FORCE_ON
FORCE_ON = True
for triplet in os.walk(dpath):
for file in triplet[2]:
fpath = os.path.join(triplet[0], file)
if not os.path.islink(fpath):
do_file(fpath)
if len(sys.argv) < 2:
sys.stderr.write("Usage:\n%s <file> [on|off]\n%s <dir> [on|off]\n" % (sys.argv[0], sys.argv[0]))
sys.exit(1)
path = sys.argv[1]
if os.path.isfile(path):
do_file(path)
elif os.path.isdir(path):
do_dir(path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment