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