1 #define PY_SSIZE_T_CLEAN
3 #include <attr/xattr.h>
6 /* Compatibility with python 2.4 regarding python size type (PEP 353) */
7 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
8 typedef int Py_ssize_t;
9 #define PY_SSIZE_T_MAX INT_MAX
10 #define PY_SSIZE_T_MIN INT_MIN
13 /* the estimated (startup) attribute buffer size in
15 #define ESTIMATE_ATTR_SIZE 256
17 typedef enum {T_FD, T_PATH, T_LINK} target_e;
27 /** Converts from a string, file or int argument to what we need. */
28 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) {
30 if(PyString_Check(myobj)) {
31 tgt->type = nofollow ? T_LINK : T_PATH;
32 tgt->name = PyString_AS_STRING(myobj);
33 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
37 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
43 /* Combine a namespace string and an attribute name into a
44 fully-qualified name */
45 static const char* merge_ns(const char *ns, const char *name, char **buf) {
48 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
49 if((*buf = PyMem_Malloc(new_size)) == NULL) {
53 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
54 if(cnt > new_size || cnt < 0) {
55 PyErr_SetString(PyExc_ValueError,
56 "can't format the attribute name");
67 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
69 return flistxattr(tgt->fd, list, size);
70 else if (tgt->type == T_LINK)
71 return llistxattr(tgt->name, list, size);
73 return listxattr(tgt->name, list, size);
76 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
79 return fgetxattr(tgt->fd, name, value, size);
80 else if (tgt->type == T_LINK)
81 return lgetxattr(tgt->name, name, value, size);
83 return getxattr(tgt->name, name, value, size);
86 static int _set_obj(target_t *tgt, const char *name,
87 const void *value, size_t size, int flags) {
89 return fsetxattr(tgt->fd, name, value, size, flags);
90 else if (tgt->type == T_LINK)
91 return lsetxattr(tgt->name, name, value, size, flags);
93 return setxattr(tgt->name, name, value, size, flags);
96 static int _remove_obj(target_t *tgt, const char *name) {
98 return fremovexattr(tgt->fd, name);
99 else if (tgt->type == T_LINK)
100 return lremovexattr(tgt->name, name);
102 return removexattr(tgt->name, name);
106 Checks if an attribute name matches an optional namespace.
108 If the namespace is NULL, it will return the name itself. If the
109 namespace is non-NULL and the name matches, it will return a
110 pointer to the offset in the name after the namespace and the
111 separator. If however the name doesn't match the namespace, it will
114 const char *matches_ns(const char *ns, const char *name) {
118 ns_size = strlen(ns);
120 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
121 name[ns_size] == '.')
122 return name + ns_size + 1;
126 /* Wrapper for getxattr */
127 static char __pygetxattr_doc__[] =
128 "Get the value of a given extended attribute (deprecated).\n"
131 " - a string representing filename, or a file-like object,\n"
132 " or a file descriptor; this represents the file on \n"
134 " - a string, representing the attribute whose value to retrieve;\n"
135 " usually in form of system.posix_acl or user.mime_type\n"
136 " - (optional) a boolean value (defaults to false), which, if\n"
137 " the file name given is a symbolic link, makes the\n"
138 " function operate on the symbolic link itself instead\n"
140 "@deprecated: since version 0.4, this function has been deprecated\n"
141 " by the L{get} function\n"
145 pygetxattr(PyObject *self, PyObject *args)
152 ssize_t nalloc, nret;
155 /* Parse the arguments */
156 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &nofollow))
158 if(!convertObj(myarg, &tgt, nofollow))
161 /* Find out the needed size of the buffer */
162 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
163 return PyErr_SetFromErrno(PyExc_IOError);
166 /* Try to allocate the memory, using Python's allocator */
167 if((buf = PyMem_Malloc(nalloc)) == NULL) {
172 /* Now retrieve the attribute value */
173 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
175 return PyErr_SetFromErrno(PyExc_IOError);
178 /* Create the string which will hold the result */
179 res = PyString_FromStringAndSize(buf, nret);
181 /* Free the buffer, now it is no longer needed */
184 /* Return the result */
188 /* Wrapper for getxattr */
189 static char __get_doc__[] =
190 "Get the value of a given extended attribute.\n"
193 " >>> xattr.get('/path/to/file', 'user.comment')\n"
195 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
198 "@param item: the item to query; either a string representing the\n"
199 " filename, or a file-like object, or a file descriptor\n"
200 "@param name: the attribute whose value to set; usually in form of\n"
201 " system.posix_acl or user.mime_type\n"
202 "@type name: string\n"
203 "@param nofollow: if given and True, and the function is passed a\n"
204 " filename that points to a symlink, the function will act on the\n"
205 " symlink itself instead of its target\n"
206 "@type nofollow: boolean\n"
207 "@param namespace: if given, the attribute must not contain the\n"
208 " namespace itself, but instead the namespace will be taken from\n"
210 "@type namespace: string\n"
211 "@return: the value of the extended attribute (can contain NULLs)\n"
213 "@raise EnvironmentError: caused by any system errors\n"
218 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
223 char *attrname, *namebuf;
224 const char *fullname;
227 ssize_t nalloc, nret;
229 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
231 /* Parse the arguments */
232 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|iz", kwlist,
233 &myarg, &attrname, &nofollow, &ns))
235 if(!convertObj(myarg, &tgt, nofollow))
238 fullname = merge_ns(ns, attrname, &namebuf);
240 /* Find out the needed size of the buffer */
241 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
242 return PyErr_SetFromErrno(PyExc_IOError);
245 /* Try to allocate the memory, using Python's allocator */
246 if((buf = PyMem_Malloc(nalloc)) == NULL) {
252 /* Now retrieve the attribute value */
253 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
256 return PyErr_SetFromErrno(PyExc_IOError);
259 /* Create the string which will hold the result */
260 res = PyString_FromStringAndSize(buf, nret);
262 /* Free the buffers, they are no longer needed */
266 /* Return the result */
270 /* Wrapper for getxattr */
271 static char __get_all_doc__[] =
272 "Get all the extended attributes of an item.\n"
274 "This function performs a bulk-get of all extended attribute names\n"
275 "and the corresponding value.\n"
277 " >>> xattr.get_all('/path/to/file')\n"
278 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
279 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
280 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
281 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
283 "@param item: the item to query; either a string representing the\n"
284 " filename, or a file-like object, or a file descriptor\n"
285 "@keyword namespace: an optional namespace for filtering the\n"
286 " attributes; for example, querying all user attributes can be\n"
287 " accomplished by passing namespace=L{NS_USER}\n"
288 "@type namespace: string\n"
289 "@keyword nofollow: if passed and true, if the target file is a\n"
290 " symbolic link, the attributes for the link itself will be\n"
291 " returned, instead of the attributes of the target\n"
292 "@type nofollow: boolean\n"
293 "@return: list of tuples (name, value); note that if a namespace\n"
294 " argument was passed, it (and the separator) will be stripped from\n"
295 " the names returned\n"
297 "@raise EnvironmentError: caused by any system errors\n"
298 "@note: Since reading the whole attribute list is not an atomic\n"
299 " operation, it might be possible that attributes are added\n"
300 " or removed between the initial query and the actual reading\n"
301 " of the attributes; the returned list will contain only the\n"
302 " attributes that were present at the initial listing of the\n"
303 " attribute names and that were still present when the read\n"
304 " attempt for the value is made.\n"
309 get_all(PyObject *self, PyObject *args, PyObject *keywds)
314 char *buf_list, *buf_val;
316 size_t nalloc, nlist, nval;
319 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
321 /* Parse the arguments */
322 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
323 &myarg, &dolink, &ns))
325 if(!convertObj(myarg, &tgt, dolink))
328 /* Compute first the list of attributes */
330 /* Find out the needed size of the buffer for the attribute list */
331 nalloc = _list_obj(&tgt, NULL, 0);
334 return PyErr_SetFromErrno(PyExc_IOError);
337 /* Try to allocate the memory, using Python's allocator */
338 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
343 /* Now retrieve the list of attributes */
344 nlist = _list_obj(&tgt, buf_list, nalloc);
347 PyErr_SetFromErrno(PyExc_IOError);
351 /* Create the list which will hold the result */
352 mylist = PyList_New(0);
353 nalloc = ESTIMATE_ATTR_SIZE;
354 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
359 /* Create and insert the attributes as strings in the list */
360 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
365 if((name=matches_ns(ns, s))==NULL)
367 /* Now retrieve the attribute value */
370 nval = _get_obj(&tgt, s, buf_val, nalloc);
373 if(errno == ERANGE) {
374 nval = _get_obj(&tgt, s, NULL, 0);
375 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL)
379 } else if(errno == ENODATA || errno == ENOATTR) {
380 /* this attribute has gone away since we queried
381 the attribute list */
391 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
393 PyList_Append(mylist, my_tuple);
397 /* Free the buffers, now they are no longer needed */
399 PyMem_Free(buf_list);
401 /* Return the result */
404 PyErr_SetFromErrno(PyExc_IOError);
409 PyMem_Free(buf_list);
414 static char __pysetxattr_doc__[] =
415 "Set the value of a given extended attribute (deprecated).\n"
417 "Be carefull in case you want to set attributes on symbolic\n"
418 "links, you have to use all the 5 parameters; use 0 for the \n"
419 "flags value if you want the default behavior (create or "
423 " - a string representing filename, or a file-like object,\n"
424 " or a file descriptor; this represents the file on \n"
426 " - a string, representing the attribute whose value to set;\n"
427 " usually in form of system.posix_acl or user.mime_type\n"
428 " - a string, possibly with embedded NULLs; note that there\n"
429 " are restrictions regarding the size of the value, for\n"
430 " example, for ext2/ext3, maximum size is the block size\n"
431 " - (optional) flags; if 0 or ommited the attribute will be \n"
432 " created or replaced; if XATTR_CREATE, the attribute \n"
433 " will be created, giving an error if it already exists;\n"
434 " of XATTR_REPLACE, the attribute will be replaced,\n"
435 " giving an error if it doesn't exists;\n"
436 " - (optional) a boolean value (defaults to false), which, if\n"
437 " the file name given is a symbolic link, makes the\n"
438 " function operate on the symbolic link itself instead\n"
440 "@deprecated: since version 0.4, this function has been deprecated\n"
441 " by the L{set} function\n"
444 /* Wrapper for setxattr */
446 pysetxattr(PyObject *self, PyObject *args)
457 /* Parse the arguments */
458 if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname,
459 &buf, &bufsize, &flags, &nofollow))
461 if(!convertObj(myarg, &tgt, nofollow))
464 /* Set the attribute's value */
465 if((nret = _set_obj(&tgt, attrname, buf, bufsize, flags)) == -1) {
466 return PyErr_SetFromErrno(PyExc_IOError);
469 /* Return the result */
473 static char __set_doc__[] =
474 "Set the value of a given extended attribute.\n"
477 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
478 " >>> xattr.set('/path/to/file', 'comment', 'test',"
479 " namespace=xattr.NS_USER)\n"
481 "@param item: the item to query; either a string representing the\n"
482 " filename, or a file-like object, or a file descriptor\n"
483 "@param name: the attribute whose value to set; usually in form of\n"
484 " system.posix_acl or user.mime_type\n"
485 "@type name: string\n"
486 "@param value: a string, possibly with embedded NULLs; note that there\n"
487 " are restrictions regarding the size of the value, for\n"
488 " example, for ext2/ext3, maximum size is the block size\n"
489 "@type value: string\n"
490 "@param flags: if 0 or ommited the attribute will be\n"
491 " created or replaced; if L{XATTR_CREATE}, the attribute\n"
492 " will be created, giving an error if it already exists;\n"
493 " if L{XATTR_REPLACE}, the attribute will be replaced,\n"
494 " giving an error if it doesn't exists;\n"
495 "@type flags: integer\n"
496 "@param nofollow: if given and True, and the function is passed a\n"
497 " filename that points to a symlink, the function will act on the\n"
498 " symlink itself instead of its target\n"
499 "@type nofollow: boolean\n"
500 "@param namespace: if given, the attribute must not contain the\n"
501 " namespace itself, but instead the namespace will be taken from\n"
503 "@type namespace: string\n"
505 "@raise EnvironmentError: caused by any system errors\n"
509 /* Wrapper for setxattr */
511 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
523 const char *full_name;
524 static char *kwlist[] = {"item", "name", "value", "flags",
525 "nofollow", "namespace", NULL};
527 /* Parse the arguments */
528 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oss#|iiz", kwlist,
530 &buf, &bufsize, &flags, &nofollow, &ns))
532 if(!convertObj(myarg, &tgt, nofollow))
535 full_name = merge_ns(ns, attrname, &newname);
536 /* Set the attribute's value */
537 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
541 return PyErr_SetFromErrno(PyExc_IOError);
544 /* Return the result */
549 static char __pyremovexattr_doc__[] =
550 "Remove an attribute from a file (deprecated).\n"
553 " - a string representing filename, or a file-like object,\n"
554 " or a file descriptor; this represents the file on \n"
556 " - a string, representing the attribute to be removed;\n"
557 " usually in form of system.posix_acl or user.mime_type\n"
558 " - (optional) a boolean value (defaults to false), which, if\n"
559 " the file name given is a symbolic link, makes the\n"
560 " function operate on the symbolic link itself instead\n"
562 "@deprecated: since version 0.4, this function has been deprecated\n"
567 /* Wrapper for removexattr */
569 pyremovexattr(PyObject *self, PyObject *args)
577 /* Parse the arguments */
578 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &nofollow))
581 if(!convertObj(myarg, &tgt, nofollow))
584 /* Remove the attribute */
585 if((nret = _remove_obj(&tgt, attrname)) == -1) {
586 return PyErr_SetFromErrno(PyExc_IOError);
589 /* Return the result */
593 static char __remove_doc__[] =
594 "Remove an attribute from a file.\n"
597 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
599 "@param item: the item to query; either a string representing the\n"
600 " filename, or a file-like object, or a file descriptor\n"
601 "@param name: the attribute whose value to set; usually in form of\n"
602 " system.posix_acl or user.mime_type\n"
603 "@type name: string\n"
604 "@param nofollow: if given and True, and the function is passed a\n"
605 " filename that points to a symlink, the function will act on the\n"
606 " symlink itself instead of its target\n"
607 "@type nofollow: boolean\n"
608 "@param namespace: if given, the attribute must not contain the\n"
609 " namespace itself, but instead the namespace will be taken from\n"
611 "@type namespace: string\n"
614 "@raise EnvironmentError: caused by any system errors\n"
617 /* Wrapper for removexattr */
619 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
623 char *attrname, *name_buf;
625 const char *full_name;
628 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
630 /* Parse the arguments */
631 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|iz", kwlist,
632 &myarg, &attrname, &nofollow, &ns))
635 if(!convertObj(myarg, &tgt, nofollow))
637 full_name = merge_ns(ns, attrname, &name_buf);
638 if(full_name == NULL)
641 /* Remove the attribute */
642 nret = _remove_obj(&tgt, full_name);
643 PyMem_Free(name_buf);
645 return PyErr_SetFromErrno(PyExc_IOError);
648 /* Return the result */
652 static char __pylistxattr_doc__[] =
653 "Return the list of attribute names for a file (deprecated).\n"
656 " - a string representing filename, or a file-like object,\n"
657 " or a file descriptor; this represents the file to \n"
659 " - (optional) a boolean value (defaults to false), which, if\n"
660 " the file name given is a symbolic link, makes the\n"
661 " function operate on the symbolic link itself instead\n"
663 "@deprecated: since version 0.4, this function has been deprecated\n"
668 /* Wrapper for listxattr */
670 pylistxattr(PyObject *self, PyObject *args)
674 ssize_t nalloc, nret;
681 /* Parse the arguments */
682 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
684 if(!convertObj(myarg, &tgt, nofollow))
687 /* Find out the needed size of the buffer */
688 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
689 return PyErr_SetFromErrno(PyExc_IOError);
692 /* Try to allocate the memory, using Python's allocator */
693 if((buf = PyMem_Malloc(nalloc)) == NULL) {
698 /* Now retrieve the list of attributes */
699 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
701 return PyErr_SetFromErrno(PyExc_IOError);
704 /* Compute the number of attributes in the list */
705 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
709 /* Create the list which will hold the result */
710 mylist = PyList_New(nattrs);
712 /* Create and insert the attributes as strings in the list */
713 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
714 PyList_SET_ITEM(mylist, nattrs, PyString_FromString(s));
718 /* Free the buffer, now it is no longer needed */
721 /* Return the result */
725 static char __list_doc__[] =
726 "Return the list of attribute names for a file.\n"
729 " >>> xattr.list('/path/to/file')\n"
730 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
731 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
732 " ['test', 'comment']\n"
734 "@param item: the item to query; either a string representing the\n"
735 " filename, or a file-like object, or a file descriptor\n"
736 "@param nofollow: if given and True, and the function is passed a\n"
737 " filename that points to a symlink, the function will act on the\n"
738 " symlink itself instead of its target\n"
739 "@type nofollow: boolean\n"
740 "@param namespace: if given, the attribute must not contain the\n"
741 " namespace itself, but instead the namespace will be taken from\n"
743 "@type namespace: string\n"
744 "@return: list of strings; note that if a namespace argument was\n"
745 " passed, it (and the separator) will be stripped from the names\n"
748 "@raise EnvironmentError: caused by any system errors\n"
752 /* Wrapper for listxattr */
754 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
758 ssize_t nalloc, nret;
765 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
767 /* Parse the arguments */
768 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
769 &myarg, &nofollow, &ns))
771 if(!convertObj(myarg, &tgt, nofollow))
774 /* Find out the needed size of the buffer */
775 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
776 return PyErr_SetFromErrno(PyExc_IOError);
779 /* Try to allocate the memory, using Python's allocator */
780 if((buf = PyMem_Malloc(nalloc)) == NULL) {
785 /* Now retrieve the list of attributes */
786 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
788 return PyErr_SetFromErrno(PyExc_IOError);
791 /* Compute the number of attributes in the list */
792 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
793 if(matches_ns(ns, s)!=NULL)
796 /* Create the list which will hold the result */
797 mylist = PyList_New(nattrs);
799 /* Create and insert the attributes as strings in the list */
800 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
801 const char *name = matches_ns(ns, s);
803 PyList_SET_ITEM(mylist, nattrs, PyString_FromString(name));
808 /* Free the buffer, now it is no longer needed */
811 /* Return the result */
815 static PyMethodDef xattr_methods[] = {
816 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
817 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
819 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
821 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
822 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
824 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
825 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
827 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
828 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
830 {NULL, NULL, 0, NULL} /* Sentinel */
833 static char __xattr_doc__[] = \
834 "Interface to extended filesystem attributes.\n"
836 "This module gives access to the extended attributes present\n"
837 "in some operating systems/filesystems. You can list attributes,\n"
838 "get, set and remove them.\n"
840 "The module exposes two sets of functions:\n"
841 " - the 'old' L{listxattr}, L{getxattr}, L{setxattr}, L{removexattr}\n"
842 " functions which are deprecated since version 0.4\n"
843 " - the new L{list}, L{get}, L{get_all}, L{set}, L{remove} functions\n"
844 " which expose a namespace-aware API and simplify a bit the calling\n"
845 " model by using keyword arguments\n"
848 " >>> import xattr\n"
849 " >>> xattr.listxattr(\"file.txt\")\n"
850 " ['user.mime_type']\n"
851 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
853 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
854 "\"Simple text file\")\n"
855 " >>> xattr.listxattr(\"file.txt\")\n"
856 " ['user.mime_type', 'user.comment']\n"
857 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
859 "@note: Most or all errors reported by the system while using the xattr\n"
860 "library will be reported by raising a L{EnvironmentError}; under Linux,\n"
861 "the following C{errno} values are used:\n"
862 " - C{ENOATTR} and C{ENODATA} mean that the attribute name is invalid\n"
863 " - C{ENOTSUP} and C{EOPNOTSUPP} mean that the filesystem does not\n"
864 " support extended attributes, or that the namespace is invalid\n"
865 " - C{E2BIG} mean that the attribute value is too big\n"
866 " - C{ERANGE} mean that the attribute name is too big (it might also\n"
867 " mean an error in the xattr module itself)\n"
868 " - C{ENOSPC} and C{EDQUOT} are documented as meaning out of disk space\n"
869 " or out of disk space because of quota limits\n"
871 "@group Deprecated API: *xattr\n"
872 "@group Namespace constants: NS_*\n"
873 "@group set function flags: XATTR_CREATE, XATTR_REPLACE\n"
874 "@sort: list, get, get_all, set, remove, listxattr, getxattr, setxattr\n"
881 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
883 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
884 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
885 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
886 PyModule_AddStringConstant(m, "__license__",
887 "GNU Lesser General Public License (LGPL)");
888 PyModule_AddStringConstant(m, "__docformat__", "epytext en");
890 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
891 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
893 /* namespace constants */
894 PyModule_AddStringConstant(m, "NS_SECURITY", "security");
895 PyModule_AddStringConstant(m, "NS_SYSTEM", "system");
896 PyModule_AddStringConstant(m, "NS_TRUSTED", "trusted");
897 PyModule_AddStringConstant(m, "NS_USER", "user");