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 "s"
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"
89 #define NS_CHANGED_DOC \
90 ".. versionchanged:: 0.5.1\n" \
91 " The namespace argument, if passed, cannot be None anymore; to\n" \
92 " explicitly specify an empty namespace, pass an empty\n" \
93 " string (byte string under Python 3)."
96 /* the estimated (startup) attribute buffer size in
98 #define ESTIMATE_ATTR_SIZE 256
100 typedef enum {T_FD, T_PATH, T_LINK} target_e;
111 /* Cleans up a tgt structure */
112 static void free_tgt(target_t *tgt) {
113 if (tgt->tmp != NULL) {
118 /* Used for cpychecker: */
119 /* The checker automatically defines this preprocessor name when creating
120 the custom attribute: */
121 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
122 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
123 __attribute__((cpychecker_negative_result_sets_exception))
125 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
128 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow)
129 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
131 static int merge_ns(const char *ns, const char *name,
132 const char **result, char **buf)
133 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
136 /** Converts from a string, file or int argument to what we need.
138 * Returns -1 on failure, 0 on success.
140 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) {
143 if(PyBytes_Check(myobj)) {
144 tgt->type = nofollow ? T_LINK : T_PATH;
145 tgt->name = PyBytes_AS_STRING(myobj);
146 } else if(PyUnicode_Check(myobj)) {
147 tgt->type = nofollow ? T_LINK : T_PATH;
149 PyUnicode_AsEncodedString(myobj,
150 Py_FileSystemDefaultEncoding, "strict");
153 tgt->name = PyBytes_AS_STRING(tgt->tmp);
154 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
158 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
164 /* Combine a namespace string and an attribute name into a
165 fully-qualified name */
166 static int merge_ns(const char *ns, const char *name,
167 const char **result, char **buf) {
168 if(ns != NULL && *ns != '\0') {
170 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
171 if((*buf = PyMem_Malloc(new_size)) == NULL) {
175 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
176 if(cnt > new_size || cnt < 0) {
177 PyErr_SetString(PyExc_ValueError,
178 "can't format the attribute name");
190 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
191 if(tgt->type == T_FD)
192 return flistxattr(tgt->fd, list, size);
193 else if (tgt->type == T_LINK)
194 return llistxattr(tgt->name, list, size);
196 return listxattr(tgt->name, list, size);
199 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
201 if(tgt->type == T_FD)
202 return fgetxattr(tgt->fd, name, value, size);
203 else if (tgt->type == T_LINK)
204 return lgetxattr(tgt->name, name, value, size);
206 return getxattr(tgt->name, name, value, size);
209 static int _set_obj(target_t *tgt, const char *name,
210 const void *value, size_t size, int flags) {
211 if(tgt->type == T_FD)
212 return fsetxattr(tgt->fd, name, value, size, flags);
213 else if (tgt->type == T_LINK)
214 return lsetxattr(tgt->name, name, value, size, flags);
216 return setxattr(tgt->name, name, value, size, flags);
219 static int _remove_obj(target_t *tgt, const char *name) {
220 if(tgt->type == T_FD)
221 return fremovexattr(tgt->fd, name);
222 else if (tgt->type == T_LINK)
223 return lremovexattr(tgt->name, name);
225 return removexattr(tgt->name, name);
229 Checks if an attribute name matches an optional namespace.
231 If the namespace is NULL or an empty string, it will return the
232 name itself. If the namespace is non-NULL and the name matches, it
233 will return a pointer to the offset in the name after the namespace
234 and the separator. If however the name doesn't match the namespace,
238 const char *matches_ns(const char *ns, const char *name) {
240 if (ns == NULL || *ns == '\0')
242 ns_size = strlen(ns);
244 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
245 name[ns_size] == '.')
246 return name + ns_size + 1;
250 /* Wrapper for getxattr */
251 static char __pygetxattr_doc__[] =
252 "getxattr(item, attribute[, nofollow=False])\n"
253 "Get the value of a given extended attribute (deprecated).\n"
259 ".. deprecated:: 0.4\n"
260 " this function has been deprecated\n"
261 " by the :func:`get` function.\n"
265 pygetxattr(PyObject *self, PyObject *args)
270 char *attrname = NULL;
272 ssize_t nalloc, nret;
275 /* Parse the arguments */
276 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
278 if(convert_obj(myarg, &tgt, nofollow) < 0) {
283 /* Find out the needed size of the buffer */
284 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
285 res = PyErr_SetFromErrno(PyExc_IOError);
289 /* Try to allocate the memory, using Python's allocator */
290 if((buf = PyMem_Malloc(nalloc)) == NULL) {
291 res = PyErr_NoMemory();
295 /* Now retrieve the attribute value */
296 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
297 res = PyErr_SetFromErrno(PyExc_IOError);
301 /* Create the string which will hold the result */
302 res = PyBytes_FromStringAndSize(buf, nret);
305 /* Free the buffer, now it is no longer needed */
310 PyMem_Free(attrname);
312 /* Return the result */
316 /* Wrapper for getxattr */
317 static char __get_doc__[] =
318 "get(item, name[, nofollow=False, namespace=None])\n"
319 "Get the value of a given extended attribute.\n"
322 " >>> xattr.get('/path/to/file', 'user.comment')\n"
324 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
331 ":return: the value of the extended attribute (can contain NULLs)\n"
333 ":raises EnvironmentError: caused by any system errors\n"
335 ".. versionadded:: 0.4\n"
340 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
345 char *attrname = NULL, *namebuf;
346 const char *fullname;
348 const char *ns = NULL;
349 ssize_t nalloc, nret;
351 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
353 /* Parse the arguments */
354 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
355 &myarg, NULL, &attrname, &nofollow, &ns))
357 if(convert_obj(myarg, &tgt, nofollow) < 0) {
362 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
367 /* Find out the needed size of the buffer */
368 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
369 res = PyErr_SetFromErrno(PyExc_IOError);
373 /* Try to allocate the memory, using Python's allocator */
374 if((buf = PyMem_Malloc(nalloc)) == NULL) {
375 res = PyErr_NoMemory();
379 /* Now retrieve the attribute value */
380 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
381 res = PyErr_SetFromErrno(PyExc_IOError);
385 /* Create the string which will hold the result */
386 res = PyBytes_FromStringAndSize(buf, nret);
388 /* Free the buffers, they are no longer needed */
396 PyMem_Free(attrname);
398 /* Return the result */
402 /* Wrapper for getxattr */
403 static char __get_all_doc__[] =
404 "get_all(item[, nofollow=False, namespace=None])\n"
405 "Get all the extended attributes of an item.\n"
407 "This function performs a bulk-get of all extended attribute names\n"
408 "and the corresponding value.\n"
411 " >>> xattr.get_all('/path/to/file')\n"
412 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
413 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
414 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
415 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
418 ":keyword namespace: an optional namespace for filtering the\n"
419 " attributes; for example, querying all user attributes can be\n"
420 " accomplished by passing namespace=:const:`NS_USER`\n"
421 ":type namespace: string\n"
423 ":return: list of tuples (name, value); note that if a namespace\n"
424 " argument was passed, it (and the separator) will be stripped from\n"
425 " the names returned\n"
427 ":raises EnvironmentError: caused by any system errors\n"
429 ".. note:: Since reading the whole attribute list is not an atomic\n"
430 " operation, it might be possible that attributes are added\n"
431 " or removed between the initial query and the actual reading\n"
432 " of the attributes; the returned list will contain only the\n"
433 " attributes that were present at the initial listing of the\n"
434 " attribute names and that were still present when the read\n"
435 " attempt for the value is made.\n"
436 ".. versionadded:: 0.4\n"
441 get_all(PyObject *self, PyObject *args, PyObject *keywds)
443 PyObject *myarg, *res;
445 const char *ns = NULL;
446 char *buf_list, *buf_val;
448 ssize_t nalloc, nlist, nval;
451 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
453 /* Parse the arguments */
454 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
455 &myarg, &nofollow, &ns))
457 if(convert_obj(myarg, &tgt, nofollow) < 0)
460 /* Compute first the list of attributes */
462 /* Find out the needed size of the buffer for the attribute list */
463 nalloc = _list_obj(&tgt, NULL, 0);
466 res = PyErr_SetFromErrno(PyExc_IOError);
470 /* Try to allocate the memory, using Python's allocator */
471 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
472 res = PyErr_NoMemory();
476 /* Now retrieve the list of attributes */
477 nlist = _list_obj(&tgt, buf_list, nalloc);
480 res = PyErr_SetFromErrno(PyExc_IOError);
484 /* Create the list which will hold the result */
485 mylist = PyList_New(0);
491 nalloc = ESTIMATE_ATTR_SIZE;
492 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
494 res = PyErr_NoMemory();
498 /* Create and insert the attributes as strings in the list */
499 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
504 if((name=matches_ns(ns, s))==NULL)
506 /* Now retrieve the attribute value */
509 nval = _get_obj(&tgt, s, buf_val, nalloc);
512 if(errno == ERANGE) {
513 nval = _get_obj(&tgt, s, NULL, 0);
514 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) {
515 res = PyErr_NoMemory();
521 } else if(errno == ENODATA || errno == ENOATTR) {
522 /* this attribute has gone away since we queried
523 the attribute list */
527 /* else we're dealing with a different error, which we
528 don't know how to handle nicely, so we abort */
530 res = PyErr_SetFromErrno(PyExc_IOError);
538 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
540 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
542 if (my_tuple == NULL) {
547 PyList_Append(mylist, my_tuple);
551 /* Successful exit */
558 PyMem_Free(buf_list);
563 /* Return the result */
568 static char __pysetxattr_doc__[] =
569 "setxattr(item, name, value[, flags=0, nofollow=False])\n"
570 "Set the value of a given extended attribute (deprecated).\n"
572 "Be careful in case you want to set attributes on symbolic\n"
573 "links, you have to use all the 5 parameters; use 0 for the \n"
574 "flags value if you want the default behaviour (create or "
583 ".. deprecated:: 0.4\n"
584 " this function has been deprecated\n"
585 " by the :func:`set` function.\n"
588 /* Wrapper for setxattr */
590 pysetxattr(PyObject *self, PyObject *args)
592 PyObject *myarg, *res;
594 char *attrname = NULL;
601 /* Parse the arguments */
602 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
603 NULL, &buf, &bufsize, &flags, &nofollow))
605 if(convert_obj(myarg, &tgt, nofollow) < 0) {
610 /* Set the attribute's value */
611 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
616 res = PyErr_SetFromErrno(PyExc_IOError);
624 PyMem_Free(attrname);
627 /* Return the result */
631 static char __set_doc__[] =
632 "set(item, name, value[, flags=0, namespace=None])\n"
633 "Set the value of a given extended attribute.\n"
637 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
638 " >>> xattr.set('/path/to/file', 'comment', 'test',"
639 " namespace=xattr.NS_USER)\n"
648 ":raises EnvironmentError: caused by any system errors\n"
650 ".. versionadded:: 0.4\n"
654 /* Wrapper for setxattr */
656 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
658 PyObject *myarg, *res;
660 char *attrname = NULL;
666 const char *ns = NULL;
668 const char *full_name;
669 static char *kwlist[] = {"item", "name", "value", "flags",
670 "nofollow", "namespace", NULL};
672 /* Parse the arguments */
673 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
674 kwlist, &myarg, NULL, &attrname, NULL,
675 &buf, &bufsize, &flags, &nofollow, &ns))
677 if(convert_obj(myarg, &tgt, nofollow) < 0) {
682 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
687 /* Set the attribute's value */
688 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
695 res = PyErr_SetFromErrno(PyExc_IOError);
703 PyMem_Free(attrname);
706 /* Return the result */
711 static char __pyremovexattr_doc__[] =
712 "removexattr(item, name[, nofollow])\n"
713 "Remove an attribute from a file (deprecated).\n"
719 ".. deprecated:: 0.4\n"
720 " this function has been deprecated by the :func:`remove` function.\n"
723 /* Wrapper for removexattr */
725 pyremovexattr(PyObject *self, PyObject *args)
727 PyObject *myarg, *res;
729 char *attrname = NULL;
733 /* Parse the arguments */
734 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
737 if(convert_obj(myarg, &tgt, nofollow) < 0) {
742 /* Remove the attribute */
743 nret = _remove_obj(&tgt, attrname);
748 res = PyErr_SetFromErrno(PyExc_IOError);
756 PyMem_Free(attrname);
758 /* Return the result */
762 static char __remove_doc__[] =
763 "remove(item, name[, nofollow=False, namespace=None])\n"
764 "Remove an attribute from a file.\n"
768 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
775 ":raises EnvironmentError: caused by any system errors\n"
777 ".. versionadded:: 0.4\n"
781 /* Wrapper for removexattr */
783 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
785 PyObject *myarg, *res;
787 char *attrname = NULL, *name_buf;
788 const char *ns = NULL;
789 const char *full_name;
792 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
794 /* Parse the arguments */
795 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
796 &myarg, NULL, &attrname, &nofollow, &ns))
799 if(convert_obj(myarg, &tgt, nofollow) < 0) {
804 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
809 /* Remove the attribute */
810 nret = _remove_obj(&tgt, full_name);
812 PyMem_Free(name_buf);
817 res = PyErr_SetFromErrno(PyExc_IOError);
825 PyMem_Free(attrname);
827 /* Return the result */
831 static char __pylistxattr_doc__[] =
832 "listxattr(item[, nofollow=False])\n"
833 "Return the list of attribute names for a file (deprecated).\n"
838 ".. deprecated:: 0.4\n"
839 " this function has been deprecated by the :func:`list` function.\n"
842 /* Wrapper for listxattr */
844 pylistxattr(PyObject *self, PyObject *args)
848 ssize_t nalloc, nret;
855 /* Parse the arguments */
856 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
858 if(convert_obj(myarg, &tgt, nofollow) < 0)
861 /* Find out the needed size of the buffer */
862 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
863 mylist = PyErr_SetFromErrno(PyExc_IOError);
867 /* Try to allocate the memory, using Python's allocator */
868 if((buf = PyMem_Malloc(nalloc)) == NULL) {
869 mylist = PyErr_NoMemory();
873 /* Now retrieve the list of attributes */
874 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
875 mylist = PyErr_SetFromErrno(PyExc_IOError);
879 /* Compute the number of attributes in the list */
880 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
884 /* Create the list which will hold the result */
885 mylist = PyList_New(nattrs);
889 /* Create and insert the attributes as strings in the list */
890 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
891 PyObject *item = PyBytes_FromString(s);
897 PyList_SET_ITEM(mylist, nattrs, item);
902 /* Free the buffer, now it is no longer needed */
908 /* Return the result */
912 static char __list_doc__[] =
913 "list(item[, nofollow=False, namespace=None])\n"
914 "Return the list of attribute names for a file.\n"
918 " >>> xattr.list('/path/to/file')\n"
919 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
920 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
921 " ['test', 'comment']\n"
926 ":returns: the list of attributes; note that if a namespace \n"
927 " argument was passed, it (and the separator) will be stripped\n"
931 ":raises EnvironmentError: caused by any system errors\n"
933 ".. versionadded:: 0.4\n"
937 /* Wrapper for listxattr */
939 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
943 ssize_t nalloc, nret;
946 const char *ns = NULL;
950 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
952 /* Parse the arguments */
953 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
954 &myarg, &nofollow, &ns))
956 if(convert_obj(myarg, &tgt, nofollow) < 0) {
961 /* Find out the needed size of the buffer */
962 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
963 res = PyErr_SetFromErrno(PyExc_IOError);
967 /* Try to allocate the memory, using Python's allocator */
968 if((buf = PyMem_Malloc(nalloc)) == NULL) {
969 res = PyErr_NoMemory();
973 /* Now retrieve the list of attributes */
974 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
975 res = PyErr_SetFromErrno(PyExc_IOError);
979 /* Compute the number of attributes in the list */
980 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
981 if(matches_ns(ns, s) != NULL)
984 /* Create the list which will hold the result */
985 res = PyList_New(nattrs);
989 /* Create and insert the attributes as strings in the list */
990 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
991 const char *name = matches_ns(ns, s);
993 PyObject *item = PyBytes_FromString(name);
999 PyList_SET_ITEM(res, nattrs, item);
1005 /* Free the buffer, now it is no longer needed */
1012 /* Return the result */
1016 static PyMethodDef xattr_methods[] = {
1017 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1018 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1020 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1022 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1023 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1025 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1026 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1028 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1029 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1031 {NULL, NULL, 0, NULL} /* Sentinel */
1034 static char __xattr_doc__[] = \
1035 "This module gives access to the extended attributes present\n"
1036 "in some operating systems/filesystems. You can list attributes,\n"
1037 "get, set and remove them.\n"
1039 "The module exposes two sets of functions:\n"
1040 " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n"
1041 " :func:`removexattr`\n"
1042 " functions which are deprecated since version 0.4\n"
1043 " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n"
1044 " :func:`remove` functions\n"
1045 " which expose a namespace-aware API and simplify a bit the calling\n"
1046 " model by using keyword arguments\n"
1049 " >>> import xattr\n"
1050 " >>> xattr.listxattr(\"file.txt\")\n"
1051 " ['user.mime_type']\n"
1052 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1054 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1055 "\"Simple text file\")\n"
1056 " >>> xattr.listxattr(\"file.txt\")\n"
1057 " ['user.mime_type', 'user.comment']\n"
1058 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1060 ".. note:: Most or all errors reported by the system while using\n"
1061 " the ``xattr`` library will be reported by raising\n"
1062 " a :exc:`EnvironmentError`; under\n"
1063 " Linux, the following ``errno`` values are used:\n"
1065 " - ``ENOATTR`` and ``ENODATA`` mean that the attribute name is\n"
1067 " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n"
1068 " support extended attributes, or that the namespace is invalid\n"
1069 " - ``E2BIG`` mean that the attribute value is too big\n"
1070 " - ``ERANGE`` mean that the attribute name is too big (it might also\n"
1071 " mean an error in the xattr module itself)\n"
1072 " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n"
1073 " space or out of disk space because of quota limits\n"
1074 ".. note:: Under Python 3, the namespace argument is a byte string,\n"
1075 " not a unicode string.\n"
1081 static struct PyModuleDef xattrmodule = {
1082 PyModuleDef_HEAD_INIT,
1089 #define INITERROR return NULL
1095 #define INITERROR return
1100 PyObject *ns_security = NULL;
1101 PyObject *ns_system = NULL;
1102 PyObject *ns_trusted = NULL;
1103 PyObject *ns_user = NULL;
1105 PyObject *m = PyModule_Create(&xattrmodule);
1107 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1112 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1113 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1114 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1115 PyModule_AddStringConstant(m, "__license__",
1116 "GNU Lesser General Public License (LGPL)");
1117 PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en");
1119 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1120 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1122 /* namespace constants */
1123 if((ns_security = PyBytes_FromString("security")) == NULL)
1125 if((ns_system = PyBytes_FromString("system")) == NULL)
1127 if((ns_trusted = PyBytes_FromString("trusted")) == NULL)
1129 if((ns_user = PyBytes_FromString("user")) == NULL)
1131 if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0)
1134 if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0)
1137 if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0)
1140 if(PyModule_AddObject(m, "NS_USER", ns_user) < 0)
1151 Py_XDECREF(ns_user);
1152 Py_XDECREF(ns_trusted);
1153 Py_XDECREF(ns_system);
1154 Py_XDECREF(ns_security);