2 xattr - a python module for manipulating filesystem extended attributes
4 Copyright (C) 2002, 2003, 2006, 2008, 2012, 2013, 2015
5 Iustin Pop <iustin@k1024.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #define PY_SSIZE_T_CLEAN
26 #if defined(__APPLE__)
27 #include <sys/xattr.h>
28 #elif defined(__linux__)
29 #include <attr/xattr.h>
33 /* Compatibility with python 2.4 regarding python size type (PEP 353) */
34 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
35 typedef int Py_ssize_t;
36 #define PY_SSIZE_T_MAX INT_MAX
37 #define PY_SSIZE_T_MIN INT_MIN
40 #if PY_MAJOR_VERSION >= 3
42 #define BYTES_CHAR "y"
43 #define BYTES_TUPLE "yy#"
45 #define BYTES_CHAR "s"
46 #define BYTES_TUPLE "ss#"
47 #define PyBytes_Check PyString_Check
48 #define PyBytes_AS_STRING PyString_AS_STRING
49 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
50 #define PyBytes_FromString PyString_FromString
54 ":param item: a string representing a file-name, or a file-like\n" \
55 " object, or a file descriptor; this represents the file on \n" \
58 #define NOFOLLOW_DOC \
59 ":param nofollow: if true and if\n" \
60 " the file name given is a symbolic link, the\n" \
61 " function will operate on the symbolic link itself instead\n" \
62 " of its target; defaults to false\n" \
63 ":type nofollow: boolean, optional\n" \
66 ":param namespace: if given, the attribute must not contain the\n" \
67 " namespace, but instead it will be taken from this parameter\n" \
68 ":type namespace: bytes\n"
70 #define NAME_GET_DOC \
71 ":param string name: the attribute whose value to retrieve;\n" \
72 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
74 #define NAME_SET_DOC \
75 ":param string name: the attribute whose value to set;\n" \
76 " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n"
78 #define NAME_REMOVE_DOC \
79 ":param string name: the attribute to remove;\n" \
80 " usually in the form of ``system.posix_acl`` or \n" \
81 " ``user.mime_type``\n"
84 ":param string value: possibly with embedded NULLs; note that there\n" \
85 " are restrictions regarding the size of the value, for\n" \
86 " example, for ext2/ext3, maximum size is the block size\n" \
89 ":param flags: if 0 or omitted the attribute will be\n" \
90 " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" \
91 " will be created, giving an error if it already exists;\n" \
92 " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" \
93 " giving an error if it doesn't exist;\n" \
94 ":type flags: integer\n"
96 #define NS_CHANGED_DOC \
97 ".. versionchanged:: 0.5.1\n" \
98 " The namespace argument, if passed, cannot be None anymore; to\n" \
99 " explicitly specify an empty namespace, pass an empty\n" \
100 " string (byte string under Python 3)."
103 /* The initial I/O buffer size for list and get operations; if the
104 * actual values will be smaller than this, we save a syscall out of
105 * two and allocate more memory upfront than needed, otherwise we
106 * incur three syscalls (get with ENORANGE, get with 0 to compute
107 * actual size, final get). The test suite is marginally faster (5%)
108 * with this, so it seems worth doing.
110 #define ESTIMATE_ATTR_SIZE 1024
112 typedef enum {T_FD, T_PATH, T_LINK} target_e;
123 /* Cleans up a tgt structure */
124 static void free_tgt(target_t *tgt) {
125 if (tgt->tmp != NULL) {
130 /* Used for cpychecker: */
131 /* The checker automatically defines this preprocessor name when creating
132 the custom attribute: */
133 #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
134 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
135 __attribute__((cpychecker_negative_result_sets_exception))
137 #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
140 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow)
141 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
143 static int merge_ns(const char *ns, const char *name,
144 const char **result, char **buf)
145 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
148 /** Converts from a string, file or int argument to what we need.
150 * Returns -1 on failure, 0 on success.
152 static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) {
155 if(PyBytes_Check(myobj)) {
156 tgt->type = nofollow ? T_LINK : T_PATH;
157 tgt->name = PyBytes_AS_STRING(myobj);
158 } else if(PyUnicode_Check(myobj)) {
159 tgt->type = nofollow ? T_LINK : T_PATH;
161 PyUnicode_AsEncodedString(myobj,
162 Py_FileSystemDefaultEncoding,
171 tgt->name = PyBytes_AS_STRING(tgt->tmp);
172 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
176 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
184 /* Combine a namespace string and an attribute name into a
185 fully-qualified name */
186 static int merge_ns(const char *ns, const char *name,
187 const char **result, char **buf) {
188 if(ns != NULL && *ns != '\0') {
190 /* The value of new_size is related to/must be kept in-sync
191 with the format string below */
192 size_t new_size = strlen(ns) + 1 + strlen(name) + 1;
193 if((*buf = PyMem_Malloc(new_size)) == NULL) {
197 cnt = snprintf(*buf, new_size, "%s.%s", ns, name);
198 if((size_t) cnt >= new_size || cnt < 0) {
199 PyErr_SetString(PyExc_ValueError,
200 "unexpected: can't format the attribute name");
212 #if defined(__APPLE__)
213 static inline ssize_t _listxattr(const char *path, char *namebuf, size_t size) {
214 return listxattr(path, namebuf, size, 0);
216 static inline ssize_t _llistxattr(const char *path, char *namebuf, size_t size) {
217 return listxattr(path, namebuf, size, XATTR_NOFOLLOW);
219 static inline ssize_t _flistxattr(int fd, char *namebuf, size_t size) {
220 return flistxattr(fd, namebuf, size, 0);
223 static inline ssize_t _getxattr (const char *path, const char *name, void *value, size_t size) {
224 return getxattr(path, name, value, size, 0, 0);
226 static inline ssize_t _lgetxattr (const char *path, const char *name, void *value, size_t size) {
227 return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
229 static inline ssize_t _fgetxattr (int filedes, const char *name, void *value, size_t size) {
230 return fgetxattr(filedes, name, value, size, 0, 0);
233 // [fl]setxattr: Both OS X and Linux define XATTR_CREATE and XATTR_REPLACE for the last option.
234 static inline int _setxattr(const char *path, const char *name, const void *value, size_t size, int flags) {
235 return setxattr(path, name, value, size, 0, flags);
237 static inline int _lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) {
238 return setxattr(path, name, value, size, 0, flags & XATTR_NOFOLLOW);
240 static inline int _fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags) {
241 return fsetxattr(filedes, name, value, size, 0, flags);
244 static inline int _removexattr(const char *path, const char *name) {
245 return removexattr(path, name, 0);
247 static inline int _lremovexattr(const char *path, const char *name) {
248 return removexattr(path, name, XATTR_NOFOLLOW);
250 static inline int _fremovexattr(int filedes, const char *name) {
251 return fremovexattr(filedes, name, 0);
254 #elif defined(__linux__)
255 #define _listxattr(path, list, size) listxattr(path, list, size)
256 #define _llistxattr(path, list, size) llistxattr(path, list, size)
257 #define _flistxattr(fd, list, size) flistxattr(fd, list, size)
259 #define _getxattr(path, name, value, size) getxattr(path, name, value, size)
260 #define _lgetxattr(path, name, value, size) lgetxattr(path, name, value, size)
261 #define _fgetxattr(fd, name, value, size) fgetxattr(fd, name, value, size)
263 #define _setxattr(path, name, value, size, flags) setxattr(path, name, value, size, flags)
264 #define _lsetxattr(path, name, value, size, flags) lsetxattr(path, name, value, size, flags)
265 #define _fsetxattr(fd, name, value, size, flags) fsetxattr(fd, name, value, size, flags)
267 #define _removexattr(path, name) removexattr(path, name)
268 #define _lremovexattr(path, name) lremovexattr(path, name)
269 #define _fremovexattr(fd, name) fremovexattr(fd, name)
273 typedef ssize_t (*buf_getter)(target_t *tgt, const char *name,
274 void *output, size_t size);
276 static ssize_t _list_obj(target_t *tgt, const char *unused, void *list,
278 if(tgt->type == T_FD)
279 return _flistxattr(tgt->fd, list, size);
280 else if (tgt->type == T_LINK)
281 return _llistxattr(tgt->name, list, size);
283 return _listxattr(tgt->name, list, size);
286 static ssize_t _get_obj(target_t *tgt, const char *name, void *value,
288 if(tgt->type == T_FD)
289 return _fgetxattr(tgt->fd, name, value, size);
290 else if (tgt->type == T_LINK)
291 return _lgetxattr(tgt->name, name, value, size);
293 return _getxattr(tgt->name, name, value, size);
296 static int _set_obj(target_t *tgt, const char *name,
297 const void *value, size_t size, int flags) {
298 if(tgt->type == T_FD)
299 return _fsetxattr(tgt->fd, name, value, size, flags);
300 else if (tgt->type == T_LINK)
301 return _lsetxattr(tgt->name, name, value, size, flags);
303 return _setxattr(tgt->name, name, value, size, flags);
306 static int _remove_obj(target_t *tgt, const char *name) {
307 if(tgt->type == T_FD)
308 return _fremovexattr(tgt->fd, name);
309 else if (tgt->type == T_LINK)
310 return _lremovexattr(tgt->name, name);
312 return _removexattr(tgt->name, name);
315 /* Perform a get/list operation with appropriate buffer size,
316 * determined dynamically.
319 * - getter: the function that actually does the I/O.
320 * - tgt, name: passed to the getter.
321 * - buffer: pointer to either an already allocated memory area (in
322 * which case size contains its current size), or NULL to
323 * allocate. In all cases (success or failure), the caller should
324 * deallocate the buffer, using PyMem_Free(). Note that if size is
325 * zero but buffer already points to allocate memory, it will be
327 * - size: either size of current buffer (if non-NULL), or size for
328 * initial allocation (if non-zero), or a zero value which means
329 * auto-allocate buffer with automatically queried size. Value will
330 * be updated upon return with the current buffer size.
331 * - io_errno: if non-NULL, the actual errno will be recorded here; if
332 * zero, the call was successful and the output/size/nval are valid.
334 * Return value: if positive or zero, buffer will contain the read
335 * value. Otherwise, io_errno will contain the I/O errno, or zero
336 * to signify a Python-level error. In all cases, the Python-level
337 * error is set to the appropriate value.
339 static ssize_t _generic_get(buf_getter getter, target_t *tgt,
344 CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
346 static ssize_t _generic_get(buf_getter getter, target_t *tgt,
352 /* Clear errno for now, will only set it when it fails in I/O. */
353 if (io_errno != NULL) {
357 #define EXIT_IOERROR() \
359 if (io_errno != NULL) { \
362 PyErr_SetFromErrno(PyExc_IOError); \
366 /* Initialize the buffer, if needed. */
367 if (*size == 0 || *buffer == NULL) {
370 if ((nalloc = getter(tgt, name, NULL, 0)) == -1) {
374 /* Empty, so no need to retrieve it. */
379 if((*buffer = PyMem_Malloc(*size)) == NULL) {
384 // Try to get the value, while increasing the buffer if too small.
385 while((res = getter(tgt, name, *buffer, *size)) == -1) {
386 if(errno == ERANGE) {
387 ssize_t realloc_size_s = getter(tgt, name, NULL, 0);
388 /* ERANGE + proper size _should_ not fail, but... */
389 if(realloc_size_s == -1) {
392 size_t realloc_size = (size_t) realloc_size_s;
394 if((tmp_buf = PyMem_Realloc(*buffer, realloc_size)) == NULL) {
399 *size = realloc_size;
402 /* else we're dealing with a different error, which we
403 don't know how to handle nicely, so we return */
412 Checks if an attribute name matches an optional namespace.
414 If the namespace is NULL or an empty string, it will return the
415 name itself. If the namespace is non-NULL and the name matches, it
416 will return a pointer to the offset in the name after the namespace
417 and the separator. If however the name doesn't match the namespace,
421 const char *matches_ns(const char *ns, const char *name) {
423 if (ns == NULL || *ns == '\0')
425 ns_size = strlen(ns);
427 if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) &&
428 name[ns_size] == '.')
429 return name + ns_size + 1;
433 /* Wrapper for getxattr */
434 static char __pygetxattr_doc__[] =
435 "getxattr(item, attribute[, nofollow=False])\n"
436 "Get the value of a given extended attribute (deprecated).\n"
442 ".. deprecated:: 0.4\n"
443 " this function has been deprecated\n"
444 " by the :func:`get` function.\n"
448 pygetxattr(PyObject *self, PyObject *args)
453 char *attrname = NULL;
456 size_t nalloc = ESTIMATE_ATTR_SIZE;
459 /* Parse the arguments */
460 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
462 if(convert_obj(myarg, &tgt, nofollow) < 0) {
467 nret = _generic_get(_get_obj, &tgt, attrname, &buf, &nalloc, NULL);
472 /* Create the string which will hold the result */
473 res = PyBytes_FromStringAndSize(buf, nret);
476 /* Free the buffer, now it is no longer needed */
480 PyMem_Free(attrname);
482 /* Return the result */
486 /* Wrapper for getxattr */
487 static char __get_doc__[] =
488 "get(item, name[, nofollow=False, namespace=None])\n"
489 "Get the value of a given extended attribute.\n"
492 " >>> xattr.get('/path/to/file', 'user.comment')\n"
494 " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n"
501 ":return: the value of the extended attribute (can contain NULLs)\n"
503 ":raises EnvironmentError: caused by any system errors\n"
505 ".. versionadded:: 0.4\n"
510 xattr_get(PyObject *self, PyObject *args, PyObject *keywds)
515 char *attrname = NULL, *namebuf;
516 const char *fullname;
518 const char *ns = NULL;
520 size_t nalloc = ESTIMATE_ATTR_SIZE;
521 PyObject *res = NULL;
522 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
524 /* Parse the arguments */
525 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
526 &myarg, NULL, &attrname, &nofollow, &ns))
529 if(convert_obj(myarg, &tgt, nofollow) < 0) {
533 if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) {
537 nret = _generic_get(_get_obj, &tgt, fullname, &buf, &nalloc, NULL);
542 /* Create the string which will hold the result */
543 res = PyBytes_FromStringAndSize(buf, nret);
545 /* Free the buffers, they are no longer needed */
552 PyMem_Free(attrname);
554 /* Return the result */
558 /* Wrapper for getxattr */
559 static char __get_all_doc__[] =
560 "get_all(item[, nofollow=False, namespace=None])\n"
561 "Get all the extended attributes of an item.\n"
563 "This function performs a bulk-get of all extended attribute names\n"
564 "and the corresponding value.\n"
567 " >>> xattr.get_all('/path/to/file')\n"
568 " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n"
569 " ('system.posix_acl_access', '\\x02\\x00...')]\n"
570 " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n"
571 " [('mime-type', 'plain/text'), ('comment', 'test')]\n"
574 ":keyword namespace: an optional namespace for filtering the\n"
575 " attributes; for example, querying all user attributes can be\n"
576 " accomplished by passing namespace=:const:`NS_USER`\n"
577 ":type namespace: string\n"
579 ":return: list of tuples (name, value); note that if a namespace\n"
580 " argument was passed, it (and the separator) will be stripped from\n"
581 " the names returned\n"
583 ":raises EnvironmentError: caused by any system errors\n"
585 ".. note:: Since reading the whole attribute list is not an atomic\n"
586 " operation, it might be possible that attributes are added\n"
587 " or removed between the initial query and the actual reading\n"
588 " of the attributes; the returned list will contain only the\n"
589 " attributes that were present at the initial listing of the\n"
590 " attribute names and that were still present when the read\n"
591 " attempt for the value is made.\n"
592 ".. versionadded:: 0.4\n"
597 get_all(PyObject *self, PyObject *args, PyObject *keywds)
599 PyObject *myarg, *res;
601 const char *ns = NULL;
602 char *buf_list = NULL, *buf_val = NULL;
604 size_t nalloc = ESTIMATE_ATTR_SIZE;
608 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
611 /* Parse the arguments */
612 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
613 &myarg, &nofollow, &ns))
615 if(convert_obj(myarg, &tgt, nofollow) < 0)
619 /* Compute first the list of attributes */
620 nlist = _generic_get(_list_obj, &tgt, NULL, &buf_list,
623 /* We can't handle any errors, and the Python error is already
624 set, just bail out. */
628 /* Create the list which will hold the result. */
629 mylist = PyList_New(0);
634 nalloc = ESTIMATE_ATTR_SIZE;
635 /* Create and insert the attributes as strings in the list */
636 for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) {
640 if((name = matches_ns(ns, s)) == NULL)
642 /* Now retrieve the attribute value */
643 nval = _generic_get(_get_obj, &tgt, s, &buf_val, &nalloc, &io_errno);
647 io_errno == ENODATA ||
649 io_errno == ENOATTR) {
657 my_tuple = Py_BuildValue(BYTES_TUPLE, name, buf_val, nval);
658 if (my_tuple == NULL) {
662 PyList_Append(mylist, my_tuple);
666 /* Successful exit */
673 PyMem_Free(buf_list);
678 /* Return the result */
683 static char __pysetxattr_doc__[] =
684 "setxattr(item, name, value[, flags=0, nofollow=False])\n"
685 "Set the value of a given extended attribute (deprecated).\n"
687 "Be careful in case you want to set attributes on symbolic\n"
688 "links, you have to use all the 5 parameters; use 0 for the \n"
689 "flags value if you want the default behaviour (create or "
698 ".. deprecated:: 0.4\n"
699 " this function has been deprecated\n"
700 " by the :func:`set` function.\n"
703 /* Wrapper for setxattr */
705 pysetxattr(PyObject *self, PyObject *args)
707 PyObject *myarg, *res;
709 char *attrname = NULL;
711 Py_ssize_t bufsize_s;
717 /* Parse the arguments */
718 if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname,
719 NULL, &buf, &bufsize_s, &flags, &nofollow))
723 PyErr_SetString(PyExc_ValueError,
724 "negative value size?!");
728 bufsize = (size_t) bufsize_s;
730 if(convert_obj(myarg, &tgt, nofollow) < 0) {
735 /* Set the attribute's value */
736 nret = _set_obj(&tgt, attrname, buf, bufsize, flags);
741 res = PyErr_SetFromErrno(PyExc_IOError);
749 PyMem_Free(attrname);
752 /* Return the result */
756 static char __set_doc__[] =
757 "set(item, name, value[, flags=0, namespace=None])\n"
758 "Set the value of a given extended attribute.\n"
762 " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n"
763 " >>> xattr.set('/path/to/file', 'comment', 'test',"
764 " namespace=xattr.NS_USER)\n"
773 ":raises EnvironmentError: caused by any system errors\n"
775 ".. versionadded:: 0.4\n"
779 /* Wrapper for setxattr */
781 xattr_set(PyObject *self, PyObject *args, PyObject *keywds)
783 PyObject *myarg, *res;
785 char *attrname = NULL;
787 Py_ssize_t bufsize_s;
792 const char *ns = NULL;
794 const char *full_name;
795 static char *kwlist[] = {"item", "name", "value", "flags",
796 "nofollow", "namespace", NULL};
798 /* Parse the arguments */
799 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR,
800 kwlist, &myarg, NULL, &attrname, NULL,
801 &buf, &bufsize_s, &flags, &nofollow, &ns))
805 PyErr_SetString(PyExc_ValueError,
806 "negative value size?!");
810 bufsize = (size_t) bufsize_s;
812 if(convert_obj(myarg, &tgt, nofollow) < 0) {
817 if(merge_ns(ns, attrname, &full_name, &newname) < 0) {
822 /* Set the attribute's value */
823 nret = _set_obj(&tgt, full_name, buf, bufsize, flags);
830 res = PyErr_SetFromErrno(PyExc_IOError);
838 PyMem_Free(attrname);
841 /* Return the result */
846 static char __pyremovexattr_doc__[] =
847 "removexattr(item, name[, nofollow])\n"
848 "Remove an attribute from a file (deprecated).\n"
854 ".. deprecated:: 0.4\n"
855 " this function has been deprecated by the :func:`remove` function.\n"
858 /* Wrapper for removexattr */
860 pyremovexattr(PyObject *self, PyObject *args)
862 PyObject *myarg, *res;
864 char *attrname = NULL;
868 /* Parse the arguments */
869 if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow))
872 if(convert_obj(myarg, &tgt, nofollow) < 0) {
877 /* Remove the attribute */
878 nret = _remove_obj(&tgt, attrname);
883 res = PyErr_SetFromErrno(PyExc_IOError);
891 PyMem_Free(attrname);
893 /* Return the result */
897 static char __remove_doc__[] =
898 "remove(item, name[, nofollow=False, namespace=None])\n"
899 "Remove an attribute from a file.\n"
903 " >>> xattr.remove('/path/to/file', 'user.comment')\n"
910 ":raises EnvironmentError: caused by any system errors\n"
912 ".. versionadded:: 0.4\n"
916 /* Wrapper for removexattr */
918 xattr_remove(PyObject *self, PyObject *args, PyObject *keywds)
920 PyObject *myarg, *res;
922 char *attrname = NULL, *name_buf;
923 const char *ns = NULL;
924 const char *full_name;
927 static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL};
929 /* Parse the arguments */
930 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist,
931 &myarg, NULL, &attrname, &nofollow, &ns))
934 if(convert_obj(myarg, &tgt, nofollow) < 0) {
939 if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) {
944 /* Remove the attribute */
945 nret = _remove_obj(&tgt, full_name);
947 PyMem_Free(name_buf);
952 res = PyErr_SetFromErrno(PyExc_IOError);
960 PyMem_Free(attrname);
962 /* Return the result */
966 static char __pylistxattr_doc__[] =
967 "listxattr(item[, nofollow=False])\n"
968 "Return the list of attribute names for a file (deprecated).\n"
973 ".. deprecated:: 0.4\n"
974 " this function has been deprecated by the :func:`list` function.\n"
977 /* Wrapper for listxattr */
979 pylistxattr(PyObject *self, PyObject *args)
984 size_t nalloc = ESTIMATE_ATTR_SIZE;
991 /* Parse the arguments */
992 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
994 if(convert_obj(myarg, &tgt, nofollow) < 0)
997 nret = _generic_get(_list_obj, &tgt, NULL, &buf, &nalloc, NULL);
1003 /* Compute the number of attributes in the list */
1004 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
1008 /* Create the list which will hold the result */
1009 mylist = PyList_New(nattrs);
1010 if(mylist == NULL) {
1014 /* Create and insert the attributes as strings in the list */
1015 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
1016 PyObject *item = PyBytes_FromString(s);
1022 PyList_SET_ITEM(mylist, nattrs, item);
1027 /* Free the buffer, now it is no longer needed */
1031 /* Return the result */
1035 static char __list_doc__[] =
1036 "list(item[, nofollow=False, namespace=None])\n"
1037 "Return the list of attribute names for a file.\n"
1041 " >>> xattr.list('/path/to/file')\n"
1042 " ['user.test', 'user.comment', 'system.posix_acl_access']\n"
1043 " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n"
1044 " ['test', 'comment']\n"
1049 ":returns: the list of attributes; note that if a namespace \n"
1050 " argument was passed, it (and the separator) will be stripped\n"
1054 ":raises EnvironmentError: caused by any system errors\n"
1056 ".. versionadded:: 0.4\n"
1060 /* Wrapper for listxattr */
1062 xattr_list(PyObject *self, PyObject *args, PyObject *keywds)
1067 size_t nalloc = ESTIMATE_ATTR_SIZE;
1070 const char *ns = NULL;
1074 static char *kwlist[] = {"item", "nofollow", "namespace", NULL};
1076 /* Parse the arguments */
1077 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist,
1078 &myarg, &nofollow, &ns))
1081 if(convert_obj(myarg, &tgt, nofollow) < 0) {
1084 nret = _generic_get(_list_obj, &tgt, NULL, &buf, &nalloc, NULL);
1089 /* Compute the number of attributes in the list */
1090 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
1091 if(matches_ns(ns, s) != NULL)
1095 /* Create the list which will hold the result */
1096 if((res = PyList_New(nattrs)) == NULL) {
1100 /* Create and insert the attributes as strings in the list */
1101 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
1102 const char *name = matches_ns(ns, s);
1104 PyObject *item = PyBytes_FromString(name);
1110 PyList_SET_ITEM(res, nattrs, item);
1116 /* Free the buffer, now it is no longer needed */
1123 /* Return the result */
1127 static PyMethodDef xattr_methods[] = {
1128 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
1129 {"get", (PyCFunction) xattr_get, METH_VARARGS | METH_KEYWORDS,
1131 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
1133 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
1134 {"set", (PyCFunction) xattr_set, METH_VARARGS | METH_KEYWORDS,
1136 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
1137 {"remove", (PyCFunction) xattr_remove, METH_VARARGS | METH_KEYWORDS,
1139 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
1140 {"list", (PyCFunction) xattr_list, METH_VARARGS | METH_KEYWORDS,
1142 {NULL, NULL, 0, NULL} /* Sentinel */
1145 static char __xattr_doc__[] = \
1146 "This module gives access to the extended attributes present\n"
1147 "in some operating systems/filesystems. You can list attributes,\n"
1148 "get, set and remove them.\n"
1150 "The module exposes two sets of functions:\n"
1151 " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n"
1152 " :func:`removexattr`\n"
1153 " functions which are deprecated since version 0.4\n"
1154 " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n"
1155 " :func:`remove` functions\n"
1156 " which expose a namespace-aware API and simplify a bit the calling\n"
1157 " model by using keyword arguments\n"
1160 " >>> import xattr\n"
1161 " >>> xattr.listxattr(\"file.txt\")\n"
1162 " ['user.mime_type']\n"
1163 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
1165 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
1166 "\"Simple text file\")\n"
1167 " >>> xattr.listxattr(\"file.txt\")\n"
1168 " ['user.mime_type', 'user.comment']\n"
1169 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
1171 ".. note:: Most or all errors reported by the system while using\n"
1172 " the ``xattr`` library will be reported by raising\n"
1173 " a :exc:`EnvironmentError`; under\n"
1174 " Linux, the following ``errno`` values are used:\n"
1176 " - ``ENOATTR`` and ``ENODATA`` mean that the attribute name is\n"
1178 " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n"
1179 " support extended attributes, or that the namespace is invalid\n"
1180 " - ``E2BIG`` mean that the attribute value is too big\n"
1181 " - ``ERANGE`` mean that the attribute name is too big (it might also\n"
1182 " mean an error in the xattr module itself)\n"
1183 " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n"
1184 " space or out of disk space because of quota limits\n"
1185 ".. note:: Under Python 3, the namespace argument is a byte string,\n"
1186 " not a unicode string.\n"
1192 static struct PyModuleDef xattrmodule = {
1193 PyModuleDef_HEAD_INIT,
1200 #define INITERROR return NULL
1206 #define INITERROR return
1211 PyObject *ns_security = NULL;
1212 PyObject *ns_system = NULL;
1213 PyObject *ns_trusted = NULL;
1214 PyObject *ns_user = NULL;
1216 PyObject *m = PyModule_Create(&xattrmodule);
1218 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
1223 PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR);
1224 PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL);
1225 PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION);
1226 PyModule_AddStringConstant(m, "__license__",
1227 "GNU Lesser General Public License (LGPL)");
1228 PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en");
1230 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
1231 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
1233 /* namespace constants */
1234 if((ns_security = PyBytes_FromString("security")) == NULL)
1236 if((ns_system = PyBytes_FromString("system")) == NULL)
1238 if((ns_trusted = PyBytes_FromString("trusted")) == NULL)
1240 if((ns_user = PyBytes_FromString("user")) == NULL)
1242 if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0)
1245 if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0)
1248 if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0)
1251 if(PyModule_AddObject(m, "NS_USER", ns_user) < 0)
1262 Py_XDECREF(ns_user);
1263 Py_XDECREF(ns_trusted);
1264 Py_XDECREF(ns_system);
1265 Py_XDECREF(ns_security);