From 5acd7118334702b1db910f1fa382ecfd12a4c010 Mon Sep 17 00:00:00 2001 From: Alex Dehnert Date: Thu, 15 Dec 2011 20:06:14 -0500 Subject: [PATCH 01/10] Correct documention A group's membership is PTEntry.members, not PTEntry.users Signed-off-by: Alex Dehnert --- afs/pts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afs/pts.py b/afs/pts.py index e9f3c98..95c6d4a 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') From 11c564550ae1c27e01680698ef45503a201820ed Mon Sep 17 00:00:00 2001 From: Alex Dehnert Date: Fri, 16 Dec 2011 13:55:29 -0500 Subject: [PATCH 02/10] Notice libafsauthent_pic.a library in lib64 If available, we want to build against the _pic variant of the libafsauthent library. On Fedora, that's in lib64, not lib, so we need to pick it up there too. Signed-off-by: Alex Dehnert --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 378c7dc..8ffc684 100755 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ '%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 = '' From 34664fc9d0004b676b98c434b9b60cf93c2c8dca Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Fri, 19 Jul 2013 18:11:19 -0400 Subject: [PATCH 03/10] _pts: Remove unreachable return statements Fixes warning: afs/_pts.pyx:115:8: Unreachable code warning: afs/_pts.pyx:130:8: Unreachable code Signed-off-by: Anders Kaseorg --- afs/_pts.pyx | 2 -- 1 file changed, 2 deletions(-) diff --git a/afs/_pts.pyx b/afs/_pts.pyx index 3c10b70..0dd65ef 100644 --- a/afs/_pts.pyx +++ b/afs/_pts.pyx @@ -112,7 +112,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 +126,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 From af39e19de81b970bb335f7647fc81fd6ab455340 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Fri, 19 Jul 2013 18:15:40 -0400 Subject: [PATCH 04/10] _util: Remove extern from definitions that are not extern Fixes warning: afs/_util.pyx:15:5: Function 'pioctl_read' previously declared as 'private' warning: afs/_util.pyx:29:5: Function 'pioctl_write' previously declared as 'private' Signed-off-by: Anders Kaseorg --- afs/_util.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/afs/_util.pyx b/afs/_util.pyx index c80bcd6..b87eef0 100644 --- a/afs/_util.pyx +++ b/afs/_util.pyx @@ -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 From ab661405ea4c18a78c0b63979155a4b878fdcfd6 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Fri, 19 Jul 2013 18:30:39 -0400 Subject: [PATCH 05/10] PTS.__cinit__: Prevent use of uninitialized security object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, PTS.__cinit__ would leave sc uninitialized when passed an invalid negative sec argument. Fixes afs/_pts.c: In function ‘__pyx_pf_3afs_4_pts_3PTS___cinit__’: afs/_pts.c:2999:56: warning: ‘__pyx_v_sc’ may be used uninitialized in this function [-Wmaybe-uninitialized] (__pyx_v_serverconns[__pyx_v_i]) = rx_NewConnection((__pyx_v_info.hostAddr[__pyx_v_i]).sin_addr.s_addr, (__pyx_v_info.hostAddr[__pyx_v_i]).sin_port, PRSRV, __pyx_v_sc, __pyx_t_9); ^ Signed-off-by: Anders Kaseorg --- afs/_pts.pyx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/afs/_pts.pyx b/afs/_pts.pyx index 0dd65ef..b211b56 100644 --- a/afs/_pts.pyx +++ b/afs/_pts.pyx @@ -225,7 +225,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)) @@ -235,6 +237,7 @@ cdef class PTS: if sec >= 2: # No really - we wanted authentication pyafs_error(code) + sc = rxnull_NewClientSecurityObject() sec = 0 else: if sec == 3: @@ -244,11 +247,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: From 9fff3fda865c6fbd551565aa145ea9633d074028 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Fri, 13 Dec 2019 01:29:12 -0500 Subject: [PATCH 06/10] Use Python 3-compatible exceptions --- afs/acl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afs/acl.py b/afs/acl.py index 20a416f..1729442 100644 --- a/afs/acl.py +++ b/afs/acl.py @@ -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: From fcefc40148f9bc55c4c48afc07435304901bd12f Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Fri, 13 Dec 2019 12:19:50 -0500 Subject: [PATCH 07/10] Link against new AFS libraries --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8ffc684..6e890f4 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ 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): From d919aa2453da3441c5e04a42421ebf4c58b3695a Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Fri, 13 Dec 2019 12:20:25 -0500 Subject: [PATCH 08/10] Python 3-compatible string and path handling --- afs/_acl.pyx | 15 ++++++++------- afs/_fs.pyx | 23 ++++++++++++----------- afs/_pts.pyx | 1 + afs/_util.pyx | 7 ++++++- afs/acl.py | 2 +- afs/pts.py | 2 +- 6 files changed, 29 insertions(+), 21 deletions(-) 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 b211b56..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 diff --git a/afs/_util.pyx b/afs/_util.pyx index b87eef0..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 @@ -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 1729442..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), diff --git a/afs/pts.py b/afs/pts.py index 95c6d4a..eb69c77 100644 --- a/afs/pts.py +++ b/afs/pts.py @@ -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) From 6cb4e4d8206eca2d84f838c86a217c2622d27cd5 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Fri, 13 Dec 2019 12:22:36 -0500 Subject: [PATCH 09/10] Bump version number --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6e890f4..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']: @@ -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", From 300a92404859ed99a8d9db066b9526c363760e21 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Sun, 26 Jul 2020 23:50:23 -0400 Subject: [PATCH 10/10] Fix unit tests --- afs/tests/test__pts.py | 63 +++++++++++++++++++++++------------------- afs/tests/test_acl.py | 2 +- 2 files changed, 35 insertions(+), 30 deletions(-) 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