2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008 Iustin Pop <iusty@k1024.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #define PY_SSIZE_T_CLEAN
25 #include <attr/xattr.h>
28 /* Compatibility with python 2.4 regarding python size type (PEP 353) */
29 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
30 typedef int Py_ssize_t;
31 #define PY_SSIZE_T_MAX INT_MAX
32 #define PY_SSIZE_T_MIN INT_MIN
35 #if PY_MAJOR_VERSION >= 3
38 #define PyBytes_Check PyString_Check
39 #define PyBytes_AS_STRING PyString_AS_STRING
40 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
41 #define PyBytes_FromString PyString_FromString
44 /* the estimated (startup) attribute buffer size in
46 #define ESTIMATE_ATTR_SIZE 256
48 typedef enum {T_FD, T_PATH, T_LINK} target_e;
58 /** Converts from a string, file or int argument to what we need. */
59 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) {
61 if(PyString_Check(myobj)) {
62 tgt->type = nofollow ? T_LINK : T_PATH;
63 tgt->name = PyString_AS_STRING(myobj);
64 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
68 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
74 /* Combine a namespace string and an attribute name into a
75 fully-qualified name */
76 static const char* merge_ns(const char *ns, const char *name, char **buf) {
79 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
80 if((*buf = PyMem_Malloc(new_size)) == NULL) {
84 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
85 if(cnt > new_size || cnt < 0) {
86 PyErr_SetString(PyExc_ValueError,
87 "can't format the attribute name");
98 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
100 return flistxattr(tgt->fd, list, size);
101 else if (tgt->type == T_LINK)
102 return llistxattr(tgt->name, list, size);
104 return listxattr(tgt->name, list, size);
107 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
109 if(tgt->type == T_FD)
110 return fgetxattr(tgt->fd, name, value, size);
111 else if (tgt->type == T_LINK)
112 return lgetxattr(tgt->name, name, value, size);
114 return getxattr(tgt->name, name, value, size);
117 static int _set_obj(target_t *tgt, const char *name,
118 const void *value, size_t size, int flags) {
119 if(tgt->type == T_FD)
120 return fsetxattr(tgt->fd, name, value, size, flags);
121 else if (tgt->type == T_LINK)
122 return lsetxattr(tgt->name, name, value, size, flags);
124 return setxattr(tgt->name, name, value, size, flags);
127 static int _remove_obj(target_t *tgt, const char *name) {
128 if(tgt->type == T_FD)
129 return fremovexattr(tgt->fd, name);
130 else if (tgt->type == T_LINK)
131 return lremovexattr(tgt->name, name);
133 return removexattr(tgt->name, name);
137 Checks if an attribute name matches an optional namespace.
139 If the namespace is NULL, it will return the name itself. If the
140 namespace is non-NULL and the name matches, it will return a
141 pointer to the offset in the name after the namespace and the
142 separator. If however the name doesn't match the namespace, it will
145 const char *matches_ns(const char *ns, const char *name) {
149 ns_size = strlen(ns);
151 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
152 name[ns_size] == '.')
153 return name + ns_size + 1;
157 /* Wrapper for getxattr */
158 static char __pygetxattr_doc__[] =
159 "Get the value of a given extended attribute (deprecated).\n"
162 " - a string representing filename, or a file-like object,\n"
163 " or a file descriptor; this represents the file on \n"
165 " - a string, representing the attribute whose value to retrieve;\n"
166 " usually in form of system.posix_acl or user.mime_type\n"
167 " - (optional) a boolean value (defaults to false), which, if\n"
168 " the file name given is a symbolic link, makes the\n"
169 " function operate on the symbolic link itself instead\n"
171 "@deprecated: since version 0.4, this function has been deprecated\n"
172 " by the L{get} function\n"
176 pygetxattr(PyObject *self, PyObject *args)
183 ssize_t nalloc, nret;
186 /* Parse the arguments */
187 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &nofollow))
189 if(!convertObj(myarg, &tgt, nofollow))
192 /* Find out the needed size of the buffer */
193 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
194 return PyErr_SetFromErrno(PyExc_IOError);
197 /* Try to allocate the memory, using Python's allocator */
198 if((buf = PyMem_Malloc(nalloc)) == NULL) {
203 /* Now retrieve the attribute value */
204 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
206 return PyErr_SetFromErrno(PyExc_IOError);
209 /* Create the string which will hold the result */
210 res = PyString_FromStringAndSize(buf, nret);
212 /* Free the buffer, now it is no longer needed */
215 /* Return the result */
219 /* Wrapper for getxattr */
220 static char __get_doc__[] =
221 "Get the value of a given extended attribute.\n"
224 " >>> xattr.get('/path/to/file', 'user.comment')\n"
226 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
229 "@param item: the item to query; either a string representing the\n"
230 " filename, or a file-like object, or a file descriptor\n"
231 "@param name: the attribute whose value to set; usually in form of\n"
232 " system.posix_acl or user.mime_type\n"
233 "@type name: string\n"
234 "@param nofollow: if given and True, and the function is passed a\n"
235 " filename that points to a symlink, the function will act on the\n"
236 " symlink itself instead of its target\n"
237 "@type nofollow: boolean\n"
238 "@param namespace: if given, the attribute must not contain the\n"
239 " namespace itself, but instead the namespace will be taken from\n"
241 "@type namespace: string\n"
242 "@return: the value of the extended attribute (can contain NULLs)\n"
244 "@raise EnvironmentError: caused by any system errors\n"
249 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
254 char *attrname, *namebuf;
255 const char *fullname;
258 ssize_t nalloc, nret;
260 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
262 /* Parse the arguments */
263 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|iz", kwlist,
264 &myarg, &attrname, &nofollow, &ns))
266 if(!convertObj(myarg, &tgt, nofollow))
269 fullname = merge_ns(ns, attrname, &namebuf);
271 /* Find out the needed size of the buffer */
272 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
273 return PyErr_SetFromErrno(PyExc_IOError);
276 /* Try to allocate the memory, using Python's allocator */
277 if((buf = PyMem_Malloc(nalloc)) == NULL) {
283 /* Now retrieve the attribute value */
284 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
287 return PyErr_SetFromErrno(PyExc_IOError);
290 /* Create the string which will hold the result */
291 res = PyString_FromStringAndSize(buf, nret);
293 /* Free the buffers, they are no longer needed */
297 /* Return the result */
301 /* Wrapper for getxattr */
302 static char __get_all_doc__[] =
303 "Get all the extended attributes of an item.\n"
305 "This function performs a bulk-get of all extended attribute names\n"
306 "and the corresponding value.\n"
308 " >>> xattr.get_all('/path/to/file')\n"
309 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
310 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
311 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
312 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
314 "@param item: the item to query; either a string representing the\n"
315 " filename, or a file-like object, or a file descriptor\n"
316 "@keyword namespace: an optional namespace for filtering the\n"
317 " attributes; for example, querying all user attributes can be\n"
318 " accomplished by passing namespace=L{NS_USER}\n"
319 "@type namespace: string\n"
320 "@keyword nofollow: if passed and true, if the target file is a\n"
321 " symbolic link, the attributes for the link itself will be\n"
322 " returned, instead of the attributes of the target\n"
323 "@type nofollow: boolean\n"
324 "@return: list of tuples (name, value); note that if a namespace\n"
325 " argument was passed, it (and the separator) will be stripped from\n"
326 " the names returned\n"
328 "@raise EnvironmentError: caused by any system errors\n"
329 "@note: Since reading the whole attribute list is not an atomic\n"
330 " operation, it might be possible that attributes are added\n"
331 " or removed between the initial query and the actual reading\n"
332 " of the attributes; the returned list will contain only the\n"
333 " attributes that were present at the initial listing of the\n"
334 " attribute names and that were still present when the read\n"
335 " attempt for the value is made.\n"
340 get_all(PyObject *self, PyObject *args, PyObject *keywds)
345 char *buf_list, *buf_val;
347 size_t nalloc, nlist, nval;
350 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
352 /* Parse the arguments */
353 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
354 &myarg, &dolink, &ns))
356 if(!convertObj(myarg, &tgt, dolink))
359 /* Compute first the list of attributes */
361 /* Find out the needed size of the buffer for the attribute list */
362 nalloc = _list_obj(&tgt, NULL, 0);
365 return PyErr_SetFromErrno(PyExc_IOError);
368 /* Try to allocate the memory, using Python's allocator */
369 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
374 /* Now retrieve the list of attributes */
375 nlist = _list_obj(&tgt, buf_list, nalloc);
378 PyErr_SetFromErrno(PyExc_IOError);
382 /* Create the list which will hold the result */
383 mylist = PyList_New(0);
384 nalloc = ESTIMATE_ATTR_SIZE;
385 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
390 /* Create and insert the attributes as strings in the list */
391 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
396 if((name=matches_ns(ns, s))==NULL)
398 /* Now retrieve the attribute value */
401 nval = _get_obj(&tgt, s, buf_val, nalloc);
404 if(errno == ERANGE) {
405 nval = _get_obj(&tgt, s, NULL, 0);
406 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL)
410 } else if(errno == ENODATA || errno == ENOATTR) {
411 /* this attribute has gone away since we queried
412 the attribute list */
422 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
424 PyList_Append(mylist, my_tuple);
428 /* Free the buffers, now they are no longer needed */
430 PyMem_Free(buf_list);
432 /* Return the result */
435 PyErr_SetFromErrno(PyExc_IOError);
440 PyMem_Free(buf_list);
445 static char __pysetxattr_doc__[] =
446 "Set the value of a given extended attribute (deprecated).\n"
448 "Be carefull in case you want to set attributes on symbolic\n"
449 "links, you have to use all the 5 parameters; use 0 for the \n"
450 "flags value if you want the default behavior (create or "
454 " - a string representing filename, or a file-like object,\n"
455 " or a file descriptor; this represents the file on \n"
457 " - a string, representing the attribute whose value to set;\n"
458 " usually in form of system.posix_acl or user.mime_type\n"
459 " - a string, possibly with embedded NULLs; note that there\n"
460 " are restrictions regarding the size of the value, for\n"
461 " example, for ext2/ext3, maximum size is the block size\n"
462 " - (optional) flags; if 0 or ommited the attribute will be \n"
463 " created or replaced; if XATTR_CREATE, the attribute \n"
464 " will be created, giving an error if it already exists;\n"
465 " of XATTR_REPLACE, the attribute will be replaced,\n"
466 " giving an error if it doesn't exists;\n"
467 " - (optional) a boolean value (defaults to false), which, if\n"
468 " the file name given is a symbolic link, makes the\n"
469 " function operate on the symbolic link itself instead\n"
471 "@deprecated: since version 0.4, this function has been deprecated\n"
472 " by the L{set} function\n"
475 /* Wrapper for setxattr */
477 pysetxattr(PyObject *self, PyObject *args)
488 /* Parse the arguments */
489 if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname,
490 &buf, &bufsize, &flags, &nofollow))
492 if(!convertObj(myarg, &tgt, nofollow))
495 /* Set the attribute's value */
496 if((nret = _set_obj(&tgt, attrname, buf, bufsize, flags)) == -1) {
497 return PyErr_SetFromErrno(PyExc_IOError);
500 /* Return the result */
504 static char __set_doc__[] =
505 "Set the value of a given extended attribute.\n"
508 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
509 " >>> xattr.set('/path/to/file', 'comment', 'test',"
510 " namespace=xattr.NS_USER)\n"
512 "@param item: the item to query; either a string representing the\n"
513 " filename, or a file-like object, or a file descriptor\n"
514 "@param name: the attribute whose value to set; usually in form of\n"
515 " system.posix_acl or user.mime_type\n"
516 "@type name: string\n"
517 "@param value: a string, possibly with embedded NULLs; note that there\n"
518 " are restrictions regarding the size of the value, for\n"
519 " example, for ext2/ext3, maximum size is the block size\n"
520 "@type value: string\n"
521 "@param flags: if 0 or ommited the attribute will be\n"
522 " created or replaced; if L{XATTR_CREATE}, the attribute\n"
523 " will be created, giving an error if it already exists;\n"
524 " if L{XATTR_REPLACE}, the attribute will be replaced,\n"
525 " giving an error if it doesn't exists;\n"
526 "@type flags: integer\n"
527 "@param nofollow: if given and True, and the function is passed a\n"
528 " filename that points to a symlink, the function will act on the\n"
529 " symlink itself instead of its target\n"
530 "@type nofollow: boolean\n"
531 "@param namespace: if given, the attribute must not contain the\n"
532 " namespace itself, but instead the namespace will be taken from\n"
534 "@type namespace: string\n"
536 "@raise EnvironmentError: caused by any system errors\n"
540 /* Wrapper for setxattr */
542 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
554 const char *full_name;
555 static char *kwlist[] = {"item", "name", "value", "flags",
556 "nofollow", "namespace", NULL};
558 /* Parse the arguments */
559 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oss#|iiz", kwlist,
561 &buf, &bufsize, &flags, &nofollow, &ns))
563 if(!convertObj(myarg, &tgt, nofollow))
566 full_name = merge_ns(ns, attrname, &newname);
567 /* Set the attribute's value */
568 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
572 return PyErr_SetFromErrno(PyExc_IOError);
575 /* Return the result */
580 static char __pyremovexattr_doc__[] =
581 "Remove an attribute from a file (deprecated).\n"
584 " - a string representing filename, or a file-like object,\n"
585 " or a file descriptor; this represents the file on \n"
587 " - a string, representing the attribute to be removed;\n"
588 " usually in form of system.posix_acl or user.mime_type\n"
589 " - (optional) a boolean value (defaults to false), which, if\n"
590 " the file name given is a symbolic link, makes the\n"
591 " function operate on the symbolic link itself instead\n"
593 "@deprecated: since version 0.4, this function has been deprecated\n"
598 /* Wrapper for removexattr */
600 pyremovexattr(PyObject *self, PyObject *args)
608 /* Parse the arguments */
609 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &nofollow))
612 if(!convertObj(myarg, &tgt, nofollow))
615 /* Remove the attribute */
616 if((nret = _remove_obj(&tgt, attrname)) == -1) {
617 return PyErr_SetFromErrno(PyExc_IOError);
620 /* Return the result */
624 static char __remove_doc__[] =
625 "Remove an attribute from a file.\n"
628 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
630 "@param item: the item to query; either a string representing the\n"
631 " filename, or a file-like object, or a file descriptor\n"
632 "@param name: the attribute whose value to set; usually in form of\n"
633 " system.posix_acl or user.mime_type\n"
634 "@type name: string\n"
635 "@param nofollow: if given and True, and the function is passed a\n"
636 " filename that points to a symlink, the function will act on the\n"
637 " symlink itself instead of its target\n"
638 "@type nofollow: boolean\n"
639 "@param namespace: if given, the attribute must not contain the\n"
640 " namespace itself, but instead the namespace will be taken from\n"
642 "@type namespace: string\n"
645 "@raise EnvironmentError: caused by any system errors\n"
648 /* Wrapper for removexattr */
650 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
654 char *attrname, *name_buf;
656 const char *full_name;
659 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
661 /* Parse the arguments */
662 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|iz", kwlist,
663 &myarg, &attrname, &nofollow, &ns))
666 if(!convertObj(myarg, &tgt, nofollow))
668 full_name = merge_ns(ns, attrname, &name_buf);
669 if(full_name == NULL)
672 /* Remove the attribute */
673 nret = _remove_obj(&tgt, full_name);
674 PyMem_Free(name_buf);
676 return PyErr_SetFromErrno(PyExc_IOError);
679 /* Return the result */
683 static char __pylistxattr_doc__[] =
684 "Return the list of attribute names for a file (deprecated).\n"
687 " - a string representing filename, or a file-like object,\n"
688 " or a file descriptor; this represents the file to \n"
690 " - (optional) a boolean value (defaults to false), which, if\n"
691 " the file name given is a symbolic link, makes the\n"
692 " function operate on the symbolic link itself instead\n"
694 "@deprecated: since version 0.4, this function has been deprecated\n"
699 /* Wrapper for listxattr */
701 pylistxattr(PyObject *self, PyObject *args)
705 ssize_t nalloc, nret;
712 /* Parse the arguments */
713 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
715 if(!convertObj(myarg, &tgt, nofollow))
718 /* Find out the needed size of the buffer */
719 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
720 return PyErr_SetFromErrno(PyExc_IOError);
723 /* Try to allocate the memory, using Python's allocator */
724 if((buf = PyMem_Malloc(nalloc)) == NULL) {
729 /* Now retrieve the list of attributes */
730 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
732 return PyErr_SetFromErrno(PyExc_IOError);
735 /* Compute the number of attributes in the list */
736 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
740 /* Create the list which will hold the result */
741 mylist = PyList_New(nattrs);
743 /* Create and insert the attributes as strings in the list */
744 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
745 PyList_SET_ITEM(mylist, nattrs, PyString_FromString(s));
749 /* Free the buffer, now it is no longer needed */
752 /* Return the result */
756 static char __list_doc__[] =
757 "Return the list of attribute names for a file.\n"
760 " >>> xattr.list('/path/to/file')\n"
761 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
762 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
763 " ['test', 'comment']\n"
765 "@param item: the item to query; either a string representing the\n"
766 " filename, or a file-like object, or a file descriptor\n"
767 "@param nofollow: if given and True, and the function is passed a\n"
768 " filename that points to a symlink, the function will act on the\n"
769 " symlink itself instead of its target\n"
770 "@type nofollow: boolean\n"
771 "@param namespace: if given, the attribute must not contain the\n"
772 " namespace itself, but instead the namespace will be taken from\n"
774 "@type namespace: string\n"
775 "@return: list of strings; note that if a namespace argument was\n"
776 " passed, it (and the separator) will be stripped from the names\n"
779 "@raise EnvironmentError: caused by any system errors\n"
783 /* Wrapper for listxattr */
785 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
789 ssize_t nalloc, nret;
796 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
798 /* Parse the arguments */
799 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
800 &myarg, &nofollow, &ns))
802 if(!convertObj(myarg, &tgt, nofollow))
805 /* Find out the needed size of the buffer */
806 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
807 return PyErr_SetFromErrno(PyExc_IOError);
810 /* Try to allocate the memory, using Python's allocator */
811 if((buf = PyMem_Malloc(nalloc)) == NULL) {
816 /* Now retrieve the list of attributes */
817 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
819 return PyErr_SetFromErrno(PyExc_IOError);
822 /* Compute the number of attributes in the list */
823 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
824 if(matches_ns(ns, s)!=NULL)
827 /* Create the list which will hold the result */
828 mylist = PyList_New(nattrs);
830 /* Create and insert the attributes as strings in the list */
831 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
832 const char *name = matches_ns(ns, s);
834 PyList_SET_ITEM(mylist, nattrs, PyString_FromString(name));
839 /* Free the buffer, now it is no longer needed */
842 /* Return the result */
846 static PyMethodDef xattr_methods[] = {
847 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
848 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
850 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
852 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
853 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
855 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
856 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
858 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
859 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
861 {NULL, NULL, 0, NULL} /* Sentinel */
864 static char __xattr_doc__[] = \
865 "Interface to extended filesystem attributes.\n"
867 "This module gives access to the extended attributes present\n"
868 "in some operating systems/filesystems. You can list attributes,\n"
869 "get, set and remove them.\n"
871 "The module exposes two sets of functions:\n"
872 " - the 'old' L{listxattr}, L{getxattr}, L{setxattr}, L{removexattr}\n"
873 " functions which are deprecated since version 0.4\n"
874 " - the new L{list}, L{get}, L{get_all}, L{set}, L{remove} functions\n"
875 " which expose a namespace-aware API and simplify a bit the calling\n"
876 " model by using keyword arguments\n"
879 " >>> import xattr\n"
880 " >>> xattr.listxattr(\"file.txt\")\n"
881 " ['user.mime_type']\n"
882 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
884 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
885 "\"Simple text file\")\n"
886 " >>> xattr.listxattr(\"file.txt\")\n"
887 " ['user.mime_type', 'user.comment']\n"
888 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
890 "@note: Most or all errors reported by the system while using the xattr\n"
891 "library will be reported by raising a L{EnvironmentError}; under Linux,\n"
892 "the following C{errno} values are used:\n"
893 " - C{ENOATTR} and C{ENODATA} mean that the attribute name is invalid\n"
894 " - C{ENOTSUP} and C{EOPNOTSUPP} mean that the filesystem does not\n"
895 " support extended attributes, or that the namespace is invalid\n"
896 " - C{E2BIG} mean that the attribute value is too big\n"
897 " - C{ERANGE} mean that the attribute name is too big (it might also\n"
898 " mean an error in the xattr module itself)\n"
899 " - C{ENOSPC} and C{EDQUOT} are documented as meaning out of disk space\n"
900 " or out of disk space because of quota limits\n"
902 "@group Deprecated API: *xattr\n"
903 "@group Namespace constants: NS_*\n"
904 "@group set function flags: XATTR_CREATE, XATTR_REPLACE\n"
905 "@sort: list, get, get_all, set, remove, listxattr, getxattr, setxattr\n"
911 static struct PyModuleDef xattrmodule = {
912 PyModuleDef_HEAD_INIT,
919 #define INITERROR return NULL
925 #define INITERROR return
931 PyObject *m = PyModule_Create(&xattrmodule);
933 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
938 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
939 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
940 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
941 PyModule_AddStringConstant(m, "__license__",
942 "GNU Lesser General Public License (LGPL)");
943 PyModule_AddStringConstant(m, "__docformat__", "epytext en");
945 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
946 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
948 /* namespace constants */
949 PyModule_AddObject(m, "NS_SECURITY", PyBytes_FromString("security"));
950 PyModule_AddObject(m, "NS_SYSTEM", PyBytes_FromString("system"));
951 PyModule_AddObject(m, "NS_TRUSTED", PyBytes_FromString("trusted"));
952 PyModule_AddObject(m, "NS_USER", PyBytes_FromString("user"));