6 staticforward PyTypeObject ACLType;
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 ACLEntryType;
26 PyObject *parent; /* The parent object, so it won't run out on us */
37 /* Creation of a new ACL instance */
38 static PyObject* ACL_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
41 newacl = type->tp_alloc(type, 0);
44 ((ACLObject*)newacl)->ob_acl = NULL;
45 ((ACLObject*)newacl)->entry_id = ACL_FIRST_ENTRY;
51 /* Initialization of a new ACL instance */
52 static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) {
53 ACLObject* self = (ACLObject*) obj;
54 static char *kwlist[] = { "file", "fd", "text", "acl", NULL };
58 ACLObject* thesrc = NULL;
61 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sisO!", kwlist,
62 &file, &fd, &text, &ACLType, &thesrc))
74 PyErr_SetString(PyExc_ValueError, "a maximum of one argument must be passed");
78 /* Free the old acl_t without checking for error, we don't
80 if(self->ob_acl != NULL)
81 acl_free(self->ob_acl);
84 self->ob_acl = acl_get_file(file, ACL_TYPE_ACCESS);
86 self->ob_acl = acl_from_text(text);
88 self->ob_acl = acl_get_fd(fd);
89 else if(thesrc != NULL)
90 self->ob_acl = acl_dup(thesrc->ob_acl);
92 self->ob_acl = acl_init(0);
94 if(self->ob_acl == NULL) {
95 PyErr_SetFromErrno(PyExc_IOError);
102 /* Standard type functions */
103 static void ACL_dealloc(PyObject* obj) {
104 ACLObject *self = (ACLObject*) obj;
105 PyObject *err_type, *err_value, *err_traceback;
106 int have_error = PyErr_Occurred() ? 1 : 0;
109 PyErr_Fetch(&err_type, &err_value, &err_traceback);
110 if(acl_free(self->ob_acl) != 0)
111 PyErr_WriteUnraisable(obj);
113 PyErr_Restore(err_type, err_value, err_traceback);
117 /* Converts the acl to a text format */
118 static PyObject* ACL_repr(PyObject *obj) {
120 ACLObject *self = (ACLObject*) obj;
123 text = acl_to_text(self->ob_acl, NULL);
125 return PyErr_SetFromErrno(PyExc_IOError);
127 ret = PyString_FromString(text);
128 if(acl_free(text) != 0) {
130 return PyErr_SetFromErrno(PyExc_IOError);
136 static char __applyto_doc__[] = \
137 "Apply the ACL to a file or filehandle.\n" \
140 " - either a filename or a file-like object or an integer; this\n" \
141 " represents the filesystem object on which to act\n" \
144 /* Applyes the ACL to a file */
145 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
146 ACLObject *self = (ACLObject*) obj;
148 int type_default = 0;
149 acl_type_t type = ACL_TYPE_ACCESS;
153 if (!PyArg_ParseTuple(args, "O|i", &myarg, &type_default))
156 type = ACL_TYPE_DEFAULT;
158 if(PyString_Check(myarg)) {
159 char *filename = PyString_AS_STRING(myarg);
160 nret = acl_set_file(filename, type, self->ob_acl);
161 } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
162 nret = acl_set_fd(fd, self->ob_acl);
164 PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int, or file-like object");
168 return PyErr_SetFromErrno(PyExc_IOError);
171 /* Return the result */
176 static char __valid_doc__[] = \
177 "Test the ACL for validity.\n" \
179 "This method tests the ACL to see if it is a valid ACL\n" \
180 "in terms of the filesystem. More precisely, it checks:\n" \
181 "A valid ACL contains exactly one entry with each of the ACL_USER_OBJ,\n" \
182 "ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and\n" \
183 "ACL_GROUP tag types may appear zero or more times in an ACL. An ACL that\n" \
184 "contains entries of ACL_USER or ACL_GROUP tag types must contain exactly\n" \
185 "one entry of the ACL_MASK tag type. If an ACL contains no entries of\n" \
186 "ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n" \
188 "All user ID qualifiers must be unique among all entries of ACL_USER tag\n" \
189 "type, and all group IDs must be unique among all entries of ACL_GROUP tag\n" \
193 /* Checks the ACL for validity */
194 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
195 ACLObject *self = (ACLObject*) obj;
197 if(acl_valid(self->ob_acl) == -1) {
198 return PyErr_SetFromErrno(PyExc_IOError);
201 /* Return the result */
208 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
209 ACLObject *self = (ACLObject*) obj;
214 size = acl_size(self->ob_acl);
216 return PyErr_SetFromErrno(PyExc_IOError);
218 if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
220 buf = PyString_AsString(ret);
222 if((nsize = acl_copy_ext(buf, self->ob_acl, size)) == -1) {
224 return PyErr_SetFromErrno(PyExc_IOError);
230 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
231 ACLObject *self = (ACLObject*) obj;
236 /* Parse the argument */
237 if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
240 /* Try to import the external representation */
241 if((ptr = acl_copy_int(buf)) == NULL)
242 return PyErr_SetFromErrno(PyExc_IOError);
244 /* Free the old acl. Should we ignore errors here? */
245 if(self->ob_acl != NULL) {
246 if(acl_free(self->ob_acl) == -1)
247 return PyErr_SetFromErrno(PyExc_IOError);
252 /* Return the result */
257 static PyObject* ACL_iter(PyObject *obj) {
258 ACLObject *self = (ACLObject*)obj;
259 self->entry_id = ACL_FIRST_ENTRY;
264 static PyObject* ACL_iternext(PyObject *obj) {
265 ACLObject *self = (ACLObject*)obj;
266 acl_entry_t the_entry_t;
267 ACLEntryObject *the_entry_obj;
270 if((nerr = acl_get_entry(self->ob_acl, self->entry_id, &the_entry_t)) == -1)
271 return PyErr_SetFromErrno(PyExc_IOError);
272 self->entry_id = ACL_NEXT_ENTRY;
274 PyErr_SetObject(PyExc_StopIteration, Py_None);
278 the_entry_obj = (ACLEntryObject*) PyType_GenericNew(&ACLEntryType, NULL, NULL);
279 if(the_entry_obj == NULL)
282 the_entry_obj->ob_entry = the_entry_t;
284 the_entry_obj->parent = obj;
285 Py_INCREF(obj); /* For the reference we have in entry->parent */
287 return (PyObject*)the_entry_obj;
290 /* Creation of a new ACLEntry instance */
291 static PyObject* ACLEntry_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
294 newentry = PyType_GenericNew(type, args, keywds);
296 if(newentry != NULL) {
297 ((ACLEntryObject*)newentry)->ob_entry = NULL;
298 ((ACLEntryObject*)newentry)->parent = NULL;
304 /* Initialization of a new ACLEntry instance */
305 static int ACLEntry_init(PyObject* obj, PyObject* args, PyObject *keywds) {
306 ACLEntryObject* self = (ACLEntryObject*) obj;
307 ACLObject* parent = NULL;
309 if (!PyArg_ParseTuple(args, "O!", &ACLType, &parent))
312 /* Free the old acl_entry_t without checking for error, we don't
314 if(self->ob_entry != NULL)
315 acl_free(self->ob_entry);
317 if(acl_create_entry(&parent->ob_acl, &self->ob_entry) == -1) {
318 PyErr_SetFromErrno(PyExc_IOError);
322 self->parent = (PyObject*)parent;
328 /* Free the ACLEntry instance */
329 static void ACLEntry_dealloc(PyObject* obj) {
330 ACLEntryObject *self = (ACLEntryObject*) obj;
331 PyObject *err_type, *err_value, *err_traceback;
332 int have_error = PyErr_Occurred() ? 1 : 0;
335 PyErr_Fetch(&err_type, &err_value, &err_traceback);
336 if(self->parent != NULL) {
337 Py_DECREF(self->parent);
341 PyErr_Restore(err_type, err_value, err_traceback);
345 static int ACLEntry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
346 ACLEntryObject *self = (ACLEntryObject*) obj;
349 PyErr_SetString(PyExc_TypeError,
350 "tag type deletion is not supported");
354 if(!PyInt_Check(value)) {
355 PyErr_SetString(PyExc_TypeError,
356 "tag type must be integer");
359 if(acl_set_tag_type(self->ob_entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
360 PyErr_SetFromErrno(PyExc_IOError);
367 static PyObject* ACLEntry_get_tag_type(PyObject *obj, void* arg) {
368 ACLEntryObject *self = (ACLEntryObject*) obj;
371 if (self->ob_entry == NULL) {
372 PyErr_SetString(PyExc_AttributeError, "entry attribute");
375 if(acl_get_tag_type(self->ob_entry, &value) == -1) {
376 PyErr_SetFromErrno(PyExc_IOError);
380 return PyInt_FromLong(value);
383 static int ACLEntry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
384 ACLEntryObject *self = (ACLEntryObject*) obj;
388 PyErr_SetString(PyExc_TypeError,
389 "qualifier deletion is not supported");
393 if(!PyInt_Check(value)) {
394 PyErr_SetString(PyExc_TypeError,
395 "tag type must be integer");
398 uidgid = PyInt_AsLong(value);
399 if(acl_set_qualifier(self->ob_entry, (void*)&uidgid) == -1) {
400 PyErr_SetFromErrno(PyExc_IOError);
407 static PyObject* ACLEntry_get_qualifier(PyObject *obj, void* arg) {
408 ACLEntryObject *self = (ACLEntryObject*) obj;
412 if (self->ob_entry == NULL) {
413 PyErr_SetString(PyExc_AttributeError, "entry attribute");
416 if((p = acl_get_qualifier(self->ob_entry)) == NULL) {
417 PyErr_SetFromErrno(PyExc_IOError);
422 return PyInt_FromLong(value);
425 static PyObject* ACLEntry_get_parent(PyObject *obj, void* arg) {
426 ACLEntryObject *self = (ACLEntryObject*) obj;
428 Py_INCREF(self->parent);
434 static char __acltype_doc__[] = \
435 "Type which represents a POSIX ACL\n" \
438 " Only one keword parameter should be provided:\n"
439 " - file=\"...\", meaning create ACL representing\n"
440 " the ACL of that file\n" \
441 " - fd=<int>, meaning create ACL representing\n" \
442 " the ACL of that file descriptor\n" \
443 " - text=\"...\", meaning create ACL from a \n" \
444 " textual description\n" \
445 " - acl=<ACL instance>, meaning create a copy\n" \
446 " of an existing ACL instance\n" \
449 /* ACL type methods */
450 static PyMethodDef ACL_methods[] = {
451 {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
452 {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
454 {"__getstate__", ACL_get_state, METH_NOARGS, "Dumps the ACL to an external format."},
455 {"__setstate__", ACL_set_state, METH_VARARGS, "Loads the ACL from an external format."},
457 {NULL, NULL, 0, NULL}
461 /* The definition of the ACL Type */
462 static PyTypeObject ACLType = {
463 PyObject_HEAD_INIT(NULL)
468 ACL_dealloc, /* tp_dealloc */
473 ACL_repr, /* tp_repr */
474 0, /* tp_as_number */
475 0, /* tp_as_sequence */
476 0, /* tp_as_mapping */
482 0, /* tp_as_buffer */
483 Py_TPFLAGS_DEFAULT, /* tp_flags */
484 __acltype_doc__, /* tp_doc */
487 0, /* tp_richcompare */
488 0, /* tp_weaklistoffset */
496 ACL_methods, /* tp_methods */
501 0, /* tp_descr_get */
502 0, /* tp_descr_set */
503 0, /* tp_dictoffset */
504 ACL_init, /* tp_init */
506 ACL_new, /* tp_new */
511 /* ACLEntry type methods */
512 static PyMethodDef ACLEntry_methods[] = {
513 {NULL, NULL, 0, NULL}
516 static char __ACLEntry_tagtype_doc__[] = \
517 "The tag type of the current entry\n" \
519 "This is one of:\n" \
520 " - ACL_UNDEFINED_TAG\n" \
521 " - ACL_USER_OBJ\n" \
523 " - ACL_GROUP_OBJ\n" \
529 static char __ACLEntry_qualifier_doc__[] = \
530 "The qualifier of the current entry\n" \
532 "If the tag type is ACL_USER, this should be a user id.\n" \
533 "If the tag type if ACL_GROUP, this should be a group id.\n" \
534 "Else, it doesn't matter.\n" \
537 static char __ACLEntry_parent_doc__[] = \
538 "The parent ACL of this entry\n" \
541 /* ACLEntry getset */
542 static PyGetSetDef ACLEntry_getsets[] = {
543 {"tag_type", ACLEntry_get_tag_type, ACLEntry_set_tag_type, __ACLEntry_tagtype_doc__},
544 {"qualifier", ACLEntry_get_qualifier, ACLEntry_set_qualifier, __ACLEntry_qualifier_doc__},
545 {"parent", ACLEntry_get_parent, NULL, __ACLEntry_parent_doc__},
549 /* The definition of the ACL Entry Type */
550 static PyTypeObject ACLEntryType = {
551 PyObject_HEAD_INIT(NULL)
554 sizeof(ACLEntryObject),
556 ACLEntry_dealloc, /* tp_dealloc */
561 0, //ACLEntry_repr, /* tp_repr */
562 0, /* tp_as_number */
563 0, /* tp_as_sequence */
564 0, /* tp_as_mapping */
570 0, /* tp_as_buffer */
571 Py_TPFLAGS_DEFAULT, /* tp_flags */
572 __acltype_doc__, /* tp_doc */
575 0, /* tp_richcompare */
576 0, /* tp_weaklistoffset */
579 ACLEntry_methods, /* tp_methods */
581 ACLEntry_getsets, /* tp_getset */
584 0, /* tp_descr_get */
585 0, /* tp_descr_set */
586 0, /* tp_dictoffset */
587 ACLEntry_init, /* tp_init */
589 ACLEntry_new, /* tp_new */
596 static char __deletedef_doc__[] = \
597 "Delete the default ACL from a directory.\n" \
599 "This function deletes the default ACL associated with \n" \
600 "a directory (the ACL which will be ANDed with the mode\n" \
601 "parameter to the open, creat functions).\n" \
603 " - a string representing the directory whose default ACL\n" \
604 " should be deleted\n" \
607 /* Deletes the default ACL from a directory */
608 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
611 /* Parse the arguments */
612 if (!PyArg_ParseTuple(args, "s", &filename))
615 if(acl_delete_def_file(filename) == -1) {
616 return PyErr_SetFromErrno(PyExc_IOError);
619 /* Return the result */
624 /* The module methods */
625 static PyMethodDef aclmodule_methods[] = {
626 {"delete_default", aclmodule_delete_default, METH_VARARGS, __deletedef_doc__},
627 {NULL, NULL, 0, NULL}
630 static char __posix1e_doc__[] = \
631 "POSIX.1e ACLs manipulation\n" \
633 "This module provides support for manipulating POSIX.1e ACLS\n" \
635 "Depending on the operating system support for POSIX.1e, \n" \
636 "the ACL type will have more or less capabilities:\n" \
637 " - level 1, only basic support, you can create\n" \
638 " ACLs from files and text descriptions;\n" \
639 " once created, the type is immutable\n" \
640 " - level 2, complete support, you can alter\n"\
641 " the ACL once it is created\n" \
643 "Also, in level 2, more types will be available, corresponding\n" \
644 "to acl_entry_t, acl_permset_t, etc.\n" \
647 ">>> import posix1e\n" \
648 ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n" \
654 ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n" \
660 ">>> b.applyto(\"file.txt\")\n" \
661 ">>> print posix1e.ACL(file=\"file.txt\")\n" \
669 DL_EXPORT(void) initposix1e(void) {
672 ACLType.ob_type = &PyType_Type;
674 if(PyType_Ready(&ACLType) < 0)
678 ACLEntryType.ob_type = &PyType_Type;
680 if(PyType_Ready(&ACLEntryType) < 0)
684 m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
686 d = PyModule_GetDict(m);
691 if (PyDict_SetItemString(d, "ACL",
692 (PyObject *) &ACLType) < 0)
695 Py_INCREF(&ACLEntryType);
696 if (PyDict_SetItemString(d, "ACLEntry",
697 (PyObject *) &ACLEntryType) < 0)
700 /* 23.2.2 acl_perm_t values */
701 PyModule_AddIntConstant(m, "ACL_READ", ACL_READ);
702 PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE);
703 PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE);
705 /* 23.2.5 acl_tag_t values */
706 PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG);
707 PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ);
708 PyModule_AddIntConstant(m, "ACL_USER", ACL_USER);
709 PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ);
710 PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP);
711 PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK);
712 PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER);
714 /* 23.3.6 acl_type_t values */
715 PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS);
716 PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT);