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
38 #define PyBytes_Check PyString_Check
39 #define PyBytes_AS_STRING PyString_AS_STRING
40 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
41 #define PyBytes_FromString PyString_FromString
44 /* the estimated (startup) attribute buffer size in
46 #define ESTIMATE_ATTR_SIZE 256
48 typedef enum {T_FD, T_PATH, T_LINK} target_e;
59 /* Cleans up a tgt structure */
60 static void free_tgt(target_t *tgt) {
61 if (tgt->tmp != NULL) {
66 /* Used for cpychecker: */
67 /* The checker automatically defines this preprocessor name when creating
68 the custom attribute: */
69 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
70 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
71 __attribute__((cpychecker_negative_result_sets_exception))
73 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
76 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow)
77 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
79 /** Converts from a string, file or int argument to what we need.
81 * Returns -1 on failure, 0 on success.
83 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) {
86 if(PyBytes_Check(myobj)) {
87 tgt->type = nofollow ? T_LINK : T_PATH;
88 tgt->name = PyBytes_AS_STRING(myobj);
89 } else if(PyUnicode_Check(myobj)) {
90 tgt->type = nofollow ? T_LINK : T_PATH;
92 PyUnicode_AsEncodedString(myobj,
93 Py_FileSystemDefaultEncoding, "strict");
96 tgt->name = PyBytes_AS_STRING(tgt->tmp);
97 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
101 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
107 /* Combine a namespace string and an attribute name into a
108 fully-qualified name */
109 static const char* merge_ns(const char *ns, const char *name, char **buf) {
112 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
113 if((*buf = PyMem_Malloc(new_size)) == NULL) {
117 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
118 if(cnt > new_size || cnt < 0) {
119 PyErr_SetString(PyExc_ValueError,
120 "can't format the attribute name");
131 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
132 if(tgt->type == T_FD)
133 return flistxattr(tgt->fd, list, size);
134 else if (tgt->type == T_LINK)
135 return llistxattr(tgt->name, list, size);
137 return listxattr(tgt->name, list, size);
140 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
142 if(tgt->type == T_FD)
143 return fgetxattr(tgt->fd, name, value, size);
144 else if (tgt->type == T_LINK)
145 return lgetxattr(tgt->name, name, value, size);
147 return getxattr(tgt->name, name, value, size);
150 static int _set_obj(target_t *tgt, const char *name,
151 const void *value, size_t size, int flags) {
152 if(tgt->type == T_FD)
153 return fsetxattr(tgt->fd, name, value, size, flags);
154 else if (tgt->type == T_LINK)
155 return lsetxattr(tgt->name, name, value, size, flags);
157 return setxattr(tgt->name, name, value, size, flags);
160 static int _remove_obj(target_t *tgt, const char *name) {
161 if(tgt->type == T_FD)
162 return fremovexattr(tgt->fd, name);
163 else if (tgt->type == T_LINK)
164 return lremovexattr(tgt->name, name);
166 return removexattr(tgt->name, name);
170 Checks if an attribute name matches an optional namespace.
172 If the namespace is NULL, it will return the name itself. If the
173 namespace is non-NULL and the name matches, it will return a
174 pointer to the offset in the name after the namespace and the
175 separator. If however the name doesn't match the namespace, it will
178 const char *matches_ns(const char *ns, const char *name) {
182 ns_size = strlen(ns);
184 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
185 name[ns_size] == '.')
186 return name + ns_size + 1;
190 /* Wrapper for getxattr */
191 static char __pygetxattr_doc__[] =
192 "Get the value of a given extended attribute (deprecated).\n"
195 " - a string representing filename, or a file-like object,\n"
196 " or a file descriptor; this represents the file on \n"
198 " - a string, representing the attribute whose value to retrieve;\n"
199 " usually in form of system.posix_acl or user.mime_type\n"
200 " - (optional) a boolean value (defaults to false), which, if\n"
201 " the file name given is a symbolic link, makes the\n"
202 " function operate on the symbolic link itself instead\n"
204 "@deprecated: since version 0.4, this function has been deprecated\n"
205 " by the L{get} function\n"
209 pygetxattr(PyObject *self, PyObject *args)
214 char *attrname = NULL;
216 ssize_t nalloc, nret;
219 /* Parse the arguments */
220 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
222 if(convertObj(myarg, &tgt, nofollow) < 0) {
227 /* Find out the needed size of the buffer */
228 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
229 res = PyErr_SetFromErrno(PyExc_IOError);
233 /* Try to allocate the memory, using Python's allocator */
234 if((buf = PyMem_Malloc(nalloc)) == NULL) {
235 res = PyErr_NoMemory();
239 /* Now retrieve the attribute value */
240 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
241 res = PyErr_SetFromErrno(PyExc_IOError);
245 /* Create the string which will hold the result */
246 res = PyBytes_FromStringAndSize(buf, nret);
249 /* Free the buffer, now it is no longer needed */
254 PyMem_Free(attrname);
256 /* Return the result */
260 /* Wrapper for getxattr */
261 static char __get_doc__[] =
262 "Get the value of a given extended attribute.\n"
265 " >>> xattr.get('/path/to/file', 'user.comment')\n"
267 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
270 "@param item: the item to query; either a string representing the\n"
271 " filename, or a file-like object, or a file descriptor\n"
272 "@param name: the attribute whose value to set; usually in form of\n"
273 " system.posix_acl or user.mime_type\n"
274 "@type name: string\n"
275 "@param nofollow: if given and True, and the function is passed a\n"
276 " filename that points to a symlink, the function will act on the\n"
277 " symlink itself instead of its target\n"
278 "@type nofollow: boolean\n"
279 "@param namespace: if given, the attribute must not contain the\n"
280 " namespace itself, but instead the namespace will be taken from\n"
282 "@type namespace: string\n"
283 "@return: the value of the extended attribute (can contain NULLs)\n"
285 "@raise EnvironmentError: caused by any system errors\n"
290 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
295 char *attrname = NULL, *namebuf;
296 const char *fullname;
298 const char *ns = NULL;
299 ssize_t nalloc, nret;
301 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
303 /* Parse the arguments */
304 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist,
305 &myarg, NULL, &attrname, &nofollow, &ns))
307 if(convertObj(myarg, &tgt, nofollow) < 0) {
312 fullname = merge_ns(ns, attrname, &namebuf);
314 /* Find out the needed size of the buffer */
315 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
316 res = PyErr_SetFromErrno(PyExc_IOError);
320 /* Try to allocate the memory, using Python's allocator */
321 if((buf = PyMem_Malloc(nalloc)) == NULL) {
322 res = PyErr_NoMemory();
326 /* Now retrieve the attribute value */
327 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
328 res = PyErr_SetFromErrno(PyExc_IOError);
332 /* Create the string which will hold the result */
333 res = PyBytes_FromStringAndSize(buf, nret);
335 /* Free the buffers, they are no longer needed */
343 PyMem_Free(attrname);
345 /* Return the result */
349 /* Wrapper for getxattr */
350 static char __get_all_doc__[] =
351 "Get all the extended attributes of an item.\n"
353 "This function performs a bulk-get of all extended attribute names\n"
354 "and the corresponding value.\n"
356 " >>> xattr.get_all('/path/to/file')\n"
357 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
358 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
359 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
360 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
362 "@param item: the item to query; either a string representing the\n"
363 " filename, or a file-like object, or a file descriptor\n"
364 "@keyword namespace: an optional namespace for filtering the\n"
365 " attributes; for example, querying all user attributes can be\n"
366 " accomplished by passing namespace=L{NS_USER}\n"
367 "@type namespace: string\n"
368 "@keyword nofollow: if passed and true, if the target file is a\n"
369 " symbolic link, the attributes for the link itself will be\n"
370 " returned, instead of the attributes of the target\n"
371 "@type nofollow: boolean\n"
372 "@return: list of tuples (name, value); note that if a namespace\n"
373 " argument was passed, it (and the separator) will be stripped from\n"
374 " the names returned\n"
376 "@raise EnvironmentError: caused by any system errors\n"
377 "@note: Since reading the whole attribute list is not an atomic\n"
378 " operation, it might be possible that attributes are added\n"
379 " or removed between the initial query and the actual reading\n"
380 " of the attributes; the returned list will contain only the\n"
381 " attributes that were present at the initial listing of the\n"
382 " attribute names and that were still present when the read\n"
383 " attempt for the value is made.\n"
388 get_all(PyObject *self, PyObject *args, PyObject *keywds)
390 PyObject *myarg, *res;
392 const char *ns = NULL;
393 char *buf_list, *buf_val;
395 ssize_t nalloc, nlist, nval;
398 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
400 /* Parse the arguments */
401 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
402 &myarg, &dolink, &ns))
404 if(convertObj(myarg, &tgt, dolink) < 0)
407 /* Compute first the list of attributes */
409 /* Find out the needed size of the buffer for the attribute list */
410 nalloc = _list_obj(&tgt, NULL, 0);
413 res = PyErr_SetFromErrno(PyExc_IOError);
417 /* Try to allocate the memory, using Python's allocator */
418 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
419 res = PyErr_NoMemory();
423 /* Now retrieve the list of attributes */
424 nlist = _list_obj(&tgt, buf_list, nalloc);
427 res = PyErr_SetFromErrno(PyExc_IOError);
431 /* Create the list which will hold the result */
432 mylist = PyList_New(0);
438 nalloc = ESTIMATE_ATTR_SIZE;
439 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
441 res = PyErr_NoMemory();
445 /* Create and insert the attributes as strings in the list */
446 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
451 if((name=matches_ns(ns, s))==NULL)
453 /* Now retrieve the attribute value */
456 nval = _get_obj(&tgt, s, buf_val, nalloc);
459 if(errno == ERANGE) {
460 nval = _get_obj(&tgt, s, NULL, 0);
461 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) {
468 } else if(errno == ENODATA || errno == ENOATTR) {
469 /* this attribute has gone away since we queried
470 the attribute list */
474 /* else we're dealing with a different error, which we
475 don't know how to handle nicely, so we abort */
477 res = PyErr_SetFromErrno(PyExc_IOError);
485 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
487 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
489 if (my_tuple == NULL) {
494 PyList_Append(mylist, my_tuple);
498 /* Successful exit */
505 PyMem_Free(buf_list);
510 /* Return the result */
515 static char __pysetxattr_doc__[] =
516 "Set the value of a given extended attribute (deprecated).\n"
518 "Be carefull in case you want to set attributes on symbolic\n"
519 "links, you have to use all the 5 parameters; use 0 for the \n"
520 "flags value if you want the default behavior (create or "
524 " - a string representing filename, or a file-like object,\n"
525 " or a file descriptor; this represents the file on \n"
527 " - a string, representing the attribute whose value to set;\n"
528 " usually in form of system.posix_acl or user.mime_type\n"
529 " - a string, possibly with embedded NULLs; note that there\n"
530 " are restrictions regarding the size of the value, for\n"
531 " example, for ext2/ext3, maximum size is the block size\n"
532 " - (optional) flags; if 0 or ommited the attribute will be \n"
533 " created or replaced; if XATTR_CREATE, the attribute \n"
534 " will be created, giving an error if it already exists;\n"
535 " of XATTR_REPLACE, the attribute will be replaced,\n"
536 " giving an error if it doesn't exists;\n"
537 " - (optional) a boolean value (defaults to false), which, if\n"
538 " the file name given is a symbolic link, makes the\n"
539 " function operate on the symbolic link itself instead\n"
541 "@deprecated: since version 0.4, this function has been deprecated\n"
542 " by the L{set} function\n"
545 /* Wrapper for setxattr */
547 pysetxattr(PyObject *self, PyObject *args)
549 PyObject *myarg, *res;
551 char *attrname = NULL;
558 /* Parse the arguments */
559 if (!PyArg_ParseTuple(args, "Oetet#|bi", &myarg, NULL, &attrname,
560 NULL, &buf, &bufsize, &flags, &nofollow))
562 if(convertObj(myarg, &tgt, nofollow) < 0) {
567 /* Set the attribute's value */
568 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
573 res = PyErr_SetFromErrno(PyExc_IOError);
581 PyMem_Free(attrname);
584 /* Return the result */
588 static char __set_doc__[] =
589 "Set the value of a given extended attribute.\n"
592 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
593 " >>> xattr.set('/path/to/file', 'comment', 'test',"
594 " namespace=xattr.NS_USER)\n"
596 "@param item: the item to query; either a string representing the\n"
597 " filename, or a file-like object, or a file descriptor\n"
598 "@param name: the attribute whose value to set; usually in form of\n"
599 " system.posix_acl or user.mime_type\n"
600 "@type name: string\n"
601 "@param value: a string, possibly with embedded NULLs; note that there\n"
602 " are restrictions regarding the size of the value, for\n"
603 " example, for ext2/ext3, maximum size is the block size\n"
604 "@type value: string\n"
605 "@param flags: if 0 or ommited the attribute will be\n"
606 " created or replaced; if L{XATTR_CREATE}, the attribute\n"
607 " will be created, giving an error if it already exists;\n"
608 " if L{XATTR_REPLACE}, the attribute will be replaced,\n"
609 " giving an error if it doesn't exists;\n"
610 "@type flags: integer\n"
611 "@param nofollow: if given and True, and the function is passed a\n"
612 " filename that points to a symlink, the function will act on the\n"
613 " symlink itself instead of its target\n"
614 "@type nofollow: boolean\n"
615 "@param namespace: if given, the attribute must not contain the\n"
616 " namespace itself, but instead the namespace will be taken from\n"
618 "@type namespace: string\n"
620 "@raise EnvironmentError: caused by any system errors\n"
624 /* Wrapper for setxattr */
626 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
628 PyObject *myarg, *res;
630 char *attrname = NULL;
636 const char *ns = NULL;
638 const char *full_name;
639 static char *kwlist[] = {"item", "name", "value", "flags",
640 "nofollow", "namespace", NULL};
642 /* Parse the arguments */
643 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|iiz", kwlist,
644 &myarg, NULL, &attrname, NULL,
645 &buf, &bufsize, &flags, &nofollow, &ns))
647 if(convertObj(myarg, &tgt, nofollow) < 0) {
652 full_name = merge_ns(ns, attrname, &newname);
654 /* Set the attribute's value */
655 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
663 res = PyErr_SetFromErrno(PyExc_IOError);
671 PyMem_Free(attrname);
674 /* Return the result */
679 static char __pyremovexattr_doc__[] =
680 "Remove an attribute from a file (deprecated).\n"
683 " - a string representing filename, or a file-like object,\n"
684 " or a file descriptor; this represents the file on \n"
686 " - a string, representing the attribute to be removed;\n"
687 " usually in form of system.posix_acl or user.mime_type\n"
688 " - (optional) a boolean value (defaults to false), which, if\n"
689 " the file name given is a symbolic link, makes the\n"
690 " function operate on the symbolic link itself instead\n"
692 "@deprecated: since version 0.4, this function has been deprecated\n"
697 /* Wrapper for removexattr */
699 pyremovexattr(PyObject *self, PyObject *args)
701 PyObject *myarg, *res;
703 char *attrname = NULL;
707 /* Parse the arguments */
708 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
711 if(convertObj(myarg, &tgt, nofollow) < 0) {
716 /* Remove the attribute */
717 nret = _remove_obj(&tgt, attrname);
722 res = PyErr_SetFromErrno(PyExc_IOError);
730 PyMem_Free(attrname);
732 /* Return the result */
736 static char __remove_doc__[] =
737 "Remove an attribute from a file.\n"
740 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
742 "@param item: the item to query; either a string representing the\n"
743 " filename, or a file-like object, or a file descriptor\n"
744 "@param name: the attribute whose value to set; usually in form of\n"
745 " system.posix_acl or user.mime_type\n"
746 "@type name: string\n"
747 "@param nofollow: if given and True, and the function is passed a\n"
748 " filename that points to a symlink, the function will act on the\n"
749 " symlink itself instead of its target\n"
750 "@type nofollow: boolean\n"
751 "@param namespace: if given, the attribute must not contain the\n"
752 " namespace itself, but instead the namespace will be taken from\n"
754 "@type namespace: string\n"
757 "@raise EnvironmentError: caused by any system errors\n"
760 /* Wrapper for removexattr */
762 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
764 PyObject *myarg, *res;
766 char *attrname = NULL, *name_buf;
767 const char *ns = NULL;
768 const char *full_name;
771 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
773 /* Parse the arguments */
774 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist,
775 &myarg, NULL, &attrname, &nofollow, &ns))
778 if(convertObj(myarg, &tgt, nofollow) < 0) {
783 full_name = merge_ns(ns, attrname, &name_buf);
784 if(full_name == NULL) {
789 /* Remove the attribute */
790 nret = _remove_obj(&tgt, full_name);
792 PyMem_Free(name_buf);
797 res = PyErr_SetFromErrno(PyExc_IOError);
805 PyMem_Free(attrname);
807 /* Return the result */
811 static char __pylistxattr_doc__[] =
812 "Return the list of attribute names for a file (deprecated).\n"
815 " - a string representing filename, or a file-like object,\n"
816 " or a file descriptor; this represents the file to \n"
818 " - (optional) a boolean value (defaults to false), which, if\n"
819 " the file name given is a symbolic link, makes the\n"
820 " function operate on the symbolic link itself instead\n"
822 "@deprecated: since version 0.4, this function has been deprecated\n"
827 /* Wrapper for listxattr */
829 pylistxattr(PyObject *self, PyObject *args)
833 ssize_t nalloc, nret;
840 /* Parse the arguments */
841 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
843 if(convertObj(myarg, &tgt, nofollow) < 0)
846 /* Find out the needed size of the buffer */
847 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
848 mylist = PyErr_SetFromErrno(PyExc_IOError);
852 /* Try to allocate the memory, using Python's allocator */
853 if((buf = PyMem_Malloc(nalloc)) == NULL) {
854 mylist = PyErr_NoMemory();
858 /* Now retrieve the list of attributes */
859 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
860 mylist = PyErr_SetFromErrno(PyExc_IOError);
864 /* Compute the number of attributes in the list */
865 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
869 /* Create the list which will hold the result */
870 mylist = PyList_New(nattrs);
874 /* Create and insert the attributes as strings in the list */
875 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
876 PyObject *item = PyBytes_FromString(s);
882 PyList_SET_ITEM(mylist, nattrs, item);
887 /* Free the buffer, now it is no longer needed */
893 /* Return the result */
897 static char __list_doc__[] =
898 "Return the list of attribute names for a file.\n"
901 " >>> xattr.list('/path/to/file')\n"
902 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
903 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
904 " ['test', 'comment']\n"
906 "@param item: the item to query; either a string representing the\n"
907 " filename, or a file-like object, or a file descriptor\n"
908 "@param nofollow: if given and True, and the function is passed a\n"
909 " filename that points to a symlink, the function will act on the\n"
910 " symlink itself instead of its target\n"
911 "@type nofollow: boolean\n"
912 "@param namespace: if given, the attribute must not contain the\n"
913 " namespace itself, but instead the namespace will be taken from\n"
915 "@type namespace: string\n"
916 "@return: list of strings; note that if a namespace argument was\n"
917 " passed, it (and the separator) will be stripped from the names\n"
920 "@raise EnvironmentError: caused by any system errors\n"
924 /* Wrapper for listxattr */
926 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
930 ssize_t nalloc, nret;
937 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
939 /* Parse the arguments */
940 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iet", kwlist,
941 &myarg, &nofollow, NULL, &ns))
943 if(convertObj(myarg, &tgt, nofollow) < 0) {
948 /* Find out the needed size of the buffer */
949 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
950 res = PyErr_SetFromErrno(PyExc_IOError);
954 /* Try to allocate the memory, using Python's allocator */
955 if((buf = PyMem_Malloc(nalloc)) == NULL) {
956 res = PyErr_NoMemory();
960 /* Now retrieve the list of attributes */
961 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
962 res = PyErr_SetFromErrno(PyExc_IOError);
966 /* Compute the number of attributes in the list */
967 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
968 if(matches_ns(ns, s) != NULL)
971 /* Create the list which will hold the result */
972 res = PyList_New(nattrs);
976 /* Create and insert the attributes as strings in the list */
977 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
978 const char *name = matches_ns(ns, s);
980 PyObject *item = PyBytes_FromString(name);
986 PyList_SET_ITEM(res, nattrs, item);
992 /* Free the buffer, now it is no longer needed */
1000 /* Return the result */
1004 static PyMethodDef xattr_methods[] = {
1005 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1006 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1008 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1010 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1011 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1013 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1014 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1016 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1017 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1019 {NULL, NULL, 0, NULL} /* Sentinel */
1022 static char __xattr_doc__[] = \
1023 "Interface to extended filesystem attributes.\n"
1025 "This module gives access to the extended attributes present\n"
1026 "in some operating systems/filesystems. You can list attributes,\n"
1027 "get, set and remove them.\n"
1029 "The module exposes two sets of functions:\n"
1030 " - the 'old' L{listxattr}, L{getxattr}, L{setxattr}, L{removexattr}\n"
1031 " functions which are deprecated since version 0.4\n"
1032 " - the new L{list}, L{get}, L{get_all}, L{set}, L{remove} functions\n"
1033 " which expose a namespace-aware API and simplify a bit the calling\n"
1034 " model by using keyword arguments\n"
1037 " >>> import xattr\n"
1038 " >>> xattr.listxattr(\"file.txt\")\n"
1039 " ['user.mime_type']\n"
1040 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1042 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1043 "\"Simple text file\")\n"
1044 " >>> xattr.listxattr(\"file.txt\")\n"
1045 " ['user.mime_type', 'user.comment']\n"
1046 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1048 "@note: Most or all errors reported by the system while using the xattr\n"
1049 "library will be reported by raising a L{EnvironmentError}; under Linux,\n"
1050 "the following C{errno} values are used:\n"
1051 " - C{ENOATTR} and C{ENODATA} mean that the attribute name is invalid\n"
1052 " - C{ENOTSUP} and C{EOPNOTSUPP} mean that the filesystem does not\n"
1053 " support extended attributes, or that the namespace is invalid\n"
1054 " - C{E2BIG} mean that the attribute value is too big\n"
1055 " - C{ERANGE} mean that the attribute name is too big (it might also\n"
1056 " mean an error in the xattr module itself)\n"
1057 " - C{ENOSPC} and C{EDQUOT} are documented as meaning out of disk space\n"
1058 " or out of disk space because of quota limits\n"
1060 "@group Deprecated API: *xattr\n"
1061 "@group Namespace constants: NS_*\n"
1062 "@group set function flags: XATTR_CREATE, XATTR_REPLACE\n"
1063 "@sort: list, get, get_all, set, remove, listxattr, getxattr, setxattr\n"
1069 static struct PyModuleDef xattrmodule = {
1070 PyModuleDef_HEAD_INIT,
1077 #define INITERROR return NULL
1083 #define INITERROR return
1089 PyObject *m = PyModule_Create(&xattrmodule);
1091 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1096 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1097 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1098 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1099 PyModule_AddStringConstant(m, "__license__",
1100 "GNU Lesser General Public License (LGPL)");
1101 PyModule_AddStringConstant(m, "__docformat__", "epytext en");
1103 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1104 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1106 /* namespace constants */
1107 PyModule_AddObject(m, "NS_SECURITY", PyBytes_FromString("security"));
1108 PyModule_AddObject(m, "NS_SYSTEM", PyBytes_FromString("system"));
1109 PyModule_AddObject(m, "NS_TRUSTED", PyBytes_FromString("trusted"));
1110 PyModule_AddObject(m, "NS_USER", PyBytes_FromString("user"));