]> git.k1024.org Git - pylibacl.git/blob - acl.c
Distutils file
[pylibacl.git] / acl.c
1 #include <sys/types.h>
2 #include <sys/acl.h>
3
4 #include <Python.h>
5
6 staticforward PyTypeObject ACL_Type;
7 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
8 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
9 #ifdef HAVE_LEVEL2
10 static PyObject* ACL_get_state(PyObject *obj, PyObject* args);
11 static PyObject* ACL_set_state(PyObject *obj, PyObject* args);
12
13 staticforward PyTypeObject Entry_Type;
14 staticforward PyTypeObject Permset_Type;
15 #endif
16
17 typedef struct {
18     PyObject_HEAD
19     acl_t acl;
20     int entry_id;
21 } ACL_Object;
22
23 #ifdef HAVE_LEVEL2
24
25 typedef struct {
26     PyObject_HEAD
27     PyObject *parent_acl; /* The parent acl, so it won't run out on us */
28     acl_entry_t entry;
29 } Entry_Object;
30
31 typedef struct {
32     PyObject_HEAD
33     PyObject *parent_entry; /* The parent entry, so it won't run out on us */
34     acl_permset_t permset;
35 } Permset_Object;
36
37 #endif
38
39 /* Creation of a new ACL instance */
40 static PyObject* ACL_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
41     PyObject* newacl;
42
43     newacl = type->tp_alloc(type, 0);
44
45     if(newacl != NULL) {
46         ((ACL_Object*)newacl)->acl = NULL;
47         ((ACL_Object*)newacl)->entry_id = ACL_FIRST_ENTRY;
48     }
49
50     return newacl;
51 }
52
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 };
57     char *file = NULL;
58     char *text = NULL;
59     int fd = -1;
60     ACL_Object* thesrc = NULL;
61     int tmp;
62
63     if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sisO!", kwlist,
64                                      &file, &fd, &text, &ACL_Type, &thesrc))
65         return -1;
66     tmp = 0;
67     if(file != NULL)
68         tmp++;
69     if(text != NULL)
70         tmp++;
71     if(fd != -1)
72         tmp++;
73     if(thesrc != NULL)
74         tmp++;
75     if(tmp > 1) {
76         PyErr_SetString(PyExc_ValueError, "a maximum of one argument must be passed");
77         return -1;
78     }
79
80     /* Free the old acl_t without checking for error, we don't
81      * care right now */
82     if(self->acl != NULL)
83         acl_free(self->acl);
84
85     if(file != NULL)
86         self->acl = acl_get_file(file, ACL_TYPE_ACCESS);
87     else if(text != NULL)
88         self->acl = acl_from_text(text);
89     else if(fd != -1)
90         self->acl = acl_get_fd(fd);
91     else if(thesrc != NULL)
92         self->acl = acl_dup(thesrc->acl);
93     else
94         self->acl = acl_init(0);
95
96     if(self->acl == NULL) {
97         PyErr_SetFromErrno(PyExc_IOError);
98         return -1;
99     }
100
101     return 0;
102 }
103
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;
109
110     if (have_error)
111         PyErr_Fetch(&err_type, &err_value, &err_traceback);
112     if(acl_free(self->acl) != 0)
113         PyErr_WriteUnraisable(obj);
114     if (have_error)
115         PyErr_Restore(err_type, err_value, err_traceback);
116     PyObject_DEL(self);
117 }
118
119 /* Converts the acl to a text format */
120 static PyObject* ACL_str(PyObject *obj) {
121     char *text;
122     ACL_Object *self = (ACL_Object*) obj;
123     PyObject *ret;
124
125     text = acl_to_text(self->acl, NULL);
126     if(text == NULL) {
127         return PyErr_SetFromErrno(PyExc_IOError);
128     }
129     ret = PyString_FromString(text);
130     if(acl_free(text) != 0) {
131         Py_DECREF(ret);
132         return PyErr_SetFromErrno(PyExc_IOError);
133     }
134     return ret;
135 }
136
137 /* Custom methods */
138 static char __applyto_doc__[] = \
139 "Apply the ACL to a file or filehandle.\n" \
140 "\n" \
141 "Parameters:\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" \
144 ;
145
146 /* Applyes the ACL to a file */
147 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
148     ACL_Object *self = (ACL_Object*) obj;
149     PyObject *myarg;
150     int type_default = 0;
151     acl_type_t type = ACL_TYPE_ACCESS;
152     int nret;
153     int fd;
154
155     if (!PyArg_ParseTuple(args, "O|i", &myarg, &type_default))
156         return NULL;
157     if(type_default)
158         type = ACL_TYPE_DEFAULT;
159
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);
165     } else {
166         PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int, or file-like object");
167         return 0;
168     }
169     if(nret == -1) {
170         return PyErr_SetFromErrno(PyExc_IOError);
171     }
172
173     /* Return the result */
174     Py_INCREF(Py_None);
175     return Py_None;
176 }
177
178 static char __valid_doc__[] = \
179 "Test the ACL for validity.\n" \
180 "\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" \
189 "\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" \
192 "type." \
193 ;
194
195 /* Checks the ACL for validity */
196 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
197     ACL_Object *self = (ACL_Object*) obj;
198
199     if(acl_valid(self->acl) == -1) {
200         return PyErr_SetFromErrno(PyExc_IOError);
201     }
202
203     /* Return the result */
204     Py_INCREF(Py_None);
205     return Py_None;
206 }
207
208 #ifdef HAVE_LEVEL2
209
210 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
211     ACL_Object *self = (ACL_Object*) obj;
212     PyObject *ret;
213     ssize_t size, nsize;
214     char *buf;
215
216     size = acl_size(self->acl);
217     if(size == -1)
218         return PyErr_SetFromErrno(PyExc_IOError);
219
220     if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
221         return NULL;
222     buf = PyString_AsString(ret);
223     
224     if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) {
225         Py_DECREF(ret);
226         return PyErr_SetFromErrno(PyExc_IOError);
227     }
228     
229     return ret;
230 }
231
232 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
233     ACL_Object *self = (ACL_Object*) obj;
234     const void *buf;
235     int bufsize;
236     acl_t ptr;
237
238     /* Parse the argument */
239     if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
240         return NULL;
241
242     /* Try to import the external representation */
243     if((ptr = acl_copy_int(buf)) == NULL)
244         return PyErr_SetFromErrno(PyExc_IOError);
245         
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);
250     }
251
252     self->acl = ptr;
253
254     /* Return the result */
255     Py_INCREF(Py_None);
256     return Py_None;
257 }
258
259 static PyObject* ACL_iter(PyObject *obj) {
260     ACL_Object *self = (ACL_Object*)obj;
261     self->entry_id = ACL_FIRST_ENTRY;
262     Py_INCREF(obj);
263     return obj;
264 }
265
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;
270     int nerr;
271     
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;
275     if(nerr == 0) {
276         /* Docs says this is not needed */
277         /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/
278         return NULL;
279     }
280
281     the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL);
282     if(the_entry_obj == NULL)
283         return NULL;
284     
285     the_entry_obj->entry = the_entry_t;
286
287     the_entry_obj->parent_acl = obj;
288     Py_INCREF(obj); /* For the reference we have in entry->parent */
289
290     return (PyObject*)the_entry_obj;
291 }
292
293 /* Creation of a new Entry instance */
294 static PyObject* Entry_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
295     PyObject* newentry;
296
297     newentry = PyType_GenericNew(type, args, keywds);
298
299     if(newentry != NULL) {
300         ((Entry_Object*)newentry)->entry = NULL;
301         ((Entry_Object*)newentry)->parent_acl = NULL;
302     }
303
304     return newentry;
305 }
306
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;
311
312     if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent))
313         return -1;
314
315     if(acl_create_entry(&parent->acl, &self->entry) == -1) {
316         PyErr_SetFromErrno(PyExc_IOError);
317         return -1;
318     }
319
320     self->parent_acl = (PyObject*)parent;
321     Py_INCREF(parent);
322
323     return 0;
324 }
325
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;
331
332     if (have_error)
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;
337     }
338     if (have_error)
339         PyErr_Restore(err_type, err_value, err_traceback);
340     PyObject_DEL(self);
341 }
342
343 /* Converts the entry to a text format */
344 static PyObject* Entry_str(PyObject *obj) {
345     acl_tag_t tag;
346     uid_t qualifier;
347     void *p;
348     PyObject *ret;
349     PyObject *format, *list;
350     Entry_Object *self = (Entry_Object*) obj;
351
352     if(acl_get_tag_type(self->entry, &tag) == -1) {
353         PyErr_SetFromErrno(PyExc_IOError);
354         return NULL;
355     }
356     if(tag == ACL_USER || tag == ACL_GROUP) {
357         if((p = acl_get_qualifier(self->entry)) == NULL) {
358             PyErr_SetFromErrno(PyExc_IOError);
359             return NULL;
360         }
361         qualifier = *(uid_t*)p;
362         acl_free(p);
363     } else {
364         qualifier = 0;
365     }
366     
367     format = PyString_FromString("ACL entry for %s, rights: <unknown>");
368     if(format == NULL)
369         return NULL;
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"));
385     } else {
386         PyTuple_SetItem(list, 0, PyString_FromString("UNKNOWN_TAG_TYPE!"));
387     }
388     ret = PyString_Format(format, list);
389     Py_DECREF(format);
390     Py_DECREF(list);
391     return ret;
392 }
393
394 static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
395     Entry_Object *self = (Entry_Object*) obj;
396
397     if(value == NULL) {
398         PyErr_SetString(PyExc_TypeError,
399                         "tag type deletion is not supported");
400         return -1;
401     }
402
403     if(!PyInt_Check(value)) {
404         PyErr_SetString(PyExc_TypeError,
405                         "tag type must be integer");
406         return -1;
407     }
408     if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
409         PyErr_SetFromErrno(PyExc_IOError);
410         return -1;
411     }
412
413     return 0;
414 }
415
416 static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) {
417     Entry_Object *self = (Entry_Object*) obj;
418     acl_tag_t value;
419
420     if (self->entry == NULL) {
421         PyErr_SetString(PyExc_AttributeError, "entry attribute");
422         return NULL;
423     }
424     if(acl_get_tag_type(self->entry, &value) == -1) {
425         PyErr_SetFromErrno(PyExc_IOError);
426         return NULL;
427     }
428
429     return PyInt_FromLong(value);
430 }
431
432 static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
433     Entry_Object *self = (Entry_Object*) obj;
434     int uidgid;
435
436     if(value == NULL) {
437         PyErr_SetString(PyExc_TypeError,
438                         "qualifier deletion is not supported");
439         return -1;
440     }
441
442     if(!PyInt_Check(value)) {
443         PyErr_SetString(PyExc_TypeError,
444                         "tag type must be integer");
445         return -1;
446     }
447     uidgid = PyInt_AsLong(value);
448     if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) {
449         PyErr_SetFromErrno(PyExc_IOError);
450         return -1;
451     }
452
453     return 0;
454 }
455
456 static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) {
457     Entry_Object *self = (Entry_Object*) obj;
458     void *p;
459     int value;
460
461     if (self->entry == NULL) {
462         PyErr_SetString(PyExc_AttributeError, "entry attribute");
463         return NULL;
464     }
465     if((p = acl_get_qualifier(self->entry)) == NULL) {
466         PyErr_SetFromErrno(PyExc_IOError);
467         return NULL;
468     }
469     value = *(uid_t*)p;
470     acl_free(p);
471     
472     return PyInt_FromLong(value);
473 }
474
475 static PyObject* Entry_get_parent(PyObject *obj, void* arg) {
476     Entry_Object *self = (Entry_Object*) obj;
477     
478     Py_INCREF(self->parent_acl);
479     return self->parent_acl;
480 }
481
482 /* Creation of a new Permset instance */
483 static PyObject* Permset_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
484     PyObject* newpermset;
485
486     newpermset = PyType_GenericNew(type, args, keywds);
487
488     if(newpermset != NULL) {
489         ((Permset_Object*)newpermset)->permset = NULL;
490         ((Permset_Object*)newpermset)->parent_entry = NULL;
491     }
492
493     return newpermset;
494 }
495
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;
500
501     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent))
502         return -1;
503
504     if(acl_get_permset(parent->entry, &self->permset) == -1) {
505         PyErr_SetFromErrno(PyExc_IOError);
506         return -1;
507     }
508
509     self->parent_entry = (PyObject*)parent;
510     Py_INCREF(parent);
511
512     return 0;
513 }
514
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;
520
521     if (have_error)
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;
526     }
527     if (have_error)
528         PyErr_Restore(err_type, err_value, err_traceback);
529     PyObject_DEL(self);
530 }
531
532 static PyObject* Permset_clear(PyObject* obj, PyObject* args) {
533     Permset_Object *self = (Permset_Object*) obj;
534
535     if(acl_clear_perms(self->permset) == -1)
536         return PyErr_SetFromErrno(PyExc_IOError);
537
538     /* Return the result */
539     Py_INCREF(Py_None);
540     return Py_None;
541 }
542
543 #endif
544
545 static char __acltype_doc__[] = \
546 "Type which represents a POSIX ACL\n" \
547 "\n" \
548 "Parameters:\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" \
558 ;
559
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__},
564 #ifdef HAVE_LEVEL2
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."},
567 #endif
568     {NULL, NULL, 0, NULL}
569 };
570
571
572 /* The definition of the ACL Type */
573 static PyTypeObject ACL_Type = {
574     PyObject_HEAD_INIT(NULL)
575     0,
576     "posix1e.ACL",
577     sizeof(ACL_Object),
578     0,
579     ACL_dealloc,        /* tp_dealloc */
580     0,                  /* tp_print */
581     0,                  /* tp_getattr */
582     0,                  /* tp_setattr */
583     0,                  /* tp_compare */
584     0,                  /* tp_repr */
585     0,                  /* tp_as_number */
586     0,                  /* tp_as_sequence */
587     0,                  /* tp_as_mapping */
588     0,                  /* tp_hash */
589     0,                  /* tp_call */
590     ACL_str,            /* tp_str */
591     0,                  /* tp_getattro */
592     0,                  /* tp_setattro */
593     0,                  /* tp_as_buffer */
594     Py_TPFLAGS_DEFAULT, /* tp_flags */
595     __acltype_doc__,    /* tp_doc */
596     0,                  /* tp_traverse */
597     0,                  /* tp_clear */
598     0,                  /* tp_richcompare */
599     0,                  /* tp_weaklistoffset */
600 #ifdef HAVE_LEVEL2
601     ACL_iter,
602     ACL_iternext,
603 #else
604     0,                  /* tp_iter */
605     0,                  /* tp_iternext */
606 #endif
607     ACL_methods,        /* tp_methods */
608     0,                  /* tp_members */
609     0,                  /* tp_getset */
610     0,                  /* tp_base */
611     0,                  /* tp_dict */
612     0,                  /* tp_descr_get */
613     0,                  /* tp_descr_set */
614     0,                  /* tp_dictoffset */
615     ACL_init,           /* tp_init */
616     0,                  /* tp_alloc */
617     ACL_new,            /* tp_new */
618 };
619
620 #ifdef HAVE_LEVEL2
621
622 /* Entry type methods */
623 static PyMethodDef Entry_methods[] = {
624     {NULL, NULL, 0, NULL}
625 };
626
627 static char __Entry_tagtype_doc__[] = \
628 "The tag type of the current entry\n" \
629 "\n" \
630 "This is one of:\n" \
631 " - ACL_UNDEFINED_TAG\n" \
632 " - ACL_USER_OBJ\n" \
633 " - ACL_USER\n" \
634 " - ACL_GROUP_OBJ\n" \
635 " - ACL_GROUP\n" \
636 " - ACL_MASK\n" \
637 " - ACL_OTHER\n" \
638 ;
639
640 static char __Entry_qualifier_doc__[] = \
641 "The qualifier of the current entry\n" \
642 "\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" \
646 ;
647
648 static char __Entry_parent_doc__[] = \
649 "The parent ACL of this entry\n" \
650 ;
651
652 /* Entry getset */
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__},
657     {NULL}
658 };
659
660 /* The definition of the ACL Entry Type */
661 static PyTypeObject Entry_Type = {
662     PyObject_HEAD_INIT(NULL)
663     0,
664     "posix1e.Entry",
665     sizeof(Entry_Object),
666     0,
667     Entry_dealloc,      /* tp_dealloc */
668     0,                  /* tp_print */
669     0,                  /* tp_getattr */
670     0,                  /* tp_setattr */
671     0,                  /* tp_compare */
672     0,                  /* tp_repr */
673     0,                  /* tp_as_number */
674     0,                  /* tp_as_sequence */
675     0,                  /* tp_as_mapping */
676     0,                  /* tp_hash */
677     0,                  /* tp_call */
678     Entry_str,          /* tp_str */
679     0,                  /* tp_getattro */
680     0,                  /* tp_setattro */
681     0,                  /* tp_as_buffer */
682     Py_TPFLAGS_DEFAULT, /* tp_flags */
683     __acltype_doc__,    /* tp_doc */
684     0,                  /* tp_traverse */
685     0,                  /* tp_clear */
686     0,                  /* tp_richcompare */
687     0,                  /* tp_weaklistoffset */
688     0,                  /* tp_iter */
689     0,                  /* tp_iternext */
690     Entry_methods,   /* tp_methods */
691     0,                  /* tp_members */
692     Entry_getsets,   /* tp_getset */
693     0,                  /* tp_base */
694     0,                  /* tp_dict */
695     0,                  /* tp_descr_get */
696     0,                  /* tp_descr_set */
697     0,                  /* tp_dictoffset */
698     Entry_init,      /* tp_init */
699     0,                  /* tp_alloc */
700     Entry_new,       /* tp_new */
701 };
702
703 static char __Permset_clear_doc__[] = \
704 "Clear all permissions in the set\n" \
705 ;
706
707 /* Entry type methods */
708 static PyMethodDef Permset_methods[] = {
709     {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, },
710     {NULL, NULL, 0, NULL}
711 };
712
713 /* The definition of the ACL Entry Type */
714 static PyTypeObject Permset_Type = {
715     PyObject_HEAD_INIT(NULL)
716     0,
717     "posix1e.Permset",
718     sizeof(Permset_Object),
719     0,
720     Permset_dealloc,    /* tp_dealloc */
721     0,                  /* tp_print */
722     0,                  /* tp_getattr */
723     0,                  /* tp_setattr */
724     0,                  /* tp_compare */
725     0, //Entry_repr,      /* tp_repr */
726     0,                  /* tp_as_number */
727     0,                  /* tp_as_sequence */
728     0,                  /* tp_as_mapping */
729     0,                  /* tp_hash */
730     0,                  /* tp_call */
731     0,                  /* tp_str */
732     0,                  /* tp_getattro */
733     0,                  /* tp_setattro */
734     0,                  /* tp_as_buffer */
735     Py_TPFLAGS_DEFAULT, /* tp_flags */
736     __acltype_doc__,    /* tp_doc */
737     0,                  /* tp_traverse */
738     0,                  /* tp_clear */
739     0,                  /* tp_richcompare */
740     0,                  /* tp_weaklistoffset */
741     0,                  /* tp_iter */
742     0,                  /* tp_iternext */
743     Permset_methods,    /* tp_methods */
744     0,                  /* tp_members */
745     0,      /* tp_getset */
746     0,                  /* tp_base */
747     0,                  /* tp_dict */
748     0,                  /* tp_descr_get */
749     0,                  /* tp_descr_set */
750     0,                  /* tp_dictoffset */
751     Permset_init,       /* tp_init */
752     0,                  /* tp_alloc */
753     Permset_new,        /* tp_new */
754 };
755
756 #endif
757
758 /* Module methods */
759
760 static char __deletedef_doc__[] = \
761 "Delete the default ACL from a directory.\n" \
762 "\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" \
766 "Parameters:\n" \
767 "  - a string representing the directory whose default ACL\n" \
768 "    should be deleted\n" \
769 ;
770
771 /* Deletes the default ACL from a directory */
772 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
773     char *filename;
774
775     /* Parse the arguments */
776     if (!PyArg_ParseTuple(args, "s", &filename))
777         return NULL;
778
779     if(acl_delete_def_file(filename) == -1) {
780         return PyErr_SetFromErrno(PyExc_IOError);
781     }
782
783     /* Return the result */
784     Py_INCREF(Py_None);
785     return Py_None;
786 }
787
788 /* The module methods */
789 static PyMethodDef aclmodule_methods[] = {
790     {"delete_default", aclmodule_delete_default, METH_VARARGS, __deletedef_doc__},
791     {NULL, NULL, 0, NULL}
792 };
793
794 static char __posix1e_doc__[] = \
795 "POSIX.1e ACLs manipulation\n" \
796 "\n" \
797 "This module provides support for manipulating POSIX.1e ACLS\n" \
798 "\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" \
806 "\n" \
807 "Also, in level 2, more types will be available, corresponding\n" \
808 "to acl_entry_t, acl_permset_t, etc.\n" \
809 "\n" \
810 "Example:\n" \
811 ">>> import posix1e\n" \
812 ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n" \
813 ">>> print acl1\n" \
814 "user::rw-\n" \
815 "group::rw-\n" \
816 "other::r--\n" \
817 "\n" \
818 ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n" \
819 ">>> print b\n" \
820 "user::r-x\n" \
821 "group::---\n" \
822 "other::---\n" \
823 "\n" \
824 ">>> b.applyto(\"file.txt\")\n" \
825 ">>> print posix1e.ACL(file=\"file.txt\")\n" \
826 "user::r-x\n" \
827 "group::---\n" \
828 "other::---\n" \
829 "\n" \
830 ">>>\n" \
831 ;
832
833 DL_EXPORT(void) initposix1e(void) {
834     PyObject *m, *d;
835
836     ACL_Type.ob_type = &PyType_Type;
837     if(PyType_Ready(&ACL_Type) < 0)
838         return;
839
840 #ifdef HAVE_LEVEL2
841     Entry_Type.ob_type = &PyType_Type;
842     if(PyType_Ready(&Entry_Type) < 0)
843         return;
844
845     Permset_Type.ob_type = &PyType_Type;
846     if(PyType_Ready(&Permset_Type) < 0)
847         return;
848 #endif
849
850     m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
851
852     d = PyModule_GetDict(m);
853     if (d == NULL)
854         return;
855
856     Py_INCREF(&ACL_Type);
857     if (PyDict_SetItemString(d, "ACL",
858                              (PyObject *) &ACL_Type) < 0)
859         return;
860 #ifdef HAVE_LEVEL2
861     Py_INCREF(&Entry_Type);
862     if (PyDict_SetItemString(d, "Entry",
863                              (PyObject *) &Entry_Type) < 0)
864         return;
865
866     Py_INCREF(&Permset_Type);
867     if (PyDict_SetItemString(d, "Permset",
868                              (PyObject *) &Permset_Type) < 0)
869         return;
870
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);
875
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);
884
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);
888
889 #endif
890 }