From a5f57ccec46dae2f5f539cbd87c0950688f49ada Mon Sep 17 00:00:00 2001 From: Iustin Pop <iusty@k1024.org> Date: Tue, 26 Feb 2008 20:48:11 +0100 Subject: [PATCH] Imported upstream version 0.2.2 --- BENCHMARK | 20 + ChangeLog | 108 ++++ IMPLEMENTATION | 36 ++ MANIFEST | 12 + PKG-INFO | 12 + PLATFORMS | 23 + README | 6 + acl.c | 1302 ++++++++++++++++++++++++++++++++++++++++++++++++ os_linux.c | 6 + posix1e.html | 414 +++++++++++++++ posix1e.txt | 443 ++++++++++++++++ setup.cfg | 4 + setup.py | 44 ++ 13 files changed, 2430 insertions(+) create mode 100644 BENCHMARK create mode 100644 ChangeLog create mode 100644 IMPLEMENTATION create mode 100644 MANIFEST create mode 100644 PKG-INFO create mode 100644 PLATFORMS create mode 100644 README create mode 100644 acl.c create mode 100644 os_linux.c create mode 100644 posix1e.html create mode 100644 posix1e.txt create mode 100644 setup.cfg create mode 100755 setup.py diff --git a/BENCHMARK b/BENCHMARK new file mode 100644 index 0000000..3c9cea1 --- /dev/null +++ b/BENCHMARK @@ -0,0 +1,20 @@ +On my Duron 1000, Linux 2.4, creating 1.000.000 ACLs and discarding them: + +empty ACL: 4.48user 0.03system 0:04.50elapsed 100%CPU +from text: 13.87user 0.09system 0:13.97elapsed 99%CPU +XFS, file: 14.17user 14.95system 0:29.13elapsed 99%CPU + +creating a list from the entries of an ACL: +no entries: 3.86user 0.01system 0:03.86elapsed 100%CPU +6 entries: 16.39user 0.00system 0:16.38elapsed 100%CPU + +As you can see, creating from file is the longest (as expected). More than +half time when creating from file was in kernel mode. + + +In freebsd 4.6, UNDER VMWARE!!!!, same machine: +empty ACL: 3.409u 0.432s 0:03.85 99.4% 516+15695k 0+0io 0pf+0w +from text: 10.672u 1.016s 0:11.71 99.7% 508+24230k 0+0io 0pf+0w + +Interesting results, it seems from text is faster here - but here +the library doens't support editing, so maybe that's why. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..35f2eb4 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,108 @@ +2006-12-03 11:15 Iustin Pop <iusty@k1024.org> + + * setup.py: Add support for building on GNU/kFreeBSD + +2004-04-27 20:27 Iustin Pop <iusty@k1024.org> + + * MANIFEST.in: Added ChangeLog to distribution + +2002-12-29 20:41 Iustin Pop <iusty@k1024.org> + + * BENCHMARK, MANIFEST.in, setup.py: Release 0.2.1 + +2002-12-29 06:48 Iustin Pop <iusty@k1024.org> + + * acl.c: Fixed compilation on LEVEL1 platform (broke since after + 0.1) + +2002-12-29 06:36 Iustin Pop <iusty@k1024.org> + + * BENCHMARK, acl.c: Added missing functionality (acl_calc_mask) and + some convenience functions. + +2002-12-27 21:55 Iustin Pop <iusty@k1024.org> + + * MANIFEST.in, setup.py: Small changes + +2002-12-27 19:47 Iustin Pop <iusty@k1024.org> + + * IMPLEMENTATION, acl.c: Prepare for release 0.2 + +2002-12-27 19:43 Iustin Pop <iusty@k1024.org> + + * Makefile: Small makefile + +2002-12-27 19:42 Iustin Pop <iusty@k1024.org> + + * MANIFEST.in: Distutils file + +2002-12-27 19:42 Iustin Pop <iusty@k1024.org> + + * os_linux.c: Linux-specific file + +2002-12-27 11:35 Iustin Pop <iusty@k1024.org> + + * PORTING: Informations for porting to other platforms. + +2002-12-26 09:21 Iustin Pop <iusty@k1024.org> + + * acl.c: Added the Permset type/object and some other naming + changes + +2002-12-26 06:48 Iustin Pop <iusty@k1024.org> + + * acl.c: Renamed type & object names from ACLType to ACL_Type and + so on. Also ACLEntry is now jus Entry. + +2002-12-26 06:43 Iustin Pop <iusty@k1024.org> + + * acl.c: Renamed some fields from ob_x to x, as per other modules + in python + +2002-12-26 06:41 Iustin Pop <iusty@k1024.org> + + * IMPLEMENTATION, acl.c: Added acl_entry_t type (named + ACLEntryType, respectively ACLEntryObject) + +2002-12-26 03:24 Iustin Pop <iusty@k1024.org> + + * acl.c: Documentation typo + +2002-12-24 15:35 Iustin Pop <iusty@k1024.org> + + * setup.cfg: Added setup.cfg, mainly for bdist_rpm + +2002-12-24 15:29 Iustin Pop <iusty@k1024.org> + + * setup.py: Don't call python2, only python + +2002-12-24 15:19 Iustin Pop <iusty@k1024.org> + + * acl.c, setup.py: Prepare for first public release + +2002-12-24 03:35 Iustin Pop <iusty@k1024.org> + + * PLATFORMS, acl.c, setup.py: Moved to real instance creation via + type() + +2002-12-23 21:05 Iustin Pop <iusty@k1024.org> + + * IMPLEMENTATION, PLATFORMS, README, acl.c, setup.py: Addedd + __setstate__ and some docs + +2002-12-23 16:55 Iustin Pop <iusty@k1024.org> + + * README, setup.py: Initial revision + +2002-12-23 16:55 Iustin Pop <iusty@k1024.org> + + * acl.c: Many functions added, started working on level 2 support + +2002-12-21 21:55 Iustin Pop <iusty@k1024.org> + + * acl.c: Initial revision + +2002-12-21 21:55 + + * branches, tags, .: New repository initialized by cvs2svn. + diff --git a/IMPLEMENTATION b/IMPLEMENTATION new file mode 100644 index 0000000..64ad4a5 --- /dev/null +++ b/IMPLEMENTATION @@ -0,0 +1,36 @@ +The IEEE 1003.1e draft 17 ("POSIX.1e") describes a set of 28 +functions. These are grouped into three groups, based on their +portability: + - first group, the most portable one. All systems which claim to + support POSIX.1e should implement these: + acl_delete_def_file(3), acl_dup(3), acl_free(3), acl_from_text(3), + acl_get_fd(3), acl_get_file(3), acl_init(3), acl_set_fd(3), + acl_set_file(3), acl_to_text(3), acl_valid(3) + + - second group, containing the rest of the POSIX ACL functions. Systems + which claim to fully implement POSIX.1e should implement these: + acl_add_perm(3), acl_calc_mask(3), acl_clear_perms(3), acl_copy_entry(3), + acl_copy_ext(3), acl_copy_int(3), acl_create_entry(3), + acl_delete_entry(3), acl_delete_perm(3), acl_get_entry(3), + acl_get_permset(3), acl_get_qualifier(3), acl_get_tag_type(3), + acl_set_permset(3), acl_set_qualifier(3), acl_set_tag_type(3), + acl_size(3) + + - third group, containing extra functions implemented by each OS. These + are non-portable version. Both Linux and FreeBSD implement some extra + function. + +Thus we have the level of compliance. Depending on whether the system +library support the second group, you get some extra methods for the +ACL object. + +Internal structure + The POSIX draft has the following stuff (correct me if I'm wrong): + - an ACL is denoted by acl_t + - an ACL contains many acl_entry_t, these are the individual entries + in the list; they always! belong to an acl_t + - each entry_t has a qualifier (think uid_t or gid_t), whose type is + denoted by the acl_tag_t type, and an acl_permset_t + - the acl_permset_t can contain acl_perm_t value (ACL_READ, ACL_WRITE, + ACL_EXECUTE, ACL_ADD, ACL_DELETE, ...) + - function to manipulate all these, and functions to manipulate files diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..6d339f4 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,12 @@ +BENCHMARK +ChangeLog +IMPLEMENTATION +MANIFEST +PLATFORMS +README +acl.c +os_linux.c +posix1e.html +posix1e.txt +setup.cfg +setup.py diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..1752799 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 1.0 +Name: pylibacl +Version: 0.2.2 +Summary: POSIX.1e ACLs for python +Home-page: http://pylibacl.sourceforge.net +Author: Iustin Pop +Author-email: iusty@k1024.org +License: GPL +Description: This is a C extension module for Python which + implements POSIX ACLs manipulation. It is a wrapper on top + of the systems's acl C library - see acl(5). +Platform: UNKNOWN diff --git a/PLATFORMS b/PLATFORMS new file mode 100644 index 0000000..ab2d28b --- /dev/null +++ b/PLATFORMS @@ -0,0 +1,23 @@ +The current supported platforms: + +Linux + + It needs kernel 2.4 or higher and the libacl library installed (with + development headers, if installing from rpm). The url is + http://acl.bestbits.at if using for ext2/ext3 and JFS, and + http://oss.sgi.com/projects/xfs/ if using for XFS. + + The level of compliance is level 2 (see IMPLEMENTATION). + + +FreeBSD + + The current tested version is 4.6. I hope to be able to test 5.0 after + it's released. + + The level of compliance is level 1. I hope that in FreeBSD 5 they will + improve. + + +For any other platform, volunteers are welcome. To add support, look +into setup.py at first and then into acl.c diff --git a/README b/README new file mode 100644 index 0000000..e17837d --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +This is an extension for Python which implements POSIX ACLs (POSIX.1e). + +To see the supported platforms, look at PLATFORMS. +To see internal details, look at IMPLEMENTATION. + +Iustin Pop, <iusty@k1024.org> diff --git a/acl.c b/acl.c new file mode 100644 index 0000000..e4248a6 --- /dev/null +++ b/acl.c @@ -0,0 +1,1302 @@ +#include <Python.h> + +#include <sys/types.h> +#include <sys/acl.h> + +#ifdef HAVE_LINUX +#include "os_linux.c" +#endif + +staticforward PyTypeObject ACL_Type; +static PyObject* ACL_applyto(PyObject* obj, PyObject* args); +static PyObject* ACL_valid(PyObject* obj, PyObject* args); + +#ifdef HAVE_LEVEL2 +static PyObject* ACL_get_state(PyObject *obj, PyObject* args); +static PyObject* ACL_set_state(PyObject *obj, PyObject* args); + +staticforward PyTypeObject Entry_Type; +staticforward PyTypeObject Permset_Type; +static PyObject* Permset_new(PyTypeObject* type, PyObject* args, PyObject *keywds); +#endif + +static acl_perm_t holder_ACL_EXECUTE = ACL_EXECUTE; +static acl_perm_t holder_ACL_READ = ACL_READ; +static acl_perm_t holder_ACL_WRITE = ACL_WRITE; + +typedef struct { + PyObject_HEAD + acl_t acl; +#ifdef HAVE_LEVEL2 + int entry_id; +#endif +} ACL_Object; + +#ifdef HAVE_LEVEL2 + +typedef struct { + PyObject_HEAD + PyObject *parent_acl; /* The parent acl, so it won't run out on us */ + acl_entry_t entry; +} Entry_Object; + +typedef struct { + PyObject_HEAD + PyObject *parent_entry; /* The parent entry, so it won't run out on us */ + acl_permset_t permset; +} Permset_Object; + +#endif + +/* Creation of a new ACL instance */ +static PyObject* ACL_new(PyTypeObject* type, PyObject* args, PyObject *keywds) { + PyObject* newacl; + + newacl = type->tp_alloc(type, 0); + + if(newacl != NULL) { + ((ACL_Object*)newacl)->acl = NULL; +#ifdef HAVEL_LEVEL2 + ((ACL_Object*)newacl)->entry_id = ACL_FIRST_ENTRY; +#endif + } + + return newacl; +} + +/* Initialization of a new ACL instance */ +static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) { + ACL_Object* self = (ACL_Object*) obj; + static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", NULL }; + char *file = NULL; + char *filedef = NULL; + char *text = NULL; + int fd = -1; + ACL_Object* thesrc = NULL; + + if(!PyTuple_Check(args) || PyTuple_Size(args) != 0 || + (keywds != NULL && PyDict_Check(keywds) && PyDict_Size(keywds) > 1)) { + PyErr_SetString(PyExc_ValueError, "a max of one keyword argument must be passed"); + return -1; + } + if(!PyArg_ParseTupleAndKeywords(args, keywds, "|sisO!s", kwlist, + &file, &fd, &text, &ACL_Type, &thesrc, &filedef)) + return -1; + + /* Free the old acl_t without checking for error, we don't + * care right now */ + if(self->acl != NULL) + acl_free(self->acl); + + if(file != NULL) + self->acl = acl_get_file(file, ACL_TYPE_ACCESS); + else if(text != NULL) + self->acl = acl_from_text(text); + else if(fd != -1) + self->acl = acl_get_fd(fd); + else if(thesrc != NULL) + self->acl = acl_dup(thesrc->acl); + else if(filedef != NULL) + self->acl = acl_get_file(filedef, ACL_TYPE_DEFAULT); + else + self->acl = acl_init(0); + + if(self->acl == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + return 0; +} + +/* Standard type functions */ +static void ACL_dealloc(PyObject* obj) { + ACL_Object *self = (ACL_Object*) obj; + PyObject *err_type, *err_value, *err_traceback; + int have_error = PyErr_Occurred() ? 1 : 0; + + if (have_error) + PyErr_Fetch(&err_type, &err_value, &err_traceback); + if(self->acl != NULL && acl_free(self->acl) != 0) + PyErr_WriteUnraisable(obj); + if (have_error) + PyErr_Restore(err_type, err_value, err_traceback); + PyObject_DEL(self); +} + +/* Converts the acl to a text format */ +static PyObject* ACL_str(PyObject *obj) { + char *text; + ACL_Object *self = (ACL_Object*) obj; + PyObject *ret; + + text = acl_to_text(self->acl, NULL); + if(text == NULL) { + return PyErr_SetFromErrno(PyExc_IOError); + } + ret = PyString_FromString(text); + if(acl_free(text) != 0) { + Py_DECREF(ret); + return PyErr_SetFromErrno(PyExc_IOError); + } + return ret; +} + +/* Custom methods */ +static char __applyto_doc__[] = \ +"Apply the ACL to a file or filehandle.\n" \ +"\n" \ +"Parameters:\n" \ +" - either a filename or a file-like object or an integer; this\n" \ +" represents the filesystem object on which to act\n" \ +" - optional flag representing the type of ACL to set, either\n" \ +" ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT\n" \ +; + +/* Applyes the ACL to a file */ +static PyObject* ACL_applyto(PyObject* obj, PyObject* args) { + ACL_Object *self = (ACL_Object*) obj; + PyObject *myarg; + acl_type_t type = ACL_TYPE_ACCESS; + int nret; + int fd; + + if (!PyArg_ParseTuple(args, "O|i", &myarg, &type)) + return NULL; + + if(PyString_Check(myarg)) { + char *filename = PyString_AS_STRING(myarg); + nret = acl_set_file(filename, type, self->acl); + } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) { + nret = acl_set_fd(fd, self->acl); + } else { + PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int, or file-like object"); + return 0; + } + if(nret == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +static char __valid_doc__[] = \ +"Test the ACL for validity.\n" \ +"\n" \ +"This method tests the ACL to see if it is a valid ACL\n" \ +"in terms of the filesystem. More precisely, it checks:\n" \ +"A valid ACL contains exactly one entry with each of the ACL_USER_OBJ,\n" \ +"ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and\n" \ +"ACL_GROUP tag types may appear zero or more times in an ACL. An ACL that\n" \ +"contains entries of ACL_USER or ACL_GROUP tag types must contain exactly\n" \ +"one entry of the ACL_MASK tag type. If an ACL contains no entries of\n" \ +"ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n" \ +"\n" \ +"All user ID qualifiers must be unique among all entries of ACL_USER tag\n" \ +"type, and all group IDs must be unique among all entries of ACL_GROUP tag\n" \ +"type.\n" \ +"\n" \ +"The method will return 1 for a valid ACL and 0 for an invalid one.\n" \ +"This has been chosen because the specification for acl_valid in POSIX.1e\n" \ +"documents only one possible value for errno in case of an invalid ACL, \n" \ +"so we can't differentiate between classes of errors. Other suggestions \n" \ +"are welcome.\n" \ +; + +/* Checks the ACL for validity */ +static PyObject* ACL_valid(PyObject* obj, PyObject* args) { + ACL_Object *self = (ACL_Object*) obj; + + if(acl_valid(self->acl) == -1) { + Py_INCREF(Py_False); + return Py_False; + } else { + Py_INCREF(Py_True); + return Py_True; + } +} + +#ifdef HAVE_LEVEL2 + +static PyObject* ACL_get_state(PyObject *obj, PyObject* args) { + ACL_Object *self = (ACL_Object*) obj; + PyObject *ret; + ssize_t size, nsize; + char *buf; + + size = acl_size(self->acl); + if(size == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + if((ret = PyString_FromStringAndSize(NULL, size)) == NULL) + return NULL; + buf = PyString_AsString(ret); + + if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) { + Py_DECREF(ret); + return PyErr_SetFromErrno(PyExc_IOError); + } + + return ret; +} + +static PyObject* ACL_set_state(PyObject *obj, PyObject* args) { + ACL_Object *self = (ACL_Object*) obj; + const void *buf; + int bufsize; + acl_t ptr; + + /* Parse the argument */ + if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize)) + return NULL; + + /* Try to import the external representation */ + if((ptr = acl_copy_int(buf)) == NULL) + return PyErr_SetFromErrno(PyExc_IOError); + + /* Free the old acl. Should we ignore errors here? */ + if(self->acl != NULL) { + if(acl_free(self->acl) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + } + + self->acl = ptr; + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +/* tp_iter for the ACL type; since it can be iterated only + * destructively, the type is its iterator + */ +static PyObject* ACL_iter(PyObject *obj) { + ACL_Object *self = (ACL_Object*)obj; + self->entry_id = ACL_FIRST_ENTRY; + Py_INCREF(obj); + return obj; +} + +/* the tp_iternext function for the ACL type */ +static PyObject* ACL_iternext(PyObject *obj) { + ACL_Object *self = (ACL_Object*)obj; + acl_entry_t the_entry_t; + Entry_Object *the_entry_obj; + int nerr; + + nerr = acl_get_entry(self->acl, self->entry_id, &the_entry_t); + self->entry_id = ACL_NEXT_ENTRY; + if(nerr == -1) + return PyErr_SetFromErrno(PyExc_IOError); + else if(nerr == 0) { + /* Docs says this is not needed */ + /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/ + return NULL; + } + + the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL); + if(the_entry_obj == NULL) + return NULL; + + the_entry_obj->entry = the_entry_t; + + the_entry_obj->parent_acl = obj; + Py_INCREF(obj); /* For the reference we have in entry->parent */ + + return (PyObject*)the_entry_obj; +} + +static char __ACL_delete_entry_doc__[] = \ +"Deletes an entry from the ACL.\n" \ +"\n" \ +"Note: Only with level 2\n" \ +"Parameters:\n" \ +" - the Entry object which should be deleted; note that after\n" \ +" this function is called, that object is unusable any longer\n" \ +" and should be deleted\n" \ +; + +/* Deletes an entry from the ACL */ +static PyObject* ACL_delete_entry(PyObject *obj, PyObject *args) { + ACL_Object *self = (ACL_Object*)obj; + Entry_Object *e; + + if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &e)) + return NULL; + + if(acl_delete_entry(self->acl, e->entry) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +static char __ACL_calc_mask_doc__[] = \ +"Compute the file group class mask.\n" \ +"\n" \ +"The calc_mask() method calculates and sets the permissions \n" \ +"associated with the ACL_MASK Entry of the ACL.\n" \ +"The value of the new permissions is the union of the permissions \n" \ +"granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or \n" \ +"ACL_USER. If the ACL already contains an ACL_MASK entry, its \n" \ +"permissions are overwritten; if it does not contain an ACL_MASK \n" \ +"Entry, one is added.\n" \ +"\n" \ +"The order of existing entries in the ACL is undefined after this \n" \ +"function.\n" \ +; + +/* Updates the mask entry in the ACL */ +static PyObject* ACL_calc_mask(PyObject *obj, PyObject *args) { + ACL_Object *self = (ACL_Object*)obj; + + if(acl_calc_mask(&self->acl) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +static char __ACL_append_doc__[] = \ +"Append a new Entry to the ACL and return it.\n" \ +"\n" \ +"This is a convenience function to create a new Entry \n" \ +"and append it to the ACL.\n" \ +"If a parameter of type Entry instance is given, the \n" \ +"entry will be a copy of that one (as if copied with \n" \ +"Entry.copy()), otherwise, the new entry will be empty.\n" \ +; + +/* Convenience method to create a new Entry */ +static PyObject* ACL_append(PyObject *obj, PyObject *args) { + ACL_Object* self = (ACL_Object*) obj; + Entry_Object* newentry; + Entry_Object* oldentry = NULL; + int nret; + + newentry = (Entry_Object*)PyType_GenericNew(&Entry_Type, NULL, NULL); + if(newentry == NULL) { + return NULL; + } + + if (!PyArg_ParseTuple(args, "|O!", &Entry_Type, &oldentry)) + return NULL; + + nret = acl_create_entry(&self->acl, &newentry->entry); + if(nret == -1) { + Py_DECREF(newentry); + return PyErr_SetFromErrno(PyExc_IOError); + } + + if(oldentry != NULL) { + nret = acl_copy_entry(newentry->entry, oldentry->entry); + if(nret == -1) { + Py_DECREF(newentry); + return PyErr_SetFromErrno(PyExc_IOError); + } + } + + newentry->parent_acl = obj; + Py_INCREF(obj); + + return (PyObject*)newentry; +} + +/***** Entry type *****/ + +/* Creation of a new Entry instance */ +static PyObject* Entry_new(PyTypeObject* type, PyObject* args, PyObject *keywds) { + PyObject* newentry; + + newentry = PyType_GenericNew(type, args, keywds); + + if(newentry != NULL) { + ((Entry_Object*)newentry)->entry = NULL; + ((Entry_Object*)newentry)->parent_acl = NULL; + } + + return newentry; +} + +/* Initialization of a new Entry instance */ +static int Entry_init(PyObject* obj, PyObject* args, PyObject *keywds) { + Entry_Object* self = (Entry_Object*) obj; + ACL_Object* parent = NULL; + + if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent)) + return -1; + + if(acl_create_entry(&parent->acl, &self->entry) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + self->parent_acl = (PyObject*)parent; + Py_INCREF(parent); + + return 0; +} + +/* Free the Entry instance */ +static void Entry_dealloc(PyObject* obj) { + Entry_Object *self = (Entry_Object*) obj; + PyObject *err_type, *err_value, *err_traceback; + int have_error = PyErr_Occurred() ? 1 : 0; + + if (have_error) + PyErr_Fetch(&err_type, &err_value, &err_traceback); + if(self->parent_acl != NULL) { + Py_DECREF(self->parent_acl); + self->parent_acl = NULL; + } + if (have_error) + PyErr_Restore(err_type, err_value, err_traceback); + PyObject_DEL(self); +} + +/* Converts the entry to a text format */ +static PyObject* Entry_str(PyObject *obj) { + acl_tag_t tag; + uid_t qualifier; + void *p; + PyObject *ret; + PyObject *format, *list; + Entry_Object *self = (Entry_Object*) obj; + + if(acl_get_tag_type(self->entry, &tag) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if(tag == ACL_USER || tag == ACL_GROUP) { + if((p = acl_get_qualifier(self->entry)) == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + qualifier = *(uid_t*)p; + acl_free(p); + } else { + qualifier = 0; + } + + format = PyString_FromString("ACL entry for %s"); + if(format == NULL) + return NULL; + list = PyTuple_New(1); + if(tag == ACL_UNDEFINED_TAG) { + PyTuple_SetItem(list, 0, PyString_FromString("undefined type")); + } else if(tag == ACL_USER_OBJ) { + PyTuple_SetItem(list, 0, PyString_FromString("the owner")); + } else if(tag == ACL_GROUP_OBJ) { + PyTuple_SetItem(list, 0, PyString_FromString("the group")); + } else if(tag == ACL_OTHER) { + PyTuple_SetItem(list, 0, PyString_FromString("the others")); + } else if(tag == ACL_USER) { + PyTuple_SetItem(list, 0, PyString_FromFormat("user with uid %d", qualifier)); + } else if(tag == ACL_GROUP) { + PyTuple_SetItem(list, 0, PyString_FromFormat("group with gid %d", qualifier)); + } else if(tag == ACL_MASK) { + PyTuple_SetItem(list, 0, PyString_FromString("the mask")); + } else { + PyTuple_SetItem(list, 0, PyString_FromString("UNKNOWN_TAG_TYPE!")); + } + ret = PyString_Format(format, list); + Py_DECREF(format); + Py_DECREF(list); + return ret; +} + +/* Sets the tag type of the entry */ +static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) { + Entry_Object *self = (Entry_Object*) obj; + + if(value == NULL) { + PyErr_SetString(PyExc_TypeError, + "tag type deletion is not supported"); + return -1; + } + + if(!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "tag type must be integer"); + return -1; + } + if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + return 0; +} + +/* Returns the tag type of the entry */ +static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) { + Entry_Object *self = (Entry_Object*) obj; + acl_tag_t value; + + if (self->entry == NULL) { + PyErr_SetString(PyExc_AttributeError, "entry attribute"); + return NULL; + } + if(acl_get_tag_type(self->entry, &value) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + return PyInt_FromLong(value); +} + +/* Sets the qualifier (either uid_t or gid_t) for the entry, + * usable only if the tag type if ACL_USER or ACL_GROUP + */ +static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) { + Entry_Object *self = (Entry_Object*) obj; + int uidgid; + + if(value == NULL) { + PyErr_SetString(PyExc_TypeError, + "qualifier deletion is not supported"); + return -1; + } + + if(!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "tag type must be integer"); + return -1; + } + uidgid = PyInt_AsLong(value); + if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + return 0; +} + +/* Returns the qualifier of the entry */ +static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) { + Entry_Object *self = (Entry_Object*) obj; + void *p; + int value; + + if (self->entry == NULL) { + PyErr_SetString(PyExc_AttributeError, "entry attribute"); + return NULL; + } + if((p = acl_get_qualifier(self->entry)) == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + value = *(uid_t*)p; + acl_free(p); + + return PyInt_FromLong(value); +} + +/* Returns the parent ACL of the entry */ +static PyObject* Entry_get_parent(PyObject *obj, void* arg) { + Entry_Object *self = (Entry_Object*) obj; + + Py_INCREF(self->parent_acl); + return self->parent_acl; +} + +/* Returns the a new Permset representing the permset of the entry + * FIXME: Should return a new reference to the same object, which + * should be created at init time! +*/ +static PyObject* Entry_get_permset(PyObject *obj, void* arg) { + Entry_Object *self = (Entry_Object*)obj; + PyObject *p; + Permset_Object *ps; + + p = Permset_new(&Permset_Type, NULL, NULL); + if(p == NULL) + return NULL; + ps = (Permset_Object*)p; + if(acl_get_permset(self->entry, &ps->permset) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + ps->parent_entry = obj; + Py_INCREF(obj); + + return (PyObject*)p; +} + +/* Sets the permset of the entry to the passed Permset */ +static int Entry_set_permset(PyObject* obj, PyObject* value, void* arg) { + Entry_Object *self = (Entry_Object*)obj; + Permset_Object *p; + + if(!PyObject_IsInstance(value, (PyObject*)&Permset_Type)) { + PyErr_SetString(PyExc_TypeError, "argument 1 must be posix1e.Permset"); + return -1; + } + p = (Permset_Object*)value; + if(acl_set_permset(self->entry, p->permset) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + return 0; +} + +static char __Entry_copy_doc__[] = \ +"Copy an ACL entry.\n" \ +"\n" \ +"This method sets all the parameters to those of another\n" \ +"entry, even one of another's ACL\n" \ +"Parameters:\n" \ +" - src, instance of type Entry\n" \ +; + +/* Sets all the entry parameters to another's entry */ +static PyObject* Entry_copy(PyObject *obj, PyObject *args) { + Entry_Object *self = (Entry_Object*)obj; + Entry_Object *other; + + if(!PyArg_ParseTuple(args, "O!", &Entry_Type, &other)) + return NULL; + + if(acl_copy_entry(self->entry, other->entry) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +/**** Permset type *****/ + +/* Creation of a new Permset instance */ +static PyObject* Permset_new(PyTypeObject* type, PyObject* args, PyObject *keywds) { + PyObject* newpermset; + + newpermset = PyType_GenericNew(type, args, keywds); + + if(newpermset != NULL) { + ((Permset_Object*)newpermset)->permset = NULL; + ((Permset_Object*)newpermset)->parent_entry = NULL; + } + + return newpermset; +} + +/* Initialization of a new Permset instance */ +static int Permset_init(PyObject* obj, PyObject* args, PyObject *keywds) { + Permset_Object* self = (Permset_Object*) obj; + Entry_Object* parent = NULL; + + if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent)) + return -1; + + if(acl_get_permset(parent->entry, &self->permset) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + self->parent_entry = (PyObject*)parent; + Py_INCREF(parent); + + return 0; +} + +/* Free the Permset instance */ +static void Permset_dealloc(PyObject* obj) { + Permset_Object *self = (Permset_Object*) obj; + PyObject *err_type, *err_value, *err_traceback; + int have_error = PyErr_Occurred() ? 1 : 0; + + if (have_error) + PyErr_Fetch(&err_type, &err_value, &err_traceback); + if(self->parent_entry != NULL) { + Py_DECREF(self->parent_entry); + self->parent_entry = NULL; + } + if (have_error) + PyErr_Restore(err_type, err_value, err_traceback); + PyObject_DEL(self); +} + +/* Permset string representation */ +static PyObject* Permset_str(PyObject *obj) { + Permset_Object *self = (Permset_Object*) obj; + char pstr[3]; + + pstr[0] = get_perm(self->permset, ACL_READ) ? 'r' : '-'; + pstr[1] = get_perm(self->permset, ACL_WRITE) ? 'w' : '-'; + pstr[2] = get_perm(self->permset, ACL_EXECUTE) ? 'x' : '-'; + return PyString_FromStringAndSize(pstr, 3); +} + +static char __Permset_clear_doc__[] = \ +"Clear all permissions from the permission set.\n" \ +; + +/* Clears all permissions from the permset */ +static PyObject* Permset_clear(PyObject* obj, PyObject* args) { + Permset_Object *self = (Permset_Object*) obj; + + if(acl_clear_perms(self->permset) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* Permset_get_right(PyObject *obj, void* arg) { + Permset_Object *self = (Permset_Object*) obj; + + if(get_perm(self->permset, *(acl_perm_t*)arg)) { + Py_INCREF(Py_True); + return Py_True; + } else { + Py_INCREF(Py_False); + return Py_False; + } +} + +static int Permset_set_right(PyObject* obj, PyObject* value, void* arg) { + Permset_Object *self = (Permset_Object*) obj; + int on; + int nerr; + + if(!PyInt_Check(value)) { + PyErr_SetString(PyExc_ValueError, "a maximum of one argument must be passed"); + return -1; + } + on = PyInt_AsLong(value); + if(on) + nerr = acl_add_perm(self->permset, *(acl_perm_t*)arg); + else + nerr = acl_delete_perm(self->permset, *(acl_perm_t*)arg); + if(nerr == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + return 0; +} + +static char __Permset_add_doc__[] = \ +"Add a permission to the permission set.\n" \ +"\n" \ +"The add() function adds the permission contained in \n" \ +"the argument perm to the permission set. An attempt \n" \ +"to add a permission that is already contained in the \n" \ +"permission set is not considered an error.\n" \ +"Parameters:\n" \ +" - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" \ +"Return value:\n" \ +" None\n" \ +"Can raise: IOError\n" \ +; + +static PyObject* Permset_add(PyObject* obj, PyObject* args) { + Permset_Object *self = (Permset_Object*) obj; + int right; + + if (!PyArg_ParseTuple(args, "i", &right)) + return NULL; + + if(acl_add_perm(self->permset, (acl_perm_t) right) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +static char __Permset_delete_doc__[] = \ +"Delete a permission from the permission set.\n" \ +"\n" \ +"The delete() function deletes the permission contained in \n" \ +"the argument perm from the permission set. An attempt \n" \ +"to delete a permission that is not contained in the \n" \ +"permission set is not considered an error.\n" \ +"Parameters:\n" \ +" - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" \ +"Return value:\n" \ +" None\n" \ +"Can raise: IOError\n" \ +; + +static PyObject* Permset_delete(PyObject* obj, PyObject* args) { + Permset_Object *self = (Permset_Object*) obj; + int right; + + if (!PyArg_ParseTuple(args, "i", &right)) + return NULL; + + if(acl_delete_perm(self->permset, (acl_perm_t) right) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +static char __Permset_test_doc__[] = \ +"Test if a permission exists in the permission set.\n" \ +"\n" \ +"The test() function tests if the permission contained in \n" \ +"the argument perm exits the permission set.\n" \ +"Parameters:\n" \ +" - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" \ +"Return value:\n" \ +" Bool\n" \ +"Can raise: IOError\n" \ +; + +static PyObject* Permset_test(PyObject* obj, PyObject* args) { + Permset_Object *self = (Permset_Object*) obj; + int right; + int ret; + + if (!PyArg_ParseTuple(args, "i", &right)) + return NULL; + + ret = get_perm(self->permset, (acl_perm_t) right); + if(ret == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + if(ret) { + Py_INCREF(Py_True); + return Py_True; + } else { + Py_INCREF(Py_False); + return Py_False; + } +} + +#endif + +static char __ACL_Type_doc__[] = \ +"Type which represents a POSIX ACL\n" \ +"\n" \ +"Parameters:\n" \ +" Only one keword parameter should be provided:\n" +" - file=\"...\", meaning create ACL representing\n" +" the access ACL of that file\n" \ +" - filedef=\"...\", meaning create ACL representing\n" +" the default ACL of that directory\n" \ +" - fd=<int>, meaning create ACL representing\n" \ +" the access ACL of that file descriptor\n" \ +" - text=\"...\", meaning create ACL from a \n" \ +" textual description\n" \ +" - acl=<ACL instance>, meaning create a copy\n" \ +" of an existing ACL instance\n" \ +"If no parameters are passed, create an empty ACL; this\n" \ +"makes sense only when your OS supports ACL modification\n" \ +" (i.e. it implements full POSIX.1e support)\n" \ +; + +/* ACL type methods */ +static PyMethodDef ACL_methods[] = { + {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__}, + {"valid", ACL_valid, METH_NOARGS, __valid_doc__}, +#ifdef HAVE_LEVEL2 + {"__getstate__", ACL_get_state, METH_NOARGS, "Dumps the ACL to an external format."}, + {"__setstate__", ACL_set_state, METH_VARARGS, "Loads the ACL from an external format."}, + {"delete_entry", ACL_delete_entry, METH_VARARGS, __ACL_delete_entry_doc__}, + {"calc_mask", ACL_calc_mask, METH_NOARGS, __ACL_calc_mask_doc__}, + {"append", ACL_append, METH_VARARGS, __ACL_append_doc__}, +#endif + {NULL, NULL, 0, NULL} +}; + + +/* The definition of the ACL Type */ +static PyTypeObject ACL_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "posix1e.ACL", + sizeof(ACL_Object), + 0, + ACL_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + ACL_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + __ACL_Type_doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#ifdef HAVE_LEVEL2 + ACL_iter, + ACL_iternext, +#else + 0, /* tp_iter */ + 0, /* tp_iternext */ +#endif + ACL_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + ACL_init, /* tp_init */ + 0, /* tp_alloc */ + ACL_new, /* tp_new */ +}; + +#ifdef HAVE_LEVEL2 + +/* Entry type methods */ +static PyMethodDef Entry_methods[] = { + {"copy", Entry_copy, METH_VARARGS, __Entry_copy_doc__}, + {NULL, NULL, 0, NULL} +}; + +static char __Entry_tagtype_doc__[] = \ +"The tag type of the current entry\n" \ +"\n" \ +"This is one of:\n" \ +" - ACL_UNDEFINED_TAG\n" \ +" - ACL_USER_OBJ\n" \ +" - ACL_USER\n" \ +" - ACL_GROUP_OBJ\n" \ +" - ACL_GROUP\n" \ +" - ACL_MASK\n" \ +" - ACL_OTHER\n" \ +; + +static char __Entry_qualifier_doc__[] = \ +"The qualifier of the current entry\n" \ +"\n" \ +"If the tag type is ACL_USER, this should be a user id.\n" \ +"If the tag type if ACL_GROUP, this should be a group id.\n" \ +"Else, it doesn't matter.\n" \ +; + +static char __Entry_parent_doc__[] = \ +"The parent ACL of this entry\n" \ +; + +static char __Entry_permset_doc__[] = \ +"The permission set of this ACL entry\n" \ +; + +/* Entry getset */ +static PyGetSetDef Entry_getsets[] = { + {"tag_type", Entry_get_tag_type, Entry_set_tag_type, __Entry_tagtype_doc__}, + {"qualifier", Entry_get_qualifier, Entry_set_qualifier, __Entry_qualifier_doc__}, + {"parent", Entry_get_parent, NULL, __Entry_parent_doc__}, + {"permset", Entry_get_permset, Entry_set_permset, __Entry_permset_doc__}, + {NULL} +}; + +static char __Entry_Type_doc__[] = \ +"Type which represents an entry in an ACL.\n" \ +"\n" \ +"The type exists only if the OS has full support for POSIX.1e\n" \ +"Can be created either by:\n" \ +" e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n" \ +"or by:\n" \ +" for entry in myACL:\n" \ +" print entry\n" \ +"\n" \ +"Note that the Entry keeps a reference to its ACL, so even if \n" \ +"you delete the ACL, it won't be cleaned up and will continue to \n" \ +"exist until its Entry(ies) will be deleted.\n" \ +; +/* The definition of the Entry Type */ +static PyTypeObject Entry_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "posix1e.Entry", + sizeof(Entry_Object), + 0, + Entry_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + Entry_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + __Entry_Type_doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Entry_methods, /* tp_methods */ + 0, /* tp_members */ + Entry_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + Entry_init, /* tp_init */ + 0, /* tp_alloc */ + Entry_new, /* tp_new */ +}; + +/* Permset type methods */ +static PyMethodDef Permset_methods[] = { + {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, }, + {"add", Permset_add, METH_VARARGS, __Permset_add_doc__, }, + {"delete", Permset_delete, METH_VARARGS, __Permset_delete_doc__, }, + {"test", Permset_test, METH_VARARGS, __Permset_test_doc__, }, + {NULL, NULL, 0, NULL} +}; + +static char __Permset_execute_doc__[] = \ +"Execute permsission\n" \ +"\n" \ +"This is a convenience method of access; the \n" \ +"same effect can be achieved using the functions\n" \ +"add(), test(), delete(), and those can take any \n" \ +"permission defined by your platform.\n" \ +; + +static char __Permset_read_doc__[] = \ +"Read permsission\n" \ +"\n" \ +"This is a convenience method of access; the \n" \ +"same effect can be achieved using the functions\n" \ +"add(), test(), delete(), and those can take any \n" \ +"permission defined by your platform.\n" \ +; + +static char __Permset_write_doc__[] = \ +"Write permsission\n" \ +"\n" \ +"This is a convenience method of access; the \n" \ +"same effect can be achieved using the functions\n" \ +"add(), test(), delete(), and those can take any \n" \ +"permission defined by your platform.\n" \ +; + +/* Permset getset */ +static PyGetSetDef Permset_getsets[] = { + {"execute", Permset_get_right, Permset_set_right, \ + __Permset_execute_doc__, &holder_ACL_EXECUTE}, + {"read", Permset_get_right, Permset_set_right, \ + __Permset_read_doc__, &holder_ACL_READ}, + {"write", Permset_get_right, Permset_set_right, \ + __Permset_write_doc__, &holder_ACL_WRITE}, + {NULL} +}; + +static char __Permset_Type_doc__[] = \ +"Type which represents the permission set in an ACL entry\n" \ +"\n" \ +"The type exists only if the OS has full support for POSIX.1e\n" \ +"Can be created either by:\n" \ +" perms = myEntry.permset\n" \ +"or by:\n" \ +" perms = posix1e.Permset(myEntry)\n" \ +"\n" \ +"Note that the Permset keeps a reference to its Entry, so even if \n" \ +"you delete the entry, it won't be cleaned up and will continue to \n" \ +"exist until its Permset will be deleted.\n" \ +; + +/* The definition of the Permset Type */ +static PyTypeObject Permset_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "posix1e.Permset", + sizeof(Permset_Object), + 0, + Permset_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + Permset_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + __Permset_Type_doc__,/* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Permset_methods, /* tp_methods */ + 0, /* tp_members */ + Permset_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + Permset_init, /* tp_init */ + 0, /* tp_alloc */ + Permset_new, /* tp_new */ +}; + +#endif + +/* Module methods */ + +static char __deletedef_doc__[] = \ +"Delete the default ACL from a directory.\n" \ +"\n" \ +"This function deletes the default ACL associated with \n" \ +"a directory (the ACL which will be ANDed with the mode\n" \ +"parameter to the open, creat functions).\n" \ +"Parameters:\n" \ +" - a string representing the directory whose default ACL\n" \ +" should be deleted\n" \ +; + +/* Deletes the default ACL from a directory */ +static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) { + char *filename; + + /* Parse the arguments */ + if (!PyArg_ParseTuple(args, "s", &filename)) + return NULL; + + if(acl_delete_def_file(filename) == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } + + /* Return the result */ + Py_INCREF(Py_None); + return Py_None; +} + +/* The module methods */ +static PyMethodDef aclmodule_methods[] = { + {"delete_default", aclmodule_delete_default, METH_VARARGS, __deletedef_doc__}, + {NULL, NULL, 0, NULL} +}; + +static char __posix1e_doc__[] = \ +"POSIX.1e ACLs manipulation\n" \ +"\n" \ +"This module provides support for manipulating POSIX.1e ACLS\n" \ +"\n" \ +"Depending on the operating system support for POSIX.1e, \n" \ +"the ACL type will have more or less capabilities:\n" \ +" - level 1, only basic support, you can create\n" \ +" ACLs from files and text descriptions;\n" \ +" once created, the type is immutable\n" \ +" - level 2, complete support, you can alter\n"\ +" the ACL once it is created\n" \ +"\n" \ +"Also, in level 2, more types are available, corresponding\n" \ +"to acl_entry_t (Entry type), acl_permset_t (Permset type).\n" \ +"\n" \ +"Example:\n" \ +">>> import posix1e\n" \ +">>> acl1 = posix1e.ACL(file=\"file.txt\") \n" \ +">>> print acl1\n" \ +"user::rw-\n" \ +"group::rw-\n" \ +"other::r--\n" \ +"\n" \ +">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n" \ +">>> print b\n" \ +"user::r-x\n" \ +"group::---\n" \ +"other::---\n" \ +"\n" \ +">>> b.applyto(\"file.txt\")\n" \ +">>> print posix1e.ACL(file=\"file.txt\")\n" \ +"user::r-x\n" \ +"group::---\n" \ +"other::---\n" \ +"\n" \ +">>>\n" \ +; + +void initposix1e(void) { + PyObject *m, *d; + + ACL_Type.ob_type = &PyType_Type; + if(PyType_Ready(&ACL_Type) < 0) + return; + +#ifdef HAVE_LEVEL2 + Entry_Type.ob_type = &PyType_Type; + if(PyType_Ready(&Entry_Type) < 0) + return; + + Permset_Type.ob_type = &PyType_Type; + if(PyType_Ready(&Permset_Type) < 0) + return; +#endif + + m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__); + + d = PyModule_GetDict(m); + if (d == NULL) + return; + + Py_INCREF(&ACL_Type); + if (PyDict_SetItemString(d, "ACL", + (PyObject *) &ACL_Type) < 0) + return; + + /* 23.3.6 acl_type_t values */ + PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS); + PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT); + + +#ifdef HAVE_LEVEL2 + Py_INCREF(&Entry_Type); + if (PyDict_SetItemString(d, "Entry", + (PyObject *) &Entry_Type) < 0) + return; + + Py_INCREF(&Permset_Type); + if (PyDict_SetItemString(d, "Permset", + (PyObject *) &Permset_Type) < 0) + return; + + /* 23.2.2 acl_perm_t values */ + PyModule_AddIntConstant(m, "ACL_READ", ACL_READ); + PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE); + PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE); + + /* 23.2.5 acl_tag_t values */ + PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG); + PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ); + PyModule_AddIntConstant(m, "ACL_USER", ACL_USER); + PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ); + PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP); + PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK); + PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER); + +#endif +} diff --git a/os_linux.c b/os_linux.c new file mode 100644 index 0000000..1fb7203 --- /dev/null +++ b/os_linux.c @@ -0,0 +1,6 @@ +#include <acl/libacl.h> + +int get_perm(acl_permset_t permset, acl_perm_t perm) +{ + return acl_get_perm(permset, perm); +} diff --git a/posix1e.html b/posix1e.html new file mode 100644 index 0000000..9b488ff --- /dev/null +++ b/posix1e.html @@ -0,0 +1,414 @@ + +<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html><head><title>Python: module posix1e</title> +<style type="text/css"><!-- +TT { font-family: lucidatypewriter, lucida console, courier } +--></style></head><body bgcolor="#f0f0f8"> + +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading"> +<tr bgcolor="#7799ee"> +<td valign=bottom> <br> +<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>posix1e</strong></big></big></font></td +><td align=right valign=bottom +><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/iusty/work/pylibacl/build/lib.linux-i686-2.2/posix1e.so">/home/iusty/work/pylibacl/build/lib.linux-i686-2.2/posix1e.so</a></font></td></tr></table> + <p><tt>POSIX.1e ACLs manipulation<br> + <br> +This module provides support for manipulating POSIX.1e ACLS<br> + <br> +Depending on the operating system support for POSIX.1e, <br> +the <a href="#ACL">ACL</a> type will have more or less capabilities:<br> + - level 1, only basic support, you can create<br> + ACLs from files and text descriptions;<br> + once created, the type is immutable<br> + - level 2, complete support, you can alter<br> + the <a href="#ACL">ACL</a> once it is created<br> + <br> +Also, in level 2, more types are available, corresponding<br> +to acl_entry_t (<a href="#Entry">Entry</a> type), acl_permset_t (<a href="#Permset">Permset</a> type).<br> + <br> +Example:<br> +>>> import posix1e<br> +>>> acl1 = posix1e.<a href="#ACL">ACL</a>(file="file.txt") <br> +>>> print acl1<br> +user::rw-<br> +group::rw-<br> +other::r--<br> + <br> +>>> b = posix1e.<a href="#ACL">ACL</a>(text="u::rx,g::-,o::-")<br> +>>> print b<br> +user::r-x<br> +group::---<br> +other::---<br> + <br> +>>> b.applyto("file.txt")<br> +>>> print posix1e.<a href="#ACL">ACL</a>(file="file.txt")<br> +user::r-x<br> +group::---<br> +other::---<br> + <br> +>>></tt></p> + +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> +<tr bgcolor="#ee77aa"> +<td colspan=3 valign=bottom> <br> +<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr> + +<tr><td bgcolor="#ee77aa"><tt> </tt></td><td> </td> +<td width="100%"><dl> +<dt><font face="helvetica, arial"><a href="__builtin__.html#object">__builtin__.object</a> +</font></dt><dd> +<dl> +<dt><font face="helvetica, arial"><a href="posix1e.html#ACL">ACL</a> +</font></dt><dt><font face="helvetica, arial"><a href="posix1e.html#Entry">Entry</a> +</font></dt><dt><font face="helvetica, arial"><a href="posix1e.html#Permset">Permset</a> +</font></dt></dl> +</dd> +</dl> + +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> +<tr bgcolor="#ffc8d8"> +<td colspan=3 valign=bottom> <br> +<font color="#000000" face="helvetica, arial"><a name="ACL">class <strong>ACL</strong></a>(<a href="__builtin__.html#object">__builtin__.object</a>)</font></td></tr> + +<tr bgcolor="#ffc8d8"><td rowspan=2><tt> </tt></td> +<td colspan=2><tt>Type which represents a POSIX <a href="#ACL">ACL</a><br> + <br> +Parameters:<br> + Only one keword parameter should be provided:<br> + - file="...", meaning create <a href="#ACL">ACL</a> representing<br> + the access <a href="#ACL">ACL</a> of that file<br> + - filedef="...", meaning create <a href="#ACL">ACL</a> representing<br> + the default <a href="#ACL">ACL</a> of that directory<br> + - fd=<int>, meaning create <a href="#ACL">ACL</a> representing<br> + the access <a href="#ACL">ACL</a> of that file descriptor<br> + - text="...", meaning create <a href="#ACL">ACL</a> from a <br> + textual description<br> + - acl=<<a href="#ACL">ACL</a> instance>, meaning create a copy<br> + of an existing <a href="#ACL">ACL</a> instance<br> +If no parameters are passed, create an empty <a href="#ACL">ACL</a>; this<br> +makes sense only when your OS supports <a href="#ACL">ACL</a> modification<br> + (i.e. it implements full POSIX.1e support)<br> </tt></td></tr> +<tr><td> </td> +<td width="100%">Methods defined here:<br> +<dl><dt><a name="ACL-__getstate__"><strong>__getstate__</strong></a>(...)</dt><dd><tt>Dumps the <a href="#ACL">ACL</a> to an external format.</tt></dd></dl> + +<dl><dt><a name="ACL-__init__"><strong>__init__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__init__">__init__</a>(...) initializes x; see x.__class__.__doc__ for signature</tt></dd></dl> + +<dl><dt><a name="ACL-__iter__"><strong>__iter__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__iter__">__iter__</a>() <==> iter(x)</tt></dd></dl> + +<dl><dt><a name="ACL-__setstate__"><strong>__setstate__</strong></a>(...)</dt><dd><tt>Loads the <a href="#ACL">ACL</a> from an external format.</tt></dd></dl> + +<dl><dt><a name="ACL-__str__"><strong>__str__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__str__">__str__</a>() <==> str(x)</tt></dd></dl> + +<dl><dt><a name="ACL-append"><strong>append</strong></a>(...)</dt><dd><tt>Append a new <a href="#Entry">Entry</a> to the <a href="#ACL">ACL</a> and return it.<br> + <br> +This is a convenience function to create a new <a href="#Entry">Entry</a> <br> +and append it to the <a href="#ACL">ACL</a>.<br> +If a parameter of type <a href="#Entry">Entry</a> instance is given, the <br> +entry will be a copy of that one (as if copied with <br> +<a href="#Entry">Entry</a>.copy()), otherwise, the new entry will be empty.</tt></dd></dl> + +<dl><dt><a name="ACL-applyto"><strong>applyto</strong></a>(...)</dt><dd><tt>Apply the <a href="#ACL">ACL</a> to a file or filehandle.<br> + <br> +Parameters:<br> + - either a filename or a file-like <a href="__builtin__.html#object">object</a> or an integer; this<br> + represents the filesystem <a href="__builtin__.html#object">object</a> on which to act<br> + - optional flag representing the type of <a href="#ACL">ACL</a> to set, either<br> + ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT</tt></dd></dl> + +<dl><dt><a name="ACL-calc_mask"><strong>calc_mask</strong></a>(...)</dt><dd><tt>Compute the file group class mask.<br> + <br> +The <a href="#ACL-calc_mask">calc_mask</a>() method calculates and sets the permissions <br> +associated with the ACL_MASK <a href="#Entry">Entry</a> of the <a href="#ACL">ACL</a>.<br> +The value of the new permissions is the union of the permissions <br> +granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or <br> +ACL_USER. If the <a href="#ACL">ACL</a> already contains an ACL_MASK entry, its <br> +permissions are overwritten; if it does not contain an ACL_MASK <br> +<a href="#Entry">Entry</a>, one is added.<br> + <br> +The order of existing entries in the <a href="#ACL">ACL</a> is undefined after this <br> +function.</tt></dd></dl> + +<dl><dt><a name="ACL-delete_entry"><strong>delete_entry</strong></a>(...)</dt><dd><tt>Deletes an entry from the <a href="#ACL">ACL</a>.<br> + <br> +Note: Only with level 2<br> +Parameters:<br> + - the <a href="#Entry">Entry</a> <a href="__builtin__.html#object">object</a> which should be deleted; note that after<br> + this function is called, that <a href="__builtin__.html#object">object</a> is unusable any longer<br> + and should be deleted</tt></dd></dl> + +<dl><dt><a name="ACL-next"><strong>next</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-next">next</a>() -> the next value, or raise StopIteration</tt></dd></dl> + +<dl><dt><a name="ACL-valid"><strong>valid</strong></a>(...)</dt><dd><tt>Test the <a href="#ACL">ACL</a> for validity.<br> + <br> +This method tests the <a href="#ACL">ACL</a> to see if it is a valid <a href="#ACL">ACL</a><br> +in terms of the filesystem. More precisely, it checks:<br> +A valid <a href="#ACL">ACL</a> contains exactly one entry with each of the ACL_USER_OBJ,<br> +ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and<br> +ACL_GROUP tag types may appear zero or more times in an <a href="#ACL">ACL</a>. An <a href="#ACL">ACL</a> that<br> +contains entries of ACL_USER or ACL_GROUP tag types must contain exactly<br> +one entry of the ACL_MASK tag type. If an <a href="#ACL">ACL</a> contains no entries of<br> +ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.<br> + <br> +All user ID qualifiers must be unique among all entries of ACL_USER tag<br> +type, and all group IDs must be unique among all entries of ACL_GROUP tag<br> +type.<br> + <br> +The method will return 1 for a valid <a href="#ACL">ACL</a> and 0 for an invalid one.<br> +This has been chosen because the specification for acl_valid in POSIX.1e<br> +documents only one possible value for errno in case of an invalid <a href="#ACL">ACL</a>, <br> +so we can't differentiate between classes of errors. Other suggestions <br> +are welcome.</tt></dd></dl> + +<hr> +Data and non-method functions defined here:<br> +<dl><dt><strong>__doc__</strong> = 'Type which represents a POSIX ACL<font color="#c040c0">\n\n</font>Parameters:<font color="#c040c0">\n</font> ...tion<font color="#c040c0">\n</font> (i.e. it implements full POSIX.1e support)<font color="#c040c0">\n</font>'<dd><tt>str(<a href="__builtin__.html#object">object</a>) -> string<br> + <br> +Return a nice string representation of the <a href="__builtin__.html#object">object</a>.<br> +If the argument is a string, the return value is the same <a href="__builtin__.html#object">object</a>.</tt></dl> + +<dl><dt><strong>__new__</strong> = <built-in method __new__ of type object><dd><tt>T.<a href="#ACL-__new__">__new__</a>(S, ...) -> a new <a href="__builtin__.html#object">object</a> with type S, a subtype of T</tt></dl> + +<hr> +Methods inherited from <a href="__builtin__.html#object">__builtin__.object</a>:<br> +<dl><dt><a name="ACL-__delattr__"><strong>__delattr__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__delattr__">__delattr__</a>('name') <==> del x.name</tt></dd></dl> + +<dl><dt><a name="ACL-__getattribute__"><strong>__getattribute__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__getattribute__">__getattribute__</a>('name') <==> x.name</tt></dd></dl> + +<dl><dt><a name="ACL-__hash__"><strong>__hash__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__hash__">__hash__</a>() <==> hash(x)</tt></dd></dl> + +<dl><dt><a name="ACL-__reduce__"><strong>__reduce__</strong></a>(...)</dt><dd><tt>helper for pickle</tt></dd></dl> + +<dl><dt><a name="ACL-__repr__"><strong>__repr__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__repr__">__repr__</a>() <==> repr(x)</tt></dd></dl> + +<dl><dt><a name="ACL-__setattr__"><strong>__setattr__</strong></a>(...)</dt><dd><tt>x.<a href="#ACL-__setattr__">__setattr__</a>('name', value) <==> x.name = value</tt></dd></dl> + +<hr> +Data and non-method functions inherited from <a href="__builtin__.html#object">__builtin__.object</a>:<br> +<dl><dt><strong>__class__</strong> = <type 'type'><dd><tt>the <a href="__builtin__.html#object">object</a>'s class</tt></dl> + +</td></tr></table> +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> +<tr bgcolor="#ffc8d8"> +<td colspan=3 valign=bottom> <br> +<font color="#000000" face="helvetica, arial"><a name="Entry">class <strong>Entry</strong></a>(<a href="__builtin__.html#object">__builtin__.object</a>)</font></td></tr> + +<tr bgcolor="#ffc8d8"><td rowspan=2><tt> </tt></td> +<td colspan=2><tt>Type which represents an entry in an <a href="#ACL">ACL</a>.<br> + <br> +The type exists only if the OS has full support for POSIX.1e<br> +Can be created either by:<br> + e = posix1e.<a href="#Entry">Entry</a>(myACL) # this creates a new entry in the <a href="#ACL">ACL</a><br> +or by:<br> + for entry in myACL:<br> + print entry<br> + <br> +Note that the <a href="#Entry">Entry</a> keeps a reference to its <a href="#ACL">ACL</a>, so even if <br> +you delete the <a href="#ACL">ACL</a>, it won't be cleaned up and will continue to <br> +exist until its <a href="#Entry">Entry</a>(ies) will be deleted.<br> </tt></td></tr> +<tr><td> </td> +<td width="100%">Methods defined here:<br> +<dl><dt><a name="Entry-__init__"><strong>__init__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__init__">__init__</a>(...) initializes x; see x.__class__.__doc__ for signature</tt></dd></dl> + +<dl><dt><a name="Entry-__str__"><strong>__str__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__str__">__str__</a>() <==> str(x)</tt></dd></dl> + +<dl><dt><a name="Entry-copy"><strong>copy</strong></a>(...)</dt><dd><tt>Copy an <a href="#ACL">ACL</a> entry.<br> + <br> +This method sets all the parameters to those of another<br> +entry, even one of another's <a href="#ACL">ACL</a><br> +Parameters:<br> + - src, instance of type <a href="#Entry">Entry</a></tt></dd></dl> + +<hr> +Data and non-method functions defined here:<br> +<dl><dt><strong>__doc__</strong> = 'Type which represents an entry in an ACL.<font color="#c040c0">\n\n</font>The t... to <font color="#c040c0">\n</font>exist until its Entry(ies) will be deleted.<font color="#c040c0">\n</font>'<dd><tt>str(<a href="__builtin__.html#object">object</a>) -> string<br> + <br> +Return a nice string representation of the <a href="__builtin__.html#object">object</a>.<br> +If the argument is a string, the return value is the same <a href="__builtin__.html#object">object</a>.</tt></dl> + +<dl><dt><strong>__new__</strong> = <built-in method __new__ of type object><dd><tt>T.<a href="#Entry-__new__">__new__</a>(S, ...) -> a new <a href="__builtin__.html#object">object</a> with type S, a subtype of T</tt></dl> + +<dl><dt><strong>parent</strong> = <attribute 'parent' of 'posix1e.Entry' objects><dd><tt>The parent <a href="#ACL">ACL</a> of this entry</tt></dl> + +<dl><dt><strong>permset</strong> = <attribute 'permset' of 'posix1e.Entry' objects><dd><tt>The permission set of this <a href="#ACL">ACL</a> entry</tt></dl> + +<dl><dt><strong>qualifier</strong> = <attribute 'qualifier' of 'posix1e.Entry' objects><dd><tt>The qualifier of the current entry<br> + <br> +If the tag type is ACL_USER, this should be a user id.<br> +If the tag type if ACL_GROUP, this should be a group id.<br> +Else, it doesn't matter.</tt></dl> + +<dl><dt><strong>tag_type</strong> = <attribute 'tag_type' of 'posix1e.Entry' objects><dd><tt>The tag type of the current entry<br> + <br> +This is one of:<br> + - ACL_UNDEFINED_TAG<br> + - ACL_USER_OBJ<br> + - ACL_USER<br> + - ACL_GROUP_OBJ<br> + - ACL_GROUP<br> + - ACL_MASK<br> + - ACL_OTHER</tt></dl> + +<hr> +Methods inherited from <a href="__builtin__.html#object">__builtin__.object</a>:<br> +<dl><dt><a name="Entry-__delattr__"><strong>__delattr__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__delattr__">__delattr__</a>('name') <==> del x.name</tt></dd></dl> + +<dl><dt><a name="Entry-__getattribute__"><strong>__getattribute__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__getattribute__">__getattribute__</a>('name') <==> x.name</tt></dd></dl> + +<dl><dt><a name="Entry-__hash__"><strong>__hash__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__hash__">__hash__</a>() <==> hash(x)</tt></dd></dl> + +<dl><dt><a name="Entry-__reduce__"><strong>__reduce__</strong></a>(...)</dt><dd><tt>helper for pickle</tt></dd></dl> + +<dl><dt><a name="Entry-__repr__"><strong>__repr__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__repr__">__repr__</a>() <==> repr(x)</tt></dd></dl> + +<dl><dt><a name="Entry-__setattr__"><strong>__setattr__</strong></a>(...)</dt><dd><tt>x.<a href="#Entry-__setattr__">__setattr__</a>('name', value) <==> x.name = value</tt></dd></dl> + +<hr> +Data and non-method functions inherited from <a href="__builtin__.html#object">__builtin__.object</a>:<br> +<dl><dt><strong>__class__</strong> = <type 'type'><dd><tt>the <a href="__builtin__.html#object">object</a>'s class</tt></dl> + +</td></tr></table> +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> +<tr bgcolor="#ffc8d8"> +<td colspan=3 valign=bottom> <br> +<font color="#000000" face="helvetica, arial"><a name="Permset">class <strong>Permset</strong></a>(<a href="__builtin__.html#object">__builtin__.object</a>)</font></td></tr> + +<tr bgcolor="#ffc8d8"><td rowspan=2><tt> </tt></td> +<td colspan=2><tt>Type which represents the permission set in an <a href="#ACL">ACL</a> entry<br> + <br> +The type exists only if the OS has full support for POSIX.1e<br> +Can be created either by:<br> + perms = myEntry.permset<br> +or by:<br> + perms = posix1e.<a href="#Permset">Permset</a>(myEntry)<br> + <br> +Note that the <a href="#Permset">Permset</a> keeps a reference to its <a href="#Entry">Entry</a>, so even if <br> +you delete the entry, it won't be cleaned up and will continue to <br> +exist until its <a href="#Permset">Permset</a> will be deleted.<br> </tt></td></tr> +<tr><td> </td> +<td width="100%">Methods defined here:<br> +<dl><dt><a name="Permset-__init__"><strong>__init__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__init__">__init__</a>(...) initializes x; see x.__class__.__doc__ for signature</tt></dd></dl> + +<dl><dt><a name="Permset-__str__"><strong>__str__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__str__">__str__</a>() <==> str(x)</tt></dd></dl> + +<dl><dt><a name="Permset-add"><strong>add</strong></a>(...)</dt><dd><tt>Add a permission to the permission set.<br> + <br> +The <a href="#Permset-add">add</a>() function adds the permission contained in <br> +the argument perm to the permission set. An attempt <br> +to add a permission that is already contained in the <br> +permission set is not considered an error.<br> +Parameters:<br> + - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...<br> +Return value:<br> + None<br> +Can raise: IOError</tt></dd></dl> + +<dl><dt><a name="Permset-clear"><strong>clear</strong></a>(...)</dt><dd><tt>Clear all permissions from the permission set.</tt></dd></dl> + +<dl><dt><a name="Permset-delete"><strong>delete</strong></a>(...)</dt><dd><tt>Delete a permission from the permission set.<br> + <br> +The <a href="#Permset-delete">delete</a>() function deletes the permission contained in <br> +the argument perm from the permission set. An attempt <br> +to delete a permission that is not contained in the <br> +permission set is not considered an error.<br> +Parameters:<br> + - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...<br> +Return value:<br> + None<br> +Can raise: IOError</tt></dd></dl> + +<dl><dt><a name="Permset-test"><strong>test</strong></a>(...)</dt><dd><tt>Test if a permission exists in the permission set.<br> + <br> +The <a href="#Permset-test">test</a>() function tests if the permission contained in <br> +the argument perm exits the permission set.<br> +Parameters:<br> + - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...<br> +Return value:<br> + Bool<br> +Can raise: IOError</tt></dd></dl> + +<hr> +Data and non-method functions defined here:<br> +<dl><dt><strong>__doc__</strong> = 'Type which represents the permission set in an A...nue to <font color="#c040c0">\n</font>exist until its Permset will be deleted.<font color="#c040c0">\n</font>'<dd><tt>str(<a href="__builtin__.html#object">object</a>) -> string<br> + <br> +Return a nice string representation of the <a href="__builtin__.html#object">object</a>.<br> +If the argument is a string, the return value is the same <a href="__builtin__.html#object">object</a>.</tt></dl> + +<dl><dt><strong>__new__</strong> = <built-in method __new__ of type object><dd><tt>T.<a href="#Permset-__new__">__new__</a>(S, ...) -> a new <a href="__builtin__.html#object">object</a> with type S, a subtype of T</tt></dl> + +<dl><dt><strong>execute</strong> = <attribute 'execute' of 'posix1e.Permset' objects><dd><tt>Execute permsission<br> + <br> +This is a convenience method of access; the <br> +same effect can be achieved using the functions<br> +<a href="#Permset-add">add</a>(), <a href="#Permset-test">test</a>(), <a href="#Permset-delete">delete</a>(), and those can take any <br> +permission defined by your platform.</tt></dl> + +<dl><dt><strong>read</strong> = <attribute 'read' of 'posix1e.Permset' objects><dd><tt>Read permsission<br> + <br> +This is a convenience method of access; the <br> +same effect can be achieved using the functions<br> +<a href="#Permset-add">add</a>(), <a href="#Permset-test">test</a>(), <a href="#Permset-delete">delete</a>(), and those can take any <br> +permission defined by your platform.</tt></dl> + +<dl><dt><strong>write</strong> = <attribute 'write' of 'posix1e.Permset' objects><dd><tt>Write permsission<br> + <br> +This is a convenience method of access; the <br> +same effect can be achieved using the functions<br> +<a href="#Permset-add">add</a>(), <a href="#Permset-test">test</a>(), <a href="#Permset-delete">delete</a>(), and those can take any <br> +permission defined by your platform.</tt></dl> + +<hr> +Methods inherited from <a href="__builtin__.html#object">__builtin__.object</a>:<br> +<dl><dt><a name="Permset-__delattr__"><strong>__delattr__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__delattr__">__delattr__</a>('name') <==> del x.name</tt></dd></dl> + +<dl><dt><a name="Permset-__getattribute__"><strong>__getattribute__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__getattribute__">__getattribute__</a>('name') <==> x.name</tt></dd></dl> + +<dl><dt><a name="Permset-__hash__"><strong>__hash__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__hash__">__hash__</a>() <==> hash(x)</tt></dd></dl> + +<dl><dt><a name="Permset-__reduce__"><strong>__reduce__</strong></a>(...)</dt><dd><tt>helper for pickle</tt></dd></dl> + +<dl><dt><a name="Permset-__repr__"><strong>__repr__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__repr__">__repr__</a>() <==> repr(x)</tt></dd></dl> + +<dl><dt><a name="Permset-__setattr__"><strong>__setattr__</strong></a>(...)</dt><dd><tt>x.<a href="#Permset-__setattr__">__setattr__</a>('name', value) <==> x.name = value</tt></dd></dl> + +<hr> +Data and non-method functions inherited from <a href="__builtin__.html#object">__builtin__.object</a>:<br> +<dl><dt><strong>__class__</strong> = <type 'type'><dd><tt>the <a href="__builtin__.html#object">object</a>'s class</tt></dl> + +</td></tr></table></td></tr></table> +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> +<tr bgcolor="#eeaa77"> +<td colspan=3 valign=bottom> <br> +<font color="#ffffff" face="helvetica, arial"><big><strong>Functions</strong></big></font></td></tr> + +<tr><td bgcolor="#eeaa77"><tt> </tt></td><td> </td> +<td width="100%"><dl><dt><a name="-delete_default"><strong>delete_default</strong></a>(...)</dt><dd><tt>Delete the default <a href="#ACL">ACL</a> from a directory.<br> + <br> +This function deletes the default <a href="#ACL">ACL</a> associated with <br> +a directory (the <a href="#ACL">ACL</a> which will be ANDed with the mode<br> +parameter to the open, creat functions).<br> +Parameters:<br> + - a string representing the directory whose default <a href="#ACL">ACL</a><br> + should be deleted</tt></dd></dl> +</td></tr></table> +<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> +<tr bgcolor="#55aa55"> +<td colspan=3 valign=bottom> <br> +<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr> + +<tr><td bgcolor="#55aa55"><tt> </tt></td><td> </td> +<td width="100%"><strong>ACL_EXECUTE</strong> = 1<br> +<strong>ACL_GROUP</strong> = 8<br> +<strong>ACL_GROUP_OBJ</strong> = 4<br> +<strong>ACL_MASK</strong> = 16<br> +<strong>ACL_OTHER</strong> = 32<br> +<strong>ACL_READ</strong> = 4<br> +<strong>ACL_TYPE_ACCESS</strong> = 32768<br> +<strong>ACL_TYPE_DEFAULT</strong> = 16384<br> +<strong>ACL_UNDEFINED_TAG</strong> = 0<br> +<strong>ACL_USER</strong> = 2<br> +<strong>ACL_USER_OBJ</strong> = 1<br> +<strong>ACL_WRITE</strong> = 2<br> +<strong>__file__</strong> = '/home/iusty/work/pylibacl/build/lib.linux-i686-2.2/posix1e.so'<br> +<strong>__name__</strong> = 'posix1e'</td></tr></table> +</body></html> \ No newline at end of file diff --git a/posix1e.txt b/posix1e.txt new file mode 100644 index 0000000..7657830 --- /dev/null +++ b/posix1e.txt @@ -0,0 +1,443 @@ +Python Library Documentation: module posix1e + +NAME + posix1e - POSIX.1e ACLs manipulation + +FILE + /home/iusty/work/pylibacl/build/lib.linux-i686-2.2/posix1e.so + +DESCRIPTION + This module provides support for manipulating POSIX.1e ACLS + + Depending on the operating system support for POSIX.1e, + the ACL type will have more or less capabilities: + - level 1, only basic support, you can create + ACLs from files and text descriptions; + once created, the type is immutable + - level 2, complete support, you can alter + the ACL once it is created + + Also, in level 2, more types are available, corresponding + to acl_entry_t (Entry type), acl_permset_t (Permset type). + + Example: + >>> import posix1e + >>> acl1 = posix1e.ACL(file="file.txt") + >>> print acl1 + user::rw- + group::rw- + other::r-- + + >>> b = posix1e.ACL(text="u::rx,g::-,o::-") + >>> print b + user::r-x + group::--- + other::--- + + >>> b.applyto("file.txt") + >>> print posix1e.ACL(file="file.txt") + user::r-x + group::--- + other::--- + + >>> + +CLASSES + __builtin__.object + ACL + Entry + Permset + + class ACL(__builtin__.object) + | Type which represents a POSIX ACL + | + | Parameters: + | Only one keword parameter should be provided: + | - file="...", meaning create ACL representing + | the access ACL of that file + | - filedef="...", meaning create ACL representing + | the default ACL of that directory + | - fd=<int>, meaning create ACL representing + | the access ACL of that file descriptor + | - text="...", meaning create ACL from a + | textual description + | - acl=<ACL instance>, meaning create a copy + | of an existing ACL instance + | If no parameters are passed, create an empty ACL; this + | makes sense only when your OS supports ACL modification + | (i.e. it implements full POSIX.1e support) + | + | Methods defined here: + | + | __getstate__(...) + | Dumps the ACL to an external format. + | + | __init__(...) + | x.__init__(...) initializes x; see x.__class__.__doc__ for signature + | + | __iter__(...) + | x.__iter__() <==> iter(x) + | + | __setstate__(...) + | Loads the ACL from an external format. + | + | __str__(...) + | x.__str__() <==> str(x) + | + | append(...) + | Append a new Entry to the ACL and return it. + | + | This is a convenience function to create a new Entry + | and append it to the ACL. + | If a parameter of type Entry instance is given, the + | entry will be a copy of that one (as if copied with + | Entry.copy()), otherwise, the new entry will be empty. + | + | applyto(...) + | Apply the ACL to a file or filehandle. + | + | Parameters: + | - either a filename or a file-like object or an integer; this + | represents the filesystem object on which to act + | - optional flag representing the type of ACL to set, either + | ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT + | + | calc_mask(...) + | Compute the file group class mask. + | + | The calc_mask() method calculates and sets the permissions + | associated with the ACL_MASK Entry of the ACL. + | The value of the new permissions is the union of the permissions + | granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or + | ACL_USER. If the ACL already contains an ACL_MASK entry, its + | permissions are overwritten; if it does not contain an ACL_MASK + | Entry, one is added. + | + | The order of existing entries in the ACL is undefined after this + | function. + | + | delete_entry(...) + | Deletes an entry from the ACL. + | + | Note: Only with level 2 + | Parameters: + | - the Entry object which should be deleted; note that after + | this function is called, that object is unusable any longer + | and should be deleted + | + | next(...) + | x.next() -> the next value, or raise StopIteration + | + | valid(...) + | Test the ACL for validity. + | + | This method tests the ACL to see if it is a valid ACL + | in terms of the filesystem. More precisely, it checks: + | A valid ACL contains exactly one entry with each of the ACL_USER_OBJ, + | ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and + | ACL_GROUP tag types may appear zero or more times in an ACL. An ACL that + | contains entries of ACL_USER or ACL_GROUP tag types must contain exactly + | one entry of the ACL_MASK tag type. If an ACL contains no entries of + | ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional. + | + | All user ID qualifiers must be unique among all entries of ACL_USER tag + | type, and all group IDs must be unique among all entries of ACL_GROUP tag + | type. + | + | The method will return 1 for a valid ACL and 0 for an invalid one. + | This has been chosen because the specification for acl_valid in POSIX.1e + | documents only one possible value for errno in case of an invalid ACL, + | so we can't differentiate between classes of errors. Other suggestions + | are welcome. + | + | ---------------------------------------------------------------------- + | Data and non-method functions defined here: + | + | __doc__ = 'Type which represents a POSIX ACL\n\nParameters:\n ...tion\... + | str(object) -> string + | + | Return a nice string representation of the object. + | If the argument is a string, the return value is the same object. + | + | __new__ = <built-in method __new__ of type object> + | T.__new__(S, ...) -> a new object with type S, a subtype of T + | + | ---------------------------------------------------------------------- + | Methods inherited from __builtin__.object: + | + | __delattr__(...) + | x.__delattr__('name') <==> del x.name + | + | __getattribute__(...) + | x.__getattribute__('name') <==> x.name + | + | __hash__(...) + | x.__hash__() <==> hash(x) + | + | __reduce__(...) + | helper for pickle + | + | __repr__(...) + | x.__repr__() <==> repr(x) + | + | __setattr__(...) + | x.__setattr__('name', value) <==> x.name = value + | + | ---------------------------------------------------------------------- + | Data and non-method functions inherited from __builtin__.object: + | + | __class__ = <type 'type'> + | the object's class + + class Entry(__builtin__.object) + | Type which represents an entry in an ACL. + | + | The type exists only if the OS has full support for POSIX.1e + | Can be created either by: + | e = posix1e.Entry(myACL) # this creates a new entry in the ACL + | or by: + | for entry in myACL: + | print entry + | + | Note that the Entry keeps a reference to its ACL, so even if + | you delete the ACL, it won't be cleaned up and will continue to + | exist until its Entry(ies) will be deleted. + | + | Methods defined here: + | + | __init__(...) + | x.__init__(...) initializes x; see x.__class__.__doc__ for signature + | + | __str__(...) + | x.__str__() <==> str(x) + | + | copy(...) + | Copy an ACL entry. + | + | This method sets all the parameters to those of another + | entry, even one of another's ACL + | Parameters: + | - src, instance of type Entry + | + | ---------------------------------------------------------------------- + | Data and non-method functions defined here: + | + | __doc__ = 'Type which represents an entry in an ACL.\n\nThe t... to \n... + | str(object) -> string + | + | Return a nice string representation of the object. + | If the argument is a string, the return value is the same object. + | + | __new__ = <built-in method __new__ of type object> + | T.__new__(S, ...) -> a new object with type S, a subtype of T + | + | parent = <attribute 'parent' of 'posix1e.Entry' objects> + | The parent ACL of this entry + | + | + | permset = <attribute 'permset' of 'posix1e.Entry' objects> + | The permission set of this ACL entry + | + | + | qualifier = <attribute 'qualifier' of 'posix1e.Entry' objects> + | The qualifier of the current entry + | + | If the tag type is ACL_USER, this should be a user id. + | If the tag type if ACL_GROUP, this should be a group id. + | Else, it doesn't matter. + | + | + | tag_type = <attribute 'tag_type' of 'posix1e.Entry' objects> + | The tag type of the current entry + | + | This is one of: + | - ACL_UNDEFINED_TAG + | - ACL_USER_OBJ + | - ACL_USER + | - ACL_GROUP_OBJ + | - ACL_GROUP + | - ACL_MASK + | - ACL_OTHER + | + | + | ---------------------------------------------------------------------- + | Methods inherited from __builtin__.object: + | + | __delattr__(...) + | x.__delattr__('name') <==> del x.name + | + | __getattribute__(...) + | x.__getattribute__('name') <==> x.name + | + | __hash__(...) + | x.__hash__() <==> hash(x) + | + | __reduce__(...) + | helper for pickle + | + | __repr__(...) + | x.__repr__() <==> repr(x) + | + | __setattr__(...) + | x.__setattr__('name', value) <==> x.name = value + | + | ---------------------------------------------------------------------- + | Data and non-method functions inherited from __builtin__.object: + | + | __class__ = <type 'type'> + | the object's class + + class Permset(__builtin__.object) + | Type which represents the permission set in an ACL entry + | + | The type exists only if the OS has full support for POSIX.1e + | Can be created either by: + | perms = myEntry.permset + | or by: + | perms = posix1e.Permset(myEntry) + | + | Note that the Permset keeps a reference to its Entry, so even if + | you delete the entry, it won't be cleaned up and will continue to + | exist until its Permset will be deleted. + | + | Methods defined here: + | + | __init__(...) + | x.__init__(...) initializes x; see x.__class__.__doc__ for signature + | + | __str__(...) + | x.__str__() <==> str(x) + | + | add(...) + | Add a permission to the permission set. + | + | The add() function adds the permission contained in + | the argument perm to the permission set. An attempt + | to add a permission that is already contained in the + | permission set is not considered an error. + | Parameters: + | - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ... + | Return value: + | None + | Can raise: IOError + | + | clear(...) + | Clear all permissions from the permission set. + | + | delete(...) + | Delete a permission from the permission set. + | + | The delete() function deletes the permission contained in + | the argument perm from the permission set. An attempt + | to delete a permission that is not contained in the + | permission set is not considered an error. + | Parameters: + | - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ... + | Return value: + | None + | Can raise: IOError + | + | test(...) + | Test if a permission exists in the permission set. + | + | The test() function tests if the permission contained in + | the argument perm exits the permission set. + | Parameters: + | - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ... + | Return value: + | Bool + | Can raise: IOError + | + | ---------------------------------------------------------------------- + | Data and non-method functions defined here: + | + | __doc__ = 'Type which represents the permission set in an A...nue to \... + | str(object) -> string + | + | Return a nice string representation of the object. + | If the argument is a string, the return value is the same object. + | + | __new__ = <built-in method __new__ of type object> + | T.__new__(S, ...) -> a new object with type S, a subtype of T + | + | execute = <attribute 'execute' of 'posix1e.Permset' objects> + | Execute permsission + | + | This is a convenience method of access; the + | same effect can be achieved using the functions + | add(), test(), delete(), and those can take any + | permission defined by your platform. + | + | + | read = <attribute 'read' of 'posix1e.Permset' objects> + | Read permsission + | + | This is a convenience method of access; the + | same effect can be achieved using the functions + | add(), test(), delete(), and those can take any + | permission defined by your platform. + | + | + | write = <attribute 'write' of 'posix1e.Permset' objects> + | Write permsission + | + | This is a convenience method of access; the + | same effect can be achieved using the functions + | add(), test(), delete(), and those can take any + | permission defined by your platform. + | + | + | ---------------------------------------------------------------------- + | Methods inherited from __builtin__.object: + | + | __delattr__(...) + | x.__delattr__('name') <==> del x.name + | + | __getattribute__(...) + | x.__getattribute__('name') <==> x.name + | + | __hash__(...) + | x.__hash__() <==> hash(x) + | + | __reduce__(...) + | helper for pickle + | + | __repr__(...) + | x.__repr__() <==> repr(x) + | + | __setattr__(...) + | x.__setattr__('name', value) <==> x.name = value + | + | ---------------------------------------------------------------------- + | Data and non-method functions inherited from __builtin__.object: + | + | __class__ = <type 'type'> + | the object's class + +FUNCTIONS + delete_default(...) + Delete the default ACL from a directory. + + This function deletes the default ACL associated with + a directory (the ACL which will be ANDed with the mode + parameter to the open, creat functions). + Parameters: + - a string representing the directory whose default ACL + should be deleted + +DATA + ACL_EXECUTE = 1 + ACL_GROUP = 8 + ACL_GROUP_OBJ = 4 + ACL_MASK = 16 + ACL_OTHER = 32 + ACL_READ = 4 + ACL_TYPE_ACCESS = 32768 + ACL_TYPE_DEFAULT = 16384 + ACL_UNDEFINED_TAG = 0 + ACL_USER = 2 + ACL_USER_OBJ = 1 + ACL_WRITE = 2 + __file__ = '/home/iusty/work/pylibacl/build/lib.linux-i686-2.2/posix1e... + __name__ = 'posix1e' + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..f8c1ed7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,4 @@ +[bdist_rpm] +release = 1 +requires = libacl +;build_requires = libacl libacl-devel diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..95231f8 --- /dev/null +++ b/setup.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +import distutils, os +from distutils.core import setup, Extension + +(u_sysname, u_nodename, u_release, u_version, u_machine) = os.uname() + +macros = [] +libs = [] +if u_sysname == "Linux": + macros.append(("HAVE_LINUX", None)) + macros.append(("HAVE_LEVEL2", None)) + libs.append("acl") +elif u_sysname == "GNU/kFreeBSD": + macros.append(("HAVE_LINUX", None)) + macros.append(("HAVE_LEVEL2", None)) + libs.append("acl") +elif u_sysname == "FreeBSD": + macros.append(("HAVE_FREEBSD", None)) +else: + raise ValueError("I don't know your system '%s'." + " Please contact the author" % u_sysname) + +long_desc = """This is a C extension module for Python which +implements POSIX ACLs manipulation. It is a wrapper on top +of the systems's acl C library - see acl(5).""" +version = "0.2.2" +setup(name="pylibacl", + version=version, + description="POSIX.1e ACLs for python", + long_description=long_desc, + author="Iustin Pop", + author_email="iusty@k1024.org", + url="http://pylibacl.sourceforge.net", + license="GPL", + ext_modules=[Extension("posix1e", ["acl.c"], + libraries=libs, + define_macros=macros, + )], + data_files=[("/usr/share/doc/pylibacl-%s" % version, + ["README","IMPLEMENTATION", "PLATFORMS", + "BENCHMARK", + "posix1e.html", "posix1e.txt"])], + ) -- 2.39.5