2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008 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 /** Converts from a string, file or int argument to what we need. */
67 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) {
70 if(PyBytes_Check(myobj)) {
71 tgt->type = nofollow ? T_LINK : T_PATH;
72 tgt->name = PyBytes_AS_STRING(myobj);
73 } else if(PyUnicode_Check(myobj)) {
74 tgt->type = nofollow ? T_LINK : T_PATH;
76 PyUnicode_AsEncodedString(myobj,
77 Py_FileSystemDefaultEncoding, "strict");
80 tgt->name = PyBytes_AS_STRING(tgt->tmp);
81 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
85 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
91 /* Combine a namespace string and an attribute name into a
92 fully-qualified name */
93 static const char* merge_ns(const char *ns, const char *name, char **buf) {
96 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
97 if((*buf = PyMem_Malloc(new_size)) == NULL) {
101 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
102 if(cnt > new_size || cnt < 0) {
103 PyErr_SetString(PyExc_ValueError,
104 "can't format the attribute name");
115 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
116 if(tgt->type == T_FD)
117 return flistxattr(tgt->fd, list, size);
118 else if (tgt->type == T_LINK)
119 return llistxattr(tgt->name, list, size);
121 return listxattr(tgt->name, list, size);
124 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
126 if(tgt->type == T_FD)
127 return fgetxattr(tgt->fd, name, value, size);
128 else if (tgt->type == T_LINK)
129 return lgetxattr(tgt->name, name, value, size);
131 return getxattr(tgt->name, name, value, size);
134 static int _set_obj(target_t *tgt, const char *name,
135 const void *value, size_t size, int flags) {
136 if(tgt->type == T_FD)
137 return fsetxattr(tgt->fd, name, value, size, flags);
138 else if (tgt->type == T_LINK)
139 return lsetxattr(tgt->name, name, value, size, flags);
141 return setxattr(tgt->name, name, value, size, flags);
144 static int _remove_obj(target_t *tgt, const char *name) {
145 if(tgt->type == T_FD)
146 return fremovexattr(tgt->fd, name);
147 else if (tgt->type == T_LINK)
148 return lremovexattr(tgt->name, name);
150 return removexattr(tgt->name, name);
154 Checks if an attribute name matches an optional namespace.
156 If the namespace is NULL, it will return the name itself. If the
157 namespace is non-NULL and the name matches, it will return a
158 pointer to the offset in the name after the namespace and the
159 separator. If however the name doesn't match the namespace, it will
162 const char *matches_ns(const char *ns, const char *name) {
166 ns_size = strlen(ns);
168 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
169 name[ns_size] == '.')
170 return name + ns_size + 1;
174 /* Wrapper for getxattr */
175 static char __pygetxattr_doc__[] =
176 "Get the value of a given extended attribute (deprecated).\n"
179 " - a string representing filename, or a file-like object,\n"
180 " or a file descriptor; this represents the file on \n"
182 " - a string, representing the attribute whose value to retrieve;\n"
183 " usually in form of system.posix_acl or user.mime_type\n"
184 " - (optional) a boolean value (defaults to false), which, if\n"
185 " the file name given is a symbolic link, makes the\n"
186 " function operate on the symbolic link itself instead\n"
188 "@deprecated: since version 0.4, this function has been deprecated\n"
189 " by the L{get} function\n"
193 pygetxattr(PyObject *self, PyObject *args)
198 char *attrname = NULL;
200 ssize_t nalloc, nret;
203 /* Parse the arguments */
204 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
206 if(!convertObj(myarg, &tgt, nofollow)) {
211 /* Find out the needed size of the buffer */
212 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
213 res = PyErr_SetFromErrno(PyExc_IOError);
217 /* Try to allocate the memory, using Python's allocator */
218 if((buf = PyMem_Malloc(nalloc)) == NULL) {
219 res = PyErr_NoMemory();
223 /* Now retrieve the attribute value */
224 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
225 res = PyErr_SetFromErrno(PyExc_IOError);
229 /* Create the string which will hold the result */
230 res = PyBytes_FromStringAndSize(buf, nret);
233 /* Free the buffer, now it is no longer needed */
238 PyMem_Free(attrname);
240 /* Return the result */
244 /* Wrapper for getxattr */
245 static char __get_doc__[] =
246 "Get the value of a given extended attribute.\n"
249 " >>> xattr.get('/path/to/file', 'user.comment')\n"
251 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
254 "@param item: the item to query; either a string representing the\n"
255 " filename, or a file-like object, or a file descriptor\n"
256 "@param name: the attribute whose value to set; usually in form of\n"
257 " system.posix_acl or user.mime_type\n"
258 "@type name: string\n"
259 "@param nofollow: if given and True, and the function is passed a\n"
260 " filename that points to a symlink, the function will act on the\n"
261 " symlink itself instead of its target\n"
262 "@type nofollow: boolean\n"
263 "@param namespace: if given, the attribute must not contain the\n"
264 " namespace itself, but instead the namespace will be taken from\n"
266 "@type namespace: string\n"
267 "@return: the value of the extended attribute (can contain NULLs)\n"
269 "@raise EnvironmentError: caused by any system errors\n"
274 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
279 char *attrname = NULL, *namebuf;
280 const char *fullname;
283 ssize_t nalloc, nret;
285 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
287 /* Parse the arguments */
288 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist,
289 &myarg, NULL, &attrname, &nofollow, &ns))
291 if(!convertObj(myarg, &tgt, nofollow)) {
296 fullname = merge_ns(ns, attrname, &namebuf);
298 /* Find out the needed size of the buffer */
299 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
300 res = PyErr_SetFromErrno(PyExc_IOError);
304 /* Try to allocate the memory, using Python's allocator */
305 if((buf = PyMem_Malloc(nalloc)) == NULL) {
306 res = PyErr_NoMemory();
310 /* Now retrieve the attribute value */
311 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
312 res = PyErr_SetFromErrno(PyExc_IOError);
316 /* Create the string which will hold the result */
317 res = PyBytes_FromStringAndSize(buf, nret);
319 /* Free the buffers, they are no longer needed */
327 PyMem_Free(attrname);
329 /* Return the result */
333 /* Wrapper for getxattr */
334 static char __get_all_doc__[] =
335 "Get all the extended attributes of an item.\n"
337 "This function performs a bulk-get of all extended attribute names\n"
338 "and the corresponding value.\n"
340 " >>> xattr.get_all('/path/to/file')\n"
341 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
342 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
343 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
344 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
346 "@param item: the item to query; either a string representing the\n"
347 " filename, or a file-like object, or a file descriptor\n"
348 "@keyword namespace: an optional namespace for filtering the\n"
349 " attributes; for example, querying all user attributes can be\n"
350 " accomplished by passing namespace=L{NS_USER}\n"
351 "@type namespace: string\n"
352 "@keyword nofollow: if passed and true, if the target file is a\n"
353 " symbolic link, the attributes for the link itself will be\n"
354 " returned, instead of the attributes of the target\n"
355 "@type nofollow: boolean\n"
356 "@return: list of tuples (name, value); note that if a namespace\n"
357 " argument was passed, it (and the separator) will be stripped from\n"
358 " the names returned\n"
360 "@raise EnvironmentError: caused by any system errors\n"
361 "@note: Since reading the whole attribute list is not an atomic\n"
362 " operation, it might be possible that attributes are added\n"
363 " or removed between the initial query and the actual reading\n"
364 " of the attributes; the returned list will contain only the\n"
365 " attributes that were present at the initial listing of the\n"
366 " attribute names and that were still present when the read\n"
367 " attempt for the value is made.\n"
372 get_all(PyObject *self, PyObject *args, PyObject *keywds)
374 PyObject *myarg, *res;
377 char *buf_list, *buf_val;
379 ssize_t nalloc, nlist, nval;
382 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
384 /* Parse the arguments */
385 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
386 &myarg, &dolink, &ns))
388 if(!convertObj(myarg, &tgt, dolink))
391 /* Compute first the list of attributes */
393 /* Find out the needed size of the buffer for the attribute list */
394 nalloc = _list_obj(&tgt, NULL, 0);
397 res = PyErr_SetFromErrno(PyExc_IOError);
401 /* Try to allocate the memory, using Python's allocator */
402 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
403 res = PyErr_NoMemory();
407 /* Now retrieve the list of attributes */
408 nlist = _list_obj(&tgt, buf_list, nalloc);
411 res = PyErr_SetFromErrno(PyExc_IOError);
415 /* Create the list which will hold the result */
416 mylist = PyList_New(0);
417 nalloc = ESTIMATE_ATTR_SIZE;
418 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
420 res = PyErr_NoMemory();
424 /* Create and insert the attributes as strings in the list */
425 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
430 if((name=matches_ns(ns, s))==NULL)
432 /* Now retrieve the attribute value */
435 nval = _get_obj(&tgt, s, buf_val, nalloc);
438 if(errno == ERANGE) {
439 nval = _get_obj(&tgt, s, NULL, 0);
440 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) {
447 } else if(errno == ENODATA || errno == ENOATTR) {
448 /* this attribute has gone away since we queried
449 the attribute list */
453 res = PyErr_SetFromErrno(PyExc_IOError);
461 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
463 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
466 PyList_Append(mylist, my_tuple);
470 /* Successfull exit */
477 PyMem_Free(buf_list);
482 /* Return the result */
487 static char __pysetxattr_doc__[] =
488 "Set the value of a given extended attribute (deprecated).\n"
490 "Be carefull in case you want to set attributes on symbolic\n"
491 "links, you have to use all the 5 parameters; use 0 for the \n"
492 "flags value if you want the default behavior (create or "
496 " - a string representing filename, or a file-like object,\n"
497 " or a file descriptor; this represents the file on \n"
499 " - a string, representing the attribute whose value to set;\n"
500 " usually in form of system.posix_acl or user.mime_type\n"
501 " - a string, possibly with embedded NULLs; note that there\n"
502 " are restrictions regarding the size of the value, for\n"
503 " example, for ext2/ext3, maximum size is the block size\n"
504 " - (optional) flags; if 0 or ommited the attribute will be \n"
505 " created or replaced; if XATTR_CREATE, the attribute \n"
506 " will be created, giving an error if it already exists;\n"
507 " of XATTR_REPLACE, the attribute will be replaced,\n"
508 " giving an error if it doesn't exists;\n"
509 " - (optional) a boolean value (defaults to false), which, if\n"
510 " the file name given is a symbolic link, makes the\n"
511 " function operate on the symbolic link itself instead\n"
513 "@deprecated: since version 0.4, this function has been deprecated\n"
514 " by the L{set} function\n"
517 /* Wrapper for setxattr */
519 pysetxattr(PyObject *self, PyObject *args)
521 PyObject *myarg, *res;
523 char *attrname = NULL;
530 /* Parse the arguments */
531 if (!PyArg_ParseTuple(args, "Oetet#|bi", &myarg, NULL, &attrname,
532 NULL, &buf, &bufsize, &flags, &nofollow))
534 if(!convertObj(myarg, &tgt, nofollow)) {
539 /* Set the attribute's value */
540 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
545 res = PyErr_SetFromErrno(PyExc_IOError);
553 PyMem_Free(attrname);
556 /* Return the result */
560 static char __set_doc__[] =
561 "Set the value of a given extended attribute.\n"
564 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
565 " >>> xattr.set('/path/to/file', 'comment', 'test',"
566 " namespace=xattr.NS_USER)\n"
568 "@param item: the item to query; either a string representing the\n"
569 " filename, or a file-like object, or a file descriptor\n"
570 "@param name: the attribute whose value to set; usually in form of\n"
571 " system.posix_acl or user.mime_type\n"
572 "@type name: string\n"
573 "@param value: a string, possibly with embedded NULLs; note that there\n"
574 " are restrictions regarding the size of the value, for\n"
575 " example, for ext2/ext3, maximum size is the block size\n"
576 "@type value: string\n"
577 "@param flags: if 0 or ommited the attribute will be\n"
578 " created or replaced; if L{XATTR_CREATE}, the attribute\n"
579 " will be created, giving an error if it already exists;\n"
580 " if L{XATTR_REPLACE}, the attribute will be replaced,\n"
581 " giving an error if it doesn't exists;\n"
582 "@type flags: integer\n"
583 "@param nofollow: if given and True, and the function is passed a\n"
584 " filename that points to a symlink, the function will act on the\n"
585 " symlink itself instead of its target\n"
586 "@type nofollow: boolean\n"
587 "@param namespace: if given, the attribute must not contain the\n"
588 " namespace itself, but instead the namespace will be taken from\n"
590 "@type namespace: string\n"
592 "@raise EnvironmentError: caused by any system errors\n"
596 /* Wrapper for setxattr */
598 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
600 PyObject *myarg, *res;
602 char *attrname = NULL;
610 const char *full_name;
611 static char *kwlist[] = {"item", "name", "value", "flags",
612 "nofollow", "namespace", NULL};
614 /* Parse the arguments */
615 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|iiz", kwlist,
616 &myarg, NULL, &attrname, NULL,
617 &buf, &bufsize, &flags, &nofollow, &ns))
619 if(!convertObj(myarg, &tgt, nofollow)) {
624 full_name = merge_ns(ns, attrname, &newname);
626 /* Set the attribute's value */
627 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
635 res = PyErr_SetFromErrno(PyExc_IOError);
643 PyMem_Free(attrname);
646 /* Return the result */
651 static char __pyremovexattr_doc__[] =
652 "Remove an attribute from a file (deprecated).\n"
655 " - a string representing filename, or a file-like object,\n"
656 " or a file descriptor; this represents the file on \n"
658 " - a string, representing the attribute to be removed;\n"
659 " usually in form of system.posix_acl or user.mime_type\n"
660 " - (optional) a boolean value (defaults to false), which, if\n"
661 " the file name given is a symbolic link, makes the\n"
662 " function operate on the symbolic link itself instead\n"
664 "@deprecated: since version 0.4, this function has been deprecated\n"
669 /* Wrapper for removexattr */
671 pyremovexattr(PyObject *self, PyObject *args)
673 PyObject *myarg, *res;
675 char *attrname = NULL;
679 /* Parse the arguments */
680 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
683 if(!convertObj(myarg, &tgt, nofollow)) {
688 /* Remove the attribute */
689 nret = _remove_obj(&tgt, attrname);
694 res = PyErr_SetFromErrno(PyExc_IOError);
702 PyMem_Free(attrname);
704 /* Return the result */
708 static char __remove_doc__[] =
709 "Remove an attribute from a file.\n"
712 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
714 "@param item: the item to query; either a string representing the\n"
715 " filename, or a file-like object, or a file descriptor\n"
716 "@param name: the attribute whose value to set; usually in form of\n"
717 " system.posix_acl or user.mime_type\n"
718 "@type name: string\n"
719 "@param nofollow: if given and True, and the function is passed a\n"
720 " filename that points to a symlink, the function will act on the\n"
721 " symlink itself instead of its target\n"
722 "@type nofollow: boolean\n"
723 "@param namespace: if given, the attribute must not contain the\n"
724 " namespace itself, but instead the namespace will be taken from\n"
726 "@type namespace: string\n"
729 "@raise EnvironmentError: caused by any system errors\n"
732 /* Wrapper for removexattr */
734 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
736 PyObject *myarg, *res;
738 char *attrname = NULL, *name_buf;
740 const char *full_name;
743 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
745 /* Parse the arguments */
746 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist,
747 &myarg, NULL, &attrname, &nofollow, &ns))
750 if(!convertObj(myarg, &tgt, nofollow)) {
755 full_name = merge_ns(ns, attrname, &name_buf);
756 if(full_name == NULL) {
761 /* Remove the attribute */
762 nret = _remove_obj(&tgt, full_name);
764 PyMem_Free(name_buf);
769 res = PyErr_SetFromErrno(PyExc_IOError);
777 PyMem_Free(attrname);
779 /* Return the result */
783 static char __pylistxattr_doc__[] =
784 "Return the list of attribute names for a file (deprecated).\n"
787 " - a string representing filename, or a file-like object,\n"
788 " or a file descriptor; this represents the file to \n"
790 " - (optional) a boolean value (defaults to false), which, if\n"
791 " the file name given is a symbolic link, makes the\n"
792 " function operate on the symbolic link itself instead\n"
794 "@deprecated: since version 0.4, this function has been deprecated\n"
799 /* Wrapper for listxattr */
801 pylistxattr(PyObject *self, PyObject *args)
805 ssize_t nalloc, nret;
812 /* Parse the arguments */
813 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
815 if(!convertObj(myarg, &tgt, nofollow))
818 /* Find out the needed size of the buffer */
819 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
820 mylist = PyErr_SetFromErrno(PyExc_IOError);
824 /* Try to allocate the memory, using Python's allocator */
825 if((buf = PyMem_Malloc(nalloc)) == NULL) {
826 mylist = PyErr_NoMemory();
830 /* Now retrieve the list of attributes */
831 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
832 mylist = PyErr_SetFromErrno(PyExc_IOError);
836 /* Compute the number of attributes in the list */
837 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
841 /* Create the list which will hold the result */
842 mylist = PyList_New(nattrs);
844 /* Create and insert the attributes as strings in the list */
845 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
846 PyList_SET_ITEM(mylist, nattrs, PyBytes_FromString(s));
851 /* Free the buffer, now it is no longer needed */
857 /* Return the result */
861 static char __list_doc__[] =
862 "Return the list of attribute names for a file.\n"
865 " >>> xattr.list('/path/to/file')\n"
866 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
867 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
868 " ['test', 'comment']\n"
870 "@param item: the item to query; either a string representing the\n"
871 " filename, or a file-like object, or a file descriptor\n"
872 "@param nofollow: if given and True, and the function is passed a\n"
873 " filename that points to a symlink, the function will act on the\n"
874 " symlink itself instead of its target\n"
875 "@type nofollow: boolean\n"
876 "@param namespace: if given, the attribute must not contain the\n"
877 " namespace itself, but instead the namespace will be taken from\n"
879 "@type namespace: string\n"
880 "@return: list of strings; note that if a namespace argument was\n"
881 " passed, it (and the separator) will be stripped from the names\n"
884 "@raise EnvironmentError: caused by any system errors\n"
888 /* Wrapper for listxattr */
890 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
894 ssize_t nalloc, nret;
901 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
903 /* Parse the arguments */
904 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iet", kwlist,
905 &myarg, &nofollow, NULL, &ns))
907 if(!convertObj(myarg, &tgt, nofollow)) {
912 /* Find out the needed size of the buffer */
913 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
914 res = PyErr_SetFromErrno(PyExc_IOError);
918 /* Try to allocate the memory, using Python's allocator */
919 if((buf = PyMem_Malloc(nalloc)) == NULL) {
920 res = PyErr_NoMemory();
924 /* Now retrieve the list of attributes */
925 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
926 res = PyErr_SetFromErrno(PyExc_IOError);
930 /* Compute the number of attributes in the list */
931 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
932 if(matches_ns(ns, s) != NULL)
935 /* Create the list which will hold the result */
936 res = PyList_New(nattrs);
938 /* Create and insert the attributes as strings in the list */
939 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
940 const char *name = matches_ns(ns, s);
942 PyList_SET_ITEM(res, nattrs, PyBytes_FromString(name));
948 /* Free the buffer, now it is no longer needed */
956 /* Return the result */
960 static PyMethodDef xattr_methods[] = {
961 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
962 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
964 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
966 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
967 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
969 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
970 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
972 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
973 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
975 {NULL, NULL, 0, NULL} /* Sentinel */
978 static char __xattr_doc__[] = \
979 "Interface to extended filesystem attributes.\n"
981 "This module gives access to the extended attributes present\n"
982 "in some operating systems/filesystems. You can list attributes,\n"
983 "get, set and remove them.\n"
985 "The module exposes two sets of functions:\n"
986 " - the 'old' L{listxattr}, L{getxattr}, L{setxattr}, L{removexattr}\n"
987 " functions which are deprecated since version 0.4\n"
988 " - the new L{list}, L{get}, L{get_all}, L{set}, L{remove} functions\n"
989 " which expose a namespace-aware API and simplify a bit the calling\n"
990 " model by using keyword arguments\n"
993 " >>> import xattr\n"
994 " >>> xattr.listxattr(\"file.txt\")\n"
995 " ['user.mime_type']\n"
996 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
998 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
999 "\"Simple text file\")\n"
1000 " >>> xattr.listxattr(\"file.txt\")\n"
1001 " ['user.mime_type', 'user.comment']\n"
1002 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1004 "@note: Most or all errors reported by the system while using the xattr\n"
1005 "library will be reported by raising a L{EnvironmentError}; under Linux,\n"
1006 "the following C{errno} values are used:\n"
1007 " - C{ENOATTR} and C{ENODATA} mean that the attribute name is invalid\n"
1008 " - C{ENOTSUP} and C{EOPNOTSUPP} mean that the filesystem does not\n"
1009 " support extended attributes, or that the namespace is invalid\n"
1010 " - C{E2BIG} mean that the attribute value is too big\n"
1011 " - C{ERANGE} mean that the attribute name is too big (it might also\n"
1012 " mean an error in the xattr module itself)\n"
1013 " - C{ENOSPC} and C{EDQUOT} are documented as meaning out of disk space\n"
1014 " or out of disk space because of quota limits\n"
1016 "@group Deprecated API: *xattr\n"
1017 "@group Namespace constants: NS_*\n"
1018 "@group set function flags: XATTR_CREATE, XATTR_REPLACE\n"
1019 "@sort: list, get, get_all, set, remove, listxattr, getxattr, setxattr\n"
1025 static struct PyModuleDef xattrmodule = {
1026 PyModuleDef_HEAD_INIT,
1033 #define INITERROR return NULL
1039 #define INITERROR return
1045 PyObject *m = PyModule_Create(&xattrmodule);
1047 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1052 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1053 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1054 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1055 PyModule_AddStringConstant(m, "__license__",
1056 "GNU Lesser General Public License (LGPL)");
1057 PyModule_AddStringConstant(m, "__docformat__", "epytext en");
1059 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1060 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1062 /* namespace constants */
1063 PyModule_AddObject(m, "NS_SECURITY", PyBytes_FromString("security"));
1064 PyModule_AddObject(m, "NS_SYSTEM", PyBytes_FromString("system"));
1065 PyModule_AddObject(m, "NS_TRUSTED", PyBytes_FromString("trusted"));
1066 PyModule_AddObject(m, "NS_USER", PyBytes_FromString("user"));