Last active
March 29, 2018 04:08
-
-
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.)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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