]> git.k1024.org Git - pylibacl.git/blob - acl.c
Add a Darwin build option
[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     const char *format = "|sisO!sH";
76     mode_t mode = 0;
77 #else
78     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", NULL };
79     const 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 /* Custom methods */
166 static char __applyto_doc__[] =
167     "Apply the ACL to a file or filehandle.\n"
168     "\n"
169     "Parameters:\n"
170     "  - either a filename or a file-like object or an integer; this\n"
171     "    represents the filesystem object on which to act\n"
172     "  - optional flag representing the type of ACL to set, either\n"
173     "    ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT\n"
174     ;
175
176 /* Applyes the ACL to a file */
177 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
178     ACL_Object *self = (ACL_Object*) obj;
179     PyObject *myarg;
180     acl_type_t type = ACL_TYPE_ACCESS;
181     int nret;
182     int fd;
183
184     if (!PyArg_ParseTuple(args, "O|i", &myarg, &type))
185         return NULL;
186
187     if(PyString_Check(myarg)) {
188         char *filename = PyString_AS_STRING(myarg);
189         nret = acl_set_file(filename, type, self->acl);
190     } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
191         nret = acl_set_fd(fd, self->acl);
192     } else {
193         PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int,"
194                         " or file-like object");
195         return 0;
196     }
197     if(nret == -1) {
198         return PyErr_SetFromErrno(PyExc_IOError);
199     }
200
201     /* Return the result */
202     Py_INCREF(Py_None);
203     return Py_None;
204 }
205
206 static char __valid_doc__[] =
207     "Test the ACL for validity.\n"
208     "\n"
209     "This method tests the ACL to see if it is a valid ACL\n"
210     "in terms of the filesystem. More precisely, it checks that:\n"
211     "\n"
212     "The ACL contains exactly one entry with each of the\n"
213     "ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries\n"
214     "with ACL_USER and ACL_GROUP tag types may appear zero or more\n"
215     "times in an ACL. An ACL that contains entries of ACL_USER or\n"
216     "ACL_GROUP tag types must contain exactly one entry of the \n"
217     "ACL_MASK tag type. If an ACL contains no entries of\n"
218     "ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n"
219     "\n"
220     "All user ID qualifiers must be unique among all entries of\n"
221     "the ACL_USER tag type, and all group IDs must be unique among all\n"
222     "entries of ACL_GROUP tag type.\n"
223     "\n"
224     "The method will return 1 for a valid ACL and 0 for an invalid one.\n"
225     "This has been chosen because the specification for acl_valid in\n"
226     "the POSIX.1e standard documents only one possible value for errno\n"
227     "in case of an invalid ACL, so we can't differentiate between\n"
228     "classes of errors. Other suggestions are welcome.\n"
229     ;
230
231 /* Checks the ACL for validity */
232 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
233     ACL_Object *self = (ACL_Object*) obj;
234
235     if(acl_valid(self->acl) == -1) {
236         Py_INCREF(Py_False);
237         return Py_False;
238     } else {
239         Py_INCREF(Py_True);
240         return Py_True;
241     }
242 }
243
244 #ifdef HAVE_LEVEL2
245
246 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
247     ACL_Object *self = (ACL_Object*) obj;
248     PyObject *ret;
249     ssize_t size, nsize;
250     char *buf;
251
252     size = acl_size(self->acl);
253     if(size == -1)
254         return PyErr_SetFromErrno(PyExc_IOError);
255
256     if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
257         return NULL;
258     buf = PyString_AsString(ret);
259
260     if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) {
261         Py_DECREF(ret);
262         return PyErr_SetFromErrno(PyExc_IOError);
263     }
264
265     return ret;
266 }
267
268 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
269     ACL_Object *self = (ACL_Object*) obj;
270     const void *buf;
271     int bufsize;
272     acl_t ptr;
273
274     /* Parse the argument */
275     if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
276         return NULL;
277
278     /* Try to import the external representation */
279     if((ptr = acl_copy_int(buf)) == NULL)
280         return PyErr_SetFromErrno(PyExc_IOError);
281
282     /* Free the old acl. Should we ignore errors here? */
283     if(self->acl != NULL) {
284         if(acl_free(self->acl) == -1)
285             return PyErr_SetFromErrno(PyExc_IOError);
286     }
287
288     self->acl = ptr;
289
290     /* Return the result */
291     Py_INCREF(Py_None);
292     return Py_None;
293 }
294
295 /* tp_iter for the ACL type; since it can be iterated only
296  * destructively, the type is its iterator
297  */
298 static PyObject* ACL_iter(PyObject *obj) {
299     ACL_Object *self = (ACL_Object*)obj;
300     self->entry_id = ACL_FIRST_ENTRY;
301     Py_INCREF(obj);
302     return obj;
303 }
304
305 /* the tp_iternext function for the ACL type */
306 static PyObject* ACL_iternext(PyObject *obj) {
307     ACL_Object *self = (ACL_Object*)obj;
308     acl_entry_t the_entry_t;
309     Entry_Object *the_entry_obj;
310     int nerr;
311
312     nerr = acl_get_entry(self->acl, self->entry_id, &the_entry_t);
313     self->entry_id = ACL_NEXT_ENTRY;
314     if(nerr == -1)
315         return PyErr_SetFromErrno(PyExc_IOError);
316     else if(nerr == 0) {
317         /* Docs says this is not needed */
318         /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/
319         return NULL;
320     }
321
322     the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL);
323     if(the_entry_obj == NULL)
324         return NULL;
325
326     the_entry_obj->entry = the_entry_t;
327
328     the_entry_obj->parent_acl = obj;
329     Py_INCREF(obj); /* For the reference we have in entry->parent */
330
331     return (PyObject*)the_entry_obj;
332 }
333
334 static char __ACL_delete_entry_doc__[] =
335     "Deletes an entry from the ACL.\n"
336     "\n"
337     "Note: Only with level 2\n"
338     "Parameters:\n"
339     " - the Entry object which should be deleted; note that after\n"
340     "   this function is called, that object is unusable any longer\n"
341     "   and should be deleted\n"
342     ;
343
344 /* Deletes an entry from the ACL */
345 static PyObject* ACL_delete_entry(PyObject *obj, PyObject *args) {
346     ACL_Object *self = (ACL_Object*)obj;
347     Entry_Object *e;
348
349     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &e))
350         return NULL;
351
352     if(acl_delete_entry(self->acl, e->entry) == -1)
353         return PyErr_SetFromErrno(PyExc_IOError);
354
355     /* Return the result */
356     Py_INCREF(Py_None);
357     return Py_None;
358 }
359
360 static char __ACL_calc_mask_doc__[] =
361     "Compute the file group class mask.\n"
362     "\n"
363     "The calc_mask() method calculates and sets the permissions \n"
364     "associated with the ACL_MASK Entry of the ACL.\n"
365     "The value of the new permissions is the union of the permissions \n"
366     "granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or \n"
367     "ACL_USER.  If the ACL already contains an ACL_MASK entry, its \n"
368     "permissions are overwritten; if it does not contain an ACL_MASK \n"
369     "Entry, one is added.\n"
370     "\n"
371     "The order of existing entries in the ACL is undefined after this \n"
372     "function.\n"
373     ;
374
375 /* Updates the mask entry in the ACL */
376 static PyObject* ACL_calc_mask(PyObject *obj, PyObject *args) {
377     ACL_Object *self = (ACL_Object*)obj;
378
379     if(acl_calc_mask(&self->acl) == -1)
380         return PyErr_SetFromErrno(PyExc_IOError);
381
382     /* Return the result */
383     Py_INCREF(Py_None);
384     return Py_None;
385 }
386
387 static char __ACL_append_doc__[] =
388     "Append a new Entry to the ACL and return it.\n"
389     "\n"
390     "This is a convenience function to create a new Entry \n"
391     "and append it to the ACL.\n"
392     "If a parameter of type Entry instance is given, the \n"
393     "entry will be a copy of that one (as if copied with \n"
394     "Entry.copy()), otherwise, the new entry will be empty.\n"
395     ;
396
397 /* Convenience method to create a new Entry */
398 static PyObject* ACL_append(PyObject *obj, PyObject *args) {
399     ACL_Object* self = (ACL_Object*) obj;
400     Entry_Object* newentry;
401     Entry_Object* oldentry = NULL;
402     int nret;
403
404     newentry = (Entry_Object*)PyType_GenericNew(&Entry_Type, NULL, NULL);
405     if(newentry == NULL) {
406         return NULL;
407     }
408
409     if (!PyArg_ParseTuple(args, "|O!", &Entry_Type, &oldentry))
410         return NULL;
411
412     nret = acl_create_entry(&self->acl, &newentry->entry);
413     if(nret == -1) {
414         Py_DECREF(newentry);
415         return PyErr_SetFromErrno(PyExc_IOError);
416     }
417
418     if(oldentry != NULL) {
419         nret = acl_copy_entry(newentry->entry, oldentry->entry);
420         if(nret == -1) {
421             Py_DECREF(newentry);
422             return PyErr_SetFromErrno(PyExc_IOError);
423         }
424     }
425
426     newentry->parent_acl = obj;
427     Py_INCREF(obj);
428
429     return (PyObject*)newentry;
430 }
431
432 /***** Entry type *****/
433
434 /* Creation of a new Entry instance */
435 static PyObject* Entry_new(PyTypeObject* type, PyObject* args,
436                            PyObject *keywds) {
437     PyObject* newentry;
438
439     newentry = PyType_GenericNew(type, args, keywds);
440
441     if(newentry != NULL) {
442         ((Entry_Object*)newentry)->entry = NULL;
443         ((Entry_Object*)newentry)->parent_acl = NULL;
444     }
445
446     return newentry;
447 }
448
449 /* Initialization of a new Entry instance */
450 static int Entry_init(PyObject* obj, PyObject* args, PyObject *keywds) {
451     Entry_Object* self = (Entry_Object*) obj;
452     ACL_Object* parent = NULL;
453
454     if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent))
455         return -1;
456
457     if(acl_create_entry(&parent->acl, &self->entry) == -1) {
458         PyErr_SetFromErrno(PyExc_IOError);
459         return -1;
460     }
461
462     self->parent_acl = (PyObject*)parent;
463     Py_INCREF(parent);
464
465     return 0;
466 }
467
468 /* Free the Entry instance */
469 static void Entry_dealloc(PyObject* obj) {
470     Entry_Object *self = (Entry_Object*) obj;
471     PyObject *err_type, *err_value, *err_traceback;
472     int have_error = PyErr_Occurred() ? 1 : 0;
473
474     if (have_error)
475         PyErr_Fetch(&err_type, &err_value, &err_traceback);
476     if(self->parent_acl != NULL) {
477         Py_DECREF(self->parent_acl);
478         self->parent_acl = NULL;
479     }
480     if (have_error)
481         PyErr_Restore(err_type, err_value, err_traceback);
482     PyObject_DEL(self);
483 }
484
485 /* Converts the entry to a text format */
486 static PyObject* Entry_str(PyObject *obj) {
487     acl_tag_t tag;
488     uid_t qualifier;
489     void *p;
490     PyObject *ret;
491     PyObject *format, *list;
492     Entry_Object *self = (Entry_Object*) obj;
493
494     if(acl_get_tag_type(self->entry, &tag) == -1) {
495         PyErr_SetFromErrno(PyExc_IOError);
496         return NULL;
497     }
498     if(tag == ACL_USER || tag == ACL_GROUP) {
499         if((p = acl_get_qualifier(self->entry)) == NULL) {
500             PyErr_SetFromErrno(PyExc_IOError);
501             return NULL;
502         }
503         qualifier = *(uid_t*)p;
504         acl_free(p);
505     } else {
506         qualifier = 0;
507     }
508
509     format = PyString_FromString("ACL entry for %s");
510     if(format == NULL)
511         return NULL;
512     list = PyTuple_New(1);
513     if(tag == ACL_UNDEFINED_TAG) {
514         PyTuple_SetItem(list, 0, PyString_FromString("undefined type"));
515     } else if(tag == ACL_USER_OBJ) {
516         PyTuple_SetItem(list, 0, PyString_FromString("the owner"));
517     } else if(tag == ACL_GROUP_OBJ) {
518         PyTuple_SetItem(list, 0, PyString_FromString("the group"));
519     } else if(tag == ACL_OTHER) {
520         PyTuple_SetItem(list, 0, PyString_FromString("the others"));
521     } else if(tag == ACL_USER) {
522         PyTuple_SetItem(list, 0, PyString_FromFormat("user with uid %d",
523                                                      qualifier));
524     } else if(tag == ACL_GROUP) {
525         PyTuple_SetItem(list, 0, PyString_FromFormat("group with gid %d",
526                                                      qualifier));
527     } else if(tag == ACL_MASK) {
528         PyTuple_SetItem(list, 0, PyString_FromString("the mask"));
529     } else {
530         PyTuple_SetItem(list, 0, PyString_FromString("UNKNOWN_TAG_TYPE!"));
531     }
532     ret = PyString_Format(format, list);
533     Py_DECREF(format);
534     Py_DECREF(list);
535     return ret;
536 }
537
538 /* Sets the tag type of the entry */
539 static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
540     Entry_Object *self = (Entry_Object*) obj;
541
542     if(value == NULL) {
543         PyErr_SetString(PyExc_TypeError,
544                         "tag type deletion is not supported");
545         return -1;
546     }
547
548     if(!PyInt_Check(value)) {
549         PyErr_SetString(PyExc_TypeError,
550                         "tag type must be integer");
551         return -1;
552     }
553     if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
554         PyErr_SetFromErrno(PyExc_IOError);
555         return -1;
556     }
557
558     return 0;
559 }
560
561 /* Returns the tag type of the entry */
562 static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) {
563     Entry_Object *self = (Entry_Object*) obj;
564     acl_tag_t value;
565
566     if (self->entry == NULL) {
567         PyErr_SetString(PyExc_AttributeError, "entry attribute");
568         return NULL;
569     }
570     if(acl_get_tag_type(self->entry, &value) == -1) {
571         PyErr_SetFromErrno(PyExc_IOError);
572         return NULL;
573     }
574
575     return PyInt_FromLong(value);
576 }
577
578 /* Sets the qualifier (either uid_t or gid_t) for the entry,
579  * usable only if the tag type if ACL_USER or ACL_GROUP
580  */
581 static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
582     Entry_Object *self = (Entry_Object*) obj;
583     int uidgid;
584
585     if(value == NULL) {
586         PyErr_SetString(PyExc_TypeError,
587                         "qualifier deletion is not supported");
588         return -1;
589     }
590
591     if(!PyInt_Check(value)) {
592         PyErr_SetString(PyExc_TypeError,
593                         "tag type must be integer");
594         return -1;
595     }
596     uidgid = PyInt_AsLong(value);
597     if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) {
598         PyErr_SetFromErrno(PyExc_IOError);
599         return -1;
600     }
601
602     return 0;
603 }
604
605 /* Returns the qualifier of the entry */
606 static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) {
607     Entry_Object *self = (Entry_Object*) obj;
608     void *p;
609     int value;
610
611     if (self->entry == NULL) {
612         PyErr_SetString(PyExc_AttributeError, "entry attribute");
613         return NULL;
614     }
615     if((p = acl_get_qualifier(self->entry)) == NULL) {
616         PyErr_SetFromErrno(PyExc_IOError);
617         return NULL;
618     }
619     value = *(uid_t*)p;
620     acl_free(p);
621
622     return PyInt_FromLong(value);
623 }
624
625 /* Returns the parent ACL of the entry */
626 static PyObject* Entry_get_parent(PyObject *obj, void* arg) {
627     Entry_Object *self = (Entry_Object*) obj;
628
629     Py_INCREF(self->parent_acl);
630     return self->parent_acl;
631 }
632
633 /* Returns the a new Permset representing the permset of the entry
634  * FIXME: Should return a new reference to the same object, which
635  * should be created at init time!
636  */
637 static PyObject* Entry_get_permset(PyObject *obj, void* arg) {
638     Entry_Object *self = (Entry_Object*)obj;
639     PyObject *p;
640     Permset_Object *ps;
641
642     p = Permset_new(&Permset_Type, NULL, NULL);
643     if(p == NULL)
644         return NULL;
645     ps = (Permset_Object*)p;
646     if(acl_get_permset(self->entry, &ps->permset) == -1) {
647         PyErr_SetFromErrno(PyExc_IOError);
648         return NULL;
649     }
650     ps->parent_entry = obj;
651     Py_INCREF(obj);
652
653     return (PyObject*)p;
654 }
655
656 /* Sets the permset of the entry to the passed Permset */
657 static int Entry_set_permset(PyObject* obj, PyObject* value, void* arg) {
658     Entry_Object *self = (Entry_Object*)obj;
659     Permset_Object *p;
660
661     if(!PyObject_IsInstance(value, (PyObject*)&Permset_Type)) {
662         PyErr_SetString(PyExc_TypeError, "argument 1 must be posix1e.Permset");
663         return -1;
664     }
665     p = (Permset_Object*)value;
666     if(acl_set_permset(self->entry, p->permset) == -1) {
667         PyErr_SetFromErrno(PyExc_IOError);
668         return -1;
669     }
670     return 0;
671 }
672
673 static char __Entry_copy_doc__[] =
674     "Copy an ACL entry.\n"
675     "\n"
676     "This method sets all the parameters to those of another\n"
677     "entry, even one of another's ACL\n"
678     "Parameters:\n"
679     " - src, instance of type Entry\n"
680     ;
681
682 /* Sets all the entry parameters to another's entry */
683 static PyObject* Entry_copy(PyObject *obj, PyObject *args) {
684     Entry_Object *self = (Entry_Object*)obj;
685     Entry_Object *other;
686
687     if(!PyArg_ParseTuple(args, "O!", &Entry_Type, &other))
688         return NULL;
689
690     if(acl_copy_entry(self->entry, other->entry) == -1)
691         return PyErr_SetFromErrno(PyExc_IOError);
692
693     Py_INCREF(Py_None);
694     return Py_None;
695 }
696
697 /**** Permset type *****/
698
699 /* Creation of a new Permset instance */
700 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
701                              PyObject *keywds) {
702     PyObject* newpermset;
703
704     newpermset = PyType_GenericNew(type, args, keywds);
705
706     if(newpermset != NULL) {
707         ((Permset_Object*)newpermset)->permset = NULL;
708         ((Permset_Object*)newpermset)->parent_entry = NULL;
709     }
710
711     return newpermset;
712 }
713
714 /* Initialization of a new Permset instance */
715 static int Permset_init(PyObject* obj, PyObject* args, PyObject *keywds) {
716     Permset_Object* self = (Permset_Object*) obj;
717     Entry_Object* parent = NULL;
718
719     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent))
720         return -1;
721
722     if(acl_get_permset(parent->entry, &self->permset) == -1) {
723         PyErr_SetFromErrno(PyExc_IOError);
724         return -1;
725     }
726
727     self->parent_entry = (PyObject*)parent;
728     Py_INCREF(parent);
729
730     return 0;
731 }
732
733 /* Free the Permset instance */
734 static void Permset_dealloc(PyObject* obj) {
735     Permset_Object *self = (Permset_Object*) obj;
736     PyObject *err_type, *err_value, *err_traceback;
737     int have_error = PyErr_Occurred() ? 1 : 0;
738
739     if (have_error)
740         PyErr_Fetch(&err_type, &err_value, &err_traceback);
741     if(self->parent_entry != NULL) {
742         Py_DECREF(self->parent_entry);
743         self->parent_entry = NULL;
744     }
745     if (have_error)
746         PyErr_Restore(err_type, err_value, err_traceback);
747     PyObject_DEL(self);
748 }
749
750 /* Permset string representation */
751 static PyObject* Permset_str(PyObject *obj) {
752     Permset_Object *self = (Permset_Object*) obj;
753     char pstr[3];
754
755     pstr[0] = get_perm(self->permset, ACL_READ) ? 'r' : '-';
756     pstr[1] = get_perm(self->permset, ACL_WRITE) ? 'w' : '-';
757     pstr[2] = get_perm(self->permset, ACL_EXECUTE) ? 'x' : '-';
758     return PyString_FromStringAndSize(pstr, 3);
759 }
760
761 static char __Permset_clear_doc__[] =
762     "Clear all permissions from the permission set.\n"
763     ;
764
765 /* Clears all permissions from the permset */
766 static PyObject* Permset_clear(PyObject* obj, PyObject* args) {
767     Permset_Object *self = (Permset_Object*) obj;
768
769     if(acl_clear_perms(self->permset) == -1)
770         return PyErr_SetFromErrno(PyExc_IOError);
771
772     /* Return the result */
773     Py_INCREF(Py_None);
774     return Py_None;
775 }
776
777 static PyObject* Permset_get_right(PyObject *obj, void* arg) {
778     Permset_Object *self = (Permset_Object*) obj;
779
780     if(get_perm(self->permset, *(acl_perm_t*)arg)) {
781         Py_INCREF(Py_True);
782         return Py_True;
783     } else {
784         Py_INCREF(Py_False);
785         return Py_False;
786     }
787 }
788
789 static int Permset_set_right(PyObject* obj, PyObject* value, void* arg) {
790     Permset_Object *self = (Permset_Object*) obj;
791     int on;
792     int nerr;
793
794     if(!PyInt_Check(value)) {
795         PyErr_SetString(PyExc_ValueError, "a maximum of one argument must"
796                         " be passed");
797         return -1;
798     }
799     on = PyInt_AsLong(value);
800     if(on)
801         nerr = acl_add_perm(self->permset, *(acl_perm_t*)arg);
802     else
803         nerr = acl_delete_perm(self->permset, *(acl_perm_t*)arg);
804     if(nerr == -1) {
805         PyErr_SetFromErrno(PyExc_IOError);
806         return -1;
807     }
808     return 0;
809 }
810
811 static char __Permset_add_doc__[] =
812     "Add a permission to the permission set.\n"
813     "\n"
814     "The add() function adds the permission contained in \n"
815     "the argument perm to the permission set.  An attempt \n"
816     "to add a permission that is already contained in the \n"
817     "permission set is not considered an error.\n"
818     "Parameters:\n"
819     "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n"
820     "Return value:\n"
821     "  None\n"
822     "Can raise: IOError\n"
823     ;
824
825 static PyObject* Permset_add(PyObject* obj, PyObject* args) {
826     Permset_Object *self = (Permset_Object*) obj;
827     int right;
828
829     if (!PyArg_ParseTuple(args, "i", &right))
830         return NULL;
831
832     if(acl_add_perm(self->permset, (acl_perm_t) right) == -1)
833         return PyErr_SetFromErrno(PyExc_IOError);
834
835     /* Return the result */
836     Py_INCREF(Py_None);
837     return Py_None;
838 }
839
840 static char __Permset_delete_doc__[] =
841     "Delete a permission from the permission set.\n"
842     "\n"
843     "The delete() function deletes the permission contained in \n"
844     "the argument perm from the permission set.  An attempt \n"
845     "to delete a permission that is not contained in the \n"
846     "permission set is not considered an error.\n"
847     "Parameters:\n"
848     "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n"
849     "Return value:\n"
850     "  None\n"
851     "Can raise: IOError\n"
852     ;
853
854 static PyObject* Permset_delete(PyObject* obj, PyObject* args) {
855     Permset_Object *self = (Permset_Object*) obj;
856     int right;
857
858     if (!PyArg_ParseTuple(args, "i", &right))
859         return NULL;
860
861     if(acl_delete_perm(self->permset, (acl_perm_t) right) == -1)
862         return PyErr_SetFromErrno(PyExc_IOError);
863
864     /* Return the result */
865     Py_INCREF(Py_None);
866     return Py_None;
867 }
868
869 static char __Permset_test_doc__[] =
870     "Test if a permission exists in the permission set.\n"
871     "\n"
872     "The test() function tests if the permission contained in \n"
873     "the argument perm exits the permission set.\n"
874     "Parameters:\n"
875     "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n"
876     "Return value:\n"
877     "  Bool\n"
878     "Can raise: IOError\n"
879     ;
880
881 static PyObject* Permset_test(PyObject* obj, PyObject* args) {
882     Permset_Object *self = (Permset_Object*) obj;
883     int right;
884     int ret;
885
886     if (!PyArg_ParseTuple(args, "i", &right))
887         return NULL;
888
889     ret = get_perm(self->permset, (acl_perm_t) right);
890     if(ret == -1)
891         return PyErr_SetFromErrno(PyExc_IOError);
892
893     if(ret) {
894         Py_INCREF(Py_True);
895         return Py_True;
896     } else {
897         Py_INCREF(Py_False);
898         return Py_False;
899     }
900 }
901
902 #endif
903
904 static char __ACL_Type_doc__[] =
905     "Type which represents a POSIX ACL\n"
906     "\n"
907     "Parameters:\n"
908     "  Only one keword parameter should be provided:\n"
909     "  - file=\"...\", meaning create ACL representing\n"
910     "    the access ACL of that file\n"
911     "  - filedef=\"...\", meaning create ACL representing\n"
912     "    the default ACL of that directory\n"
913     "  - fd=<int>, meaning create ACL representing\n"
914     "    the access ACL of that file descriptor\n"
915     "  - text=\"...\", meaning create ACL from a \n"
916     "    textual description\n"
917     "  - acl=<ACL instance>, meaning create a copy\n"
918     "    of an existing ACL instance\n"
919     "  - mode=<int>, meaning create an ACL from a numeric mode\n"
920     "    (e.g. mode=0644) (this is valid only when the C library\n"
921     "    provides the acl_from_mode call)\n"
922     "If no parameters are passed, create an empty ACL; this\n"
923     "makes sense only when your OS supports ACL modification\n"
924     " (i.e. it implements full POSIX.1e support)\n"
925     ;
926
927 /* ACL type methods */
928 static PyMethodDef ACL_methods[] = {
929     {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
930     {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
931 #ifdef HAVE_LEVEL2
932     {"__getstate__", ACL_get_state, METH_NOARGS,
933      "Dumps the ACL to an external format."},
934     {"__setstate__", ACL_set_state, METH_VARARGS,
935      "Loads the ACL from an external format."},
936     {"delete_entry", ACL_delete_entry, METH_VARARGS, __ACL_delete_entry_doc__},
937     {"calc_mask", ACL_calc_mask, METH_NOARGS, __ACL_calc_mask_doc__},
938     {"append", ACL_append, METH_VARARGS, __ACL_append_doc__},
939 #endif
940     {NULL, NULL, 0, NULL}
941 };
942
943
944 /* The definition of the ACL Type */
945 static PyTypeObject ACL_Type = {
946     PyObject_HEAD_INIT(NULL)
947     0,
948     "posix1e.ACL",
949     sizeof(ACL_Object),
950     0,
951     ACL_dealloc,        /* tp_dealloc */
952     0,                  /* tp_print */
953     0,                  /* tp_getattr */
954     0,                  /* tp_setattr */
955     0,                  /* tp_compare */
956     0,                  /* tp_repr */
957     0,                  /* tp_as_number */
958     0,                  /* tp_as_sequence */
959     0,                  /* tp_as_mapping */
960     0,                  /* tp_hash */
961     0,                  /* tp_call */
962     ACL_str,            /* tp_str */
963     0,                  /* tp_getattro */
964     0,                  /* tp_setattro */
965     0,                  /* tp_as_buffer */
966     Py_TPFLAGS_DEFAULT, /* tp_flags */
967     __ACL_Type_doc__,   /* tp_doc */
968     0,                  /* tp_traverse */
969     0,                  /* tp_clear */
970     0,                  /* tp_richcompare */
971     0,                  /* tp_weaklistoffset */
972 #ifdef HAVE_LEVEL2
973     ACL_iter,
974     ACL_iternext,
975 #else
976     0,                  /* tp_iter */
977     0,                  /* tp_iternext */
978 #endif
979     ACL_methods,        /* tp_methods */
980     0,                  /* tp_members */
981     0,                  /* tp_getset */
982     0,                  /* tp_base */
983     0,                  /* tp_dict */
984     0,                  /* tp_descr_get */
985     0,                  /* tp_descr_set */
986     0,                  /* tp_dictoffset */
987     ACL_init,           /* tp_init */
988     0,                  /* tp_alloc */
989     ACL_new,            /* tp_new */
990 };
991
992 #ifdef HAVE_LEVEL2
993
994 /* Entry type methods */
995 static PyMethodDef Entry_methods[] = {
996     {"copy", Entry_copy, METH_VARARGS, __Entry_copy_doc__},
997     {NULL, NULL, 0, NULL}
998 };
999
1000 static char __Entry_tagtype_doc__[] =
1001     "The tag type of the current entry\n"
1002     "\n"
1003     "This is one of:\n"
1004     " - ACL_UNDEFINED_TAG\n"
1005     " - ACL_USER_OBJ\n"
1006     " - ACL_USER\n"
1007     " - ACL_GROUP_OBJ\n"
1008     " - ACL_GROUP\n"
1009     " - ACL_MASK\n"
1010     " - ACL_OTHER\n"
1011     ;
1012
1013 static char __Entry_qualifier_doc__[] =
1014     "The qualifier of the current entry\n"
1015     "\n"
1016     "If the tag type is ACL_USER, this should be a user id.\n"
1017     "If the tag type if ACL_GROUP, this should be a group id.\n"
1018     "Else, it doesn't matter.\n"
1019     ;
1020
1021 static char __Entry_parent_doc__[] =
1022     "The parent ACL of this entry\n"
1023     ;
1024
1025 static char __Entry_permset_doc__[] =
1026     "The permission set of this ACL entry\n"
1027     ;
1028
1029 /* Entry getset */
1030 static PyGetSetDef Entry_getsets[] = {
1031     {"tag_type", Entry_get_tag_type, Entry_set_tag_type,
1032      __Entry_tagtype_doc__},
1033     {"qualifier", Entry_get_qualifier, Entry_set_qualifier,
1034      __Entry_qualifier_doc__},
1035     {"parent", Entry_get_parent, NULL, __Entry_parent_doc__},
1036     {"permset", Entry_get_permset, Entry_set_permset, __Entry_permset_doc__},
1037     {NULL}
1038 };
1039
1040 static char __Entry_Type_doc__[] =
1041     "Type which represents an entry in an ACL.\n"
1042     "\n"
1043     "The type exists only if the OS has full support for POSIX.1e\n"
1044     "Can be created either by:\n"
1045     "  e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n"
1046     "or by:\n"
1047     "  for entry in myACL:\n"
1048     "      print entry\n"
1049     "\n"
1050     "Note that the Entry keeps a reference to its ACL, so even if \n"
1051     "you delete the ACL, it won't be cleaned up and will continue to \n"
1052     "exist until its Entry(ies) will be deleted.\n"
1053     ;
1054 /* The definition of the Entry Type */
1055 static PyTypeObject Entry_Type = {
1056     PyObject_HEAD_INIT(NULL)
1057     0,
1058     "posix1e.Entry",
1059     sizeof(Entry_Object),
1060     0,
1061     Entry_dealloc,      /* tp_dealloc */
1062     0,                  /* tp_print */
1063     0,                  /* tp_getattr */
1064     0,                  /* tp_setattr */
1065     0,                  /* tp_compare */
1066     0,                  /* tp_repr */
1067     0,                  /* tp_as_number */
1068     0,                  /* tp_as_sequence */
1069     0,                  /* tp_as_mapping */
1070     0,                  /* tp_hash */
1071     0,                  /* tp_call */
1072     Entry_str,          /* tp_str */
1073     0,                  /* tp_getattro */
1074     0,                  /* tp_setattro */
1075     0,                  /* tp_as_buffer */
1076     Py_TPFLAGS_DEFAULT, /* tp_flags */
1077     __Entry_Type_doc__, /* tp_doc */
1078     0,                  /* tp_traverse */
1079     0,                  /* tp_clear */
1080     0,                  /* tp_richcompare */
1081     0,                  /* tp_weaklistoffset */
1082     0,                  /* tp_iter */
1083     0,                  /* tp_iternext */
1084     Entry_methods,      /* tp_methods */
1085     0,                  /* tp_members */
1086     Entry_getsets,      /* tp_getset */
1087     0,                  /* tp_base */
1088     0,                  /* tp_dict */
1089     0,                  /* tp_descr_get */
1090     0,                  /* tp_descr_set */
1091     0,                  /* tp_dictoffset */
1092     Entry_init,         /* tp_init */
1093     0,                  /* tp_alloc */
1094     Entry_new,          /* tp_new */
1095 };
1096
1097 /* Permset type methods */
1098 static PyMethodDef Permset_methods[] = {
1099     {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, },
1100     {"add", Permset_add, METH_VARARGS, __Permset_add_doc__, },
1101     {"delete", Permset_delete, METH_VARARGS, __Permset_delete_doc__, },
1102     {"test", Permset_test, METH_VARARGS, __Permset_test_doc__, },
1103     {NULL, NULL, 0, NULL}
1104 };
1105
1106 static char __Permset_execute_doc__[] =
1107     "Execute permsission\n"
1108     "\n"
1109     "This is a convenience method of access; the \n"
1110     "same effect can be achieved using the functions\n"
1111     "add(), test(), delete(), and those can take any \n"
1112     "permission defined by your platform.\n"
1113     ;
1114
1115 static char __Permset_read_doc__[] =
1116     "Read permsission\n"
1117     "\n"
1118     "This is a convenience method of access; the \n"
1119     "same effect can be achieved using the functions\n"
1120     "add(), test(), delete(), and those can take any \n"
1121     "permission defined by your platform.\n"
1122     ;
1123
1124 static char __Permset_write_doc__[] =
1125     "Write permsission\n"
1126     "\n"
1127     "This is a convenience method of access; the \n"
1128     "same effect can be achieved using the functions\n"
1129     "add(), test(), delete(), and those can take any \n"
1130     "permission defined by your platform.\n"
1131     ;
1132
1133 /* Permset getset */
1134 static PyGetSetDef Permset_getsets[] = {
1135     {"execute", Permset_get_right, Permset_set_right,
1136      __Permset_execute_doc__, &holder_ACL_EXECUTE},
1137     {"read", Permset_get_right, Permset_set_right,
1138      __Permset_read_doc__, &holder_ACL_READ},
1139     {"write", Permset_get_right, Permset_set_right,
1140      __Permset_write_doc__, &holder_ACL_WRITE},
1141     {NULL}
1142 };
1143
1144 static char __Permset_Type_doc__[] =
1145     "Type which represents the permission set in an ACL entry\n"
1146     "\n"
1147     "The type exists only if the OS has full support for POSIX.1e\n"
1148     "Can be created either by:\n"
1149     "  perms = myEntry.permset\n"
1150     "or by:\n"
1151     "  perms = posix1e.Permset(myEntry)\n"
1152     "\n"
1153     "Note that the Permset keeps a reference to its Entry, so even if \n"
1154     "you delete the entry, it won't be cleaned up and will continue to \n"
1155     "exist until its Permset will be deleted.\n"
1156     ;
1157
1158 /* The definition of the Permset Type */
1159 static PyTypeObject Permset_Type = {
1160     PyObject_HEAD_INIT(NULL)
1161     0,
1162     "posix1e.Permset",
1163     sizeof(Permset_Object),
1164     0,
1165     Permset_dealloc,    /* tp_dealloc */
1166     0,                  /* tp_print */
1167     0,                  /* tp_getattr */
1168     0,                  /* tp_setattr */
1169     0,                  /* tp_compare */
1170     0,                  /* tp_repr */
1171     0,                  /* tp_as_number */
1172     0,                  /* tp_as_sequence */
1173     0,                  /* tp_as_mapping */
1174     0,                  /* tp_hash */
1175     0,                  /* tp_call */
1176     Permset_str,        /* tp_str */
1177     0,                  /* tp_getattro */
1178     0,                  /* tp_setattro */
1179     0,                  /* tp_as_buffer */
1180     Py_TPFLAGS_DEFAULT, /* tp_flags */
1181     __Permset_Type_doc__,/* tp_doc */
1182     0,                  /* tp_traverse */
1183     0,                  /* tp_clear */
1184     0,                  /* tp_richcompare */
1185     0,                  /* tp_weaklistoffset */
1186     0,                  /* tp_iter */
1187     0,                  /* tp_iternext */
1188     Permset_methods,    /* tp_methods */
1189     0,                  /* tp_members */
1190     Permset_getsets,    /* tp_getset */
1191     0,                  /* tp_base */
1192     0,                  /* tp_dict */
1193     0,                  /* tp_descr_get */
1194     0,                  /* tp_descr_set */
1195     0,                  /* tp_dictoffset */
1196     Permset_init,       /* tp_init */
1197     0,                  /* tp_alloc */
1198     Permset_new,        /* tp_new */
1199 };
1200
1201 #endif
1202
1203 /* Module methods */
1204
1205 static char __deletedef_doc__[] =
1206     "Delete the default ACL from a directory.\n"
1207     "\n"
1208     "This function deletes the default ACL associated with \n"
1209     "a directory (the ACL which will be ANDed with the mode\n"
1210     "parameter to the open, creat functions).\n"
1211     "Parameters:\n"
1212     "  - a string representing the directory whose default ACL\n"
1213     "    should be deleted\n"
1214     ;
1215
1216 /* Deletes the default ACL from a directory */
1217 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
1218     char *filename;
1219
1220     /* Parse the arguments */
1221     if (!PyArg_ParseTuple(args, "s", &filename))
1222         return NULL;
1223
1224     if(acl_delete_def_file(filename) == -1) {
1225         return PyErr_SetFromErrno(PyExc_IOError);
1226     }
1227
1228     /* Return the result */
1229     Py_INCREF(Py_None);
1230     return Py_None;
1231 }
1232
1233 /* The module methods */
1234 static PyMethodDef aclmodule_methods[] = {
1235     {"delete_default", aclmodule_delete_default, METH_VARARGS,
1236      __deletedef_doc__},
1237     {NULL, NULL, 0, NULL}
1238 };
1239
1240 static char __posix1e_doc__[] =
1241     "POSIX.1e ACLs manipulation\n"
1242     "\n"
1243     "This module provides support for manipulating POSIX.1e ACLS\n"
1244     "\n"
1245     "Depending on the operating system support for POSIX.1e, \n"
1246     "the ACL type will have more or less capabilities:\n"
1247     "  - level 1, only basic support, you can create\n"
1248     "    ACLs from files and text descriptions;\n"
1249     "    once created, the type is immutable\n"
1250     "  - level 2, complete support, you can alter\n"
1251     "    the ACL once it is created\n"
1252     "\n"
1253     "Also, in level 2, more types are available, corresponding\n"
1254     "to acl_entry_t (Entry type), acl_permset_t (Permset type).\n"
1255     "\n"
1256     "Example:\n"
1257     ">>> import posix1e\n"
1258     ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n"
1259     ">>> print acl1\n"
1260     "user::rw-\n"
1261     "group::rw-\n"
1262     "other::r--\n"
1263     "\n"
1264     ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n"
1265     ">>> print b\n"
1266     "user::r-x\n"
1267     "group::---\n"
1268     "other::---\n"
1269     "\n"
1270     ">>> b.applyto(\"file.txt\")\n"
1271     ">>> print posix1e.ACL(file=\"file.txt\")\n"
1272     "user::r-x\n"
1273     "group::---\n"
1274     "other::---\n"
1275     "\n"
1276     ">>>\n"
1277     ;
1278
1279 void initposix1e(void) {
1280     PyObject *m, *d;
1281
1282     ACL_Type.ob_type = &PyType_Type;
1283     if(PyType_Ready(&ACL_Type) < 0)
1284         return;
1285
1286 #ifdef HAVE_LEVEL2
1287     Entry_Type.ob_type = &PyType_Type;
1288     if(PyType_Ready(&Entry_Type) < 0)
1289         return;
1290
1291     Permset_Type.ob_type = &PyType_Type;
1292     if(PyType_Ready(&Permset_Type) < 0)
1293         return;
1294 #endif
1295
1296     m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
1297
1298     d = PyModule_GetDict(m);
1299     if (d == NULL)
1300         return;
1301
1302     Py_INCREF(&ACL_Type);
1303     if (PyDict_SetItemString(d, "ACL",
1304                              (PyObject *) &ACL_Type) < 0)
1305         return;
1306
1307     /* 23.3.6 acl_type_t values */
1308     PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS);
1309     PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT);
1310
1311
1312 #ifdef HAVE_LEVEL2
1313     Py_INCREF(&Entry_Type);
1314     if (PyDict_SetItemString(d, "Entry",
1315                              (PyObject *) &Entry_Type) < 0)
1316         return;
1317
1318     Py_INCREF(&Permset_Type);
1319     if (PyDict_SetItemString(d, "Permset",
1320                              (PyObject *) &Permset_Type) < 0)
1321         return;
1322
1323     /* 23.2.2 acl_perm_t values */
1324     PyModule_AddIntConstant(m, "ACL_READ", ACL_READ);
1325     PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE);
1326     PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE);
1327
1328     /* 23.2.5 acl_tag_t values */
1329     PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG);
1330     PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ);
1331     PyModule_AddIntConstant(m, "ACL_USER", ACL_USER);
1332     PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ);
1333     PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP);
1334     PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK);
1335     PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER);
1336
1337 #endif
1338 }