2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008, 2012, 2013 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 "s"
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
47 ":param item: a string representing a file-name, or a file-like\n" \
48 " object, or a file descriptor; this represents the file on \n" \
51 #define NOFOLLOW_DOC \
52 ":param nofollow: if true and if\n" \
53 " the file name given is a symbolic link, the\n" \
54 " function will operate on the symbolic link itself instead\n" \
55 " of its target; defaults to false\n" \
56 ":type nofollow: boolean, optional\n" \
59 ":param namespace: if given, the attribute must not contain the\n" \
60 " namespace, but instead it will be taken from this parameter\n" \
61 ":type namespace: bytes\n"
63 #define NAME_GET_DOC \
64 ":param string name: the attribute whose value to retrieve;\n" \
65 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
67 #define NAME_SET_DOC \
68 ":param string name: the attribute whose value to set;\n" \
69 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
71 #define NAME_REMOVE_DOC \
72 ":param string name: the attribute to remove;\n" \
73 " usually in the form of ``system.posix_acl`` or \n" \
74 " ``user.mime_type``\n"
77 ":param string value: possibly with embedded NULLs; note that there\n" \
78 " are restrictions regarding the size of the value, for\n" \
79 " example, for ext2/ext3, maximum size is the block size\n" \
82 ":param flags: if 0 or omitted the attribute will be\n" \
83 " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" \
84 " will be created, giving an error if it already exists;\n" \
85 " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" \
86 " giving an error if it doesn't exist;\n" \
87 ":type flags: integer\n"
89 #define NS_CHANGED_DOC \
90 ".. versionchanged:: 0.5.1\n" \
91 " The namespace argument, if passed, cannot be None anymore; to\n" \
92 " explicitly specify an empty namespace, pass an empty\n" \
93 " string (byte string under Python 3)."
96 /* the estimated (startup) attribute buffer size in
98 #define ESTIMATE_ATTR_SIZE 256
100 typedef enum {T_FD, T_PATH, T_LINK} target_e;
111 /* Cleans up a tgt structure */
112 static void free_tgt(target_t *tgt) {
113 if (tgt->tmp != NULL) {
118 /* Used for cpychecker: */
119 /* The checker automatically defines this preprocessor name when creating
120 the custom attribute: */
121 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
122 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
123 __attribute__((cpychecker_negative_result_sets_exception))
125 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
128 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow)
129 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
131 static int merge_ns(const char *ns, const char *name,
132 const char **result, char **buf)
133 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
136 /** Converts from a string, file or int argument to what we need.
138 * Returns -1 on failure, 0 on success.
140 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) {
143 if(PyBytes_Check(myobj)) {
144 tgt->type = nofollow ? T_LINK : T_PATH;
145 tgt->name = PyBytes_AS_STRING(myobj);
146 } else if(PyUnicode_Check(myobj)) {
147 tgt->type = nofollow ? T_LINK : T_PATH;
149 PyUnicode_AsEncodedString(myobj,
150 Py_FileSystemDefaultEncoding,
159 tgt->name = PyBytes_AS_STRING(tgt->tmp);
160 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
164 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
170 /* Combine a namespace string and an attribute name into a
171 fully-qualified name */
172 static int merge_ns(const char *ns, const char *name,
173 const char **result, char **buf) {
174 if(ns != NULL && *ns != '\0') {
176 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
177 if((*buf = PyMem_Malloc(new_size)) == NULL) {
181 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
182 if(cnt > new_size || cnt < 0) {
183 PyErr_SetString(PyExc_ValueError,
184 "can't format the attribute name");
196 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
197 if(tgt->type == T_FD)
198 return flistxattr(tgt->fd, list, size);
199 else if (tgt->type == T_LINK)
200 return llistxattr(tgt->name, list, size);
202 return listxattr(tgt->name, list, size);
205 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
207 if(tgt->type == T_FD)
208 return fgetxattr(tgt->fd, name, value, size);
209 else if (tgt->type == T_LINK)
210 return lgetxattr(tgt->name, name, value, size);
212 return getxattr(tgt->name, name, value, size);
215 static int _set_obj(target_t *tgt, const char *name,
216 const void *value, size_t size, int flags) {
217 if(tgt->type == T_FD)
218 return fsetxattr(tgt->fd, name, value, size, flags);
219 else if (tgt->type == T_LINK)
220 return lsetxattr(tgt->name, name, value, size, flags);
222 return setxattr(tgt->name, name, value, size, flags);
225 static int _remove_obj(target_t *tgt, const char *name) {
226 if(tgt->type == T_FD)
227 return fremovexattr(tgt->fd, name);
228 else if (tgt->type == T_LINK)
229 return lremovexattr(tgt->name, name);
231 return removexattr(tgt->name, name);
235 Checks if an attribute name matches an optional namespace.
237 If the namespace is NULL or an empty string, it will return the
238 name itself. If the namespace is non-NULL and the name matches, it
239 will return a pointer to the offset in the name after the namespace
240 and the separator. If however the name doesn't match the namespace,
244 const char *matches_ns(const char *ns, const char *name) {
246 if (ns == NULL || *ns == '\0')
248 ns_size = strlen(ns);
250 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
251 name[ns_size] == '.')
252 return name + ns_size + 1;
256 /* Wrapper for getxattr */
257 static char __pygetxattr_doc__[] =
258 "getxattr(item, attribute[, nofollow=False])\n"
259 "Get the value of a given extended attribute (deprecated).\n"
265 ".. deprecated:: 0.4\n"
266 " this function has been deprecated\n"
267 " by the :func:`get` function.\n"
271 pygetxattr(PyObject *self, PyObject *args)
276 char *attrname = NULL;
278 ssize_t nalloc, nret;
281 /* Parse the arguments */
282 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
284 if(convert_obj(myarg, &tgt, nofollow) < 0) {
289 /* Find out the needed size of the buffer */
290 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
291 res = PyErr_SetFromErrno(PyExc_IOError);
295 /* Try to allocate the memory, using Python's allocator */
296 if((buf = PyMem_Malloc(nalloc)) == NULL) {
297 res = PyErr_NoMemory();
301 /* Now retrieve the attribute value */
302 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
303 res = PyErr_SetFromErrno(PyExc_IOError);
307 /* Create the string which will hold the result */
308 res = PyBytes_FromStringAndSize(buf, nret);
311 /* Free the buffer, now it is no longer needed */
316 PyMem_Free(attrname);
318 /* Return the result */
322 /* Wrapper for getxattr */
323 static char __get_doc__[] =
324 "get(item, name[, nofollow=False, namespace=None])\n"
325 "Get the value of a given extended attribute.\n"
328 " >>> xattr.get('/path/to/file', 'user.comment')\n"
330 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
337 ":return: the value of the extended attribute (can contain NULLs)\n"
339 ":raises EnvironmentError: caused by any system errors\n"
341 ".. versionadded:: 0.4\n"
346 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
351 char *attrname = NULL, *namebuf;
352 const char *fullname;
354 const char *ns = NULL;
355 ssize_t nalloc, nret;
357 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
359 /* Parse the arguments */
360 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
361 &myarg, NULL, &attrname, &nofollow, &ns))
363 if(convert_obj(myarg, &tgt, nofollow) < 0) {
368 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
373 /* Find out the needed size of the buffer */
374 if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) {
375 res = PyErr_SetFromErrno(PyExc_IOError);
379 /* Try to allocate the memory, using Python's allocator */
380 if((buf = PyMem_Malloc(nalloc)) == NULL) {
381 res = PyErr_NoMemory();
385 /* Now retrieve the attribute value */
386 if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) {
387 res = PyErr_SetFromErrno(PyExc_IOError);
391 /* Create the string which will hold the result */
392 res = PyBytes_FromStringAndSize(buf, nret);
394 /* Free the buffers, they are no longer needed */
402 PyMem_Free(attrname);
404 /* Return the result */
408 /* Wrapper for getxattr */
409 static char __get_all_doc__[] =
410 "get_all(item[, nofollow=False, namespace=None])\n"
411 "Get all the extended attributes of an item.\n"
413 "This function performs a bulk-get of all extended attribute names\n"
414 "and the corresponding value.\n"
417 " >>> xattr.get_all('/path/to/file')\n"
418 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
419 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
420 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
421 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
424 ":keyword namespace: an optional namespace for filtering the\n"
425 " attributes; for example, querying all user attributes can be\n"
426 " accomplished by passing namespace=:const:`NS_USER`\n"
427 ":type namespace: string\n"
429 ":return: list of tuples (name, value); note that if a namespace\n"
430 " argument was passed, it (and the separator) will be stripped from\n"
431 " the names returned\n"
433 ":raises EnvironmentError: caused by any system errors\n"
435 ".. note:: Since reading the whole attribute list is not an atomic\n"
436 " operation, it might be possible that attributes are added\n"
437 " or removed between the initial query and the actual reading\n"
438 " of the attributes; the returned list will contain only the\n"
439 " attributes that were present at the initial listing of the\n"
440 " attribute names and that were still present when the read\n"
441 " attempt for the value is made.\n"
442 ".. versionadded:: 0.4\n"
447 get_all(PyObject *self, PyObject *args, PyObject *keywds)
449 PyObject *myarg, *res;
451 const char *ns = NULL;
452 char *buf_list, *buf_val;
454 ssize_t nalloc, nlist, nval;
457 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
459 /* Parse the arguments */
460 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
461 &myarg, &nofollow, &ns))
463 if(convert_obj(myarg, &tgt, nofollow) < 0)
466 /* Compute first the list of attributes */
468 /* Find out the needed size of the buffer for the attribute list */
469 nalloc = _list_obj(&tgt, NULL, 0);
472 res = PyErr_SetFromErrno(PyExc_IOError);
481 /* Try to allocate the memory, using Python's allocator */
482 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
483 res = PyErr_NoMemory();
487 /* Now retrieve the list of attributes */
488 nlist = _list_obj(&tgt, buf_list, nalloc);
491 res = PyErr_SetFromErrno(PyExc_IOError);
495 /* Create the list which will hold the result */
496 mylist = PyList_New(0);
502 nalloc = ESTIMATE_ATTR_SIZE;
503 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
505 res = PyErr_NoMemory();
509 /* Create and insert the attributes as strings in the list */
510 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
515 if((name=matches_ns(ns, s))==NULL)
517 /* Now retrieve the attribute value */
520 nval = _get_obj(&tgt, s, buf_val, nalloc);
523 if(errno == ERANGE) {
524 nval = _get_obj(&tgt, s, NULL, 0);
525 if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) {
526 res = PyErr_NoMemory();
532 } else if(errno == ENODATA || errno == ENOATTR) {
533 /* this attribute has gone away since we queried
534 the attribute list */
538 /* else we're dealing with a different error, which we
539 don't know how to handle nicely, so we abort */
541 res = PyErr_SetFromErrno(PyExc_IOError);
549 my_tuple = Py_BuildValue("yy#", name, buf_val, nval);
551 my_tuple = Py_BuildValue("ss#", name, buf_val, nval);
553 if (my_tuple == NULL) {
558 PyList_Append(mylist, my_tuple);
562 /* Successful exit */
569 PyMem_Free(buf_list);
574 /* Return the result */
579 static char __pysetxattr_doc__[] =
580 "setxattr(item, name, value[, flags=0, nofollow=False])\n"
581 "Set the value of a given extended attribute (deprecated).\n"
583 "Be careful in case you want to set attributes on symbolic\n"
584 "links, you have to use all the 5 parameters; use 0 for the \n"
585 "flags value if you want the default behaviour (create or "
594 ".. deprecated:: 0.4\n"
595 " this function has been deprecated\n"
596 " by the :func:`set` function.\n"
599 /* Wrapper for setxattr */
601 pysetxattr(PyObject *self, PyObject *args)
603 PyObject *myarg, *res;
605 char *attrname = NULL;
612 /* Parse the arguments */
613 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
614 NULL, &buf, &bufsize, &flags, &nofollow))
616 if(convert_obj(myarg, &tgt, nofollow) < 0) {
621 /* Set the attribute's value */
622 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
627 res = PyErr_SetFromErrno(PyExc_IOError);
635 PyMem_Free(attrname);
638 /* Return the result */
642 static char __set_doc__[] =
643 "set(item, name, value[, flags=0, namespace=None])\n"
644 "Set the value of a given extended attribute.\n"
648 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
649 " >>> xattr.set('/path/to/file', 'comment', 'test',"
650 " namespace=xattr.NS_USER)\n"
659 ":raises EnvironmentError: caused by any system errors\n"
661 ".. versionadded:: 0.4\n"
665 /* Wrapper for setxattr */
667 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
669 PyObject *myarg, *res;
671 char *attrname = NULL;
677 const char *ns = NULL;
679 const char *full_name;
680 static char *kwlist[] = {"item", "name", "value", "flags",
681 "nofollow", "namespace", NULL};
683 /* Parse the arguments */
684 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
685 kwlist, &myarg, NULL, &attrname, NULL,
686 &buf, &bufsize, &flags, &nofollow, &ns))
688 if(convert_obj(myarg, &tgt, nofollow) < 0) {
693 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
698 /* Set the attribute's value */
699 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
706 res = PyErr_SetFromErrno(PyExc_IOError);
714 PyMem_Free(attrname);
717 /* Return the result */
722 static char __pyremovexattr_doc__[] =
723 "removexattr(item, name[, nofollow])\n"
724 "Remove an attribute from a file (deprecated).\n"
730 ".. deprecated:: 0.4\n"
731 " this function has been deprecated by the :func:`remove` function.\n"
734 /* Wrapper for removexattr */
736 pyremovexattr(PyObject *self, PyObject *args)
738 PyObject *myarg, *res;
740 char *attrname = NULL;
744 /* Parse the arguments */
745 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
748 if(convert_obj(myarg, &tgt, nofollow) < 0) {
753 /* Remove the attribute */
754 nret = _remove_obj(&tgt, attrname);
759 res = PyErr_SetFromErrno(PyExc_IOError);
767 PyMem_Free(attrname);
769 /* Return the result */
773 static char __remove_doc__[] =
774 "remove(item, name[, nofollow=False, namespace=None])\n"
775 "Remove an attribute from a file.\n"
779 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
786 ":raises EnvironmentError: caused by any system errors\n"
788 ".. versionadded:: 0.4\n"
792 /* Wrapper for removexattr */
794 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
796 PyObject *myarg, *res;
798 char *attrname = NULL, *name_buf;
799 const char *ns = NULL;
800 const char *full_name;
803 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
805 /* Parse the arguments */
806 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
807 &myarg, NULL, &attrname, &nofollow, &ns))
810 if(convert_obj(myarg, &tgt, nofollow) < 0) {
815 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
820 /* Remove the attribute */
821 nret = _remove_obj(&tgt, full_name);
823 PyMem_Free(name_buf);
828 res = PyErr_SetFromErrno(PyExc_IOError);
836 PyMem_Free(attrname);
838 /* Return the result */
842 static char __pylistxattr_doc__[] =
843 "listxattr(item[, nofollow=False])\n"
844 "Return the list of attribute names for a file (deprecated).\n"
849 ".. deprecated:: 0.4\n"
850 " this function has been deprecated by the :func:`list` function.\n"
853 /* Wrapper for listxattr */
855 pylistxattr(PyObject *self, PyObject *args)
859 ssize_t nalloc, nret;
866 /* Parse the arguments */
867 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
869 if(convert_obj(myarg, &tgt, nofollow) < 0)
872 /* Find out the needed size of the buffer */
873 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
874 mylist = PyErr_SetFromErrno(PyExc_IOError);
879 mylist = PyList_New(0);
883 /* Try to allocate the memory, using Python's allocator */
884 if((buf = PyMem_Malloc(nalloc)) == NULL) {
885 mylist = PyErr_NoMemory();
889 /* Now retrieve the list of attributes */
890 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
891 mylist = PyErr_SetFromErrno(PyExc_IOError);
895 /* Compute the number of attributes in the list */
896 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
900 /* Create the list which will hold the result */
901 mylist = PyList_New(nattrs);
905 /* Create and insert the attributes as strings in the list */
906 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
907 PyObject *item = PyBytes_FromString(s);
913 PyList_SET_ITEM(mylist, nattrs, item);
918 /* Free the buffer, now it is no longer needed */
924 /* Return the result */
928 static char __list_doc__[] =
929 "list(item[, nofollow=False, namespace=None])\n"
930 "Return the list of attribute names for a file.\n"
934 " >>> xattr.list('/path/to/file')\n"
935 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
936 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
937 " ['test', 'comment']\n"
942 ":returns: the list of attributes; note that if a namespace \n"
943 " argument was passed, it (and the separator) will be stripped\n"
947 ":raises EnvironmentError: caused by any system errors\n"
949 ".. versionadded:: 0.4\n"
953 /* Wrapper for listxattr */
955 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
959 ssize_t nalloc, nret;
962 const char *ns = NULL;
966 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
968 /* Parse the arguments */
969 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
970 &myarg, &nofollow, &ns))
972 if(convert_obj(myarg, &tgt, nofollow) < 0) {
977 /* Find out the needed size of the buffer */
978 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
979 res = PyErr_SetFromErrno(PyExc_IOError);
988 /* Try to allocate the memory, using Python's allocator */
989 if((buf = PyMem_Malloc(nalloc)) == NULL) {
990 res = PyErr_NoMemory();
994 /* Now retrieve the list of attributes */
995 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
996 res = PyErr_SetFromErrno(PyExc_IOError);
1000 /* Compute the number of attributes in the list */
1001 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
1002 if(matches_ns(ns, s) != NULL)
1005 /* Create the list which will hold the result */
1006 res = PyList_New(nattrs);
1010 /* Create and insert the attributes as strings in the list */
1011 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
1012 const char *name = matches_ns(ns, s);
1014 PyObject *item = PyBytes_FromString(name);
1020 PyList_SET_ITEM(res, nattrs, item);
1026 /* Free the buffer, now it is no longer needed */
1033 /* Return the result */
1037 static PyMethodDef xattr_methods[] = {
1038 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1039 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1041 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1043 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1044 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1046 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1047 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1049 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1050 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1052 {NULL, NULL, 0, NULL} /* Sentinel */
1055 static char __xattr_doc__[] = \
1056 "This module gives access to the extended attributes present\n"
1057 "in some operating systems/filesystems. You can list attributes,\n"
1058 "get, set and remove them.\n"
1060 "The module exposes two sets of functions:\n"
1061 " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n"
1062 " :func:`removexattr`\n"
1063 " functions which are deprecated since version 0.4\n"
1064 " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n"
1065 " :func:`remove` functions\n"
1066 " which expose a namespace-aware API and simplify a bit the calling\n"
1067 " model by using keyword arguments\n"
1070 " >>> import xattr\n"
1071 " >>> xattr.listxattr(\"file.txt\")\n"
1072 " ['user.mime_type']\n"
1073 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1075 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1076 "\"Simple text file\")\n"
1077 " >>> xattr.listxattr(\"file.txt\")\n"
1078 " ['user.mime_type', 'user.comment']\n"
1079 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1081 ".. note:: Most or all errors reported by the system while using\n"
1082 " the ``xattr`` library will be reported by raising\n"
1083 " a :exc:`EnvironmentError`; under\n"
1084 " Linux, the following ``errno`` values are used:\n"
1086 " - ``ENOATTR`` and ``ENODATA`` mean that the attribute name is\n"
1088 " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n"
1089 " support extended attributes, or that the namespace is invalid\n"
1090 " - ``E2BIG`` mean that the attribute value is too big\n"
1091 " - ``ERANGE`` mean that the attribute name is too big (it might also\n"
1092 " mean an error in the xattr module itself)\n"
1093 " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n"
1094 " space or out of disk space because of quota limits\n"
1095 ".. note:: Under Python 3, the namespace argument is a byte string,\n"
1096 " not a unicode string.\n"
1102 static struct PyModuleDef xattrmodule = {
1103 PyModuleDef_HEAD_INIT,
1110 #define INITERROR return NULL
1116 #define INITERROR return
1121 PyObject *ns_security = NULL;
1122 PyObject *ns_system = NULL;
1123 PyObject *ns_trusted = NULL;
1124 PyObject *ns_user = NULL;
1126 PyObject *m = PyModule_Create(&xattrmodule);
1128 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1133 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1134 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1135 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1136 PyModule_AddStringConstant(m, "__license__",
1137 "GNU Lesser General Public License (LGPL)");
1138 PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en");
1140 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1141 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1143 /* namespace constants */
1144 if((ns_security = PyBytes_FromString("security")) == NULL)
1146 if((ns_system = PyBytes_FromString("system")) == NULL)
1148 if((ns_trusted = PyBytes_FromString("trusted")) == NULL)
1150 if((ns_user = PyBytes_FromString("user")) == NULL)
1152 if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0)
1155 if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0)
1158 if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0)
1161 if(PyModule_AddObject(m, "NS_USER", ns_user) < 0)
1172 Py_XDECREF(ns_user);
1173 Py_XDECREF(ns_trusted);
1174 Py_XDECREF(ns_system);
1175 Py_XDECREF(ns_security);