Some enhancements to the symbolic_modes change
* Mark _symbolic_mode_to_octal and helper functions as classmethod and staticmethod These helpers should be made toplevel functions in their own module. For now, make them staticmethod/classmethod so that they can be used (and tested) without instantiating an AnsibleModule. * Move regex compilation out of loops * Get rid of python-2.4 compat
This commit is contained in:
parent
a5eea9042e
commit
6220c4aea1
1 changed files with 37 additions and 34 deletions
|
@ -243,10 +243,15 @@ FILE_COMMON_ARGUMENTS = dict(
|
||||||
|
|
||||||
PASSWD_ARG_RE = re.compile(r'^[-]{0,2}pass[-]?(word|wd)?')
|
PASSWD_ARG_RE = re.compile(r'^[-]{0,2}pass[-]?(word|wd)?')
|
||||||
|
|
||||||
# Can't use 07777 on Python 3, can't use 0o7777 on Python 2.4
|
# Used for parsing symbolic file perms
|
||||||
PERM_BITS = int('07777', 8) # file mode permission bits
|
MODE_OPERATOR_RE = re.compile(r'[+=-]')
|
||||||
EXEC_PERM_BITS = int('00111', 8) # execute permission bits
|
USERS_RE = re.compile(r'[^ugo]')
|
||||||
DEFAULT_PERM = int('0666', 8) # default file permission bits
|
PERMS_RE = re.compile(r'[^rwxXstugo]')
|
||||||
|
|
||||||
|
|
||||||
|
PERM_BITS = 0o7777 # file mode permission bits
|
||||||
|
EXEC_PERM_BITS = 0o0111 # execute permission bits
|
||||||
|
DEFAULT_PERM = 0o0666 # default file permission bits
|
||||||
|
|
||||||
|
|
||||||
def get_platform():
|
def get_platform():
|
||||||
|
@ -1300,21 +1305,24 @@ class AnsibleModule(object):
|
||||||
pass
|
pass
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def _symbolic_mode_to_octal(self, path_stat, symbolic_mode):
|
@classmethod
|
||||||
new_mode = stat.S_IMODE(path_stat.st_mode)
|
def _symbolic_mode_to_octal(cls, path_stat, symbolic_mode):
|
||||||
|
"""
|
||||||
|
This enables symbolic chmod string parsing as stated in the chmod man-page
|
||||||
|
|
||||||
# Fix for issue #14634
|
This includes things like: "u=rw-x+X,g=r-x+X,o=r-x+X"
|
||||||
# This enables symbolic chmod string parsing as stated in the chmod
|
"""
|
||||||
# man-page. This includes things like: "u=rw-x+X,g=r-x+X,o=r-x+X"
|
|
||||||
|
new_mode = stat.S_IMODE(path_stat.st_mode)
|
||||||
|
|
||||||
# Now parse all symbolic modes
|
# Now parse all symbolic modes
|
||||||
for mode in symbolic_mode.split(','):
|
for mode in symbolic_mode.split(','):
|
||||||
# Per single mode. This always contains a '+', '-' or '='
|
# Per single mode. This always contains a '+', '-' or '='
|
||||||
# Split it on that
|
# Split it on that
|
||||||
permlist = re.split(r'[+=-]', mode)
|
permlist = MODE_OPERATOR_RE.split(mode)
|
||||||
|
|
||||||
# And find all the operators
|
# And find all the operators
|
||||||
opers = re.findall(r'[+=-]', mode)
|
opers = MODE_OPERATOR_RE.findall(mode)
|
||||||
|
|
||||||
# The user(s) where it's all about is the first element in the
|
# The user(s) where it's all about is the first element in the
|
||||||
# 'permlist' list. Take that and remove it from the list.
|
# 'permlist' list. Take that and remove it from the list.
|
||||||
|
@ -1326,23 +1334,24 @@ class AnsibleModule(object):
|
||||||
|
|
||||||
# Check if there are illegal characters in the user list
|
# Check if there are illegal characters in the user list
|
||||||
# They can end up in 'users' because they are not split
|
# They can end up in 'users' because they are not split
|
||||||
if re.match(r'[^ugo]', users):
|
if USERS_RE.match(users):
|
||||||
raise ValueError("bad symbolic permission for mode: %s" % mode)
|
raise ValueError("bad symbolic permission for mode: %s" % mode)
|
||||||
|
|
||||||
# Now we have two list of equal length, one contains the requested
|
# Now we have two list of equal length, one contains the requested
|
||||||
# permissions and one with the corresponding operators.
|
# permissions and one with the corresponding operators.
|
||||||
for idx, perms in enumerate(permlist):
|
for idx, perms in enumerate(permlist):
|
||||||
# Check if there are illegal characters in the permissions
|
# Check if there are illegal characters in the permissions
|
||||||
if re.match(r'[^rwxXstugo]', perms):
|
if PERMS_RE.match(perms):
|
||||||
raise ValueError("bad symbolic permission for mode: %s" % mode)
|
raise ValueError("bad symbolic permission for mode: %s" % mode)
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
mode_to_apply = self._get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask)
|
mode_to_apply = cls._get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask)
|
||||||
new_mode = self._apply_operation_to_mode(user, opers[idx], mode_to_apply, new_mode)
|
new_mode = cls._apply_operation_to_mode(user, opers[idx], mode_to_apply, new_mode)
|
||||||
|
|
||||||
return new_mode
|
return new_mode
|
||||||
|
|
||||||
def _apply_operation_to_mode(self, user, operator, mode_to_apply, current_mode):
|
@staticmethod
|
||||||
|
def _apply_operation_to_mode(user, operator, mode_to_apply, current_mode):
|
||||||
if operator == '=':
|
if operator == '=':
|
||||||
if user == 'u':
|
if user == 'u':
|
||||||
mask = stat.S_IRWXU | stat.S_ISUID
|
mask = stat.S_IRWXU | stat.S_ISUID
|
||||||
|
@ -1360,14 +1369,8 @@ class AnsibleModule(object):
|
||||||
new_mode = current_mode - (current_mode & mode_to_apply)
|
new_mode = current_mode - (current_mode & mode_to_apply)
|
||||||
return new_mode
|
return new_mode
|
||||||
|
|
||||||
def _get_octal_mode_from_symbolic_perms(self, path_stat, user, perms, use_umask):
|
@staticmethod
|
||||||
def _apply_umask(perm, use_umask, rev_umask):
|
def _get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask):
|
||||||
"""Simple function to 'fake' ternary if statement"""
|
|
||||||
if use_umask:
|
|
||||||
return perm & rev_umask
|
|
||||||
else:
|
|
||||||
return perm
|
|
||||||
|
|
||||||
prev_mode = stat.S_IMODE(path_stat.st_mode)
|
prev_mode = stat.S_IMODE(path_stat.st_mode)
|
||||||
|
|
||||||
is_directory = stat.S_ISDIR(path_stat.st_mode)
|
is_directory = stat.S_ISDIR(path_stat.st_mode)
|
||||||
|
@ -1379,7 +1382,7 @@ class AnsibleModule(object):
|
||||||
# We also need the "reversed umask" for masking
|
# We also need the "reversed umask" for masking
|
||||||
umask = os.umask(0)
|
umask = os.umask(0)
|
||||||
os.umask(umask)
|
os.umask(umask)
|
||||||
rev_umask = PERM_BITS - umask
|
rev_umask = umask ^ PERM_BITS
|
||||||
|
|
||||||
# Permission bits constants documented at:
|
# Permission bits constants documented at:
|
||||||
# http://docs.python.org/2/library/stat.html#stat.S_ISUID
|
# http://docs.python.org/2/library/stat.html#stat.S_ISUID
|
||||||
|
@ -1398,27 +1401,27 @@ class AnsibleModule(object):
|
||||||
|
|
||||||
user_perms_to_modes = {
|
user_perms_to_modes = {
|
||||||
'u': {
|
'u': {
|
||||||
'r': _apply_umask(stat.S_IRUSR, use_umask, rev_umask),
|
'r': rev_umask & stat.S_IRUSR if use_umask else stat.S_IRUSR,
|
||||||
'w': _apply_umask(stat.S_IWUSR, use_umask, rev_umask),
|
'w': rev_umask & stat.S_IWUSR if use_umask else stat.S_IWUSR,
|
||||||
'x': _apply_umask(stat.S_IXUSR, use_umask, rev_umask),
|
'x': rev_umask & stat.S_IXUSR if use_umask else stat.S_IXUSR,
|
||||||
's': stat.S_ISUID,
|
's': stat.S_ISUID,
|
||||||
't': 0,
|
't': 0,
|
||||||
'u': prev_mode & stat.S_IRWXU,
|
'u': prev_mode & stat.S_IRWXU,
|
||||||
'g': (prev_mode & stat.S_IRWXG) << 3,
|
'g': (prev_mode & stat.S_IRWXG) << 3,
|
||||||
'o': (prev_mode & stat.S_IRWXO) << 6},
|
'o': (prev_mode & stat.S_IRWXO) << 6},
|
||||||
'g': {
|
'g': {
|
||||||
'r': _apply_umask(stat.S_IRGRP, use_umask, rev_umask),
|
'r': rev_umask & stat.S_IRGRP if use_umask else stat.S_IRGRP,
|
||||||
'w': _apply_umask(stat.S_IWGRP, use_umask, rev_umask),
|
'w': rev_umask & stat.S_IWGRP if use_umask else stat.S_IWGRP,
|
||||||
'x': _apply_umask(stat.S_IXGRP, use_umask, rev_umask),
|
'x': rev_umask & stat.S_IXGRP if use_umask else stat.S_IXGRP,
|
||||||
's': stat.S_ISGID,
|
's': stat.S_ISGID,
|
||||||
't': 0,
|
't': 0,
|
||||||
'u': (prev_mode & stat.S_IRWXU) >> 3,
|
'u': (prev_mode & stat.S_IRWXU) >> 3,
|
||||||
'g': prev_mode & stat.S_IRWXG,
|
'g': prev_mode & stat.S_IRWXG,
|
||||||
'o': (prev_mode & stat.S_IRWXO) << 3},
|
'o': (prev_mode & stat.S_IRWXO) << 3},
|
||||||
'o': {
|
'o': {
|
||||||
'r': _apply_umask(stat.S_IROTH, use_umask, rev_umask),
|
'r': rev_umask & stat.S_IROTH if use_umask else stat.S_IROTH,
|
||||||
'w': _apply_umask(stat.S_IWOTH, use_umask, rev_umask),
|
'w': rev_umask & stat.S_IWOTH if use_umask else stat.S_IWOTH,
|
||||||
'x': _apply_umask(stat.S_IXOTH, use_umask, rev_umask),
|
'x': rev_umask & stat.S_IXOTH if use_umask else stat.S_IXOTH,
|
||||||
's': 0,
|
's': 0,
|
||||||
't': stat.S_ISVTX,
|
't': stat.S_ISVTX,
|
||||||
'u': (prev_mode & stat.S_IRWXU) >> 6,
|
'u': (prev_mode & stat.S_IRWXU) >> 6,
|
||||||
|
|
Loading…
Reference in a new issue