2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008, 2012 Iustin Pop <iusty@k1024.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #define PY_SSIZE_T_CLEAN
25 #include <attr/xattr.h>
28 /* Compatibility with python 2.4 regarding python size type (PEP 353) */
29 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
30 typedef int Py_ssize_t;
31 #define PY_SSIZE_T_MAX INT_MAX
32 #define PY_SSIZE_T_MIN INT_MIN
35 #if PY_MAJOR_VERSION >= 3
37 #define BYTES_CHAR "y"
39 #define BYTES_CHAR "z"
40 #define PyBytes_Check PyString_Check
41 #define PyBytes_AS_STRING PyString_AS_STRING
42 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
43 #define PyBytes_FromString PyString_FromString
46 /* the estimated (startup) attribute buffer size in
48 #define ESTIMATE_ATTR_SIZE 256
50 typedef enum {T_FD, T_PATH, T_LINK} target_e;
61 /* Cleans up a tgt structure */
62 static void free_tgt(target_t *tgt) {
63 if (tgt->tmp != NULL) {
68 /* Used for cpychecker: */
69 /* The checker automatically defines this preprocessor name when creating
70 the custom attribute: */
71 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
72 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
73 __attribute__((cpychecker_negative_result_sets_exception))
75 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
78 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow)
79 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
81 static int merge_ns(const char *ns, const char *name,
82 const char **result, char **buf)
83 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
86 /** Converts from a string, file or int argument to what we need.
88 * Returns -1 on failure, 0 on success.
90 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) {
93 if(PyBytes_Check(myobj)) {
94 tgt->type = nofollow ? T_LINK : T_PATH;
95 tgt->name = PyBytes_AS_STRING(myobj);
96 } else if(PyUnicode_Check(myobj)) {
97 tgt->type = nofollow ? T_LINK : T_PATH;
99 PyUnicode_AsEncodedString(myobj,
100 Py_FileSystemDefaultEncoding, "strict");
103 tgt->name = PyBytes_AS_STRING(tgt->tmp);
104 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
108 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
114 /* Combine a namespace string and an attribute name into a
115 fully-qualified name */
116 static int merge_ns(const char *ns, const char *name,
117 const char **result, char **buf) {
118 if(ns != NULL && *ns != '\0') {
120 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
121 if((*buf = PyMem_Malloc(new_size)) == NULL) {
125 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
126 if(cnt > new_size || cnt < 0) {
127 PyErr_SetString(PyExc_ValueError,
128 "can't format the attribute name");
140 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
141 if(tgt->type == T_FD)
142 return flistxattr(tgt->fd, list, size);
143 else if (tgt->type == T_LINK)
144 return llistxattr(tgt->name, list, size);
146 return listxattr(tgt->name, list, size);
149 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
151 if(tgt->type == T_FD)
152 return fgetxattr(tgt->fd, name, value, size);
153 else if (tgt->type == T_LINK)
154 return lgetxattr(tgt->name, name, value, size);
156 return getxattr(tgt->name, name, value, size);
159 static int _set_obj(target_t *tgt, const char *name,
160 const void *value, size_t size, int flags) {
161 if(tgt->type == T_FD)
162 return fsetxattr(tgt->fd, name, value, size, flags);
163 else if (tgt->type == T_LINK)
164 return lsetxattr(tgt->name, name, value, size, flags);
166 return setxattr(tgt->name, name, value, size, flags);
169 static int _remove_obj(target_t *tgt, const char *name) {
170 if(tgt->type == T_FD)
171 return fremovexattr(tgt->fd, name);
172 else if (tgt->type == T_LINK)
173 return lremovexattr(tgt->name, name);
175 return removexattr(tgt->name, name);
179 Checks if an attribute name matches an optional namespace.
181 If the namespace is NULL, it will return the name itself. If the
182 namespace is non-NULL and the name matches, it will return a
183 pointer to the offset in the name after the namespace and the
184 separator. If however the name doesn't match the namespace, it will
187 const char *matches_ns(const char *ns, const char *name) {
191 ns_size = strlen(ns);
193 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
194 name[ns_size] == '.')
195 return name + ns_size + 1;
199 /* Wrapper for getxattr */
200 static char __pygetxattr_doc__[] =
201 "Get the value of a given extended attribute (deprecated).\n"
204 " - a string representing filename, or a file-like object,\n"
205 " or a file descriptor; this represents the file on \n"
207 " - a string, representing the attribute whose value to retrieve;\n"
208 " usually in form of system.posix_acl or user.mime_type\n"
209 " - (optional) a boolean value (defaults to false), which, if\n"
210 " the file name given is a symbolic link, makes the\n"
211 " function operate on the symbolic link itself instead\n"
213 "@deprecated: since version 0.4, this function has been deprecated\n"
214 " by the L{get} function\n"
218 pygetxattr(PyObject *self, PyObject *args)
223 char *attrname = NULL;
225 ssize_t nalloc, nret;
228 /* Parse the arguments */
229 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
231 if(convertObj(myarg, &tgt, nofollow) < 0) {
236 /* Find out the needed size of the buffer */
237 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
238 res = PyErr_SetFromErrno(PyExc_IOError);
242 /* Try to allocate the memory, using Python's allocator */
243 if((buf = PyMem_Malloc(nalloc)) == NULL) {
244 res = PyErr_NoMemory();
248 /* Now retrieve the attribute value */
249 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
250 res = PyErr_SetFromErrno(PyExc_IOError);
254 /* Create the string which will hold the result */
255 res = PyBytes_FromStringAndSize(buf, nret);
258 /* Free the buffer, now it is no longer needed */
263 PyMem_Free(attrname);
265 /* Return the result */
269 /* Wrapper for getxattr */
270 static char __get_doc__[] =
271 "Get the value of a given extended attribute.\n"
274 " >>> xattr.get('/path/to/file', 'user.comment')\n"
276 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
279 "@param item: the item to query; either a string representing the\n"
280 " filename, or a file-like object, or a file descriptor\n"
281 "@param name: the attribute whose value to set; usually in form of\n"
282 " system.posix_acl or user.mime_type\n"
283 "@type name: string\n"
284 "@param nofollow: if given and True, and the function is passed a\n"
285 " filename that points to a symlink, the function will act on the\n"
286 " symlink itself instead of its target\n"
287 "@type nofollow: boolean\n"
288 "@param namespace: if given, the attribute must not contain the\n"
289 " namespace itself, but instead the namespace will be taken from\n"
291 "@type namespace: string\n"
292 "@return: the value of the extended attribute (can contain NULLs)\n"
294 "@raise EnvironmentError: caused by any system errors\n"
299 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
304 char *attrname = NULL, *namebuf;
305 const char *fullname;
307 const char *ns = NULL;
308 ssize_t nalloc, nret;
310 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
312 /* Parse the arguments */
313 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
314 &myarg, NULL, &attrname, &nofollow, &ns))
316 if(convertObj(myarg, &tgt, nofollow) < 0) {
321 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
326 /* Find out the needed size of the buffer */
327 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
328 res = PyErr_SetFromErrno(PyExc_IOError);
332 /* Try to allocate the memory, using Python's allocator */
333 if((buf = PyMem_Malloc(nalloc)) == NULL) {
334 res = PyErr_NoMemory();
338 /* Now retrieve the attribute value */
339 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
340 res = PyErr_SetFromErrno(PyExc_IOError);
344 /* Create the string which will hold the result */
345 res = PyBytes_FromStringAndSize(buf, nret);
347 /* Free the buffers, they are no longer needed */
355 PyMem_Free(attrname);
357 /* Return the result */
361 /* Wrapper for getxattr */
362 static char __get_all_doc__[] =
363 "Get all the extended attributes of an item.\n"
365 "This function performs a bulk-get of all extended attribute names\n"
366 "and the corresponding value.\n"
368 " >>> xattr.get_all('/path/to/file')\n"
369 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
370 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
371 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
372 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
374 "@param item: the item to query; either a string representing the\n"
375 " filename, or a file-like object, or a file descriptor\n"
376 "@keyword namespace: an optional namespace for filtering the\n"
377 " attributes; for example, querying all user attributes can be\n"
378 " accomplished by passing namespace=L{NS_USER}\n"
379 "@type namespace: string\n"
380 "@keyword nofollow: if passed and true, if the target file is a\n"
381 " symbolic link, the attributes for the link itself will be\n"
382 " returned, instead of the attributes of the target\n"
383 "@type nofollow: boolean\n"
384 "@return: list of tuples (name, value); note that if a namespace\n"
385 " argument was passed, it (and the separator) will be stripped from\n"
386 " the names returned\n"
388 "@raise EnvironmentError: caused by any system errors\n"
389 "@note: Since reading the whole attribute list is not an atomic\n"
390 " operation, it might be possible that attributes are added\n"
391 " or removed between the initial query and the actual reading\n"
392 " of the attributes; the returned list will contain only the\n"
393 " attributes that were present at the initial listing of the\n"
394 " attribute names and that were still present when the read\n"
395 " attempt for the value is made.\n"
400 get_all(PyObject *self, PyObject *args, PyObject *keywds)
402 PyObject *myarg, *res;
404 const char *ns = NULL;
405 char *buf_list, *buf_val;
407 ssize_t nalloc, nlist, nval;
410 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
412 /* Parse the arguments */
413 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
414 &myarg, &nofollow, &ns))
416 if(convertObj(myarg, &tgt, nofollow) < 0)
419 /* Compute first the list of attributes */
421 /* Find out the needed size of the buffer for the attribute list */
422 nalloc = _list_obj(&tgt, NULL, 0);
425 res = PyErr_SetFromErrno(PyExc_IOError);
429 /* Try to allocate the memory, using Python's allocator */
430 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
431 res = PyErr_NoMemory();
435 /* Now retrieve the list of attributes */
436 nlist = _list_obj(&tgt, buf_list, nalloc);
439 res = PyErr_SetFromErrno(PyExc_IOError);
443 /* Create the list which will hold the result */
444 mylist = PyList_New(0);
450 nalloc = ESTIMATE_ATTR_SIZE;
451 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
453 res = PyErr_NoMemory();
457 /* Create and insert the attributes as strings in the list */
458 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
463 if((name=matches_ns(ns, s))==NULL)
465 /* Now retrieve the attribute value */
468 nval = _get_obj(&tgt, s, buf_val, nalloc);
471 if(errno == ERANGE) {
472 nval = _get_obj(&tgt, s, NULL, 0);
473 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) {
474 res = PyErr_NoMemory();
480 } else if(errno == ENODATA || errno == ENOATTR) {
481 /* this attribute has gone away since we queried
482 the attribute list */
486 /* else we're dealing with a different error, which we
487 don't know how to handle nicely, so we abort */
489 res = PyErr_SetFromErrno(PyExc_IOError);
497 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
499 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
501 if (my_tuple == NULL) {
506 PyList_Append(mylist, my_tuple);
510 /* Successful exit */
517 PyMem_Free(buf_list);
522 /* Return the result */
527 static char __pysetxattr_doc__[] =
528 "Set the value of a given extended attribute (deprecated).\n"
530 "Be careful in case you want to set attributes on symbolic\n"
531 "links, you have to use all the 5 parameters; use 0 for the \n"
532 "flags value if you want the default behaviour (create or "
536 " - a string representing a file-name, or a file-like object,\n"
537 " or a file descriptor; this represents the file on \n"
539 " - a string, representing the attribute whose value to set;\n"
540 " usually in form of system.posix_acl or user.mime_type\n"
541 " - a string, possibly with embedded NULLs; note that there\n"
542 " are restrictions regarding the size of the value, for\n"
543 " example, for ext2/ext3, maximum size is the block size\n"
544 " - (optional) flags; if 0 or omitted the attribute will be \n"
545 " created or replaced; if XATTR_CREATE, the attribute \n"
546 " will be created, giving an error if it already exists;\n"
547 " of XATTR_REPLACE, the attribute will be replaced,\n"
548 " giving an error if it doesn't exists;\n"
549 " - (optional) a boolean value (defaults to false), which, if\n"
550 " the file name given is a symbolic link, makes the\n"
551 " function operate on the symbolic link itself instead\n"
553 "@deprecated: since version 0.4, this function has been deprecated\n"
554 " by the L{set} function\n"
557 /* Wrapper for setxattr */
559 pysetxattr(PyObject *self, PyObject *args)
561 PyObject *myarg, *res;
563 char *attrname = NULL;
570 /* Parse the arguments */
571 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
572 NULL, &buf, &bufsize, &flags, &nofollow))
574 if(convertObj(myarg, &tgt, nofollow) < 0) {
579 /* Set the attribute's value */
580 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
585 res = PyErr_SetFromErrno(PyExc_IOError);
593 PyMem_Free(attrname);
596 /* Return the result */
600 static char __set_doc__[] =
601 "Set the value of a given extended attribute.\n"
604 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
605 " >>> xattr.set('/path/to/file', 'comment', 'test',"
606 " namespace=xattr.NS_USER)\n"
608 "@param item: the item to query; either a string representing the\n"
609 " filename, or a file-like object, or a file descriptor\n"
610 "@param name: the attribute whose value to set; usually in form of\n"
611 " system.posix_acl or user.mime_type\n"
612 "@type name: string\n"
613 "@param value: a string, possibly with embedded NULLs; note that there\n"
614 " are restrictions regarding the size of the value, for\n"
615 " example, for ext2/ext3, maximum size is the block size\n"
616 "@type value: string\n"
617 "@param flags: if 0 or ommited the attribute will be\n"
618 " created or replaced; if L{XATTR_CREATE}, the attribute\n"
619 " will be created, giving an error if it already exists;\n"
620 " if L{XATTR_REPLACE}, the attribute will be replaced,\n"
621 " giving an error if it doesn't exists;\n"
622 "@type flags: integer\n"
623 "@param nofollow: if given and True, and the function is passed a\n"
624 " filename that points to a symlink, the function will act on the\n"
625 " symlink itself instead of its target\n"
626 "@type nofollow: boolean\n"
627 "@param namespace: if given, the attribute must not contain the\n"
628 " namespace itself, but instead the namespace will be taken from\n"
630 "@type namespace: string\n"
632 "@raise EnvironmentError: caused by any system errors\n"
636 /* Wrapper for setxattr */
638 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
640 PyObject *myarg, *res;
642 char *attrname = NULL;
648 const char *ns = NULL;
650 const char *full_name;
651 static char *kwlist[] = {"item", "name", "value", "flags",
652 "nofollow", "namespace", NULL};
654 /* Parse the arguments */
655 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
656 kwlist, &myarg, NULL, &attrname, NULL,
657 &buf, &bufsize, &flags, &nofollow, &ns))
659 if(convertObj(myarg, &tgt, nofollow) < 0) {
664 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
669 /* Set the attribute's value */
670 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
677 res = PyErr_SetFromErrno(PyExc_IOError);
685 PyMem_Free(attrname);
688 /* Return the result */
693 static char __pyremovexattr_doc__[] =
694 "Remove an attribute from a file (deprecated).\n"
697 " - a string representing a file-name, or a file-like object,\n"
698 " or a file descriptor; this represents the file on \n"
700 " - a string, representing the attribute to be removed;\n"
701 " usually in form of system.posix_acl or user.mime_type\n"
702 " - (optional) a boolean value (defaults to false), which, if\n"
703 " the file name given is a symbolic link, makes the\n"
704 " function operate on the symbolic link itself instead\n"
706 "@deprecated: since version 0.4, this function has been deprecated\n"
711 /* Wrapper for removexattr */
713 pyremovexattr(PyObject *self, PyObject *args)
715 PyObject *myarg, *res;
717 char *attrname = NULL;
721 /* Parse the arguments */
722 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
725 if(convertObj(myarg, &tgt, nofollow) < 0) {
730 /* Remove the attribute */
731 nret = _remove_obj(&tgt, attrname);
736 res = PyErr_SetFromErrno(PyExc_IOError);
744 PyMem_Free(attrname);
746 /* Return the result */
750 static char __remove_doc__[] =
751 "Remove an attribute from a file.\n"
754 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
756 "@param item: the item to query; either a string representing the\n"
757 " filename, or a file-like object, or a file descriptor\n"
758 "@param name: the attribute whose value to set; usually in form of\n"
759 " system.posix_acl or user.mime_type\n"
760 "@type name: string\n"
761 "@param nofollow: if given and True, and the function is passed a\n"
762 " filename that points to a symlink, the function will act on the\n"
763 " symlink itself instead of its target\n"
764 "@type nofollow: boolean\n"
765 "@param namespace: if given, the attribute must not contain the\n"
766 " namespace itself, but instead the namespace will be taken from\n"
768 "@type namespace: string\n"
771 "@raise EnvironmentError: caused by any system errors\n"
774 /* Wrapper for removexattr */
776 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
778 PyObject *myarg, *res;
780 char *attrname = NULL, *name_buf;
781 const char *ns = NULL;
782 const char *full_name;
785 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
787 /* Parse the arguments */
788 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
789 &myarg, NULL, &attrname, &nofollow, &ns))
792 if(convertObj(myarg, &tgt, nofollow) < 0) {
797 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
802 /* Remove the attribute */
803 nret = _remove_obj(&tgt, full_name);
805 PyMem_Free(name_buf);
810 res = PyErr_SetFromErrno(PyExc_IOError);
818 PyMem_Free(attrname);
820 /* Return the result */
824 static char __pylistxattr_doc__[] =
825 "Return the list of attribute names for a file (deprecated).\n"
828 " - a string representing filename, or a file-like object,\n"
829 " or a file descriptor; this represents the file to \n"
831 " - (optional) a boolean value (defaults to false), which, if\n"
832 " the file name given is a symbolic link, makes the\n"
833 " function operate on the symbolic link itself instead\n"
835 "@deprecated: since version 0.4, this function has been deprecated\n"
840 /* Wrapper for listxattr */
842 pylistxattr(PyObject *self, PyObject *args)
846 ssize_t nalloc, nret;
853 /* Parse the arguments */
854 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
856 if(convertObj(myarg, &tgt, nofollow) < 0)
859 /* Find out the needed size of the buffer */
860 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
861 mylist = PyErr_SetFromErrno(PyExc_IOError);
865 /* Try to allocate the memory, using Python's allocator */
866 if((buf = PyMem_Malloc(nalloc)) == NULL) {
867 mylist = PyErr_NoMemory();
871 /* Now retrieve the list of attributes */
872 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
873 mylist = PyErr_SetFromErrno(PyExc_IOError);
877 /* Compute the number of attributes in the list */
878 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
882 /* Create the list which will hold the result */
883 mylist = PyList_New(nattrs);
887 /* Create and insert the attributes as strings in the list */
888 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
889 PyObject *item = PyBytes_FromString(s);
895 PyList_SET_ITEM(mylist, nattrs, item);
900 /* Free the buffer, now it is no longer needed */
906 /* Return the result */
910 static char __list_doc__[] =
911 "Return the list of attribute names for a file.\n"
914 " >>> xattr.list('/path/to/file')\n"
915 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
916 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
917 " ['test', 'comment']\n"
919 "@param item: the item to query; either a string representing the\n"
920 " filename, or a file-like object, or a file descriptor\n"
921 "@param nofollow: if given and True, and the function is passed a\n"
922 " filename that points to a symlink, the function will act on the\n"
923 " symlink itself instead of its target\n"
924 "@type nofollow: boolean\n"
925 "@param namespace: if given, the attribute must not contain the\n"
926 " namespace itself, but instead the namespace will be taken from\n"
928 "@type namespace: string\n"
929 "@return: list of strings; note that if a namespace argument was\n"
930 " passed, it (and the separator) will be stripped from the names\n"
933 "@raise EnvironmentError: caused by any system errors\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(convertObj(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 "Interface to extended filesystem attributes.\n"
1037 "This module gives access to the extended attributes present\n"
1038 "in some operating systems/filesystems. You can list attributes,\n"
1039 "get, set and remove them.\n"
1041 "The module exposes two sets of functions:\n"
1042 " - the 'old' L{listxattr}, L{getxattr}, L{setxattr}, L{removexattr}\n"
1043 " functions which are deprecated since version 0.4\n"
1044 " - the new L{list}, L{get}, L{get_all}, L{set}, L{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 the xattr\n"
1061 "library will be reported by raising a L{EnvironmentError}; under Linux,\n"
1062 "the following C{errno} values are used:\n"
1063 " - C{ENOATTR} and C{ENODATA} mean that the attribute name is invalid\n"
1064 " - C{ENOTSUP} and C{EOPNOTSUPP} mean that the filesystem does not\n"
1065 " support extended attributes, or that the namespace is invalid\n"
1066 " - C{E2BIG} mean that the attribute value is too big\n"
1067 " - C{ERANGE} mean that the attribute name is too big (it might also\n"
1068 " mean an error in the xattr module itself)\n"
1069 " - C{ENOSPC} and C{EDQUOT} are documented as meaning out of disk space\n"
1070 " or out of disk space because of quota limits\n"
1072 "@group Deprecated API: *xattr\n"
1073 "@group Namespace constants: NS_*\n"
1074 "@group set function flags: XATTR_CREATE, XATTR_REPLACE\n"
1075 "@sort: list, get, get_all, set, remove, listxattr, getxattr, setxattr\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__", "epytext 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);