2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008, 2012 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
37 #define BYTES_CHAR "y"
39 #define BYTES_CHAR "z"
40 #define PyBytes_Check PyString_Check
41 #define PyBytes_AS_STRING PyString_AS_STRING
42 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
43 #define PyBytes_FromString PyString_FromString
47 ":param item: a string representing a file-name, or a file-like\n" \
48 " object, or a file descriptor; this represents the file on \n" \
51 #define NOFOLLOW_DOC \
52 ":param nofollow: if true and if\n" \
53 " the file name given is a symbolic link, the\n" \
54 " function will operate on the symbolic link itself instead\n" \
55 " of its target; defaults to false\n" \
56 ":type nofollow: boolean, optional\n" \
59 ":param namespace: if given, the attribute must not contain the\n" \
60 " namespace, but instead it will be taken from this parameter\n" \
61 ":type namespace: bytes\n"
63 #define NAME_GET_DOC \
64 ":param string name: the attribute whose value to retrieve;\n" \
65 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
67 #define NAME_SET_DOC \
68 ":param string name: the attribute whose value to set;\n" \
69 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
71 #define NAME_REMOVE_DOC \
72 ":param string name: the attribute to remove;\n" \
73 " usually in the form of ``system.posix_acl`` or \n" \
74 " ``user.mime_type``\n"
77 ":param string value: possibly with embedded NULLs; note that there\n" \
78 " are restrictions regarding the size of the value, for\n" \
79 " example, for ext2/ext3, maximum size is the block size\n" \
82 ":param flags: if 0 or omitted the attribute will be\n" \
83 " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" \
84 " will be created, giving an error if it already exists;\n" \
85 " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" \
86 " giving an error if it doesn't exist;\n" \
87 ":type flags: integer\n"
90 /* the estimated (startup) attribute buffer size in
92 #define ESTIMATE_ATTR_SIZE 256
94 typedef enum {T_FD, T_PATH, T_LINK} target_e;
105 /* Cleans up a tgt structure */
106 static void free_tgt(target_t *tgt) {
107 if (tgt->tmp != NULL) {
112 /* Used for cpychecker: */
113 /* The checker automatically defines this preprocessor name when creating
114 the custom attribute: */
115 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
116 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
117 __attribute__((cpychecker_negative_result_sets_exception))
119 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
122 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow)
123 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
125 static int merge_ns(const char *ns, const char *name,
126 const char **result, char **buf)
127 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
130 /** Converts from a string, file or int argument to what we need.
132 * Returns -1 on failure, 0 on success.
134 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) {
137 if(PyBytes_Check(myobj)) {
138 tgt->type = nofollow ? T_LINK : T_PATH;
139 tgt->name = PyBytes_AS_STRING(myobj);
140 } else if(PyUnicode_Check(myobj)) {
141 tgt->type = nofollow ? T_LINK : T_PATH;
143 PyUnicode_AsEncodedString(myobj,
144 Py_FileSystemDefaultEncoding, "strict");
147 tgt->name = PyBytes_AS_STRING(tgt->tmp);
148 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
152 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
158 /* Combine a namespace string and an attribute name into a
159 fully-qualified name */
160 static int merge_ns(const char *ns, const char *name,
161 const char **result, char **buf) {
162 if(ns != NULL && *ns != '\0') {
164 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
165 if((*buf = PyMem_Malloc(new_size)) == NULL) {
169 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
170 if(cnt > new_size || cnt < 0) {
171 PyErr_SetString(PyExc_ValueError,
172 "can't format the attribute name");
184 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
185 if(tgt->type == T_FD)
186 return flistxattr(tgt->fd, list, size);
187 else if (tgt->type == T_LINK)
188 return llistxattr(tgt->name, list, size);
190 return listxattr(tgt->name, list, size);
193 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
195 if(tgt->type == T_FD)
196 return fgetxattr(tgt->fd, name, value, size);
197 else if (tgt->type == T_LINK)
198 return lgetxattr(tgt->name, name, value, size);
200 return getxattr(tgt->name, name, value, size);
203 static int _set_obj(target_t *tgt, const char *name,
204 const void *value, size_t size, int flags) {
205 if(tgt->type == T_FD)
206 return fsetxattr(tgt->fd, name, value, size, flags);
207 else if (tgt->type == T_LINK)
208 return lsetxattr(tgt->name, name, value, size, flags);
210 return setxattr(tgt->name, name, value, size, flags);
213 static int _remove_obj(target_t *tgt, const char *name) {
214 if(tgt->type == T_FD)
215 return fremovexattr(tgt->fd, name);
216 else if (tgt->type == T_LINK)
217 return lremovexattr(tgt->name, name);
219 return removexattr(tgt->name, name);
223 Checks if an attribute name matches an optional namespace.
225 If the namespace is NULL or an empty string, it will return the
226 name itself. If the namespace is non-NULL and the name matches, it
227 will return a pointer to the offset in the name after the namespace
228 and the separator. If however the name doesn't match the namespace,
232 const char *matches_ns(const char *ns, const char *name) {
234 if (ns == NULL || *ns == '\0')
236 ns_size = strlen(ns);
238 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
239 name[ns_size] == '.')
240 return name + ns_size + 1;
244 /* Wrapper for getxattr */
245 static char __pygetxattr_doc__[] =
246 "getxattr(item, attribute[, nofollow=False])\n"
247 "Get the value of a given extended attribute (deprecated).\n"
253 ".. deprecated:: 0.4\n"
254 " this function has been deprecated\n"
255 " by the :func:`get` function.\n"
259 pygetxattr(PyObject *self, PyObject *args)
264 char *attrname = NULL;
266 ssize_t nalloc, nret;
269 /* Parse the arguments */
270 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
272 if(convert_obj(myarg, &tgt, nofollow) < 0) {
277 /* Find out the needed size of the buffer */
278 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
279 res = PyErr_SetFromErrno(PyExc_IOError);
283 /* Try to allocate the memory, using Python's allocator */
284 if((buf = PyMem_Malloc(nalloc)) == NULL) {
285 res = PyErr_NoMemory();
289 /* Now retrieve the attribute value */
290 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
291 res = PyErr_SetFromErrno(PyExc_IOError);
295 /* Create the string which will hold the result */
296 res = PyBytes_FromStringAndSize(buf, nret);
299 /* Free the buffer, now it is no longer needed */
304 PyMem_Free(attrname);
306 /* Return the result */
310 /* Wrapper for getxattr */
311 static char __get_doc__[] =
312 "get(item, name[, nofollow=False, namespace=None])\n"
313 "Get the value of a given extended attribute.\n"
316 " >>> xattr.get('/path/to/file', 'user.comment')\n"
318 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
325 ":return: the value of the extended attribute (can contain NULLs)\n"
327 ":raises EnvironmentError: caused by any system errors\n"
329 ".. versionadded:: 0.4\n"
333 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
338 char *attrname = NULL, *namebuf;
339 const char *fullname;
341 const char *ns = NULL;
342 ssize_t nalloc, nret;
344 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
346 /* Parse the arguments */
347 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
348 &myarg, NULL, &attrname, &nofollow, &ns))
350 if(convert_obj(myarg, &tgt, nofollow) < 0) {
355 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
360 /* Find out the needed size of the buffer */
361 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
362 res = PyErr_SetFromErrno(PyExc_IOError);
366 /* Try to allocate the memory, using Python's allocator */
367 if((buf = PyMem_Malloc(nalloc)) == NULL) {
368 res = PyErr_NoMemory();
372 /* Now retrieve the attribute value */
373 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
374 res = PyErr_SetFromErrno(PyExc_IOError);
378 /* Create the string which will hold the result */
379 res = PyBytes_FromStringAndSize(buf, nret);
381 /* Free the buffers, they are no longer needed */
389 PyMem_Free(attrname);
391 /* Return the result */
395 /* Wrapper for getxattr */
396 static char __get_all_doc__[] =
397 "get_all(item[, nofollow=False, namespace=None])\n"
398 "Get all the extended attributes of an item.\n"
400 "This function performs a bulk-get of all extended attribute names\n"
401 "and the corresponding value.\n"
404 " >>> xattr.get_all('/path/to/file')\n"
405 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
406 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
407 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
408 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
411 ":keyword namespace: an optional namespace for filtering the\n"
412 " attributes; for example, querying all user attributes can be\n"
413 " accomplished by passing namespace=:const:`NS_USER`\n"
414 ":type namespace: string\n"
416 ":return: list of tuples (name, value); note that if a namespace\n"
417 " argument was passed, it (and the separator) will be stripped from\n"
418 " the names returned\n"
420 ":raises EnvironmentError: caused by any system errors\n"
422 ".. note:: Since reading the whole attribute list is not an atomic\n"
423 " operation, it might be possible that attributes are added\n"
424 " or removed between the initial query and the actual reading\n"
425 " of the attributes; the returned list will contain only the\n"
426 " attributes that were present at the initial listing of the\n"
427 " attribute names and that were still present when the read\n"
428 " attempt for the value is made.\n"
429 ".. versionadded:: 0.4\n"
433 get_all(PyObject *self, PyObject *args, PyObject *keywds)
435 PyObject *myarg, *res;
437 const char *ns = NULL;
438 char *buf_list, *buf_val;
440 ssize_t nalloc, nlist, nval;
443 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
445 /* Parse the arguments */
446 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
447 &myarg, &nofollow, &ns))
449 if(convert_obj(myarg, &tgt, nofollow) < 0)
452 /* Compute first the list of attributes */
454 /* Find out the needed size of the buffer for the attribute list */
455 nalloc = _list_obj(&tgt, NULL, 0);
458 res = PyErr_SetFromErrno(PyExc_IOError);
462 /* Try to allocate the memory, using Python's allocator */
463 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
464 res = PyErr_NoMemory();
468 /* Now retrieve the list of attributes */
469 nlist = _list_obj(&tgt, buf_list, nalloc);
472 res = PyErr_SetFromErrno(PyExc_IOError);
476 /* Create the list which will hold the result */
477 mylist = PyList_New(0);
483 nalloc = ESTIMATE_ATTR_SIZE;
484 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
486 res = PyErr_NoMemory();
490 /* Create and insert the attributes as strings in the list */
491 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
496 if((name=matches_ns(ns, s))==NULL)
498 /* Now retrieve the attribute value */
501 nval = _get_obj(&tgt, s, buf_val, nalloc);
504 if(errno == ERANGE) {
505 nval = _get_obj(&tgt, s, NULL, 0);
506 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) {
507 res = PyErr_NoMemory();
513 } else if(errno == ENODATA || errno == ENOATTR) {
514 /* this attribute has gone away since we queried
515 the attribute list */
519 /* else we're dealing with a different error, which we
520 don't know how to handle nicely, so we abort */
522 res = PyErr_SetFromErrno(PyExc_IOError);
530 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
532 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
534 if (my_tuple == NULL) {
539 PyList_Append(mylist, my_tuple);
543 /* Successful exit */
550 PyMem_Free(buf_list);
555 /* Return the result */
560 static char __pysetxattr_doc__[] =
561 "setxattr(item, name, value[, flags=0, nofollow=False])\n"
562 "Set the value of a given extended attribute (deprecated).\n"
564 "Be careful in case you want to set attributes on symbolic\n"
565 "links, you have to use all the 5 parameters; use 0 for the \n"
566 "flags value if you want the default behaviour (create or "
575 ".. deprecated:: 0.4\n"
576 " this function has been deprecated\n"
577 " by the :func:`set` function.\n"
580 /* Wrapper for setxattr */
582 pysetxattr(PyObject *self, PyObject *args)
584 PyObject *myarg, *res;
586 char *attrname = NULL;
593 /* Parse the arguments */
594 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
595 NULL, &buf, &bufsize, &flags, &nofollow))
597 if(convert_obj(myarg, &tgt, nofollow) < 0) {
602 /* Set the attribute's value */
603 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
608 res = PyErr_SetFromErrno(PyExc_IOError);
616 PyMem_Free(attrname);
619 /* Return the result */
623 static char __set_doc__[] =
624 "set(item, name, value[, flags=0, namespace=None])\n"
625 "Set the value of a given extended attribute.\n"
629 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
630 " >>> xattr.set('/path/to/file', 'comment', 'test',"
631 " namespace=xattr.NS_USER)\n"
640 ":raises EnvironmentError: caused by any system errors\n"
642 ".. versionadded:: 0.4\n"
645 /* Wrapper for setxattr */
647 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
649 PyObject *myarg, *res;
651 char *attrname = NULL;
657 const char *ns = NULL;
659 const char *full_name;
660 static char *kwlist[] = {"item", "name", "value", "flags",
661 "nofollow", "namespace", NULL};
663 /* Parse the arguments */
664 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
665 kwlist, &myarg, NULL, &attrname, NULL,
666 &buf, &bufsize, &flags, &nofollow, &ns))
668 if(convert_obj(myarg, &tgt, nofollow) < 0) {
673 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
678 /* Set the attribute's value */
679 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
686 res = PyErr_SetFromErrno(PyExc_IOError);
694 PyMem_Free(attrname);
697 /* Return the result */
702 static char __pyremovexattr_doc__[] =
703 "removexattr(item, name[, nofollow])\n"
704 "Remove an attribute from a file (deprecated).\n"
710 ".. deprecated:: 0.4\n"
711 " this function has been deprecated by the :func:`remove` function.\n"
714 /* Wrapper for removexattr */
716 pyremovexattr(PyObject *self, PyObject *args)
718 PyObject *myarg, *res;
720 char *attrname = NULL;
724 /* Parse the arguments */
725 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
728 if(convert_obj(myarg, &tgt, nofollow) < 0) {
733 /* Remove the attribute */
734 nret = _remove_obj(&tgt, attrname);
739 res = PyErr_SetFromErrno(PyExc_IOError);
747 PyMem_Free(attrname);
749 /* Return the result */
753 static char __remove_doc__[] =
754 "remove(item, name[, nofollow=False, namespace=None])\n"
755 "Remove an attribute from a file.\n"
759 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
766 ":raises EnvironmentError: caused by any system errors\n"
768 ".. versionadded:: 0.4\n"
771 /* Wrapper for removexattr */
773 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
775 PyObject *myarg, *res;
777 char *attrname = NULL, *name_buf;
778 const char *ns = NULL;
779 const char *full_name;
782 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
784 /* Parse the arguments */
785 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
786 &myarg, NULL, &attrname, &nofollow, &ns))
789 if(convert_obj(myarg, &tgt, nofollow) < 0) {
794 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
799 /* Remove the attribute */
800 nret = _remove_obj(&tgt, full_name);
802 PyMem_Free(name_buf);
807 res = PyErr_SetFromErrno(PyExc_IOError);
815 PyMem_Free(attrname);
817 /* Return the result */
821 static char __pylistxattr_doc__[] =
822 "listxattr(item[, nofollow=False])\n"
823 "Return the list of attribute names for a file (deprecated).\n"
828 ".. deprecated:: 0.4\n"
829 " this function has been deprecated by the :func:`list` function.\n"
832 /* Wrapper for listxattr */
834 pylistxattr(PyObject *self, PyObject *args)
838 ssize_t nalloc, nret;
845 /* Parse the arguments */
846 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
848 if(convert_obj(myarg, &tgt, nofollow) < 0)
851 /* Find out the needed size of the buffer */
852 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
853 mylist = PyErr_SetFromErrno(PyExc_IOError);
857 /* Try to allocate the memory, using Python's allocator */
858 if((buf = PyMem_Malloc(nalloc)) == NULL) {
859 mylist = PyErr_NoMemory();
863 /* Now retrieve the list of attributes */
864 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
865 mylist = PyErr_SetFromErrno(PyExc_IOError);
869 /* Compute the number of attributes in the list */
870 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
874 /* Create the list which will hold the result */
875 mylist = PyList_New(nattrs);
879 /* Create and insert the attributes as strings in the list */
880 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
881 PyObject *item = PyBytes_FromString(s);
887 PyList_SET_ITEM(mylist, nattrs, item);
892 /* Free the buffer, now it is no longer needed */
898 /* Return the result */
902 static char __list_doc__[] =
903 "list(item[, nofollow=False, namespace=None])\n"
904 "Return the list of attribute names for a file.\n"
908 " >>> xattr.list('/path/to/file')\n"
909 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
910 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
911 " ['test', 'comment']\n"
916 ":returns: the list of attributes; note that if a namespace \n"
917 " argument was passed, it (and the separator) will be stripped\n"
921 ":raises EnvironmentError: caused by any system errors\n"
923 ".. versionadded:: 0.4\n"
926 /* Wrapper for listxattr */
928 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
932 ssize_t nalloc, nret;
935 const char *ns = NULL;
939 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
941 /* Parse the arguments */
942 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
943 &myarg, &nofollow, &ns))
945 if(convert_obj(myarg, &tgt, nofollow) < 0) {
950 /* Find out the needed size of the buffer */
951 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
952 res = PyErr_SetFromErrno(PyExc_IOError);
956 /* Try to allocate the memory, using Python's allocator */
957 if((buf = PyMem_Malloc(nalloc)) == NULL) {
958 res = PyErr_NoMemory();
962 /* Now retrieve the list of attributes */
963 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
964 res = PyErr_SetFromErrno(PyExc_IOError);
968 /* Compute the number of attributes in the list */
969 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
970 if(matches_ns(ns, s) != NULL)
973 /* Create the list which will hold the result */
974 res = PyList_New(nattrs);
978 /* Create and insert the attributes as strings in the list */
979 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
980 const char *name = matches_ns(ns, s);
982 PyObject *item = PyBytes_FromString(name);
988 PyList_SET_ITEM(res, nattrs, item);
994 /* Free the buffer, now it is no longer needed */
1001 /* Return the result */
1005 static PyMethodDef xattr_methods[] = {
1006 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1007 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1009 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1011 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1012 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1014 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1015 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1017 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1018 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1020 {NULL, NULL, 0, NULL} /* Sentinel */
1023 static char __xattr_doc__[] = \
1024 "This module gives access to the extended attributes present\n"
1025 "in some operating systems/filesystems. You can list attributes,\n"
1026 "get, set and remove them.\n"
1028 "The module exposes two sets of functions:\n"
1029 " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n"
1030 " :func:`removexattr`\n"
1031 " functions which are deprecated since version 0.4\n"
1032 " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n"
1033 " :func:`remove` functions\n"
1034 " which expose a namespace-aware API and simplify a bit the calling\n"
1035 " model by using keyword arguments\n"
1038 " >>> import xattr\n"
1039 " >>> xattr.listxattr(\"file.txt\")\n"
1040 " ['user.mime_type']\n"
1041 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1043 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1044 "\"Simple text file\")\n"
1045 " >>> xattr.listxattr(\"file.txt\")\n"
1046 " ['user.mime_type', 'user.comment']\n"
1047 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1049 ".. note:: Most or all errors reported by the system while using\n"
1050 " the ``xattr`` library will be reported by raising\n"
1051 " a :exc:`EnvironmentError`; under\n"
1052 " Linux, the following ``errno`` values are used:\n"
1054 " - ``ENOATTR`` and ``ENODATA`` mean that the attribute name is\n"
1056 " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n"
1057 " support extended attributes, or that the namespace is invalid\n"
1058 " - ``E2BIG`` mean that the attribute value is too big\n"
1059 " - ``ERANGE`` mean that the attribute name is too big (it might also\n"
1060 " mean an error in the xattr module itself)\n"
1061 " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n"
1062 " space or out of disk space because of quota limits\n"
1068 static struct PyModuleDef xattrmodule = {
1069 PyModuleDef_HEAD_INIT,
1076 #define INITERROR return NULL
1082 #define INITERROR return
1087 PyObject *ns_security = NULL;
1088 PyObject *ns_system = NULL;
1089 PyObject *ns_trusted = NULL;
1090 PyObject *ns_user = NULL;
1092 PyObject *m = PyModule_Create(&xattrmodule);
1094 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1099 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1100 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1101 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1102 PyModule_AddStringConstant(m, "__license__",
1103 "GNU Lesser General Public License (LGPL)");
1104 PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en");
1106 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1107 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1109 /* namespace constants */
1110 if((ns_security = PyBytes_FromString("security")) == NULL)
1112 if((ns_system = PyBytes_FromString("system")) == NULL)
1114 if((ns_trusted = PyBytes_FromString("trusted")) == NULL)
1116 if((ns_user = PyBytes_FromString("user")) == NULL)
1118 if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0)
1121 if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0)
1124 if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0)
1127 if(PyModule_AddObject(m, "NS_USER", ns_user) < 0)
1138 Py_XDECREF(ns_user);
1139 Py_XDECREF(ns_trusted);
1140 Py_XDECREF(ns_system);
1141 Py_XDECREF(ns_security);