source: trunk/packages/python-afs/afs/acl.py @ 2877

Last change on this file since 2877 was 2599, checked in by broder, 15 years ago

Import python-afs.

Debathena should eventually be importing PyAFS for
<http://debathena.mit.edu/trac/ticket/395>, so hopefully this is only
temporary.

File size: 3.3 KB
Line 
1from afs import _acl
2from afs._acl import READ, WRITE, INSERT, LOOKUP, DELETE, LOCK, ADMINISTER, \
3    USR0, USR1, USR2, USR3, USR4, USR5, USR6, USR7
4from afs._acl import getCallerAccess
5
6_canonical = {
7    "read": "rl",
8    "write": "rlidwk",
9    "all": "rlidwka",
10    "mail": "lik",
11    "none": "",
12}
13
14_reverseCanonical = dict((y, x) for (x, y) in _canonical.iteritems())
15
16_charBitAssoc = [
17    ('r', READ),
18    ('l', LOOKUP),
19    ('i', INSERT),
20    ('d', DELETE),
21    ('w', WRITE),
22    ('k', LOCK),
23    ('a', ADMINISTER),
24    ('A', USR0),
25    ('B', USR1),
26    ('C', USR2),
27    ('D', USR3),
28    ('E', USR4),
29    ('F', USR5),
30    ('G', USR6),
31    ('H', USR7),
32]
33
34_char2bit = dict(_charBitAssoc)
35
36
37def rightsToEnglish(s):
38    """Turns a rlwidwka string into a canonical name if possible"""
39    if s in _reverseCanonical:
40        return _reverseCanonical[s]
41    else:
42        return ''
43
44def readRights(s):
45    """Canonicalizes string rights to bitmask"""
46    if s in _canonical: s = _canonical[s]
47    return _parseRights(s)
48
49def showRights(r):
50    """Takes a bitmask and returns a rwlidka string"""
51    s = ""
52    for char,mask in _charBitAssoc:
53        if r & mask == mask: s += char
54    return s
55
56def _parseRights(s):
57    """Parses a rwlid... rights tring to bitmask"""
58    r = 0
59    try:
60        for c in s:
61            r = r | _char2bit[c]
62    except KeyError:
63        raise ValueError
64    return r
65
66def _parseAcl(inp):
67    lines = inp.split("\n")
68    npos = int(lines[0].split(" ")[0])
69    pos = {}
70    neg = {}
71    for l in lines[2:]:
72        if l == "": continue
73        name, acl = l.split()
74        if npos:
75            npos -= 1
76            pos[name] = int(acl)
77        else:
78            # negative acl
79            neg[name] = int(acl)
80    return (pos, neg)
81
82def _unparseAcl(pos, neg):
83    npos = len(pos)
84    nneg = len(neg)
85    acl = "%d\n%d\n" % (npos, nneg)
86    for p in pos.items():
87        acl += "%s\t%d\n" % p
88    for n in neg.items():
89        acl += "%s\t%d\n" % n
90    return acl
91
92class ACL(object):
93    def __init__(self, pos, neg):
94        """
95        ``pos``
96            Dictionary of usernames to positive ACL bitmasks
97        ``neg``
98            Dictionary of usernames to negative ACL bitmasks
99        """
100        self.pos = pos
101        self.neg = neg
102    @staticmethod
103    def retrieve(dir, follow=True):
104        """Retrieve the ACL for an AFS directory"""
105        pos, neg = _parseAcl(_acl.getAcl(dir, follow))
106        return ACL(pos, neg)
107    def apply(self, dir, follow=True):
108        """Apply the ACL to a directory"""
109        self._clean()
110        _acl.setAcl(dir, _unparseAcl(self.pos, self.neg), follow)
111    def _clean(self):
112        """Clean an ACL by removing any entries whose bitmask is 0"""
113        for n,a in self.pos.items():
114            if a == 0:
115                del self.pos[n]
116        for n,a in self.neg.items():
117            if a == 0:
118                del self.neg[n]
119    def set(self, user, bitmask, negative=False):
120        """Set the bitmask for a given user"""
121        if bitmask < 0 or bitmask > max(_char2bit.values()):
122            raise ValueError, "Invalid bitmask"
123        if negative:
124            self.neg[user] = bitmask
125        else:
126            self.pos[user] = bitmask
127    def remove(self, user, negative=False):
128        """Convenience function to removeSet the bitmask for a given user"""
129        self.set(user, 0, negative)
130       
Note: See TracBrowser for help on using the repository browser.