2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008, 2012, 2013, 2015
5 Iustin Pop <iustin@k1024.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #define PY_SSIZE_T_CLEAN
26 #include <attr/xattr.h>
29 /* Compatibility with python 2.4 regarding python size type (PEP 353) */
30 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
31 typedef int Py_ssize_t;
32 #define PY_SSIZE_T_MAX INT_MAX
33 #define PY_SSIZE_T_MIN INT_MIN
36 #if PY_MAJOR_VERSION >= 3
38 #define BYTES_CHAR "y"
40 #define BYTES_CHAR "s"
41 #define PyBytes_Check PyString_Check
42 #define PyBytes_AS_STRING PyString_AS_STRING
43 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
44 #define PyBytes_FromString PyString_FromString
48 ":param item: a string representing a file-name, or a file-like\n" \
49 " object, or a file descriptor; this represents the file on \n" \
52 #define NOFOLLOW_DOC \
53 ":param nofollow: if true and if\n" \
54 " the file name given is a symbolic link, the\n" \
55 " function will operate on the symbolic link itself instead\n" \
56 " of its target; defaults to false\n" \
57 ":type nofollow: boolean, optional\n" \
60 ":param namespace: if given, the attribute must not contain the\n" \
61 " namespace, but instead it will be taken from this parameter\n" \
62 ":type namespace: bytes\n"
64 #define NAME_GET_DOC \
65 ":param string name: the attribute whose value to retrieve;\n" \
66 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
68 #define NAME_SET_DOC \
69 ":param string name: the attribute whose value to set;\n" \
70 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
72 #define NAME_REMOVE_DOC \
73 ":param string name: the attribute to remove;\n" \
74 " usually in the form of ``system.posix_acl`` or \n" \
75 " ``user.mime_type``\n"
78 ":param string value: possibly with embedded NULLs; note that there\n" \
79 " are restrictions regarding the size of the value, for\n" \
80 " example, for ext2/ext3, maximum size is the block size\n" \
83 ":param flags: if 0 or omitted the attribute will be\n" \
84 " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" \
85 " will be created, giving an error if it already exists;\n" \
86 " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" \
87 " giving an error if it doesn't exist;\n" \
88 ":type flags: integer\n"
90 #define NS_CHANGED_DOC \
91 ".. versionchanged:: 0.5.1\n" \
92 " The namespace argument, if passed, cannot be None anymore; to\n" \
93 " explicitly specify an empty namespace, pass an empty\n" \
94 " string (byte string under Python 3)."
97 /* the estimated (startup) attribute buffer size in
99 #define ESTIMATE_ATTR_SIZE 256
101 typedef enum {T_FD, T_PATH, T_LINK} target_e;
112 /* Cleans up a tgt structure */
113 static void free_tgt(target_t *tgt) {
114 if (tgt->tmp != NULL) {
119 /* Used for cpychecker: */
120 /* The checker automatically defines this preprocessor name when creating
121 the custom attribute: */
122 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
123 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
124 __attribute__((cpychecker_negative_result_sets_exception))
126 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
129 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow)
130 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
132 static int merge_ns(const char *ns, const char *name,
133 const char **result, char **buf)
134 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
137 /** Converts from a string, file or int argument to what we need.
139 * Returns -1 on failure, 0 on success.
141 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) {
144 if(PyBytes_Check(myobj)) {
145 tgt->type = nofollow ? T_LINK : T_PATH;
146 tgt->name = PyBytes_AS_STRING(myobj);
147 } else if(PyUnicode_Check(myobj)) {
148 tgt->type = nofollow ? T_LINK : T_PATH;
150 PyUnicode_AsEncodedString(myobj,
151 Py_FileSystemDefaultEncoding,
160 tgt->name = PyBytes_AS_STRING(tgt->tmp);
161 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
165 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
171 /* Combine a namespace string and an attribute name into a
172 fully-qualified name */
173 static int merge_ns(const char *ns, const char *name,
174 const char **result, char **buf) {
175 if(ns != NULL && *ns != '\0') {
177 /* The value of new_size is related to/must be kept in-sync
178 with the format string below */
179 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
180 if((*buf = PyMem_Malloc(new_size)) == NULL) {
184 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
185 if((size_t) cnt >= new_size || cnt < 0) {
186 PyErr_SetString(PyExc_ValueError,
187 "unexpected: can't format the attribute name");
199 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
200 if(tgt->type == T_FD)
201 return flistxattr(tgt->fd, list, size);
202 else if (tgt->type == T_LINK)
203 return llistxattr(tgt->name, list, size);
205 return listxattr(tgt->name, list, size);
208 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
210 if(tgt->type == T_FD)
211 return fgetxattr(tgt->fd, name, value, size);
212 else if (tgt->type == T_LINK)
213 return lgetxattr(tgt->name, name, value, size);
215 return getxattr(tgt->name, name, value, size);
218 static int _set_obj(target_t *tgt, const char *name,
219 const void *value, size_t size, int flags) {
220 if(tgt->type == T_FD)
221 return fsetxattr(tgt->fd, name, value, size, flags);
222 else if (tgt->type == T_LINK)
223 return lsetxattr(tgt->name, name, value, size, flags);
225 return setxattr(tgt->name, name, value, size, flags);
228 static int _remove_obj(target_t *tgt, const char *name) {
229 if(tgt->type == T_FD)
230 return fremovexattr(tgt->fd, name);
231 else if (tgt->type == T_LINK)
232 return lremovexattr(tgt->name, name);
234 return removexattr(tgt->name, name);
238 Checks if an attribute name matches an optional namespace.
240 If the namespace is NULL or an empty string, it will return the
241 name itself. If the namespace is non-NULL and the name matches, it
242 will return a pointer to the offset in the name after the namespace
243 and the separator. If however the name doesn't match the namespace,
247 const char *matches_ns(const char *ns, const char *name) {
249 if (ns == NULL || *ns == '\0')
251 ns_size = strlen(ns);
253 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
254 name[ns_size] == '.')
255 return name + ns_size + 1;
259 /* Wrapper for getxattr */
260 static char __pygetxattr_doc__[] =
261 "getxattr(item, attribute[, nofollow=False])\n"
262 "Get the value of a given extended attribute (deprecated).\n"
268 ".. deprecated:: 0.4\n"
269 " this function has been deprecated\n"
270 " by the :func:`get` function.\n"
274 pygetxattr(PyObject *self, PyObject *args)
279 char *attrname = NULL;
281 ssize_t nalloc_s, nret;
285 /* Parse the arguments */
286 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
288 if(convert_obj(myarg, &tgt, nofollow) < 0) {
293 /* Find out the needed size of the buffer */
294 if((nalloc_s = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
295 res = PyErr_SetFromErrno(PyExc_IOError);
299 nalloc = (size_t) nalloc_s;
301 /* Try to allocate the memory, using Python's allocator */
302 if((buf = PyMem_Malloc(nalloc)) == NULL) {
303 res = PyErr_NoMemory();
307 /* Now retrieve the attribute value */
308 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
309 res = PyErr_SetFromErrno(PyExc_IOError);
313 /* Create the string which will hold the result */
314 res = PyBytes_FromStringAndSize(buf, nret);
317 /* Free the buffer, now it is no longer needed */
322 PyMem_Free(attrname);
324 /* Return the result */
328 /* Wrapper for getxattr */
329 static char __get_doc__[] =
330 "get(item, name[, nofollow=False, namespace=None])\n"
331 "Get the value of a given extended attribute.\n"
334 " >>> xattr.get('/path/to/file', 'user.comment')\n"
336 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
343 ":return: the value of the extended attribute (can contain NULLs)\n"
345 ":raises EnvironmentError: caused by any system errors\n"
347 ".. versionadded:: 0.4\n"
352 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
357 char *attrname = NULL, *namebuf;
358 const char *fullname;
360 const char *ns = NULL;
361 ssize_t nalloc_s, nret;
364 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
366 /* Parse the arguments */
367 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
368 &myarg, NULL, &attrname, &nofollow, &ns))
370 if(convert_obj(myarg, &tgt, nofollow) < 0) {
375 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
380 /* Find out the needed size of the buffer */
381 if((nalloc_s = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
382 res = PyErr_SetFromErrno(PyExc_IOError);
386 nalloc = (size_t) nalloc_s;
388 /* Try to allocate the memory, using Python's allocator */
389 if((buf = PyMem_Malloc(nalloc)) == NULL) {
390 res = PyErr_NoMemory();
394 /* Now retrieve the attribute value */
395 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
396 res = PyErr_SetFromErrno(PyExc_IOError);
400 /* Create the string which will hold the result */
401 res = PyBytes_FromStringAndSize(buf, nret);
403 /* Free the buffers, they are no longer needed */
411 PyMem_Free(attrname);
413 /* Return the result */
417 /* Wrapper for getxattr */
418 static char __get_all_doc__[] =
419 "get_all(item[, nofollow=False, namespace=None])\n"
420 "Get all the extended attributes of an item.\n"
422 "This function performs a bulk-get of all extended attribute names\n"
423 "and the corresponding value.\n"
426 " >>> xattr.get_all('/path/to/file')\n"
427 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
428 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
429 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
430 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
433 ":keyword namespace: an optional namespace for filtering the\n"
434 " attributes; for example, querying all user attributes can be\n"
435 " accomplished by passing namespace=:const:`NS_USER`\n"
436 ":type namespace: string\n"
438 ":return: list of tuples (name, value); note that if a namespace\n"
439 " argument was passed, it (and the separator) will be stripped from\n"
440 " the names returned\n"
442 ":raises EnvironmentError: caused by any system errors\n"
444 ".. note:: Since reading the whole attribute list is not an atomic\n"
445 " operation, it might be possible that attributes are added\n"
446 " or removed between the initial query and the actual reading\n"
447 " of the attributes; the returned list will contain only the\n"
448 " attributes that were present at the initial listing of the\n"
449 " attribute names and that were still present when the read\n"
450 " attempt for the value is made.\n"
451 ".. versionadded:: 0.4\n"
456 get_all(PyObject *self, PyObject *args, PyObject *keywds)
458 PyObject *myarg, *res;
460 const char *ns = NULL;
461 char *buf_list, *buf_val, *buf_val_tmp;
463 ssize_t nalloc_s, nlist, nval_s;
467 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
469 /* Parse the arguments */
470 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
471 &myarg, &nofollow, &ns))
473 if(convert_obj(myarg, &tgt, nofollow) < 0)
476 /* Compute first the list of attributes */
478 /* Find out the needed size of the buffer for the attribute list */
479 nalloc_s = _list_obj(&tgt, NULL, 0);
482 res = PyErr_SetFromErrno(PyExc_IOError);
491 nalloc = (size_t) nalloc_s;
493 /* Try to allocate the memory, using Python's allocator */
494 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
495 res = PyErr_NoMemory();
499 /* Now retrieve the list of attributes */
500 nlist = _list_obj(&tgt, buf_list, nalloc);
503 res = PyErr_SetFromErrno(PyExc_IOError);
507 /* Create the list which will hold the result */
508 mylist = PyList_New(0);
514 nalloc = ESTIMATE_ATTR_SIZE;
515 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
517 res = PyErr_NoMemory();
521 /* Create and insert the attributes as strings in the list */
522 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
527 if((name=matches_ns(ns, s))==NULL)
529 /* Now retrieve the attribute value */
532 nval_s = _get_obj(&tgt, s, buf_val, nalloc);
535 if(errno == ERANGE) {
536 ssize_t realloc_size_s = _get_obj(&tgt, s, NULL, 0);
537 /* ERANGE + proper size should not fail, but it
538 still can, so let's check first */
539 if(realloc_size_s == -1) {
540 res = PyErr_SetFromErrno(PyExc_IOError);
544 size_t realloc_size = (size_t) realloc_size_s;
545 if((buf_val_tmp = PyMem_Realloc(buf_val, realloc_size))
547 res = PyErr_NoMemory();
551 buf_val = buf_val_tmp;
552 nalloc = realloc_size;
559 /* this attribute has gone away since we queried
560 the attribute list */
564 /* else we're dealing with a different error, which we
565 don't know how to handle nicely, so we abort */
567 res = PyErr_SetFromErrno(PyExc_IOError);
570 nval = (size_t) nval_s;
577 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
579 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
581 if (my_tuple == NULL) {
586 PyList_Append(mylist, my_tuple);
590 /* Successful exit */
597 PyMem_Free(buf_list);
602 /* Return the result */
607 static char __pysetxattr_doc__[] =
608 "setxattr(item, name, value[, flags=0, nofollow=False])\n"
609 "Set the value of a given extended attribute (deprecated).\n"
611 "Be careful in case you want to set attributes on symbolic\n"
612 "links, you have to use all the 5 parameters; use 0 for the \n"
613 "flags value if you want the default behaviour (create or "
622 ".. deprecated:: 0.4\n"
623 " this function has been deprecated\n"
624 " by the :func:`set` function.\n"
627 /* Wrapper for setxattr */
629 pysetxattr(PyObject *self, PyObject *args)
631 PyObject *myarg, *res;
633 char *attrname = NULL;
635 Py_ssize_t bufsize_s;
641 /* Parse the arguments */
642 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
643 NULL, &buf, &bufsize_s, &flags, &nofollow))
647 PyErr_SetString(PyExc_ValueError,
648 "negative value size?!");
652 bufsize = (size_t) bufsize_s;
654 if(convert_obj(myarg, &tgt, nofollow) < 0) {
659 /* Set the attribute's value */
660 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
665 res = PyErr_SetFromErrno(PyExc_IOError);
673 PyMem_Free(attrname);
676 /* Return the result */
680 static char __set_doc__[] =
681 "set(item, name, value[, flags=0, namespace=None])\n"
682 "Set the value of a given extended attribute.\n"
686 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
687 " >>> xattr.set('/path/to/file', 'comment', 'test',"
688 " namespace=xattr.NS_USER)\n"
697 ":raises EnvironmentError: caused by any system errors\n"
699 ".. versionadded:: 0.4\n"
703 /* Wrapper for setxattr */
705 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
707 PyObject *myarg, *res;
709 char *attrname = NULL;
711 Py_ssize_t bufsize_s;
716 const char *ns = NULL;
718 const char *full_name;
719 static char *kwlist[] = {"item", "name", "value", "flags",
720 "nofollow", "namespace", NULL};
722 /* Parse the arguments */
723 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
724 kwlist, &myarg, NULL, &attrname, NULL,
725 &buf, &bufsize_s, &flags, &nofollow, &ns))
729 PyErr_SetString(PyExc_ValueError,
730 "negative value size?!");
734 bufsize = (size_t) bufsize_s;
736 if(convert_obj(myarg, &tgt, nofollow) < 0) {
741 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
746 /* Set the attribute's value */
747 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
754 res = PyErr_SetFromErrno(PyExc_IOError);
762 PyMem_Free(attrname);
765 /* Return the result */
770 static char __pyremovexattr_doc__[] =
771 "removexattr(item, name[, nofollow])\n"
772 "Remove an attribute from a file (deprecated).\n"
778 ".. deprecated:: 0.4\n"
779 " this function has been deprecated by the :func:`remove` function.\n"
782 /* Wrapper for removexattr */
784 pyremovexattr(PyObject *self, PyObject *args)
786 PyObject *myarg, *res;
788 char *attrname = NULL;
792 /* Parse the arguments */
793 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
796 if(convert_obj(myarg, &tgt, nofollow) < 0) {
801 /* Remove the attribute */
802 nret = _remove_obj(&tgt, attrname);
807 res = PyErr_SetFromErrno(PyExc_IOError);
815 PyMem_Free(attrname);
817 /* Return the result */
821 static char __remove_doc__[] =
822 "remove(item, name[, nofollow=False, namespace=None])\n"
823 "Remove an attribute from a file.\n"
827 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
834 ":raises EnvironmentError: caused by any system errors\n"
836 ".. versionadded:: 0.4\n"
840 /* Wrapper for removexattr */
842 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
844 PyObject *myarg, *res;
846 char *attrname = NULL, *name_buf;
847 const char *ns = NULL;
848 const char *full_name;
851 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
853 /* Parse the arguments */
854 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
855 &myarg, NULL, &attrname, &nofollow, &ns))
858 if(convert_obj(myarg, &tgt, nofollow) < 0) {
863 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
868 /* Remove the attribute */
869 nret = _remove_obj(&tgt, full_name);
871 PyMem_Free(name_buf);
876 res = PyErr_SetFromErrno(PyExc_IOError);
884 PyMem_Free(attrname);
886 /* Return the result */
890 static char __pylistxattr_doc__[] =
891 "listxattr(item[, nofollow=False])\n"
892 "Return the list of attribute names for a file (deprecated).\n"
897 ".. deprecated:: 0.4\n"
898 " this function has been deprecated by the :func:`list` function.\n"
901 /* Wrapper for listxattr */
903 pylistxattr(PyObject *self, PyObject *args)
907 ssize_t nalloc_s, nret;
915 /* Parse the arguments */
916 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
918 if(convert_obj(myarg, &tgt, nofollow) < 0)
921 /* Find out the needed size of the buffer */
922 if((nalloc_s = _list_obj(&tgt, NULL, 0)) == -1) {
923 mylist = PyErr_SetFromErrno(PyExc_IOError);
928 mylist = PyList_New(0);
932 nalloc = (size_t) nalloc_s;
934 /* Try to allocate the memory, using Python's allocator */
935 if((buf = PyMem_Malloc(nalloc)) == NULL) {
936 mylist = PyErr_NoMemory();
940 /* Now retrieve the list of attributes */
941 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
942 mylist = PyErr_SetFromErrno(PyExc_IOError);
946 /* Compute the number of attributes in the list */
947 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
951 /* Create the list which will hold the result */
952 mylist = PyList_New(nattrs);
956 /* Create and insert the attributes as strings in the list */
957 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
958 PyObject *item = PyBytes_FromString(s);
964 PyList_SET_ITEM(mylist, nattrs, item);
969 /* Free the buffer, now it is no longer needed */
975 /* Return the result */
979 static char __list_doc__[] =
980 "list(item[, nofollow=False, namespace=None])\n"
981 "Return the list of attribute names for a file.\n"
985 " >>> xattr.list('/path/to/file')\n"
986 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
987 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
988 " ['test', 'comment']\n"
993 ":returns: the list of attributes; note that if a namespace \n"
994 " argument was passed, it (and the separator) will be stripped\n"
998 ":raises EnvironmentError: caused by any system errors\n"
1000 ".. versionadded:: 0.4\n"
1004 /* Wrapper for listxattr */
1006 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
1010 ssize_t nalloc_s, nret;
1014 const char *ns = NULL;
1018 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
1020 /* Parse the arguments */
1021 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
1022 &myarg, &nofollow, &ns))
1024 if(convert_obj(myarg, &tgt, nofollow) < 0) {
1029 /* Find out the needed size of the buffer */
1030 if((nalloc_s = _list_obj(&tgt, NULL, 0)) == -1) {
1031 res = PyErr_SetFromErrno(PyExc_IOError);
1036 res = PyList_New(0);
1040 nalloc = (size_t) nalloc_s;
1042 /* Try to allocate the memory, using Python's allocator */
1043 if((buf = PyMem_Malloc(nalloc)) == NULL) {
1044 res = PyErr_NoMemory();
1048 /* Now retrieve the list of attributes */
1049 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
1050 res = PyErr_SetFromErrno(PyExc_IOError);
1054 /* Compute the number of attributes in the list */
1055 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
1056 if(matches_ns(ns, s) != NULL)
1059 /* Create the list which will hold the result */
1060 res = PyList_New(nattrs);
1064 /* Create and insert the attributes as strings in the list */
1065 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
1066 const char *name = matches_ns(ns, s);
1068 PyObject *item = PyBytes_FromString(name);
1074 PyList_SET_ITEM(res, nattrs, item);
1080 /* Free the buffer, now it is no longer needed */
1087 /* Return the result */
1091 static PyMethodDef xattr_methods[] = {
1092 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1093 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1095 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1097 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1098 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1100 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1101 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1103 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1104 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1106 {NULL, NULL, 0, NULL} /* Sentinel */
1109 static char __xattr_doc__[] = \
1110 "This module gives access to the extended attributes present\n"
1111 "in some operating systems/filesystems. You can list attributes,\n"
1112 "get, set and remove them.\n"
1114 "The module exposes two sets of functions:\n"
1115 " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n"
1116 " :func:`removexattr`\n"
1117 " functions which are deprecated since version 0.4\n"
1118 " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n"
1119 " :func:`remove` functions\n"
1120 " which expose a namespace-aware API and simplify a bit the calling\n"
1121 " model by using keyword arguments\n"
1124 " >>> import xattr\n"
1125 " >>> xattr.listxattr(\"file.txt\")\n"
1126 " ['user.mime_type']\n"
1127 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1129 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1130 "\"Simple text file\")\n"
1131 " >>> xattr.listxattr(\"file.txt\")\n"
1132 " ['user.mime_type', 'user.comment']\n"
1133 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1135 ".. note:: Most or all errors reported by the system while using\n"
1136 " the ``xattr`` library will be reported by raising\n"
1137 " a :exc:`EnvironmentError`; under\n"
1138 " Linux, the following ``errno`` values are used:\n"
1140 " - ``ENOATTR`` and ``ENODATA`` mean that the attribute name is\n"
1142 " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n"
1143 " support extended attributes, or that the namespace is invalid\n"
1144 " - ``E2BIG`` mean that the attribute value is too big\n"
1145 " - ``ERANGE`` mean that the attribute name is too big (it might also\n"
1146 " mean an error in the xattr module itself)\n"
1147 " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n"
1148 " space or out of disk space because of quota limits\n"
1149 ".. note:: Under Python 3, the namespace argument is a byte string,\n"
1150 " not a unicode string.\n"
1156 static struct PyModuleDef xattrmodule = {
1157 PyModuleDef_HEAD_INIT,
1164 #define INITERROR return NULL
1170 #define INITERROR return
1175 PyObject *ns_security = NULL;
1176 PyObject *ns_system = NULL;
1177 PyObject *ns_trusted = NULL;
1178 PyObject *ns_user = NULL;
1180 PyObject *m = PyModule_Create(&xattrmodule);
1182 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1187 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1188 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1189 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1190 PyModule_AddStringConstant(m, "__license__",
1191 "GNU Lesser General Public License (LGPL)");
1192 PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en");
1194 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1195 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1197 /* namespace constants */
1198 if((ns_security = PyBytes_FromString("security")) == NULL)
1200 if((ns_system = PyBytes_FromString("system")) == NULL)
1202 if((ns_trusted = PyBytes_FromString("trusted")) == NULL)
1204 if((ns_user = PyBytes_FromString("user")) == NULL)
1206 if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0)
1209 if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0)
1212 if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0)
1215 if(PyModule_AddObject(m, "NS_USER", ns_user) < 0)
1226 Py_XDECREF(ns_user);
1227 Py_XDECREF(ns_trusted);
1228 Py_XDECREF(ns_system);
1229 Py_XDECREF(ns_security);