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 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
178 if((*buf = PyMem_Malloc(new_size)) == NULL) {
182 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
183 if(cnt > new_size || cnt < 0) {
184 PyErr_SetString(PyExc_ValueError,
185 "can't format the attribute name");
197 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
198 if(tgt->type == T_FD)
199 return flistxattr(tgt->fd, list, size);
200 else if (tgt->type == T_LINK)
201 return llistxattr(tgt->name, list, size);
203 return listxattr(tgt->name, list, size);
206 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
208 if(tgt->type == T_FD)
209 return fgetxattr(tgt->fd, name, value, size);
210 else if (tgt->type == T_LINK)
211 return lgetxattr(tgt->name, name, value, size);
213 return getxattr(tgt->name, name, value, size);
216 static int _set_obj(target_t *tgt, const char *name,
217 const void *value, size_t size, int flags) {
218 if(tgt->type == T_FD)
219 return fsetxattr(tgt->fd, name, value, size, flags);
220 else if (tgt->type == T_LINK)
221 return lsetxattr(tgt->name, name, value, size, flags);
223 return setxattr(tgt->name, name, value, size, flags);
226 static int _remove_obj(target_t *tgt, const char *name) {
227 if(tgt->type == T_FD)
228 return fremovexattr(tgt->fd, name);
229 else if (tgt->type == T_LINK)
230 return lremovexattr(tgt->name, name);
232 return removexattr(tgt->name, name);
236 Checks if an attribute name matches an optional namespace.
238 If the namespace is NULL or an empty string, it will return the
239 name itself. If the namespace is non-NULL and the name matches, it
240 will return a pointer to the offset in the name after the namespace
241 and the separator. If however the name doesn't match the namespace,
245 const char *matches_ns(const char *ns, const char *name) {
247 if (ns == NULL || *ns == '\0')
249 ns_size = strlen(ns);
251 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
252 name[ns_size] == '.')
253 return name + ns_size + 1;
257 /* Wrapper for getxattr */
258 static char __pygetxattr_doc__[] =
259 "getxattr(item, attribute[, nofollow=False])\n"
260 "Get the value of a given extended attribute (deprecated).\n"
266 ".. deprecated:: 0.4\n"
267 " this function has been deprecated\n"
268 " by the :func:`get` function.\n"
272 pygetxattr(PyObject *self, PyObject *args)
277 char *attrname = NULL;
279 ssize_t nalloc, nret;
282 /* Parse the arguments */
283 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
285 if(convert_obj(myarg, &tgt, nofollow) < 0) {
290 /* Find out the needed size of the buffer */
291 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
292 res = PyErr_SetFromErrno(PyExc_IOError);
296 /* Try to allocate the memory, using Python's allocator */
297 if((buf = PyMem_Malloc(nalloc)) == NULL) {
298 res = PyErr_NoMemory();
302 /* Now retrieve the attribute value */
303 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
304 res = PyErr_SetFromErrno(PyExc_IOError);
308 /* Create the string which will hold the result */
309 res = PyBytes_FromStringAndSize(buf, nret);
312 /* Free the buffer, now it is no longer needed */
317 PyMem_Free(attrname);
319 /* Return the result */
323 /* Wrapper for getxattr */
324 static char __get_doc__[] =
325 "get(item, name[, nofollow=False, namespace=None])\n"
326 "Get the value of a given extended attribute.\n"
329 " >>> xattr.get('/path/to/file', 'user.comment')\n"
331 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
338 ":return: the value of the extended attribute (can contain NULLs)\n"
340 ":raises EnvironmentError: caused by any system errors\n"
342 ".. versionadded:: 0.4\n"
347 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
352 char *attrname = NULL, *namebuf;
353 const char *fullname;
355 const char *ns = NULL;
356 ssize_t nalloc, nret;
358 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
360 /* Parse the arguments */
361 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
362 &myarg, NULL, &attrname, &nofollow, &ns))
364 if(convert_obj(myarg, &tgt, nofollow) < 0) {
369 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
374 /* Find out the needed size of the buffer */
375 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
376 res = PyErr_SetFromErrno(PyExc_IOError);
380 /* Try to allocate the memory, using Python's allocator */
381 if((buf = PyMem_Malloc(nalloc)) == NULL) {
382 res = PyErr_NoMemory();
386 /* Now retrieve the attribute value */
387 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
388 res = PyErr_SetFromErrno(PyExc_IOError);
392 /* Create the string which will hold the result */
393 res = PyBytes_FromStringAndSize(buf, nret);
395 /* Free the buffers, they are no longer needed */
403 PyMem_Free(attrname);
405 /* Return the result */
409 /* Wrapper for getxattr */
410 static char __get_all_doc__[] =
411 "get_all(item[, nofollow=False, namespace=None])\n"
412 "Get all the extended attributes of an item.\n"
414 "This function performs a bulk-get of all extended attribute names\n"
415 "and the corresponding value.\n"
418 " >>> xattr.get_all('/path/to/file')\n"
419 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
420 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
421 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
422 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
425 ":keyword namespace: an optional namespace for filtering the\n"
426 " attributes; for example, querying all user attributes can be\n"
427 " accomplished by passing namespace=:const:`NS_USER`\n"
428 ":type namespace: string\n"
430 ":return: list of tuples (name, value); note that if a namespace\n"
431 " argument was passed, it (and the separator) will be stripped from\n"
432 " the names returned\n"
434 ":raises EnvironmentError: caused by any system errors\n"
436 ".. note:: Since reading the whole attribute list is not an atomic\n"
437 " operation, it might be possible that attributes are added\n"
438 " or removed between the initial query and the actual reading\n"
439 " of the attributes; the returned list will contain only the\n"
440 " attributes that were present at the initial listing of the\n"
441 " attribute names and that were still present when the read\n"
442 " attempt for the value is made.\n"
443 ".. versionadded:: 0.4\n"
448 get_all(PyObject *self, PyObject *args, PyObject *keywds)
450 PyObject *myarg, *res;
452 const char *ns = NULL;
453 char *buf_list, *buf_val, *buf_val_tmp;
455 ssize_t nalloc, nlist, nval;
458 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
460 /* Parse the arguments */
461 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
462 &myarg, &nofollow, &ns))
464 if(convert_obj(myarg, &tgt, nofollow) < 0)
467 /* Compute first the list of attributes */
469 /* Find out the needed size of the buffer for the attribute list */
470 nalloc = _list_obj(&tgt, NULL, 0);
473 res = PyErr_SetFromErrno(PyExc_IOError);
482 /* Try to allocate the memory, using Python's allocator */
483 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
484 res = PyErr_NoMemory();
488 /* Now retrieve the list of attributes */
489 nlist = _list_obj(&tgt, buf_list, nalloc);
492 res = PyErr_SetFromErrno(PyExc_IOError);
496 /* Create the list which will hold the result */
497 mylist = PyList_New(0);
503 nalloc = ESTIMATE_ATTR_SIZE;
504 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
506 res = PyErr_NoMemory();
510 /* Create and insert the attributes as strings in the list */
511 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
516 if((name=matches_ns(ns, s))==NULL)
518 /* Now retrieve the attribute value */
521 nval = _get_obj(&tgt, s, buf_val, nalloc);
524 if(errno == ERANGE) {
525 nval = _get_obj(&tgt, s, NULL, 0);
526 /* ERANGE + proper size should not fail, but it
527 still can, so let's check first */
529 res = PyErr_SetFromErrno(PyExc_IOError);
533 if((buf_val_tmp = PyMem_Realloc(buf_val, nval)) == NULL) {
534 res = PyErr_NoMemory();
538 buf_val = buf_val_tmp;
542 } else if(errno == ENODATA || errno == ENOATTR) {
543 /* this attribute has gone away since we queried
544 the attribute list */
548 /* else we're dealing with a different error, which we
549 don't know how to handle nicely, so we abort */
551 res = PyErr_SetFromErrno(PyExc_IOError);
559 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
561 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
563 if (my_tuple == NULL) {
568 PyList_Append(mylist, my_tuple);
572 /* Successful exit */
579 PyMem_Free(buf_list);
584 /* Return the result */
589 static char __pysetxattr_doc__[] =
590 "setxattr(item, name, value[, flags=0, nofollow=False])\n"
591 "Set the value of a given extended attribute (deprecated).\n"
593 "Be careful in case you want to set attributes on symbolic\n"
594 "links, you have to use all the 5 parameters; use 0 for the \n"
595 "flags value if you want the default behaviour (create or "
604 ".. deprecated:: 0.4\n"
605 " this function has been deprecated\n"
606 " by the :func:`set` function.\n"
609 /* Wrapper for setxattr */
611 pysetxattr(PyObject *self, PyObject *args)
613 PyObject *myarg, *res;
615 char *attrname = NULL;
617 Py_ssize_t bufsize_s;
623 /* Parse the arguments */
624 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
625 NULL, &buf, &bufsize_s, &flags, &nofollow))
629 PyErr_SetString(PyExc_ValueError,
630 "negative value size?!");
634 bufsize = (size_t) bufsize_s;
636 if(convert_obj(myarg, &tgt, nofollow) < 0) {
641 /* Set the attribute's value */
642 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
647 res = PyErr_SetFromErrno(PyExc_IOError);
655 PyMem_Free(attrname);
658 /* Return the result */
662 static char __set_doc__[] =
663 "set(item, name, value[, flags=0, namespace=None])\n"
664 "Set the value of a given extended attribute.\n"
668 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
669 " >>> xattr.set('/path/to/file', 'comment', 'test',"
670 " namespace=xattr.NS_USER)\n"
679 ":raises EnvironmentError: caused by any system errors\n"
681 ".. versionadded:: 0.4\n"
685 /* Wrapper for setxattr */
687 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
689 PyObject *myarg, *res;
691 char *attrname = NULL;
693 Py_ssize_t bufsize_s;
698 const char *ns = NULL;
700 const char *full_name;
701 static char *kwlist[] = {"item", "name", "value", "flags",
702 "nofollow", "namespace", NULL};
704 /* Parse the arguments */
705 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
706 kwlist, &myarg, NULL, &attrname, NULL,
707 &buf, &bufsize_s, &flags, &nofollow, &ns))
711 PyErr_SetString(PyExc_ValueError,
712 "negative value size?!");
716 bufsize = (size_t) bufsize_s;
718 if(convert_obj(myarg, &tgt, nofollow) < 0) {
723 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
728 /* Set the attribute's value */
729 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
736 res = PyErr_SetFromErrno(PyExc_IOError);
744 PyMem_Free(attrname);
747 /* Return the result */
752 static char __pyremovexattr_doc__[] =
753 "removexattr(item, name[, nofollow])\n"
754 "Remove an attribute from a file (deprecated).\n"
760 ".. deprecated:: 0.4\n"
761 " this function has been deprecated by the :func:`remove` function.\n"
764 /* Wrapper for removexattr */
766 pyremovexattr(PyObject *self, PyObject *args)
768 PyObject *myarg, *res;
770 char *attrname = NULL;
774 /* Parse the arguments */
775 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
778 if(convert_obj(myarg, &tgt, nofollow) < 0) {
783 /* Remove the attribute */
784 nret = _remove_obj(&tgt, attrname);
789 res = PyErr_SetFromErrno(PyExc_IOError);
797 PyMem_Free(attrname);
799 /* Return the result */
803 static char __remove_doc__[] =
804 "remove(item, name[, nofollow=False, namespace=None])\n"
805 "Remove an attribute from a file.\n"
809 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
816 ":raises EnvironmentError: caused by any system errors\n"
818 ".. versionadded:: 0.4\n"
822 /* Wrapper for removexattr */
824 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
826 PyObject *myarg, *res;
828 char *attrname = NULL, *name_buf;
829 const char *ns = NULL;
830 const char *full_name;
833 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
835 /* Parse the arguments */
836 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
837 &myarg, NULL, &attrname, &nofollow, &ns))
840 if(convert_obj(myarg, &tgt, nofollow) < 0) {
845 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
850 /* Remove the attribute */
851 nret = _remove_obj(&tgt, full_name);
853 PyMem_Free(name_buf);
858 res = PyErr_SetFromErrno(PyExc_IOError);
866 PyMem_Free(attrname);
868 /* Return the result */
872 static char __pylistxattr_doc__[] =
873 "listxattr(item[, nofollow=False])\n"
874 "Return the list of attribute names for a file (deprecated).\n"
879 ".. deprecated:: 0.4\n"
880 " this function has been deprecated by the :func:`list` function.\n"
883 /* Wrapper for listxattr */
885 pylistxattr(PyObject *self, PyObject *args)
889 ssize_t nalloc, nret;
896 /* Parse the arguments */
897 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
899 if(convert_obj(myarg, &tgt, nofollow) < 0)
902 /* Find out the needed size of the buffer */
903 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
904 mylist = PyErr_SetFromErrno(PyExc_IOError);
909 mylist = PyList_New(0);
913 /* Try to allocate the memory, using Python's allocator */
914 if((buf = PyMem_Malloc(nalloc)) == NULL) {
915 mylist = PyErr_NoMemory();
919 /* Now retrieve the list of attributes */
920 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
921 mylist = PyErr_SetFromErrno(PyExc_IOError);
925 /* Compute the number of attributes in the list */
926 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
930 /* Create the list which will hold the result */
931 mylist = PyList_New(nattrs);
935 /* Create and insert the attributes as strings in the list */
936 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
937 PyObject *item = PyBytes_FromString(s);
943 PyList_SET_ITEM(mylist, nattrs, item);
948 /* Free the buffer, now it is no longer needed */
954 /* Return the result */
958 static char __list_doc__[] =
959 "list(item[, nofollow=False, namespace=None])\n"
960 "Return the list of attribute names for a file.\n"
964 " >>> xattr.list('/path/to/file')\n"
965 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
966 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
967 " ['test', 'comment']\n"
972 ":returns: the list of attributes; note that if a namespace \n"
973 " argument was passed, it (and the separator) will be stripped\n"
977 ":raises EnvironmentError: caused by any system errors\n"
979 ".. versionadded:: 0.4\n"
983 /* Wrapper for listxattr */
985 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
989 ssize_t nalloc, nret;
992 const char *ns = NULL;
996 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
998 /* Parse the arguments */
999 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
1000 &myarg, &nofollow, &ns))
1002 if(convert_obj(myarg, &tgt, nofollow) < 0) {
1007 /* Find out the needed size of the buffer */
1008 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
1009 res = PyErr_SetFromErrno(PyExc_IOError);
1014 res = PyList_New(0);
1018 /* Try to allocate the memory, using Python's allocator */
1019 if((buf = PyMem_Malloc(nalloc)) == NULL) {
1020 res = PyErr_NoMemory();
1024 /* Now retrieve the list of attributes */
1025 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
1026 res = PyErr_SetFromErrno(PyExc_IOError);
1030 /* Compute the number of attributes in the list */
1031 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
1032 if(matches_ns(ns, s) != NULL)
1035 /* Create the list which will hold the result */
1036 res = PyList_New(nattrs);
1040 /* Create and insert the attributes as strings in the list */
1041 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
1042 const char *name = matches_ns(ns, s);
1044 PyObject *item = PyBytes_FromString(name);
1050 PyList_SET_ITEM(res, nattrs, item);
1056 /* Free the buffer, now it is no longer needed */
1063 /* Return the result */
1067 static PyMethodDef xattr_methods[] = {
1068 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1069 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1071 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1073 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1074 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1076 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1077 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1079 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1080 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1082 {NULL, NULL, 0, NULL} /* Sentinel */
1085 static char __xattr_doc__[] = \
1086 "This module gives access to the extended attributes present\n"
1087 "in some operating systems/filesystems. You can list attributes,\n"
1088 "get, set and remove them.\n"
1090 "The module exposes two sets of functions:\n"
1091 " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n"
1092 " :func:`removexattr`\n"
1093 " functions which are deprecated since version 0.4\n"
1094 " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n"
1095 " :func:`remove` functions\n"
1096 " which expose a namespace-aware API and simplify a bit the calling\n"
1097 " model by using keyword arguments\n"
1100 " >>> import xattr\n"
1101 " >>> xattr.listxattr(\"file.txt\")\n"
1102 " ['user.mime_type']\n"
1103 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1105 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1106 "\"Simple text file\")\n"
1107 " >>> xattr.listxattr(\"file.txt\")\n"
1108 " ['user.mime_type', 'user.comment']\n"
1109 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1111 ".. note:: Most or all errors reported by the system while using\n"
1112 " the ``xattr`` library will be reported by raising\n"
1113 " a :exc:`EnvironmentError`; under\n"
1114 " Linux, the following ``errno`` values are used:\n"
1116 " - ``ENOATTR`` and ``ENODATA`` mean that the attribute name is\n"
1118 " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n"
1119 " support extended attributes, or that the namespace is invalid\n"
1120 " - ``E2BIG`` mean that the attribute value is too big\n"
1121 " - ``ERANGE`` mean that the attribute name is too big (it might also\n"
1122 " mean an error in the xattr module itself)\n"
1123 " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n"
1124 " space or out of disk space because of quota limits\n"
1125 ".. note:: Under Python 3, the namespace argument is a byte string,\n"
1126 " not a unicode string.\n"
1132 static struct PyModuleDef xattrmodule = {
1133 PyModuleDef_HEAD_INIT,
1140 #define INITERROR return NULL
1146 #define INITERROR return
1151 PyObject *ns_security = NULL;
1152 PyObject *ns_system = NULL;
1153 PyObject *ns_trusted = NULL;
1154 PyObject *ns_user = NULL;
1156 PyObject *m = PyModule_Create(&xattrmodule);
1158 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1163 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1164 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1165 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1166 PyModule_AddStringConstant(m, "__license__",
1167 "GNU Lesser General Public License (LGPL)");
1168 PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en");
1170 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1171 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1173 /* namespace constants */
1174 if((ns_security = PyBytes_FromString("security")) == NULL)
1176 if((ns_system = PyBytes_FromString("system")) == NULL)
1178 if((ns_trusted = PyBytes_FromString("trusted")) == NULL)
1180 if((ns_user = PyBytes_FromString("user")) == NULL)
1182 if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0)
1185 if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0)
1188 if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0)
1191 if(PyModule_AddObject(m, "NS_USER", ns_user) < 0)
1202 Py_XDECREF(ns_user);
1203 Py_XDECREF(ns_trusted);
1204 Py_XDECREF(ns_system);
1205 Py_XDECREF(ns_security);