Skip to content

Instantly share code, notes, and snippets.

@Bklyn
Created August 16, 2016 13:27
Show Gist options
  • Save Bklyn/5c7b003ad7f1e0ec81c2e0c872bc860f to your computer and use it in GitHub Desktop.
Save Bklyn/5c7b003ad7f1e0ec81c2e0c872bc860f to your computer and use it in GitHub Desktop.
Symbolic chmod in Python
# Found on https://www.daniweb.com/programming/software-development/code/243659/change-file-permissions-symbolically-linux
""" module chmodsym.py (linux)
This module defines a function chmod(location, description)
which allows to change a file's permission with a symbolic
description of the mode, similar to the shell command 'chmod'.
Tested with python 2.6 and 3.1.
"""
import os, stat
import functools
import operator
def chmod(location, description):
"""chmod(location, description) --> None
Change the access permissions of file, using a symbolic description
of the mode, similar to the format of the shell command chmod.
The format of description is
* an optional letter in o, g, u, a (no letter means a)
* an operator in +, -, =
* a sequence of letters in r, w, x, or a single letter in o, g, u
Example:
chmod(myfile, "u+x") # make the file executable for it's owner.
chmod(myfile, "o-rwx") # remove all permissions for all users not in the group.
See also the man page of chmod.
"""
if chmod.regex is None:
import re
chmod.regex = re.compile(r"(?P<who>[uoga]?)(?P<op>[+\-=])(?P<value>[ugo]|[rwx]*)")
mo = chmod.regex.match(description)
who, op, value = mo.group("who"), mo.group("op"), mo.group("value")
if not who:
who = "a"
mode = os.stat(location)[stat.ST_MODE]
if value in ("o", "g", "u"):
mask = ors((stat_bit(who, z) for z in "rwx" if (mode & stat_bit(value, z))))
else:
mask = ors((stat_bit(who, z) for z in value))
if op == "=":
mode &= ~ ors((stat_bit(who, z) for z in "rwx"))
mode = (mode & ~mask) if (op == "-") else (mode | mask)
os.chmod(location, mode)
chmod.regex = None
# Helper functions
def stat_bit(who, letter):
if who == "a":
return stat_bit("o", letter) | stat_bit("g", letter) | stat_bit("u", letter)
return getattr(stat, "S_I%s%s" % (letter.upper(), stat_bit.prefix[who]))
stat_bit.prefix = dict(u = "USR", g = "GRP", o = "OTH")
def ors(sequence, initial = 0):
return functools.reduce(operator.__or__, sequence, initial)
# Test code
def test_code():
import subprocess as sp
def touch(location):
sp.Popen("touch %s" % location, shell=True).wait()
def get_mode_by_ls(location):
"""Run ls and return a string like '-r--r--r-' giving the mode."""
popen = sp.Popen(["ls", "-l", location], stdout=sp.PIPE)
sout, serr = popen.communicate()
return sout[:10]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment