6 staticforward PyTypeObject ACL_Type;
7 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
8 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
10 static PyObject* ACL_get_state(PyObject *obj, PyObject* args);
11 static PyObject* ACL_set_state(PyObject *obj, PyObject* args);
13 staticforward PyTypeObject Entry_Type;
14 staticforward PyTypeObject Permset_Type;
27 PyObject *parent_acl; /* The parent acl, so it won't run out on us */
33 PyObject *parent_entry; /* The parent entry, so it won't run out on us */
34 acl_permset_t permset;
39 /* Creation of a new ACL instance */
40 static PyObject* ACL_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
43 newacl = type->tp_alloc(type, 0);
46 ((ACL_Object*)newacl)->acl = NULL;
47 ((ACL_Object*)newacl)->entry_id = ACL_FIRST_ENTRY;
53 /* Initialization of a new ACL instance */
54 static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) {
55 ACL_Object* self = (ACL_Object*) obj;
56 static char *kwlist[] = { "file", "fd", "text", "acl", NULL };
60 ACL_Object* thesrc = NULL;
63 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sisO!", kwlist,
64 &file, &fd, &text, &ACL_Type, &thesrc))
76 PyErr_SetString(PyExc_ValueError, "a maximum of one argument must be passed");
80 /* Free the old acl_t without checking for error, we don't
86 self->acl = acl_get_file(file, ACL_TYPE_ACCESS);
88 self->acl = acl_from_text(text);
90 self->acl = acl_get_fd(fd);
91 else if(thesrc != NULL)
92 self->acl = acl_dup(thesrc->acl);
94 self->acl = acl_init(0);
96 if(self->acl == NULL) {
97 PyErr_SetFromErrno(PyExc_IOError);
104 /* Standard type functions */
105 static void ACL_dealloc(PyObject* obj) {
106 ACL_Object *self = (ACL_Object*) obj;
107 PyObject *err_type, *err_value, *err_traceback;
108 int have_error = PyErr_Occurred() ? 1 : 0;
111 PyErr_Fetch(&err_type, &err_value, &err_traceback);
112 if(acl_free(self->acl) != 0)
113 PyErr_WriteUnraisable(obj);
115 PyErr_Restore(err_type, err_value, err_traceback);
119 /* Converts the acl to a text format */
120 static PyObject* ACL_str(PyObject *obj) {
122 ACL_Object *self = (ACL_Object*) obj;
125 text = acl_to_text(self->acl, NULL);
127 return PyErr_SetFromErrno(PyExc_IOError);
129 ret = PyString_FromString(text);
130 if(acl_free(text) != 0) {
132 return PyErr_SetFromErrno(PyExc_IOError);
138 static char __applyto_doc__[] = \
139 "Apply the ACL to a file or filehandle.\n" \
142 " - either a filename or a file-like object or an integer; this\n" \
143 " represents the filesystem object on which to act\n" \
146 /* Applyes the ACL to a file */
147 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
148 ACL_Object *self = (ACL_Object*) obj;
150 int type_default = 0;
151 acl_type_t type = ACL_TYPE_ACCESS;
155 if (!PyArg_ParseTuple(args, "O|i", &myarg, &type_default))
158 type = ACL_TYPE_DEFAULT;
160 if(PyString_Check(myarg)) {
161 char *filename = PyString_AS_STRING(myarg);
162 nret = acl_set_file(filename, type, self->acl);
163 } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
164 nret = acl_set_fd(fd, self->acl);
166 PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int, or file-like object");
170 return PyErr_SetFromErrno(PyExc_IOError);
173 /* Return the result */
178 static char __valid_doc__[] = \
179 "Test the ACL for validity.\n" \
181 "This method tests the ACL to see if it is a valid ACL\n" \
182 "in terms of the filesystem. More precisely, it checks:\n" \
183 "A valid ACL contains exactly one entry with each of the ACL_USER_OBJ,\n" \
184 "ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and\n" \
185 "ACL_GROUP tag types may appear zero or more times in an ACL. An ACL that\n" \
186 "contains entries of ACL_USER or ACL_GROUP tag types must contain exactly\n" \
187 "one entry of the ACL_MASK tag type. If an ACL contains no entries of\n" \
188 "ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n" \
190 "All user ID qualifiers must be unique among all entries of ACL_USER tag\n" \
191 "type, and all group IDs must be unique among all entries of ACL_GROUP tag\n" \
195 /* Checks the ACL for validity */
196 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
197 ACL_Object *self = (ACL_Object*) obj;
199 if(acl_valid(self->acl) == -1) {
200 return PyErr_SetFromErrno(PyExc_IOError);
203 /* Return the result */
210 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
211 ACL_Object *self = (ACL_Object*) obj;
216 size = acl_size(self->acl);
218 return PyErr_SetFromErrno(PyExc_IOError);
220 if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
222 buf = PyString_AsString(ret);
224 if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) {
226 return PyErr_SetFromErrno(PyExc_IOError);
232 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
233 ACL_Object *self = (ACL_Object*) obj;
238 /* Parse the argument */
239 if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
242 /* Try to import the external representation */
243 if((ptr = acl_copy_int(buf)) == NULL)
244 return PyErr_SetFromErrno(PyExc_IOError);
246 /* Free the old acl. Should we ignore errors here? */
247 if(self->acl != NULL) {
248 if(acl_free(self->acl) == -1)
249 return PyErr_SetFromErrno(PyExc_IOError);
254 /* Return the result */
259 static PyObject* ACL_iter(PyObject *obj) {
260 ACL_Object *self = (ACL_Object*)obj;
261 self->entry_id = ACL_FIRST_ENTRY;
266 static PyObject* ACL_iternext(PyObject *obj) {
267 ACL_Object *self = (ACL_Object*)obj;
268 acl_entry_t the_entry_t;
269 Entry_Object *the_entry_obj;
272 if((nerr = acl_get_entry(self->acl, self->entry_id, &the_entry_t)) == -1)
273 return PyErr_SetFromErrno(PyExc_IOError);
274 self->entry_id = ACL_NEXT_ENTRY;
276 /* Docs says this is not needed */
277 /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/
281 the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL);
282 if(the_entry_obj == NULL)
285 the_entry_obj->entry = the_entry_t;
287 the_entry_obj->parent_acl = obj;
288 Py_INCREF(obj); /* For the reference we have in entry->parent */
290 return (PyObject*)the_entry_obj;
293 /* Creation of a new Entry instance */
294 static PyObject* Entry_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
297 newentry = PyType_GenericNew(type, args, keywds);
299 if(newentry != NULL) {
300 ((Entry_Object*)newentry)->entry = NULL;
301 ((Entry_Object*)newentry)->parent_acl = NULL;
307 /* Initialization of a new Entry instance */
308 static int Entry_init(PyObject* obj, PyObject* args, PyObject *keywds) {
309 Entry_Object* self = (Entry_Object*) obj;
310 ACL_Object* parent = NULL;
312 if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent))
315 if(acl_create_entry(&parent->acl, &self->entry) == -1) {
316 PyErr_SetFromErrno(PyExc_IOError);
320 self->parent_acl = (PyObject*)parent;
326 /* Free the Entry instance */
327 static void Entry_dealloc(PyObject* obj) {
328 Entry_Object *self = (Entry_Object*) obj;
329 PyObject *err_type, *err_value, *err_traceback;
330 int have_error = PyErr_Occurred() ? 1 : 0;
333 PyErr_Fetch(&err_type, &err_value, &err_traceback);
334 if(self->parent_acl != NULL) {
335 Py_DECREF(self->parent_acl);
336 self->parent_acl = NULL;
339 PyErr_Restore(err_type, err_value, err_traceback);
343 /* Converts the entry to a text format */
344 static PyObject* Entry_str(PyObject *obj) {
349 PyObject *format, *list;
350 Entry_Object *self = (Entry_Object*) obj;
352 if(acl_get_tag_type(self->entry, &tag) == -1) {
353 PyErr_SetFromErrno(PyExc_IOError);
356 if(tag == ACL_USER || tag == ACL_GROUP) {
357 if((p = acl_get_qualifier(self->entry)) == NULL) {
358 PyErr_SetFromErrno(PyExc_IOError);
361 qualifier = *(uid_t*)p;
367 format = PyString_FromString("ACL entry for %s, rights: <unknown>");
370 list = PyTuple_New(1);
371 if(tag == ACL_UNDEFINED_TAG) {
372 PyTuple_SetItem(list, 0, PyString_FromString("undefined type"));
373 } else if(tag == ACL_USER_OBJ) {
374 PyTuple_SetItem(list, 0, PyString_FromString("the owner"));
375 } else if(tag == ACL_GROUP_OBJ) {
376 PyTuple_SetItem(list, 0, PyString_FromString("the group"));
377 } else if(tag == ACL_OTHER) {
378 PyTuple_SetItem(list, 0, PyString_FromString("the others"));
379 } else if(tag == ACL_USER) {
380 PyTuple_SetItem(list, 0, PyString_FromFormat("user %u", qualifier));
381 } else if(tag == ACL_GROUP) {
382 PyTuple_SetItem(list, 0, PyString_FromFormat("group %u", qualifier));
383 } else if(tag == ACL_MASK) {
384 PyTuple_SetItem(list, 0, PyString_FromString("the mask"));
386 PyTuple_SetItem(list, 0, PyString_FromString("UNKNOWN_TAG_TYPE!"));
388 ret = PyString_Format(format, list);
394 static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
395 Entry_Object *self = (Entry_Object*) obj;
398 PyErr_SetString(PyExc_TypeError,
399 "tag type deletion is not supported");
403 if(!PyInt_Check(value)) {
404 PyErr_SetString(PyExc_TypeError,
405 "tag type must be integer");
408 if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
409 PyErr_SetFromErrno(PyExc_IOError);
416 static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) {
417 Entry_Object *self = (Entry_Object*) obj;
420 if (self->entry == NULL) {
421 PyErr_SetString(PyExc_AttributeError, "entry attribute");
424 if(acl_get_tag_type(self->entry, &value) == -1) {
425 PyErr_SetFromErrno(PyExc_IOError);
429 return PyInt_FromLong(value);
432 static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
433 Entry_Object *self = (Entry_Object*) obj;
437 PyErr_SetString(PyExc_TypeError,
438 "qualifier deletion is not supported");
442 if(!PyInt_Check(value)) {
443 PyErr_SetString(PyExc_TypeError,
444 "tag type must be integer");
447 uidgid = PyInt_AsLong(value);
448 if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) {
449 PyErr_SetFromErrno(PyExc_IOError);
456 static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) {
457 Entry_Object *self = (Entry_Object*) obj;
461 if (self->entry == NULL) {
462 PyErr_SetString(PyExc_AttributeError, "entry attribute");
465 if((p = acl_get_qualifier(self->entry)) == NULL) {
466 PyErr_SetFromErrno(PyExc_IOError);
472 return PyInt_FromLong(value);
475 static PyObject* Entry_get_parent(PyObject *obj, void* arg) {
476 Entry_Object *self = (Entry_Object*) obj;
478 Py_INCREF(self->parent_acl);
479 return self->parent_acl;
482 /* Creation of a new Permset instance */
483 static PyObject* Permset_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
484 PyObject* newpermset;
486 newpermset = PyType_GenericNew(type, args, keywds);
488 if(newpermset != NULL) {
489 ((Permset_Object*)newpermset)->permset = NULL;
490 ((Permset_Object*)newpermset)->parent_entry = NULL;
496 /* Initialization of a new Permset instance */
497 static int Permset_init(PyObject* obj, PyObject* args, PyObject *keywds) {
498 Permset_Object* self = (Permset_Object*) obj;
499 Entry_Object* parent = NULL;
501 if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent))
504 if(acl_get_permset(parent->entry, &self->permset) == -1) {
505 PyErr_SetFromErrno(PyExc_IOError);
509 self->parent_entry = (PyObject*)parent;
515 /* Free the Permset instance */
516 static void Permset_dealloc(PyObject* obj) {
517 Permset_Object *self = (Permset_Object*) obj;
518 PyObject *err_type, *err_value, *err_traceback;
519 int have_error = PyErr_Occurred() ? 1 : 0;
522 PyErr_Fetch(&err_type, &err_value, &err_traceback);
523 if(self->parent_entry != NULL) {
524 Py_DECREF(self->parent_entry);
525 self->parent_entry = NULL;
528 PyErr_Restore(err_type, err_value, err_traceback);
532 static PyObject* Permset_clear(PyObject* obj, PyObject* args) {
533 Permset_Object *self = (Permset_Object*) obj;
535 if(acl_clear_perms(self->permset) == -1)
536 return PyErr_SetFromErrno(PyExc_IOError);
538 /* Return the result */
545 static char __acltype_doc__[] = \
546 "Type which represents a POSIX ACL\n" \
549 " Only one keword parameter should be provided:\n"
550 " - file=\"...\", meaning create ACL representing\n"
551 " the ACL of that file\n" \
552 " - fd=<int>, meaning create ACL representing\n" \
553 " the ACL of that file descriptor\n" \
554 " - text=\"...\", meaning create ACL from a \n" \
555 " textual description\n" \
556 " - acl=<ACL instance>, meaning create a copy\n" \
557 " of an existing ACL instance\n" \
560 /* ACL type methods */
561 static PyMethodDef ACL_methods[] = {
562 {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
563 {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
565 {"__getstate__", ACL_get_state, METH_NOARGS, "Dumps the ACL to an external format."},
566 {"__setstate__", ACL_set_state, METH_VARARGS, "Loads the ACL from an external format."},
568 {NULL, NULL, 0, NULL}
572 /* The definition of the ACL Type */
573 static PyTypeObject ACL_Type = {
574 PyObject_HEAD_INIT(NULL)
579 ACL_dealloc, /* tp_dealloc */
585 0, /* tp_as_number */
586 0, /* tp_as_sequence */
587 0, /* tp_as_mapping */
590 ACL_str, /* tp_str */
593 0, /* tp_as_buffer */
594 Py_TPFLAGS_DEFAULT, /* tp_flags */
595 __acltype_doc__, /* tp_doc */
598 0, /* tp_richcompare */
599 0, /* tp_weaklistoffset */
607 ACL_methods, /* tp_methods */
612 0, /* tp_descr_get */
613 0, /* tp_descr_set */
614 0, /* tp_dictoffset */
615 ACL_init, /* tp_init */
617 ACL_new, /* tp_new */
622 /* Entry type methods */
623 static PyMethodDef Entry_methods[] = {
624 {NULL, NULL, 0, NULL}
627 static char __Entry_tagtype_doc__[] = \
628 "The tag type of the current entry\n" \
630 "This is one of:\n" \
631 " - ACL_UNDEFINED_TAG\n" \
632 " - ACL_USER_OBJ\n" \
634 " - ACL_GROUP_OBJ\n" \
640 static char __Entry_qualifier_doc__[] = \
641 "The qualifier of the current entry\n" \
643 "If the tag type is ACL_USER, this should be a user id.\n" \
644 "If the tag type if ACL_GROUP, this should be a group id.\n" \
645 "Else, it doesn't matter.\n" \
648 static char __Entry_parent_doc__[] = \
649 "The parent ACL of this entry\n" \
653 static PyGetSetDef Entry_getsets[] = {
654 {"tag_type", Entry_get_tag_type, Entry_set_tag_type, __Entry_tagtype_doc__},
655 {"qualifier", Entry_get_qualifier, Entry_set_qualifier, __Entry_qualifier_doc__},
656 {"parent", Entry_get_parent, NULL, __Entry_parent_doc__},
660 /* The definition of the ACL Entry Type */
661 static PyTypeObject Entry_Type = {
662 PyObject_HEAD_INIT(NULL)
665 sizeof(Entry_Object),
667 Entry_dealloc, /* tp_dealloc */
673 0, /* tp_as_number */
674 0, /* tp_as_sequence */
675 0, /* tp_as_mapping */
678 Entry_str, /* tp_str */
681 0, /* tp_as_buffer */
682 Py_TPFLAGS_DEFAULT, /* tp_flags */
683 __acltype_doc__, /* tp_doc */
686 0, /* tp_richcompare */
687 0, /* tp_weaklistoffset */
690 Entry_methods, /* tp_methods */
692 Entry_getsets, /* tp_getset */
695 0, /* tp_descr_get */
696 0, /* tp_descr_set */
697 0, /* tp_dictoffset */
698 Entry_init, /* tp_init */
700 Entry_new, /* tp_new */
703 static char __Permset_clear_doc__[] = \
704 "Clear all permissions in the set\n" \
707 /* Entry type methods */
708 static PyMethodDef Permset_methods[] = {
709 {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, },
710 {NULL, NULL, 0, NULL}
713 /* The definition of the ACL Entry Type */
714 static PyTypeObject Permset_Type = {
715 PyObject_HEAD_INIT(NULL)
718 sizeof(Permset_Object),
720 Permset_dealloc, /* tp_dealloc */
725 0, //Entry_repr, /* tp_repr */
726 0, /* tp_as_number */
727 0, /* tp_as_sequence */
728 0, /* tp_as_mapping */
734 0, /* tp_as_buffer */
735 Py_TPFLAGS_DEFAULT, /* tp_flags */
736 __acltype_doc__, /* tp_doc */
739 0, /* tp_richcompare */
740 0, /* tp_weaklistoffset */
743 Permset_methods, /* tp_methods */
748 0, /* tp_descr_get */
749 0, /* tp_descr_set */
750 0, /* tp_dictoffset */
751 Permset_init, /* tp_init */
753 Permset_new, /* tp_new */
760 static char __deletedef_doc__[] = \
761 "Delete the default ACL from a directory.\n" \
763 "This function deletes the default ACL associated with \n" \
764 "a directory (the ACL which will be ANDed with the mode\n" \
765 "parameter to the open, creat functions).\n" \
767 " - a string representing the directory whose default ACL\n" \
768 " should be deleted\n" \
771 /* Deletes the default ACL from a directory */
772 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
775 /* Parse the arguments */
776 if (!PyArg_ParseTuple(args, "s", &filename))
779 if(acl_delete_def_file(filename) == -1) {
780 return PyErr_SetFromErrno(PyExc_IOError);
783 /* Return the result */
788 /* The module methods */
789 static PyMethodDef aclmodule_methods[] = {
790 {"delete_default", aclmodule_delete_default, METH_VARARGS, __deletedef_doc__},
791 {NULL, NULL, 0, NULL}
794 static char __posix1e_doc__[] = \
795 "POSIX.1e ACLs manipulation\n" \
797 "This module provides support for manipulating POSIX.1e ACLS\n" \
799 "Depending on the operating system support for POSIX.1e, \n" \
800 "the ACL type will have more or less capabilities:\n" \
801 " - level 1, only basic support, you can create\n" \
802 " ACLs from files and text descriptions;\n" \
803 " once created, the type is immutable\n" \
804 " - level 2, complete support, you can alter\n"\
805 " the ACL once it is created\n" \
807 "Also, in level 2, more types will be available, corresponding\n" \
808 "to acl_entry_t, acl_permset_t, etc.\n" \
811 ">>> import posix1e\n" \
812 ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n" \
818 ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n" \
824 ">>> b.applyto(\"file.txt\")\n" \
825 ">>> print posix1e.ACL(file=\"file.txt\")\n" \
833 DL_EXPORT(void) initposix1e(void) {
836 ACL_Type.ob_type = &PyType_Type;
837 if(PyType_Ready(&ACL_Type) < 0)
841 Entry_Type.ob_type = &PyType_Type;
842 if(PyType_Ready(&Entry_Type) < 0)
845 Permset_Type.ob_type = &PyType_Type;
846 if(PyType_Ready(&Permset_Type) < 0)
850 m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
852 d = PyModule_GetDict(m);
856 Py_INCREF(&ACL_Type);
857 if (PyDict_SetItemString(d, "ACL",
858 (PyObject *) &ACL_Type) < 0)
861 Py_INCREF(&Entry_Type);
862 if (PyDict_SetItemString(d, "Entry",
863 (PyObject *) &Entry_Type) < 0)
866 Py_INCREF(&Permset_Type);
867 if (PyDict_SetItemString(d, "Permset",
868 (PyObject *) &Permset_Type) < 0)
871 /* 23.2.2 acl_perm_t values */
872 PyModule_AddIntConstant(m, "ACL_READ", ACL_READ);
873 PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE);
874 PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE);
876 /* 23.2.5 acl_tag_t values */
877 PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG);
878 PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ);
879 PyModule_AddIntConstant(m, "ACL_USER", ACL_USER);
880 PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ);
881 PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP);
882 PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK);
883 PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER);
885 /* 23.3.6 acl_type_t values */
886 PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS);
887 PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT);