]> git.k1024.org Git - pylibacl.git/blob - acl.c
Enhance the unittest
[pylibacl.git] / acl.c
1 #include <Python.h>
2
3 #include <sys/types.h>
4 #include <sys/acl.h>
5
6 #ifdef HAVE_LINUX
7 #include "os_linux.c"
8 #endif
9
10 staticforward PyTypeObject ACL_Type;
11 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
12 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
13
14 #ifdef HAVE_LEVEL2
15 static PyObject* ACL_get_state(PyObject *obj, PyObject* args);
16 static PyObject* ACL_set_state(PyObject *obj, PyObject* args);
17
18 staticforward PyTypeObject Entry_Type;
19 staticforward PyTypeObject Permset_Type;
20 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
21                              PyObject *keywds);
22 #endif
23
24 static acl_perm_t holder_ACL_EXECUTE = ACL_EXECUTE;
25 static acl_perm_t holder_ACL_READ = ACL_READ;
26 static acl_perm_t holder_ACL_WRITE = ACL_WRITE;
27
28 typedef struct {
29     PyObject_HEAD
30     acl_t acl;
31 #ifdef HAVE_LEVEL2
32     int entry_id;
33 #endif
34 } ACL_Object;
35
36 #ifdef HAVE_LEVEL2
37
38 typedef struct {
39     PyObject_HEAD
40     PyObject *parent_acl; /* The parent acl, so it won't run out on us */
41     acl_entry_t entry;
42 } Entry_Object;
43
44 typedef struct {
45     PyObject_HEAD
46     PyObject *parent_entry; /* The parent entry, so it won't run out on us */
47     acl_permset_t permset;
48 } Permset_Object;
49
50 #endif
51
52 /* Creation of a new ACL instance */
53 static PyObject* ACL_new(PyTypeObject* type, PyObject* args,
54                          PyObject *keywds) {
55     PyObject* newacl;
56
57     newacl = type->tp_alloc(type, 0);
58
59     if(newacl != NULL) {
60         ((ACL_Object*)newacl)->acl = NULL;
61 #ifdef HAVEL_LEVEL2
62         ((ACL_Object*)newacl)->entry_id = ACL_FIRST_ENTRY;
63 #endif
64     }
65
66     return newacl;
67 }
68
69 /* Initialization of a new ACL instance */
70 static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) {
71     ACL_Object* self = (ACL_Object*) obj;
72 #ifdef HAVE_LINUX
73     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef",
74                               "mode", NULL };
75     char *format = "|sisO!sH";
76     mode_t mode = 0;
77 #else
78     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", NULL };
79     char *format = "|sisO!s";
80 #endif
81     char *file = NULL;
82     char *filedef = NULL;
83     char *text = NULL;
84     int fd = -1;
85     ACL_Object* thesrc = NULL;
86
87     if(!PyTuple_Check(args) || PyTuple_Size(args) != 0 ||
88        (keywds != NULL && PyDict_Check(keywds) && PyDict_Size(keywds) > 1)) {
89         PyErr_SetString(PyExc_ValueError, "a max of one keyword argument"
90                         " must be passed");
91         return -1;
92     }
93     if(!PyArg_ParseTupleAndKeywords(args, keywds, format, kwlist,
94                                     &file, &fd, &text, &ACL_Type,
95                                     &thesrc, &filedef
96 #ifdef HAVE_LINUX
97                                     , &mode
98 #endif
99                                     ))
100         return -1;
101
102     /* Free the old acl_t without checking for error, we don't
103      * care right now */
104     if(self->acl != NULL)
105         acl_free(self->acl);
106
107     if(file != NULL)
108         self->acl = acl_get_file(file, ACL_TYPE_ACCESS);
109     else if(text != NULL)
110         self->acl = acl_from_text(text);
111     else if(fd != -1)
112         self->acl = acl_get_fd(fd);
113     else if(thesrc != NULL)
114         self->acl = acl_dup(thesrc->acl);
115     else if(filedef != NULL)
116         self->acl = acl_get_file(filedef, ACL_TYPE_DEFAULT);
117 #ifdef HAVE_LINUX
118     else if(PyMapping_HasKeyString(keywds, kwlist[5]))
119         self->acl = acl_from_mode(mode);
120 #endif
121     else
122         self->acl = acl_init(0);
123
124     if(self->acl == NULL) {
125         PyErr_SetFromErrno(PyExc_IOError);
126         return -1;
127     }
128
129     return 0;
130 }
131
132 /* Standard type functions */
133 static void ACL_dealloc(PyObject* obj) {
134     ACL_Object *self = (ACL_Object*) obj;
135     PyObject *err_type, *err_value, *err_traceback;
136     int have_error = PyErr_Occurred() ? 1 : 0;
137
138     if (have_error)
139         PyErr_Fetch(&err_type, &err_value, &err_traceback);
140     if(self->acl != NULL && acl_free(self->acl) != 0)
141         PyErr_WriteUnraisable(obj);
142     if (have_error)
143         PyErr_Restore(err_type, err_value, err_traceback);
144     PyObject_DEL(self);
145 }
146
147 /* Converts the acl to a text format */
148 static PyObject* ACL_str(PyObject *obj) {
149     char *text;
150     ACL_Object *self = (ACL_Object*) obj;
151     PyObject *ret;
152
153     text = acl_to_text(self->acl, NULL);
154     if(text == NULL) {
155         return PyErr_SetFromErrno(PyExc_IOError);
156     }
157     ret = PyString_FromString(text);
158     if(acl_free(text) != 0) {
159         Py_DECREF(ret);
160         return PyErr_SetFromErrno(PyExc_IOError);
161     }
162     return ret;
163 }
164
165 #ifdef HAVE_LINUX
166 static char __to_any_text_doc__[] =
167   "Convert the ACL to a custom text format.\n"
168   "\n"
169   "This method encapsulates the acl_to_any_text function. It allows a \n"
170   "customized text format to be generated for the ACL. See\n"
171   "acl_to_any_text(3) for more details.\n"
172   "\n"
173   "Parameters:\n"
174   "  - prefix: if given, this string will be prepended to all lines\n"
175   "  - separator: a single character (defaults to '\\n'); this will be\n"
176   "               user to separate the entries in the ACL\n"
177   "  - options: a bitwise combination of:\n"
178   "      TEXT_ABBREVIATE: use 'u' instead of 'user', 'g' instead of \n"
179   "                       'group', etc.\n"
180   "      TEXT_NUMERIC_IDS: User and group IDs are included as decimal\n"
181   "                        numbers instead of names\n"
182   "      TEXT_SOME_EFFECTIVE: Include comments denoting the effective\n"
183   "                           permissions when some are masked\n"
184   "      TEXT_ALL_EFFECTIVE: Include comments after all ACL entries\n"
185   "                          affected by an ACL_MASK entry\n"
186   "      TEXT_SMART_INDENT: Used in combination with the _EFFECTIVE\n"
187   "                         options, this will ensure that comments \n"
188   "                         are alligned to the fourth tab position\n"
189   "                         (assuming one tab equal eight spaces\n"
190   ;
191
192 /* Converts the acl to a custom text format */
193 static PyObject* ACL_to_any_text(PyObject *obj, PyObject *args,
194                                  PyObject *kwds) {
195     char *text;
196     ACL_Object *self = (ACL_Object*) obj;
197     PyObject *ret;
198     char *arg_prefix = NULL;
199     char arg_separator = '\n';
200     int arg_options = 0;
201     static char *kwlist[] = {"prefix", "separator", "options", NULL};
202
203     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sci", kwlist, &arg_prefix,
204                                      &arg_separator, &arg_options))
205       return NULL;
206
207     text = acl_to_any_text(self->acl, arg_prefix, arg_separator, arg_options);
208     if(text == NULL) {
209         return PyErr_SetFromErrno(PyExc_IOError);
210     }
211     ret = PyString_FromString(text);
212     if(acl_free(text) != 0) {
213         Py_DECREF(ret);
214         return PyErr_SetFromErrno(PyExc_IOError);
215     }
216     return ret;
217 }
218
219 static char __check_doc__[] =
220     "Check the ACL validity.\n"
221     "\n"
222     "This is a non-portable, Linux specific extension that allow more\n"
223     "information to be retrieved in case an ACL is not valid than the\n"
224     "validate() method.\n"
225     "\n"
226     "This method will return either False (the ACL is valid), or a tuple\n"
227     "with two elements. The first element is one of the following\n"
228     "constants:\n"
229     "  - ACL_MULTI_ERROR: The ACL contains multiple entries that have a\n"
230     "                     tag type that may occur at most once\n"
231     "  - ACL_DUPLICATE_ERROR: The ACL contains multiple ACL_USER or \n"
232     "                         ACL_GROUP entries  with the same ID\n"
233     "  - ACL_MISS_ERROR: A required entry is missing\n"
234     "  - ACL_ENTRY_ERROR: The ACL contains an invalid entry tag type\n"
235     "\n"
236     "The second element of the tuple is the index of the entry that is\n"
237     "invalid (in the same order as by iterating over the ACL entry)\n"
238     ;
239
240 /* The acl_check method */
241 static PyObject* ACL_check(PyObject* obj, PyObject* args) {
242     ACL_Object *self = (ACL_Object*) obj;
243     int result;
244     int eindex;
245
246     if((result = acl_check(self->acl, &eindex)) == -1)
247         return PyErr_SetFromErrno(PyExc_IOError);
248     if(result == 0) {
249         Py_INCREF(Py_False);
250         return Py_False;
251     }
252     return PyTuple_Pack(2, PyInt_FromLong(result), PyInt_FromLong(eindex));
253 }
254
255 /* Implementation of the rich compare for ACLs */
256 static PyObject* ACL_richcompare(PyObject* o1, PyObject* o2, int op) {
257     ACL_Object *acl1, *acl2;
258     int n;
259     PyObject *ret;
260
261     if(!PyObject_IsInstance(o2, (PyObject*)&ACL_Type)) {
262         if(op == Py_EQ)
263             Py_RETURN_FALSE;
264         if(op == Py_NE)
265             Py_RETURN_TRUE;
266         PyErr_SetString(PyExc_TypeError, "can only compare to an ACL");
267         return NULL;
268     }
269
270     acl1 = (ACL_Object*)o1;
271     acl2 = (ACL_Object*)o2;
272     if((n=acl_cmp(acl1->acl, acl2->acl))==-1)
273         return PyErr_SetFromErrno(PyExc_IOError);
274     switch(op) {
275     case Py_EQ:
276         ret = n == 0 ? Py_True : Py_False;
277         break;
278     case Py_NE:
279         ret = n == 1 ? Py_True : Py_False;
280         break;
281     default:
282         ret = Py_NotImplemented;
283     }
284     Py_INCREF(ret);
285     return ret;
286 }
287 #endif
288
289 /* Implementation of the compare for ACLs */
290 static int ACL_nocmp(PyObject* o1, PyObject* o2) {
291
292     PyErr_SetString(PyExc_TypeError, "cannot compare ACLs using cmp()");
293     return -1;
294 }
295
296 /* Custom methods */
297 static char __applyto_doc__[] =
298     "Apply the ACL to a file or filehandle.\n"
299     "\n"
300     "Parameters:\n"
301     "  - either a filename or a file-like object or an integer; this\n"
302     "    represents the filesystem object on which to act\n"
303     "  - optional flag representing the type of ACL to set, either\n"
304     "    ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT\n"
305     ;
306
307 /* Applyes the ACL to a file */
308 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
309     ACL_Object *self = (ACL_Object*) obj;
310     PyObject *myarg;
311     acl_type_t type = ACL_TYPE_ACCESS;
312     int nret;
313     int fd;
314
315     if (!PyArg_ParseTuple(args, "O|i", &myarg, &type))
316         return NULL;
317
318     if(PyString_Check(myarg)) {
319         char *filename = PyString_AS_STRING(myarg);
320         nret = acl_set_file(filename, type, self->acl);
321     } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
322         nret = acl_set_fd(fd, self->acl);
323     } else {
324         PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int,"
325                         " or file-like object");
326         return 0;
327     }
328     if(nret == -1) {
329         return PyErr_SetFromErrno(PyExc_IOError);
330     }
331
332     /* Return the result */
333     Py_INCREF(Py_None);
334     return Py_None;
335 }
336
337 static char __valid_doc__[] =
338     "Test the ACL for validity.\n"
339     "\n"
340     "This method tests the ACL to see if it is a valid ACL\n"
341     "in terms of the filesystem. More precisely, it checks that:\n"
342     "\n"
343     "The ACL contains exactly one entry with each of the\n"
344     "ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries\n"
345     "with ACL_USER and ACL_GROUP tag types may appear zero or more\n"
346     "times in an ACL. An ACL that contains entries of ACL_USER or\n"
347     "ACL_GROUP tag types must contain exactly one entry of the \n"
348     "ACL_MASK tag type. If an ACL contains no entries of\n"
349     "ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n"
350     "\n"
351     "All user ID qualifiers must be unique among all entries of\n"
352     "the ACL_USER tag type, and all group IDs must be unique among all\n"
353     "entries of ACL_GROUP tag type.\n"
354     "\n"
355     "The method will return 1 for a valid ACL and 0 for an invalid one.\n"
356     "This has been chosen because the specification for acl_valid in\n"
357     "the POSIX.1e standard documents only one possible value for errno\n"
358     "in case of an invalid ACL, so we can't differentiate between\n"
359     "classes of errors. Other suggestions are welcome.\n"
360     ;
361
362 /* Checks the ACL for validity */
363 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
364     ACL_Object *self = (ACL_Object*) obj;
365
366     if(acl_valid(self->acl) == -1) {
367         Py_INCREF(Py_False);
368         return Py_False;
369     } else {
370         Py_INCREF(Py_True);
371         return Py_True;
372     }
373 }
374
375 #ifdef HAVE_LEVEL2
376
377 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
378     ACL_Object *self = (ACL_Object*) obj;
379     PyObject *ret;
380     ssize_t size, nsize;
381     char *buf;
382
383     size = acl_size(self->acl);
384     if(size == -1)
385         return PyErr_SetFromErrno(PyExc_IOError);
386
387     if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
388         return NULL;
389     buf = PyString_AsString(ret);
390
391     if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) {
392         Py_DECREF(ret);
393         return PyErr_SetFromErrno(PyExc_IOError);
394     }
395
396     return ret;
397 }
398
399 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
400     ACL_Object *self = (ACL_Object*) obj;
401     const void *buf;
402     int bufsize;
403     acl_t ptr;
404
405     /* Parse the argument */
406     if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
407         return NULL;
408
409     /* Try to import the external representation */
410     if((ptr = acl_copy_int(buf)) == NULL)
411         return PyErr_SetFromErrno(PyExc_IOError);
412
413     /* Free the old acl. Should we ignore errors here? */
414     if(self->acl != NULL) {
415         if(acl_free(self->acl) == -1)
416             return PyErr_SetFromErrno(PyExc_IOError);
417     }
418
419     self->acl = ptr;
420
421     /* Return the result */
422     Py_INCREF(Py_None);
423     return Py_None;
424 }
425
426 /* tp_iter for the ACL type; since it can be iterated only
427  * destructively, the type is its iterator
428  */
429 static PyObject* ACL_iter(PyObject *obj) {
430     ACL_Object *self = (ACL_Object*)obj;
431     self->entry_id = ACL_FIRST_ENTRY;
432     Py_INCREF(obj);
433     return obj;
434 }
435
436 /* the tp_iternext function for the ACL type */
437 static PyObject* ACL_iternext(PyObject *obj) {
438     ACL_Object *self = (ACL_Object*)obj;
439     acl_entry_t the_entry_t;
440     Entry_Object *the_entry_obj;
441     int nerr;
442
443     nerr = acl_get_entry(self->acl, self->entry_id, &the_entry_t);
444     self->entry_id = ACL_NEXT_ENTRY;
445     if(nerr == -1)
446         return PyErr_SetFromErrno(PyExc_IOError);
447     else if(nerr == 0) {
448         /* Docs says this is not needed */
449         /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/
450         return NULL;
451     }
452
453     the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL);
454     if(the_entry_obj == NULL)
455         return NULL;
456
457     the_entry_obj->entry = the_entry_t;
458
459     the_entry_obj->parent_acl = obj;
460     Py_INCREF(obj); /* For the reference we have in entry->parent */
461
462     return (PyObject*)the_entry_obj;
463 }
464
465 static char __ACL_delete_entry_doc__[] =
466     "Deletes an entry from the ACL.\n"
467     "\n"
468     "Note: Only with level 2\n"
469     "Parameters:\n"
470     " - the Entry object which should be deleted; note that after\n"
471     "   this function is called, that object is unusable any longer\n"
472     "   and should be deleted\n"
473     ;
474
475 /* Deletes an entry from the ACL */
476 static PyObject* ACL_delete_entry(PyObject *obj, PyObject *args) {
477     ACL_Object *self = (ACL_Object*)obj;
478     Entry_Object *e;
479
480     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &e))
481         return NULL;
482
483     if(acl_delete_entry(self->acl, e->entry) == -1)
484         return PyErr_SetFromErrno(PyExc_IOError);
485
486     /* Return the result */
487     Py_INCREF(Py_None);
488     return Py_None;
489 }
490
491 static char __ACL_calc_mask_doc__[] =
492     "Compute the file group class mask.\n"
493     "\n"
494     "The calc_mask() method calculates and sets the permissions \n"
495     "associated with the ACL_MASK Entry of the ACL.\n"
496     "The value of the new permissions is the union of the permissions \n"
497     "granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or \n"
498     "ACL_USER.  If the ACL already contains an ACL_MASK entry, its \n"
499     "permissions are overwritten; if it does not contain an ACL_MASK \n"
500     "Entry, one is added.\n"
501     "\n"
502     "The order of existing entries in the ACL is undefined after this \n"
503     "function.\n"
504     ;
505
506 /* Updates the mask entry in the ACL */
507 static PyObject* ACL_calc_mask(PyObject *obj, PyObject *args) {
508     ACL_Object *self = (ACL_Object*)obj;
509
510     if(acl_calc_mask(&self->acl) == -1)
511         return PyErr_SetFromErrno(PyExc_IOError);
512
513     /* Return the result */
514     Py_INCREF(Py_None);
515     return Py_None;
516 }
517
518 static char __ACL_append_doc__[] =
519     "Append a new Entry to the ACL and return it.\n"
520     "\n"
521     "This is a convenience function to create a new Entry \n"
522     "and append it to the ACL.\n"
523     "If a parameter of type Entry instance is given, the \n"
524     "entry will be a copy of that one (as if copied with \n"
525     "Entry.copy()), otherwise, the new entry will be empty.\n"
526     ;
527
528 /* Convenience method to create a new Entry */
529 static PyObject* ACL_append(PyObject *obj, PyObject *args) {
530     ACL_Object* self = (ACL_Object*) obj;
531     Entry_Object* newentry;
532     Entry_Object* oldentry = NULL;
533     int nret;
534
535     newentry = (Entry_Object*)PyType_GenericNew(&Entry_Type, NULL, NULL);
536     if(newentry == NULL) {
537         return NULL;
538     }
539
540     if (!PyArg_ParseTuple(args, "|O!", &Entry_Type, &oldentry))
541         return NULL;
542
543     nret = acl_create_entry(&self->acl, &newentry->entry);
544     if(nret == -1) {
545         Py_DECREF(newentry);
546         return PyErr_SetFromErrno(PyExc_IOError);
547     }
548
549     if(oldentry != NULL) {
550         nret = acl_copy_entry(newentry->entry, oldentry->entry);
551         if(nret == -1) {
552             Py_DECREF(newentry);
553             return PyErr_SetFromErrno(PyExc_IOError);
554         }
555     }
556
557     newentry->parent_acl = obj;
558     Py_INCREF(obj);
559
560     return (PyObject*)newentry;
561 }
562
563 /***** Entry type *****/
564
565 /* Creation of a new Entry instance */
566 static PyObject* Entry_new(PyTypeObject* type, PyObject* args,
567                            PyObject *keywds) {
568     PyObject* newentry;
569
570     newentry = PyType_GenericNew(type, args, keywds);
571
572     if(newentry != NULL) {
573         ((Entry_Object*)newentry)->entry = NULL;
574         ((Entry_Object*)newentry)->parent_acl = NULL;
575     }
576
577     return newentry;
578 }
579
580 /* Initialization of a new Entry instance */
581 static int Entry_init(PyObject* obj, PyObject* args, PyObject *keywds) {
582     Entry_Object* self = (Entry_Object*) obj;
583     ACL_Object* parent = NULL;
584
585     if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent))
586         return -1;
587
588     if(acl_create_entry(&parent->acl, &self->entry) == -1) {
589         PyErr_SetFromErrno(PyExc_IOError);
590         return -1;
591     }
592
593     self->parent_acl = (PyObject*)parent;
594     Py_INCREF(parent);
595
596     return 0;
597 }
598
599 /* Free the Entry instance */
600 static void Entry_dealloc(PyObject* obj) {
601     Entry_Object *self = (Entry_Object*) obj;
602     PyObject *err_type, *err_value, *err_traceback;
603     int have_error = PyErr_Occurred() ? 1 : 0;
604
605     if (have_error)
606         PyErr_Fetch(&err_type, &err_value, &err_traceback);
607     if(self->parent_acl != NULL) {
608         Py_DECREF(self->parent_acl);
609         self->parent_acl = NULL;
610     }
611     if (have_error)
612         PyErr_Restore(err_type, err_value, err_traceback);
613     PyObject_DEL(self);
614 }
615
616 /* Converts the entry to a text format */
617 static PyObject* Entry_str(PyObject *obj) {
618     acl_tag_t tag;
619     uid_t qualifier;
620     void *p;
621     PyObject *ret;
622     PyObject *format, *list;
623     Entry_Object *self = (Entry_Object*) obj;
624
625     if(acl_get_tag_type(self->entry, &tag) == -1) {
626         PyErr_SetFromErrno(PyExc_IOError);
627         return NULL;
628     }
629     if(tag == ACL_USER || tag == ACL_GROUP) {
630         if((p = acl_get_qualifier(self->entry)) == NULL) {
631             PyErr_SetFromErrno(PyExc_IOError);
632             return NULL;
633         }
634         qualifier = *(uid_t*)p;
635         acl_free(p);
636     } else {
637         qualifier = 0;
638     }
639
640     format = PyString_FromString("ACL entry for %s");
641     if(format == NULL)
642         return NULL;
643     list = PyTuple_New(1);
644     if(tag == ACL_UNDEFINED_TAG) {
645         PyTuple_SetItem(list, 0, PyString_FromString("undefined type"));
646     } else if(tag == ACL_USER_OBJ) {
647         PyTuple_SetItem(list, 0, PyString_FromString("the owner"));
648     } else if(tag == ACL_GROUP_OBJ) {
649         PyTuple_SetItem(list, 0, PyString_FromString("the group"));
650     } else if(tag == ACL_OTHER) {
651         PyTuple_SetItem(list, 0, PyString_FromString("the others"));
652     } else if(tag == ACL_USER) {
653         PyTuple_SetItem(list, 0, PyString_FromFormat("user with uid %d",
654                                                      qualifier));
655     } else if(tag == ACL_GROUP) {
656         PyTuple_SetItem(list, 0, PyString_FromFormat("group with gid %d",
657                                                      qualifier));
658     } else if(tag == ACL_MASK) {
659         PyTuple_SetItem(list, 0, PyString_FromString("the mask"));
660     } else {
661         PyTuple_SetItem(list, 0, PyString_FromString("UNKNOWN_TAG_TYPE!"));
662     }
663     ret = PyString_Format(format, list);
664     Py_DECREF(format);
665     Py_DECREF(list);
666     return ret;
667 }
668
669 /* Sets the tag type of the entry */
670 static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
671     Entry_Object *self = (Entry_Object*) obj;
672
673     if(value == NULL) {
674         PyErr_SetString(PyExc_TypeError,
675                         "tag type deletion is not supported");
676         return -1;
677     }
678
679     if(!PyInt_Check(value)) {
680         PyErr_SetString(PyExc_TypeError,
681                         "tag type must be integer");
682         return -1;
683     }
684     if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
685         PyErr_SetFromErrno(PyExc_IOError);
686         return -1;
687     }
688
689     return 0;
690 }
691
692 /* Returns the tag type of the entry */
693 static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) {
694     Entry_Object *self = (Entry_Object*) obj;
695     acl_tag_t value;
696
697     if (self->entry == NULL) {
698         PyErr_SetString(PyExc_AttributeError, "entry attribute");
699         return NULL;
700     }
701     if(acl_get_tag_type(self->entry, &value) == -1) {
702         PyErr_SetFromErrno(PyExc_IOError);
703         return NULL;
704     }
705
706     return PyInt_FromLong(value);
707 }
708
709 /* Sets the qualifier (either uid_t or gid_t) for the entry,
710  * usable only if the tag type if ACL_USER or ACL_GROUP
711  */
712 static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
713     Entry_Object *self = (Entry_Object*) obj;
714     int uidgid;
715
716     if(value == NULL) {
717         PyErr_SetString(PyExc_TypeError,
718                         "qualifier deletion is not supported");
719         return -1;
720     }
721
722     if(!PyInt_Check(value)) {
723         PyErr_SetString(PyExc_TypeError,
724                         "tag type must be integer");
725         return -1;
726     }
727     uidgid = PyInt_AsLong(value);
728     if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) {
729         PyErr_SetFromErrno(PyExc_IOError);
730         return -1;
731     }
732
733     return 0;
734 }
735
736 /* Returns the qualifier of the entry */
737 static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) {
738     Entry_Object *self = (Entry_Object*) obj;
739     void *p;
740     int value;
741
742     if (self->entry == NULL) {
743         PyErr_SetString(PyExc_AttributeError, "entry attribute");
744         return NULL;
745     }
746     if((p = acl_get_qualifier(self->entry)) == NULL) {
747         PyErr_SetFromErrno(PyExc_IOError);
748         return NULL;
749     }
750     value = *(uid_t*)p;
751     acl_free(p);
752
753     return PyInt_FromLong(value);
754 }
755
756 /* Returns the parent ACL of the entry */
757 static PyObject* Entry_get_parent(PyObject *obj, void* arg) {
758     Entry_Object *self = (Entry_Object*) obj;
759
760     Py_INCREF(self->parent_acl);
761     return self->parent_acl;
762 }
763
764 /* Returns the a new Permset representing the permset of the entry
765  * FIXME: Should return a new reference to the same object, which
766  * should be created at init time!
767  */
768 static PyObject* Entry_get_permset(PyObject *obj, void* arg) {
769     Entry_Object *self = (Entry_Object*)obj;
770     PyObject *p;
771     Permset_Object *ps;
772
773     p = Permset_new(&Permset_Type, NULL, NULL);
774     if(p == NULL)
775         return NULL;
776     ps = (Permset_Object*)p;
777     if(acl_get_permset(self->entry, &ps->permset) == -1) {
778         PyErr_SetFromErrno(PyExc_IOError);
779         return NULL;
780     }
781     ps->parent_entry = obj;
782     Py_INCREF(obj);
783
784     return (PyObject*)p;
785 }
786
787 /* Sets the permset of the entry to the passed Permset */
788 static int Entry_set_permset(PyObject* obj, PyObject* value, void* arg) {
789     Entry_Object *self = (Entry_Object*)obj;
790     Permset_Object *p;
791
792     if(!PyObject_IsInstance(value, (PyObject*)&Permset_Type)) {
793         PyErr_SetString(PyExc_TypeError, "argument 1 must be posix1e.Permset");
794         return -1;
795     }
796     p = (Permset_Object*)value;
797     if(acl_set_permset(self->entry, p->permset) == -1) {
798         PyErr_SetFromErrno(PyExc_IOError);
799         return -1;
800     }
801     return 0;
802 }
803
804 static char __Entry_copy_doc__[] =
805     "Copy an ACL entry.\n"
806     "\n"
807     "This method sets all the parameters to those of another\n"
808     "entry, even one of another's ACL\n"
809     "Parameters:\n"
810     " - src, instance of type Entry\n"
811     ;
812
813 /* Sets all the entry parameters to another's entry */
814 static PyObject* Entry_copy(PyObject *obj, PyObject *args) {
815     Entry_Object *self = (Entry_Object*)obj;
816     Entry_Object *other;
817
818     if(!PyArg_ParseTuple(args, "O!", &Entry_Type, &other))
819         return NULL;
820
821     if(acl_copy_entry(self->entry, other->entry) == -1)
822         return PyErr_SetFromErrno(PyExc_IOError);
823
824     Py_INCREF(Py_None);
825     return Py_None;
826 }
827
828 /**** Permset type *****/
829
830 /* Creation of a new Permset instance */
831 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
832                              PyObject *keywds) {
833     PyObject* newpermset;
834
835     newpermset = PyType_GenericNew(type, args, keywds);
836
837     if(newpermset != NULL) {
838         ((Permset_Object*)newpermset)->permset = NULL;
839         ((Permset_Object*)newpermset)->parent_entry = NULL;
840     }
841
842     return newpermset;
843 }
844
845 /* Initialization of a new Permset instance */
846 static int Permset_init(PyObject* obj, PyObject* args, PyObject *keywds) {
847     Permset_Object* self = (Permset_Object*) obj;
848     Entry_Object* parent = NULL;
849
850     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent))
851         return -1;
852
853     if(acl_get_permset(parent->entry, &self->permset) == -1) {
854         PyErr_SetFromErrno(PyExc_IOError);
855         return -1;
856     }
857
858     self->parent_entry = (PyObject*)parent;
859     Py_INCREF(parent);
860
861     return 0;
862 }
863
864 /* Free the Permset instance */
865 static void Permset_dealloc(PyObject* obj) {
866     Permset_Object *self = (Permset_Object*) obj;
867     PyObject *err_type, *err_value, *err_traceback;
868     int have_error = PyErr_Occurred() ? 1 : 0;
869
870     if (have_error)
871         PyErr_Fetch(&err_type, &err_value, &err_traceback);
872     if(self->parent_entry != NULL) {
873         Py_DECREF(self->parent_entry);
874         self->parent_entry = NULL;
875     }
876     if (have_error)
877         PyErr_Restore(err_type, err_value, err_traceback);
878     PyObject_DEL(self);
879 }
880
881 /* Permset string representation */
882 static PyObject* Permset_str(PyObject *obj) {
883     Permset_Object *self = (Permset_Object*) obj;
884     char pstr[3];
885
886     pstr[0] = get_perm(self->permset, ACL_READ) ? 'r' : '-';
887     pstr[1] = get_perm(self->permset, ACL_WRITE) ? 'w' : '-';
888     pstr[2] = get_perm(self->permset, ACL_EXECUTE) ? 'x' : '-';
889     return PyString_FromStringAndSize(pstr, 3);
890 }
891
892 static char __Permset_clear_doc__[] =
893     "Clear all permissions from the permission set.\n"
894     ;
895
896 /* Clears all permissions from the permset */
897 static PyObject* Permset_clear(PyObject* obj, PyObject* args) {
898     Permset_Object *self = (Permset_Object*) obj;
899
900     if(acl_clear_perms(self->permset) == -1)
901         return PyErr_SetFromErrno(PyExc_IOError);
902
903     /* Return the result */
904     Py_INCREF(Py_None);
905     return Py_None;
906 }
907
908 static PyObject* Permset_get_right(PyObject *obj, void* arg) {
909     Permset_Object *self = (Permset_Object*) obj;
910
911     if(get_perm(self->permset, *(acl_perm_t*)arg)) {
912         Py_INCREF(Py_True);
913         return Py_True;
914     } else {
915         Py_INCREF(Py_False);
916         return Py_False;
917     }
918 }
919
920 static int Permset_set_right(PyObject* obj, PyObject* value, void* arg) {
921     Permset_Object *self = (Permset_Object*) obj;
922     int on;
923     int nerr;
924
925     if(!PyInt_Check(value)) {
926         PyErr_SetString(PyExc_ValueError, "a maximum of one argument must"
927                         " be passed");
928         return -1;
929     }
930     on = PyInt_AsLong(value);
931     if(on)
932         nerr = acl_add_perm(self->permset, *(acl_perm_t*)arg);
933     else
934         nerr = acl_delete_perm(self->permset, *(acl_perm_t*)arg);
935     if(nerr == -1) {
936         PyErr_SetFromErrno(PyExc_IOError);
937         return -1;
938     }
939     return 0;
940 }
941
942 static char __Permset_add_doc__[] =
943     "Add a permission to the permission set.\n"
944     "\n"
945     "The add() function adds the permission contained in \n"
946     "the argument perm to the permission set.  An attempt \n"
947     "to add a permission that is already contained in the \n"
948     "permission set is not considered an error.\n"
949     "Parameters:\n"
950     "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n"
951     "Return value:\n"
952     "  None\n"
953     "Can raise: IOError\n"
954     ;
955
956 static PyObject* Permset_add(PyObject* obj, PyObject* args) {
957     Permset_Object *self = (Permset_Object*) obj;
958     int right;
959
960     if (!PyArg_ParseTuple(args, "i", &right))
961         return NULL;
962
963     if(acl_add_perm(self->permset, (acl_perm_t) right) == -1)
964         return PyErr_SetFromErrno(PyExc_IOError);
965
966     /* Return the result */
967     Py_INCREF(Py_None);
968     return Py_None;
969 }
970
971 static char __Permset_delete_doc__[] =
972     "Delete a permission from the permission set.\n"
973     "\n"
974     "The delete() function deletes the permission contained in \n"
975     "the argument perm from the permission set.  An attempt \n"
976     "to delete a permission that is not contained in the \n"
977     "permission set is not considered an error.\n"
978     "Parameters:\n"
979     "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n"
980     "Return value:\n"
981     "  None\n"
982     "Can raise: IOError\n"
983     ;
984
985 static PyObject* Permset_delete(PyObject* obj, PyObject* args) {
986     Permset_Object *self = (Permset_Object*) obj;
987     int right;
988
989     if (!PyArg_ParseTuple(args, "i", &right))
990         return NULL;
991
992     if(acl_delete_perm(self->permset, (acl_perm_t) right) == -1)
993         return PyErr_SetFromErrno(PyExc_IOError);
994
995     /* Return the result */
996     Py_INCREF(Py_None);
997     return Py_None;
998 }
999
1000 static char __Permset_test_doc__[] =
1001     "Test if a permission exists in the permission set.\n"
1002     "\n"
1003     "The test() function tests if the permission contained in \n"
1004     "the argument perm exits the permission set.\n"
1005     "Parameters:\n"
1006     "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n"
1007     "Return value:\n"
1008     "  Bool\n"
1009     "Can raise: IOError\n"
1010     ;
1011
1012 static PyObject* Permset_test(PyObject* obj, PyObject* args) {
1013     Permset_Object *self = (Permset_Object*) obj;
1014     int right;
1015     int ret;
1016
1017     if (!PyArg_ParseTuple(args, "i", &right))
1018         return NULL;
1019
1020     ret = get_perm(self->permset, (acl_perm_t) right);
1021     if(ret == -1)
1022         return PyErr_SetFromErrno(PyExc_IOError);
1023
1024     if(ret) {
1025         Py_INCREF(Py_True);
1026         return Py_True;
1027     } else {
1028         Py_INCREF(Py_False);
1029         return Py_False;
1030     }
1031 }
1032
1033 #endif
1034
1035 static char __ACL_Type_doc__[] =
1036     "Type which represents a POSIX ACL\n"
1037     "\n"
1038     "Parameters:\n"
1039     "  Only one keword parameter should be provided:\n"
1040     "  - file=\"...\", meaning create ACL representing\n"
1041     "    the access ACL of that file\n"
1042     "  - filedef=\"...\", meaning create ACL representing\n"
1043     "    the default ACL of that directory\n"
1044     "  - fd=<int>, meaning create ACL representing\n"
1045     "    the access ACL of that file descriptor\n"
1046     "  - text=\"...\", meaning create ACL from a \n"
1047     "    textual description\n"
1048     "  - acl=<ACL instance>, meaning create a copy\n"
1049     "    of an existing ACL instance\n"
1050     "  - mode=<int>, meaning create an ACL from a numeric mode\n"
1051     "    (e.g. mode=0644) (this is valid only when the C library\n"
1052     "    provides the acl_from_mode call)\n"
1053     "If no parameters are passed, create an empty ACL; this\n"
1054     "makes sense only when your OS supports ACL modification\n"
1055     " (i.e. it implements full POSIX.1e support)\n"
1056     ;
1057
1058 /* ACL type methods */
1059 static PyMethodDef ACL_methods[] = {
1060     {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
1061     {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
1062 #ifdef HAVE_LINUX
1063     {"to_any_text", (PyCFunction)ACL_to_any_text, METH_VARARGS | METH_KEYWORDS,
1064      __to_any_text_doc__},
1065     {"check", ACL_check, METH_NOARGS, __check_doc__},
1066 #endif
1067 #ifdef HAVE_LEVEL2
1068     {"__getstate__", ACL_get_state, METH_NOARGS,
1069      "Dumps the ACL to an external format."},
1070     {"__setstate__", ACL_set_state, METH_VARARGS,
1071      "Loads the ACL from an external format."},
1072     {"delete_entry", ACL_delete_entry, METH_VARARGS, __ACL_delete_entry_doc__},
1073     {"calc_mask", ACL_calc_mask, METH_NOARGS, __ACL_calc_mask_doc__},
1074     {"append", ACL_append, METH_VARARGS, __ACL_append_doc__},
1075 #endif
1076     {NULL, NULL, 0, NULL}
1077 };
1078
1079
1080 /* The definition of the ACL Type */
1081 static PyTypeObject ACL_Type = {
1082     PyObject_HEAD_INIT(NULL)
1083     0,
1084     "posix1e.ACL",
1085     sizeof(ACL_Object),
1086     0,
1087     ACL_dealloc,        /* tp_dealloc */
1088     0,                  /* tp_print */
1089     0,                  /* tp_getattr */
1090     0,                  /* tp_setattr */
1091     ACL_nocmp,          /* tp_compare */
1092     0,                  /* tp_repr */
1093     0,                  /* tp_as_number */
1094     0,                  /* tp_as_sequence */
1095     0,                  /* tp_as_mapping */
1096     0,                  /* tp_hash */
1097     0,                  /* tp_call */
1098     ACL_str,            /* tp_str */
1099     0,                  /* tp_getattro */
1100     0,                  /* tp_setattro */
1101     0,                  /* tp_as_buffer */
1102     Py_TPFLAGS_DEFAULT, /* tp_flags */
1103     __ACL_Type_doc__,   /* tp_doc */
1104     0,                  /* tp_traverse */
1105     0,                  /* tp_clear */
1106 #ifdef HAVE_LINUX
1107     ACL_richcompare,    /* tp_richcompare */
1108 #else
1109     0,                  /* tp_richcompare */
1110 #endif
1111     0,                  /* tp_weaklistoffset */
1112 #ifdef HAVE_LEVEL2
1113     ACL_iter,
1114     ACL_iternext,
1115 #else
1116     0,                  /* tp_iter */
1117     0,                  /* tp_iternext */
1118 #endif
1119     ACL_methods,        /* tp_methods */
1120     0,                  /* tp_members */
1121     0,                  /* tp_getset */
1122     0,                  /* tp_base */
1123     0,                  /* tp_dict */
1124     0,                  /* tp_descr_get */
1125     0,                  /* tp_descr_set */
1126     0,                  /* tp_dictoffset */
1127     ACL_init,           /* tp_init */
1128     0,                  /* tp_alloc */
1129     ACL_new,            /* tp_new */
1130 };
1131
1132 #ifdef HAVE_LEVEL2
1133
1134 /* Entry type methods */
1135 static PyMethodDef Entry_methods[] = {
1136     {"copy", Entry_copy, METH_VARARGS, __Entry_copy_doc__},
1137     {NULL, NULL, 0, NULL}
1138 };
1139
1140 static char __Entry_tagtype_doc__[] =
1141     "The tag type of the current entry\n"
1142     "\n"
1143     "This is one of:\n"
1144     " - ACL_UNDEFINED_TAG\n"
1145     " - ACL_USER_OBJ\n"
1146     " - ACL_USER\n"
1147     " - ACL_GROUP_OBJ\n"
1148     " - ACL_GROUP\n"
1149     " - ACL_MASK\n"
1150     " - ACL_OTHER\n"
1151     ;
1152
1153 static char __Entry_qualifier_doc__[] =
1154     "The qualifier of the current entry\n"
1155     "\n"
1156     "If the tag type is ACL_USER, this should be a user id.\n"
1157     "If the tag type if ACL_GROUP, this should be a group id.\n"
1158     "Else, it doesn't matter.\n"
1159     ;
1160
1161 static char __Entry_parent_doc__[] =
1162     "The parent ACL of this entry\n"
1163     ;
1164
1165 static char __Entry_permset_doc__[] =
1166     "The permission set of this ACL entry\n"
1167     ;
1168
1169 /* Entry getset */
1170 static PyGetSetDef Entry_getsets[] = {
1171     {"tag_type", Entry_get_tag_type, Entry_set_tag_type,
1172      __Entry_tagtype_doc__},
1173     {"qualifier", Entry_get_qualifier, Entry_set_qualifier,
1174      __Entry_qualifier_doc__},
1175     {"parent", Entry_get_parent, NULL, __Entry_parent_doc__},
1176     {"permset", Entry_get_permset, Entry_set_permset, __Entry_permset_doc__},
1177     {NULL}
1178 };
1179
1180 static char __Entry_Type_doc__[] =
1181     "Type which represents an entry in an ACL.\n"
1182     "\n"
1183     "The type exists only if the OS has full support for POSIX.1e\n"
1184     "Can be created either by:\n"
1185     "  e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n"
1186     "or by:\n"
1187     "  for entry in myACL:\n"
1188     "      print entry\n"
1189     "\n"
1190     "Note that the Entry keeps a reference to its ACL, so even if \n"
1191     "you delete the ACL, it won't be cleaned up and will continue to \n"
1192     "exist until its Entry(ies) will be deleted.\n"
1193     ;
1194 /* The definition of the Entry Type */
1195 static PyTypeObject Entry_Type = {
1196     PyObject_HEAD_INIT(NULL)
1197     0,
1198     "posix1e.Entry",
1199     sizeof(Entry_Object),
1200     0,
1201     Entry_dealloc,      /* tp_dealloc */
1202     0,                  /* tp_print */
1203     0,                  /* tp_getattr */
1204     0,                  /* tp_setattr */
1205     0,                  /* tp_compare */
1206     0,                  /* tp_repr */
1207     0,                  /* tp_as_number */
1208     0,                  /* tp_as_sequence */
1209     0,                  /* tp_as_mapping */
1210     0,                  /* tp_hash */
1211     0,                  /* tp_call */
1212     Entry_str,          /* tp_str */
1213     0,                  /* tp_getattro */
1214     0,                  /* tp_setattro */
1215     0,                  /* tp_as_buffer */
1216     Py_TPFLAGS_DEFAULT, /* tp_flags */
1217     __Entry_Type_doc__, /* tp_doc */
1218     0,                  /* tp_traverse */
1219     0,                  /* tp_clear */
1220     0,                  /* tp_richcompare */
1221     0,                  /* tp_weaklistoffset */
1222     0,                  /* tp_iter */
1223     0,                  /* tp_iternext */
1224     Entry_methods,      /* tp_methods */
1225     0,                  /* tp_members */
1226     Entry_getsets,      /* tp_getset */
1227     0,                  /* tp_base */
1228     0,                  /* tp_dict */
1229     0,                  /* tp_descr_get */
1230     0,                  /* tp_descr_set */
1231     0,                  /* tp_dictoffset */
1232     Entry_init,         /* tp_init */
1233     0,                  /* tp_alloc */
1234     Entry_new,          /* tp_new */
1235 };
1236
1237 /* Permset type methods */
1238 static PyMethodDef Permset_methods[] = {
1239     {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, },
1240     {"add", Permset_add, METH_VARARGS, __Permset_add_doc__, },
1241     {"delete", Permset_delete, METH_VARARGS, __Permset_delete_doc__, },
1242     {"test", Permset_test, METH_VARARGS, __Permset_test_doc__, },
1243     {NULL, NULL, 0, NULL}
1244 };
1245
1246 static char __Permset_execute_doc__[] =
1247     "Execute permsission\n"
1248     "\n"
1249     "This is a convenience method of access; the \n"
1250     "same effect can be achieved using the functions\n"
1251     "add(), test(), delete(), and those can take any \n"
1252     "permission defined by your platform.\n"
1253     ;
1254
1255 static char __Permset_read_doc__[] =
1256     "Read permsission\n"
1257     "\n"
1258     "This is a convenience method of access; the \n"
1259     "same effect can be achieved using the functions\n"
1260     "add(), test(), delete(), and those can take any \n"
1261     "permission defined by your platform.\n"
1262     ;
1263
1264 static char __Permset_write_doc__[] =
1265     "Write permsission\n"
1266     "\n"
1267     "This is a convenience method of access; the \n"
1268     "same effect can be achieved using the functions\n"
1269     "add(), test(), delete(), and those can take any \n"
1270     "permission defined by your platform.\n"
1271     ;
1272
1273 /* Permset getset */
1274 static PyGetSetDef Permset_getsets[] = {
1275     {"execute", Permset_get_right, Permset_set_right,
1276      __Permset_execute_doc__, &holder_ACL_EXECUTE},
1277     {"read", Permset_get_right, Permset_set_right,
1278      __Permset_read_doc__, &holder_ACL_READ},
1279     {"write", Permset_get_right, Permset_set_right,
1280      __Permset_write_doc__, &holder_ACL_WRITE},
1281     {NULL}
1282 };
1283
1284 static char __Permset_Type_doc__[] =
1285     "Type which represents the permission set in an ACL entry\n"
1286     "\n"
1287     "The type exists only if the OS has full support for POSIX.1e\n"
1288     "Can be created either by:\n"
1289     "  perms = myEntry.permset\n"
1290     "or by:\n"
1291     "  perms = posix1e.Permset(myEntry)\n"
1292     "\n"
1293     "Note that the Permset keeps a reference to its Entry, so even if \n"
1294     "you delete the entry, it won't be cleaned up and will continue to \n"
1295     "exist until its Permset will be deleted.\n"
1296     ;
1297
1298 /* The definition of the Permset Type */
1299 static PyTypeObject Permset_Type = {
1300     PyObject_HEAD_INIT(NULL)
1301     0,
1302     "posix1e.Permset",
1303     sizeof(Permset_Object),
1304     0,
1305     Permset_dealloc,    /* tp_dealloc */
1306     0,                  /* tp_print */
1307     0,                  /* tp_getattr */
1308     0,                  /* tp_setattr */
1309     0,                  /* tp_compare */
1310     0,                  /* tp_repr */
1311     0,                  /* tp_as_number */
1312     0,                  /* tp_as_sequence */
1313     0,                  /* tp_as_mapping */
1314     0,                  /* tp_hash */
1315     0,                  /* tp_call */
1316     Permset_str,        /* tp_str */
1317     0,                  /* tp_getattro */
1318     0,                  /* tp_setattro */
1319     0,                  /* tp_as_buffer */
1320     Py_TPFLAGS_DEFAULT, /* tp_flags */
1321     __Permset_Type_doc__,/* tp_doc */
1322     0,                  /* tp_traverse */
1323     0,                  /* tp_clear */
1324     0,                  /* tp_richcompare */
1325     0,                  /* tp_weaklistoffset */
1326     0,                  /* tp_iter */
1327     0,                  /* tp_iternext */
1328     Permset_methods,    /* tp_methods */
1329     0,                  /* tp_members */
1330     Permset_getsets,    /* tp_getset */
1331     0,                  /* tp_base */
1332     0,                  /* tp_dict */
1333     0,                  /* tp_descr_get */
1334     0,                  /* tp_descr_set */
1335     0,                  /* tp_dictoffset */
1336     Permset_init,       /* tp_init */
1337     0,                  /* tp_alloc */
1338     Permset_new,        /* tp_new */
1339 };
1340
1341 #endif
1342
1343 /* Module methods */
1344
1345 static char __deletedef_doc__[] =
1346     "Delete the default ACL from a directory.\n"
1347     "\n"
1348     "This function deletes the default ACL associated with \n"
1349     "a directory (the ACL which will be ANDed with the mode\n"
1350     "parameter to the open, creat functions).\n"
1351     "Parameters:\n"
1352     "  - a string representing the directory whose default ACL\n"
1353     "    should be deleted\n"
1354     ;
1355
1356 /* Deletes the default ACL from a directory */
1357 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
1358     char *filename;
1359
1360     /* Parse the arguments */
1361     if (!PyArg_ParseTuple(args, "s", &filename))
1362         return NULL;
1363
1364     if(acl_delete_def_file(filename) == -1) {
1365         return PyErr_SetFromErrno(PyExc_IOError);
1366     }
1367
1368     /* Return the result */
1369     Py_INCREF(Py_None);
1370     return Py_None;
1371 }
1372
1373 /* The module methods */
1374 static PyMethodDef aclmodule_methods[] = {
1375     {"delete_default", aclmodule_delete_default, METH_VARARGS,
1376      __deletedef_doc__},
1377     {NULL, NULL, 0, NULL}
1378 };
1379
1380 static char __posix1e_doc__[] =
1381     "POSIX.1e ACLs manipulation\n"
1382     "\n"
1383     "This module provides support for manipulating POSIX.1e ACLS\n"
1384     "\n"
1385     "Depending on the operating system support for POSIX.1e, \n"
1386     "the ACL type will have more or less capabilities:\n"
1387     "  - level 1, only basic support, you can create\n"
1388     "    ACLs from files and text descriptions;\n"
1389     "    once created, the type is immutable\n"
1390     "  - level 2, complete support, you can alter\n"
1391     "    the ACL once it is created\n"
1392     "\n"
1393     "Also, in level 2, more types are available, corresponding\n"
1394     "to acl_entry_t (Entry type), acl_permset_t (Permset type).\n"
1395     "\n"
1396     "Example:\n"
1397     ">>> import posix1e\n"
1398     ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n"
1399     ">>> print acl1\n"
1400     "user::rw-\n"
1401     "group::rw-\n"
1402     "other::r--\n"
1403     "\n"
1404     ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n"
1405     ">>> print b\n"
1406     "user::r-x\n"
1407     "group::---\n"
1408     "other::---\n"
1409     "\n"
1410     ">>> b.applyto(\"file.txt\")\n"
1411     ">>> print posix1e.ACL(file=\"file.txt\")\n"
1412     "user::r-x\n"
1413     "group::---\n"
1414     "other::---\n"
1415     "\n"
1416     ">>>\n"
1417     ;
1418
1419 void initposix1e(void) {
1420     PyObject *m, *d;
1421
1422     ACL_Type.ob_type = &PyType_Type;
1423     if(PyType_Ready(&ACL_Type) < 0)
1424         return;
1425
1426 #ifdef HAVE_LEVEL2
1427     Entry_Type.ob_type = &PyType_Type;
1428     if(PyType_Ready(&Entry_Type) < 0)
1429         return;
1430
1431     Permset_Type.ob_type = &PyType_Type;
1432     if(PyType_Ready(&Permset_Type) < 0)
1433         return;
1434 #endif
1435
1436     m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
1437
1438     d = PyModule_GetDict(m);
1439     if (d == NULL)
1440         return;
1441
1442     Py_INCREF(&ACL_Type);
1443     if (PyDict_SetItemString(d, "ACL",
1444                              (PyObject *) &ACL_Type) < 0)
1445         return;
1446
1447     /* 23.3.6 acl_type_t values */
1448     PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS);
1449     PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT);
1450
1451
1452 #ifdef HAVE_LEVEL2
1453     Py_INCREF(&Entry_Type);
1454     if (PyDict_SetItemString(d, "Entry",
1455                              (PyObject *) &Entry_Type) < 0)
1456         return;
1457
1458     Py_INCREF(&Permset_Type);
1459     if (PyDict_SetItemString(d, "Permset",
1460                              (PyObject *) &Permset_Type) < 0)
1461         return;
1462
1463     /* 23.2.2 acl_perm_t values */
1464     PyModule_AddIntConstant(m, "ACL_READ", ACL_READ);
1465     PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE);
1466     PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE);
1467
1468     /* 23.2.5 acl_tag_t values */
1469     PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG);
1470     PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ);
1471     PyModule_AddIntConstant(m, "ACL_USER", ACL_USER);
1472     PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ);
1473     PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP);
1474     PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK);
1475     PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER);
1476
1477     /* Document extended functionality via easy-to-use constants */
1478     PyModule_AddIntConstant(m, "HAS_ACL_ENTRY", 1);
1479 #else
1480     PyModule_AddIntConstant(m, "HAS_ACL_ENTRY", 0);
1481 #endif
1482
1483 #ifdef HAVE_LINUX
1484     /* Linux libacl specific acl_to_any_text constants */
1485     PyModule_AddIntConstant(m, "TEXT_ABBREVIATE", TEXT_ABBREVIATE);
1486     PyModule_AddIntConstant(m, "TEXT_NUMERIC_IDS", TEXT_NUMERIC_IDS);
1487     PyModule_AddIntConstant(m, "TEXT_SOME_EFFECTIVE", TEXT_SOME_EFFECTIVE);
1488     PyModule_AddIntConstant(m, "TEXT_ALL_EFFECTIVE", TEXT_ALL_EFFECTIVE);
1489     PyModule_AddIntConstant(m, "TEXT_SMART_INDENT", TEXT_SMART_INDENT);
1490
1491     /* Linux libacl specific acl_check constants */
1492     PyModule_AddIntConstant(m, "ACL_MULTI_ERROR", ACL_MULTI_ERROR);
1493     PyModule_AddIntConstant(m, "ACL_DUPLICATE_ERROR", ACL_DUPLICATE_ERROR);
1494     PyModule_AddIntConstant(m, "ACL_MISS_ERROR", ACL_MISS_ERROR);
1495     PyModule_AddIntConstant(m, "ACL_ENTRY_ERROR", ACL_ENTRY_ERROR);
1496
1497     /* declare the Linux extensions */
1498     PyModule_AddIntConstant(m, "HAS_ACL_FROM_MODE", 1);
1499     PyModule_AddIntConstant(m, "HAS_ACL_CHECK", 1);
1500 #else
1501     PyModule_AddIntConstant(m, "HAS_ACL_FROM_MODE", 0);
1502     PyModule_AddIntConstant(m, "HAS_ACL_CHECK", 0);
1503 #endif
1504 }