diff --git a/afs/_acl.pyx b/afs/_acl.pyx index d67885c..ca026ba 100644 --- a/afs/_acl.pyx +++ b/afs/_acl.pyx @@ -1,5 +1,6 @@ +# cython: c_string_type=str, c_string_encoding=ascii from afs._util cimport * -from afs._util import pyafs_error +from afs._util import path_to_bytes cdef extern from "afs/prs_fs.h": enum: @@ -34,15 +35,15 @@ USR7 = PRSFS_USR7 DEF MAXSIZE = 2048 -def getAcl(char* dir, int follow=1): +def getAcl(dir, int follow=1): cdef char space[MAXSIZE] - pioctl_read(dir, VIOCGETAL, space, MAXSIZE, follow) + pioctl_read(path_to_bytes(dir), VIOCGETAL, space, MAXSIZE, follow) return space -def getCallerAccess(char *dir, int follow=1): +def getCallerAccess(dir, int follow=1): cdef vcxstat2 stat - pioctl_read(dir, VIOC_GETVCXSTATUS2, &stat, sizeof(vcxstat2), follow) + pioctl_read(path_to_bytes(dir), VIOC_GETVCXSTATUS2, &stat, sizeof(vcxstat2), follow) return stat.callerAccess -def setAcl(char* dir, char* acl, int follow=1): - pioctl_write(dir, VIOCSETAL, acl, NULL, 0, follow) +def setAcl(dir, char* acl, int follow=1): + pioctl_write(path_to_bytes(dir), VIOCSETAL, acl, NULL, 0, follow) diff --git a/afs/_fs.pyx b/afs/_fs.pyx index 0ee3359..30db67b 100644 --- a/afs/_fs.pyx +++ b/afs/_fs.pyx @@ -1,12 +1,13 @@ +# cython: c_string_type=str, c_string_encoding=ascii from afs._util cimport * -from afs._util import pyafs_error +from afs._util import path_to_bytes import socket import struct import logging log = logging.getLogger('afs._fs') -def whichcell(char* path): +def whichcell(path): """ whichcell(path) -> str @@ -14,10 +15,10 @@ def whichcell(char* path): """ cdef char cell[MAXCELLCHARS] - pioctl_read(path, VIOC_FILE_CELL_NAME, cell, sizeof(cell), 1) + pioctl_read(path_to_bytes(path), VIOC_FILE_CELL_NAME, cell, sizeof(cell), 1) return cell -def _lsmount(char* parent, char* path): +def _lsmount(parent, path): """ _lsmount(parent, path) -> str @@ -26,10 +27,10 @@ def _lsmount(char* parent, char* path): """ cdef char mtpt[AFS_PIOCTL_MAXSIZE] - pioctl_write(parent, VIOC_AFS_STAT_MT_PT, path, mtpt, sizeof(mtpt), 1) + pioctl_write(path_to_bytes(parent), VIOC_AFS_STAT_MT_PT, path_to_bytes(path), mtpt, sizeof(mtpt), 1) return mtpt -def _volume_status(char* path): +def _volume_status(path): """ _volume_status(path) -> tuple() @@ -45,7 +46,7 @@ def _volume_status(char* path): cdef char *name, *offmsg cdef object py_volstat - pioctl_read(path, VIOCGETVOLSTAT, volstat_buf, sizeof(volstat_buf), 1) + pioctl_read(path_to_bytes(path), VIOCGETVOLSTAT, volstat_buf, sizeof(volstat_buf), 1) volstat = volstat_buf # You can't assign a char * to a temporary Python string # (e.g. an array slice) @@ -71,7 +72,7 @@ def _volume_status(char* path): py_volstat['PartMaxBlocks'] = volstat.PartMaxBlocks return (name, offmsg, py_volstat) -def _fid(char *path): +def _fid(path): """ _fid(path) -> dict() @@ -80,7 +81,7 @@ def _fid(char *path): cdef VenusFid vfid cdef object py_fid - pioctl_read(path, VIOCGETFID, &vfid, sizeof(VenusFid), 1) + pioctl_read(path_to_bytes(path), VIOCGETFID, &vfid, sizeof(VenusFid), 1) py_fid = dict() py_fid['Volume'] = vfid.Fid.Volume py_fid['Vnode'] = vfid.Fid.Vnode @@ -88,7 +89,7 @@ def _fid(char *path): py_fid['Cell'] = vfid.Cell return py_fid -def _whereis(char* path): +def _whereis(path): """ _whereis(path) -> list() @@ -103,7 +104,7 @@ def _whereis(char* path): cdef object py_result py_result = list() - pioctl_read(path, VIOCWHEREIS, whereis_buf, sizeof(whereis_buf), 1) + pioctl_read(path_to_bytes(path), VIOCWHEREIS, whereis_buf, sizeof(whereis_buf), 1) hosts = whereis_buf for j in range(0, AFS_MAXHOSTS): if hosts[j] == 0: diff --git a/afs/_pts.pyx b/afs/_pts.pyx index 3c10b70..6494173 100644 --- a/afs/_pts.pyx +++ b/afs/_pts.pyx @@ -1,3 +1,4 @@ +# cython: c_string_type=str, c_string_encoding=ascii from afs._util cimport * from afs._util import pyafs_error import re @@ -112,7 +113,6 @@ cdef class PTEntry: cdef int _ptentry_from_c(PTEntry p_entry, prcheckentry * c_entry) except -1: if p_entry is None: raise TypeError - return -1 p_entry.flags = c_entry.flags p_entry.id = c_entry.id @@ -127,7 +127,6 @@ cdef int _ptentry_from_c(PTEntry p_entry, prcheckentry * c_entry) except -1: cdef int _ptentry_to_c(prcheckentry * c_entry, PTEntry p_entry) except -1: if p_entry is None: raise TypeError - return -1 c_entry.flags = p_entry.flags c_entry.id = p_entry.id @@ -227,7 +226,9 @@ cdef class PTS: self.cell = info.name - if sec > 0: + if sec == 0: + sc = rxnull_NewClientSecurityObject() + else: strncpy(prin.cell, info.name, sizeof(prin.cell)) prin.instance[0] = 0 strncpy(prin.name, "afs", sizeof(prin.name)) @@ -237,6 +238,7 @@ cdef class PTS: if sec >= 2: # No really - we wanted authentication pyafs_error(code) + sc = rxnull_NewClientSecurityObject() sec = 0 else: if sec == 3: @@ -246,11 +248,7 @@ cdef class PTS: sc = rxkad_NewClientSecurityObject(level, &token.sessionKey, token.kvno, token.ticketLen, token.ticket) - - if sec == 0: - sc = rxnull_NewClientSecurityObject() - else: - sec = 2 + sec = 2 memset(serverconns, 0, sizeof(serverconns)) for 0 <= i < info.numServers: diff --git a/afs/_util.pyx b/afs/_util.pyx index c80bcd6..19f13c7 100644 --- a/afs/_util.pyx +++ b/afs/_util.pyx @@ -1,7 +1,7 @@ """ General PyAFS utilities, such as error handling """ - +# cython: c_string_type=str, c_string_encoding=ascii import sys import logging @@ -17,7 +17,7 @@ cdef int _init = 0 # Function for "reading" data from a pioctl # "outbuffer" will get populated with the data in question -cdef extern int pioctl_read(char *path, afs_int32 op, void *outbuffer, +cdef int pioctl_read(char *path, afs_int32 op, void *outbuffer, unsigned short size, afs_int32 follow) except -1: cdef ViceIoctl blob cdef afs_int32 code @@ -42,7 +42,7 @@ cdef extern int pioctl_read(char *path, afs_int32 op, void *outbuffer, # Pass NULL for outbuffer in cases where we don't get anything # back (e.g. VIOCSETAL) # "outsize" will be ignored (forced to 0) if "outbuffer" is NULL -cdef extern int pioctl_write(char *path, afs_int32 op, char *inbuffer, +cdef int pioctl_write(char *path, afs_int32 op, char *inbuffer, void *outbuffer, afs_int32 outsize, afs_int32 follow) except -1: cdef ViceIoctl blob @@ -94,3 +94,8 @@ def pyafs_error(code): if code != 0: raise AFSException(code) + +def path_to_bytes(path): + if isinstance(path, unicode): + return path.encode(sys.getfilesystemencoding(), 'surrogateescape') + return path diff --git a/afs/acl.py b/afs/acl.py index 20a416f..65ec595 100644 --- a/afs/acl.py +++ b/afs/acl.py @@ -11,7 +11,7 @@ "none": "", } -_reverseCanonical = dict((y, x) for (x, y) in _canonical.iteritems()) +_reverseCanonical = dict((y, x) for (x, y) in _canonical.items()) _charBitAssoc = [ ('r', READ), @@ -119,7 +119,7 @@ def _clean(self): def set(self, user, bitmask, negative=False): """Set the bitmask for a given user""" if bitmask < 0 or bitmask > max(_char2bit.values()): - raise ValueError, "Invalid bitmask" + raise ValueError("Invalid bitmask") if negative: self.neg[user] = bitmask else: diff --git a/afs/pts.py b/afs/pts.py index e9f3c98..eb69c77 100644 --- a/afs/pts.py +++ b/afs/pts.py @@ -215,7 +215,7 @@ class PTEntry(object): groups: For users, this contains a collection class representing the set of groups the user is a member of. - users: For groups, this contains a collection class representing + members: For groups, this contains a collection class representing the members of this group. """ _attrs = ('id', 'name', 'count', 'flags', 'ngroups', 'nusers') @@ -381,7 +381,7 @@ def getEntry(self, ident): elt) return ident - elif isinstance(ident, basestring): + elif isinstance(ident, (str, bytes)): return PTEntry(self, name=ident) else: return PTEntry(self, id=ident) diff --git a/afs/tests/test__pts.py b/afs/tests/test__pts.py index 64297b1..58e4f27 100644 --- a/afs/tests/test__pts.py +++ b/afs/tests/test__pts.py @@ -1,45 +1,50 @@ import os from afs._pts import PTS import nose +import unittest def get_this_cell(): # Feel free to add more places ThisCell might show up to_try = ['/private/var/db/openafs/etc/ThisCell', + '/opt/local/etc/openafs/ThisCell', '/etc/openafs/ThisCell', '/usr/vice/etc/ThisCell'] for f in to_try: if os.path.isfile(f): return open(f).read().strip() -def test_init_home_cell(): - p = PTS() - assert p.cell == get_this_cell(), "PTS doesn't initialize to ThisCell when none specified." - -def test_init_other_cell(): - cell = 'zone.mit.edu' - p = PTS('zone.mit.edu') - assert p.cell == cell, "PTS doesn't initialize to provided cell." - -def test_user_name_to_id(): - p = PTS() - name = 'broder' - id = p._NameToId(name) - assert id == 41803, "PTS can't convert user name to ID." - assert p._IdToName(id) == name, "PTS can't convert user ID to name." - -def test_group_name_to_id(): - p = PTS() - name = 'system:administrators' - id = p._NameToId(name) - assert id == -204, "PTS can't convert group name to ID." - assert p._IdToName(id) == name, "PTS can't convert group ID to name." - -def test_name_or_id(): - p = PTS() - name = 'system:administrators' - id = -204 - assert p._NameOrId(name) == id, "PTS._NameOrId can't identify name." - assert p._NameOrId(id) == id, "PTS._NameOrId can't identify ID." +class PTSTestCase(unittest.TestCase): + + @unittest.skipUnless(get_this_cell(), "can't find ThisCell") + def test_init_home_cell(self): + p = PTS() + self.assertEqual(p.cell, get_this_cell(), "PTS doesn't initialize to ThisCell when none specified.") + + def test_init_other_cell(self): + cell = 'zone.mit.edu' + p = PTS('zone.mit.edu') + self.assertEqual(p.cell, cell, "PTS doesn't initialize to provided cell.") + + def test_user_name_to_id(self): + p = PTS() + name = 'broder' + id = p._NameToId(name) + self.assertEqual(id, 41803, "PTS can't convert user name to ID.") + self.assertEqual(p._IdToName(id), name, "PTS can't convert user ID to name.") + + def test_group_name_to_id(self): + p = PTS() + name = 'system:administrators' + id = p._NameToId(name) + self.assertEqual(id, -204, "PTS can't convert group name to ID.") + self.assertEqual(p._IdToName(id), name, "PTS can't convert group ID to name.") + + def test_name_or_id(self): + p = PTS() + name = 'system:administrators' + id = -204 + self.assertEqual(p._NameOrId(name), id, "PTS._NameOrId can't identify name.") + self.assertEqual(p._NameOrId(id), id, "PTS._NameOrId can't identify ID.") if __name__ == '__main__': nose.main() diff --git a/afs/tests/test_acl.py b/afs/tests/test_acl.py index aa4d1ae..3e27992 100644 --- a/afs/tests/test_acl.py +++ b/afs/tests/test_acl.py @@ -11,7 +11,7 @@ def test_readRights(): def test_retrieve(): assert acl.ACL.retrieve('/afs/athena.mit.edu/contrib/bitbucket2').pos['system:anyuser'] & acl.WRITE - assert acl.ACL.retrieve('/afs/athena.mit.edu/user/t/a/tabbott').neg['yuranlu'] & acl.USR0 + assert acl.ACL.retrieve('/afs/athena.mit.edu/astaff/project/macathena/.python-afs-test').neg['mrittenb'] & acl.USR0 def test_getCallerAccess(): assert acl.getCallerAccess('/afs/athena.mit.edu/contrib/bitbucket2') & acl.WRITE diff --git a/setup.py b/setup.py index 378c7dc..9f15868 100755 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ import os for root in ['/Library/OpenAFS/Tools', + '/opt/local', '/usr/local', '/usr/afsws', '/usr']: @@ -20,11 +21,11 @@ '%s/include' % root] library_dirs = ['%s/lib' % root, '%s/lib/afs' % root] -if os.path.exists('%s/lib/libafsauthent_pic.a' % root): +if os.path.exists('%s/lib/libafsauthent_pic.a' % root) or os.path.exists('%s/lib64/libafsauthent_pic.a' % root): suffix = '_pic' else: suffix = '' -libraries = ['afsauthent%s' % suffix, 'afsrpc%s' % suffix, 'resolv'] +libraries = ['afsauthent%s' % suffix, 'afsrpc%s' % suffix, 'rokenafs', 'afshcrypto', 'resolv'] define_macros = [('AFS_PTHREAD_ENV', None)] def PyAFSExtension(module, *args, **kwargs): @@ -39,7 +40,7 @@ def PyAFSExtension(module, *args, **kwargs): setup( name="PyAFS", - version="0.2.2", + version="0.2.3", description="PyAFS - Python bindings for AFS", author="Evan Broder", author_email="broder@mit.edu",