From 818d51068602b429b969ba02cfbcc1369cf1fa84 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 22:32:07 +0200 Subject: [PATCH 01/16] Fix bugs reported by cpychecker MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Thanks to Dave Malcolm's cpychecker tool, this patch fixes a number of serious issues. All issues that were not deemed false-positives were fixed; some other issues in the same category that were found only by a high number of refcount checks are also fixed (I should split/simplify some parts of the code…). --- xattr.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/xattr.c b/xattr.c index 370324a..c4a5d6c 100644 --- a/xattr.c +++ b/xattr.c @@ -1,7 +1,7 @@ /* xattr - a python module for manipulating filesystem extended attributes - Copyright (C) 2002, 2003, 2006, 2008 Iustin Pop + Copyright (C) 2002, 2003, 2006, 2008, 2012 Iustin Pop This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -414,6 +414,11 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) /* Create the list which will hold the result */ mylist = PyList_New(0); + if(mylist == NULL) { + res = NULL; + goto free_buf_list; + } + nalloc = ESTIMATE_ATTR_SIZE; if((buf_val = PyMem_Malloc(nalloc)) == NULL) { Py_DECREF(mylist); @@ -450,6 +455,9 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) missing = 1; break; } + /* else we're dealing with a different error, which we + don't know how to handle nicely, so we abort */ + Py_DECREF(mylist); res = PyErr_SetFromErrno(PyExc_IOError); goto freebufval; } @@ -462,7 +470,11 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) #else my_tuple = Py_BuildValue("ss#", name, buf_val, nval); #endif - + if (my_tuple == NULL) { + Py_DECREF(mylist); + res = NULL; + goto freebufval; + } PyList_Append(mylist, my_tuple); Py_DECREF(my_tuple); } @@ -840,6 +852,8 @@ pylistxattr(PyObject *self, PyObject *args) /* Create the list which will hold the result */ mylist = PyList_New(nattrs); + if(mylist == NULL) + goto freebuf; /* Create and insert the attributes as strings in the list */ for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { @@ -934,6 +948,8 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) } /* Create the list which will hold the result */ res = PyList_New(nattrs); + if(res == NULL) + goto freebuf; /* Create and insert the attributes as strings in the list */ for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { -- 2.39.2 From 4fe3ade769b521f3419ddaefb47557b026cac107 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 22:37:56 +0200 Subject: [PATCH 02/16] Fix some potential issues if PyBytes_FromString fails This is unlikely, but if it happens it's ugly. --- xattr.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/xattr.c b/xattr.c index c4a5d6c..60b2e9e 100644 --- a/xattr.c +++ b/xattr.c @@ -857,7 +857,13 @@ pylistxattr(PyObject *self, PyObject *args) /* Create and insert the attributes as strings in the list */ for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { - PyList_SET_ITEM(mylist, nattrs, PyBytes_FromString(s)); + PyObject *item = PyBytes_FromString(s); + if(item == NULL) { + Py_DECREF(mylist); + mylist = NULL; + goto freebuf; + } + PyList_SET_ITEM(mylist, nattrs, item); nattrs++; } @@ -955,7 +961,13 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { const char *name = matches_ns(ns, s); if(name!=NULL) { - PyList_SET_ITEM(res, nattrs, PyBytes_FromString(name)); + PyObject *item = PyBytes_FromString(name); + if(item == NULL) { + Py_DECREF(res); + res = NULL; + goto freebuf; + } + PyList_SET_ITEM(res, nattrs, item); nattrs++; } } -- 2.39.2 From b851db83d9b453f504f4761c5d9b6fac99e6d70c Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 22:48:40 +0200 Subject: [PATCH 03/16] Fix small typo --- xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xattr.c b/xattr.c index 60b2e9e..e7f0d4d 100644 --- a/xattr.c +++ b/xattr.c @@ -479,7 +479,7 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) Py_DECREF(my_tuple); } - /* Successfull exit */ + /* Successful exit */ res = mylist; freebufval: -- 2.39.2 From 73ac62755743ca972c8d11dd17d30a8c8561f185 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 22:50:43 +0200 Subject: [PATCH 04/16] Switch to setuptools For proper testsuite support. --- setup.py | 5 ++--- test/__init__.py | 0 2 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 test/__init__.py diff --git a/setup.py b/setup.py index e6f77bc..839484a 100755 --- a/setup.py +++ b/setup.py @@ -1,8 +1,7 @@ #!/usr/bin/python import distutils -from distutils.core import setup, Extension -#from setuptools import setup, Extension +from setuptools import setup, Extension long_desc = """This is a C extension module for Python which implements extended attributes manipulation. It is a wrapper on top @@ -26,5 +25,5 @@ setup(name = "pyxattr", ext_modules = [Extension("xattr", ["xattr.c"], libraries=["attr"], define_macros=macros)], - #test_suite = "test/test_xattr", + test_suite = "test", ) diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 -- 2.39.2 From 69b35f511849f1d2ab42fadef54f7092df1c0fb7 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 23:40:35 +0200 Subject: [PATCH 05/16] Fix some const char* pointers This reduces the warnings, and it's a good thing to do. --- xattr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xattr.c b/xattr.c index e7f0d4d..92f011b 100644 --- a/xattr.c +++ b/xattr.c @@ -279,7 +279,7 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) char *attrname = NULL, *namebuf; const char *fullname; char *buf; - char *ns = NULL; + const char *ns = NULL; ssize_t nalloc, nret; PyObject *res; static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL}; @@ -373,9 +373,9 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) { PyObject *myarg, *res; int dolink=0; - char *ns = NULL; + const char *ns = NULL; char *buf_list, *buf_val; - char *s; + const char *s; ssize_t nalloc, nlist, nval; PyObject *mylist; target_t tgt; @@ -617,7 +617,7 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) int nret; int flags = 0; target_t tgt; - char *ns = NULL; + const char *ns = NULL; char *newname; const char *full_name; static char *kwlist[] = {"item", "name", "value", "flags", @@ -748,7 +748,7 @@ xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) PyObject *myarg, *res; int nofollow = 0; char *attrname = NULL, *name_buf; - char *ns = NULL; + const char *ns = NULL; const char *full_name; int nret; target_t tgt; -- 2.39.2 From f94451bb3fb57596b13295d7ad0045e866162b15 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 23:48:12 +0200 Subject: [PATCH 06/16] Switch converObj to negative error return This will allow cpychecker to know that this function has set the exception already, eliminating false positives. --- xattr.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/xattr.c b/xattr.c index 92f011b..1470deb 100644 --- a/xattr.c +++ b/xattr.c @@ -63,7 +63,10 @@ static void free_tgt(target_t *tgt) { } } -/** Converts from a string, file or int argument to what we need. */ +/** Converts from a string, file or int argument to what we need. + * + * Returns -1 on failure, 0 on success. + */ static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) { int fd; tgt->tmp = NULL; @@ -76,16 +79,16 @@ static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) { PyUnicode_AsEncodedString(myobj, Py_FileSystemDefaultEncoding, "strict"); if(tgt->tmp == NULL) - return 0; + return -1; tgt->name = PyBytes_AS_STRING(tgt->tmp); } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) { tgt->type = T_FD; tgt->fd = fd; } else { PyErr_SetString(PyExc_TypeError, "argument must be string or int"); - return 0; + return -1; } - return 1; + return 0; } /* Combine a namespace string and an attribute name into a @@ -203,7 +206,7 @@ pygetxattr(PyObject *self, PyObject *args) /* Parse the arguments */ if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } @@ -288,7 +291,7 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist, &myarg, NULL, &attrname, &nofollow, &ns)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } @@ -385,7 +388,7 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist, &myarg, &dolink, &ns)) return NULL; - if(!convertObj(myarg, &tgt, dolink)) + if(convertObj(myarg, &tgt, dolink) < 0) return NULL; /* Compute first the list of attributes */ @@ -543,7 +546,7 @@ pysetxattr(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Oetet#|bi", &myarg, NULL, &attrname, NULL, &buf, &bufsize, &flags, &nofollow)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } @@ -628,7 +631,7 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) &myarg, NULL, &attrname, NULL, &buf, &bufsize, &flags, &nofollow, &ns)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } @@ -692,7 +695,7 @@ pyremovexattr(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Oet|i", &myarg, NULL, &attrname, &nofollow)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } @@ -759,7 +762,7 @@ xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) &myarg, NULL, &attrname, &nofollow, &ns)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } @@ -824,7 +827,7 @@ pylistxattr(PyObject *self, PyObject *args) /* Parse the arguments */ if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) + if(convertObj(myarg, &tgt, nofollow) < 0) return NULL; /* Find out the needed size of the buffer */ @@ -924,7 +927,7 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iet", kwlist, &myarg, &nofollow, NULL, &ns)) return NULL; - if(!convertObj(myarg, &tgt, nofollow)) { + if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; goto freearg; } -- 2.39.2 From 70645d94d392f90ffc5260f753f8df07827654de Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 23:53:40 +0200 Subject: [PATCH 07/16] Mark convertObj as setting the exception on errors This eliminates lots of clutter from the cpychecker output, yay! --- xattr.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xattr.c b/xattr.c index 1470deb..c80314c 100644 --- a/xattr.c +++ b/xattr.c @@ -63,6 +63,19 @@ static void free_tgt(target_t *tgt) { } } +/* Used for cpychecker: */ +/* The checker automatically defines this preprocessor name when creating + the custom attribute: */ +#if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE) + #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \ +__attribute__((cpychecker_negative_result_sets_exception)) + #else + #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION + #endif + +static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; + /** Converts from a string, file or int argument to what we need. * * Returns -1 on failure, 0 on success. -- 2.39.2 From 55f52997a62b8cfc8341eb3434b659eb0f396494 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 14 May 2012 23:54:09 +0200 Subject: [PATCH 08/16] Rename a variable for more consistency At least, more consistency in the output of git grep convertObj :) --- xattr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xattr.c b/xattr.c index c80314c..a4d6988 100644 --- a/xattr.c +++ b/xattr.c @@ -388,7 +388,7 @@ static PyObject * get_all(PyObject *self, PyObject *args, PyObject *keywds) { PyObject *myarg, *res; - int dolink=0; + int nofollow=0; const char *ns = NULL; char *buf_list, *buf_val; const char *s; @@ -399,9 +399,9 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) /* Parse the arguments */ if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist, - &myarg, &dolink, &ns)) + &myarg, &nofollow, &ns)) return NULL; - if(convertObj(myarg, &tgt, dolink) < 0) + if(convertObj(myarg, &tgt, nofollow) < 0) return NULL; /* Compute first the list of attributes */ -- 2.39.2 From 3db638484def6acea263839884bcac842a8b077a Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 00:04:54 +0200 Subject: [PATCH 09/16] Fix a case of missing exception on return NULL Now that the noise is gone, this is an actual error. --- xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xattr.c b/xattr.c index a4d6988..446af0a 100644 --- a/xattr.c +++ b/xattr.c @@ -459,7 +459,7 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) if(errno == ERANGE) { nval = _get_obj(&tgt, s, NULL, 0); if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) { - res = NULL; + res = PyErr_NoMemory(); Py_DECREF(mylist); goto free_buf_list; } -- 2.39.2 From 30b2da9b56d53aca6d4a1b0b430a92331708365b Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 00:12:30 +0200 Subject: [PATCH 10/16] Rework merge_ns signature This is also in order to clarify what is an "error" return for cpychecker. Note that most calls to this function do not have yet error checking, will be fixed in separate patch. --- xattr.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/xattr.c b/xattr.c index 446af0a..ba3fb82 100644 --- a/xattr.c +++ b/xattr.c @@ -106,26 +106,28 @@ static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) { /* Combine a namespace string and an attribute name into a fully-qualified name */ -static const char* merge_ns(const char *ns, const char *name, char **buf) { +static int merge_ns(const char *ns, const char *name, + const char **result, char **buf) { if(ns != NULL) { int cnt; size_t new_size = strlen(ns) + 1 + strlen(name) + 1; if((*buf = PyMem_Malloc(new_size)) == NULL) { PyErr_NoMemory(); - return NULL; + return -1; } cnt = snprintf(*buf, new_size, "%s.%s", ns, name); if(cnt > new_size || cnt < 0) { PyErr_SetString(PyExc_ValueError, "can't format the attribute name"); PyMem_Free(*buf); - return NULL; + return -1; } - return *buf; + *result = *buf; } else { *buf = NULL; - return name; + *result = name; } + return 0; } static ssize_t _list_obj(target_t *tgt, char *list, size_t size) { @@ -309,7 +311,7 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) goto freearg; } - fullname = merge_ns(ns, attrname, &namebuf); + merge_ns(ns, attrname, &fullname, &namebuf); /* Find out the needed size of the buffer */ if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) { @@ -649,7 +651,7 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) goto freearg; } - full_name = merge_ns(ns, attrname, &newname); + merge_ns(ns, attrname, &full_name, &newname); /* Set the attribute's value */ nret = _set_obj(&tgt, full_name, buf, bufsize, flags); @@ -780,8 +782,7 @@ xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) goto freearg; } - full_name = merge_ns(ns, attrname, &name_buf); - if(full_name == NULL) { + if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) { res = NULL; goto freearg; } -- 2.39.2 From c58e742b603eeaa4c3b07e04d72a65becb82c636 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 00:17:39 +0200 Subject: [PATCH 11/16] Check merge_ns return value in all places This eliminates another potential round of errors. Also add cpychecker attribute for even less noise. --- xattr.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/xattr.c b/xattr.c index ba3fb82..dc8ad00 100644 --- a/xattr.c +++ b/xattr.c @@ -76,6 +76,11 @@ __attribute__((cpychecker_negative_result_sets_exception)) static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; +static int merge_ns(const char *ns, const char *name, + const char **result, char **buf) + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; + + /** Converts from a string, file or int argument to what we need. * * Returns -1 on failure, 0 on success. @@ -311,7 +316,10 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) goto freearg; } - merge_ns(ns, attrname, &fullname, &namebuf); + if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) { + res = NULL; + goto freearg; + } /* Find out the needed size of the buffer */ if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) { @@ -651,13 +659,15 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) goto freearg; } - merge_ns(ns, attrname, &full_name, &newname); + if(merge_ns(ns, attrname, &full_name, &newname) < 0) { + res = NULL; + goto freearg; + } /* Set the attribute's value */ nret = _set_obj(&tgt, full_name, buf, bufsize, flags); - if(newname != NULL) - PyMem_Free(newname); + PyMem_Free(newname); free_tgt(&tgt); -- 2.39.2 From b9e4cd3c6f6c775f8e416342afb7916dcab498a1 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 00:20:35 +0200 Subject: [PATCH 12/16] Fix a (harmless) integer mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This is not critical, but let's not over-optimise and request a byte when we store it anyway in an int… --- xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xattr.c b/xattr.c index dc8ad00..77fb012 100644 --- a/xattr.c +++ b/xattr.c @@ -566,7 +566,7 @@ pysetxattr(PyObject *self, PyObject *args) target_t tgt; /* Parse the arguments */ - if (!PyArg_ParseTuple(args, "Oetet#|bi", &myarg, NULL, &attrname, + if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname, NULL, &buf, &bufsize, &flags, &nofollow)) return NULL; if(convertObj(myarg, &tgt, nofollow) < 0) { -- 2.39.2 From 2f7cbf9b01a0324ed8822f1dd77308991b873890 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 00:23:12 +0200 Subject: [PATCH 13/16] A few docstring fixes --- xattr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xattr.c b/xattr.c index 77fb012..e8ab5a9 100644 --- a/xattr.c +++ b/xattr.c @@ -525,13 +525,13 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) static char __pysetxattr_doc__[] = "Set the value of a given extended attribute (deprecated).\n" "\n" - "Be carefull in case you want to set attributes on symbolic\n" + "Be careful in case you want to set attributes on symbolic\n" "links, you have to use all the 5 parameters; use 0 for the \n" - "flags value if you want the default behavior (create or " + "flags value if you want the default behaviour (create or " "replace)\n" "\n" "Parameters:\n" - " - a string representing filename, or a file-like object,\n" + " - a string representing a file-name, or a file-like object,\n" " or a file descriptor; this represents the file on \n" " which to act\n" " - a string, representing the attribute whose value to set;\n" @@ -539,7 +539,7 @@ static char __pysetxattr_doc__[] = " - a string, possibly with embedded NULLs; note that there\n" " are restrictions regarding the size of the value, for\n" " example, for ext2/ext3, maximum size is the block size\n" - " - (optional) flags; if 0 or ommited the attribute will be \n" + " - (optional) flags; if 0 or omitted the attribute will be \n" " created or replaced; if XATTR_CREATE, the attribute \n" " will be created, giving an error if it already exists;\n" " of XATTR_REPLACE, the attribute will be replaced,\n" @@ -692,7 +692,7 @@ static char __pyremovexattr_doc__[] = "Remove an attribute from a file (deprecated).\n" "\n" "Parameters:\n" - " - a string representing filename, or a file-like object,\n" + " - a string representing a file-name, or a file-like object,\n" " or a file descriptor; this represents the file on \n" " which to act\n" " - a string, representing the attribute to be removed;\n" -- 2.39.2 From 844e00dd6b10f130c7065c52c30ce990834442ba Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 00:38:56 +0200 Subject: [PATCH 14/16] Rework init sequence This makes it a bit more clean, and thus removes the last refcount issue; however, the code itself is much uglier :( --- xattr.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/xattr.c b/xattr.c index e8ab5a9..c1bd080 100644 --- a/xattr.c +++ b/xattr.c @@ -1096,6 +1096,10 @@ void initxattr(void) #endif { + PyObject *ns_security = NULL; + PyObject *ns_system = NULL; + PyObject *ns_trusted = NULL; + PyObject *ns_user = NULL; #ifdef IS_PY3K PyObject *m = PyModule_Create(&xattrmodule); #else @@ -1115,12 +1119,37 @@ initxattr(void) PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE); /* namespace constants */ - PyModule_AddObject(m, "NS_SECURITY", PyBytes_FromString("security")); - PyModule_AddObject(m, "NS_SYSTEM", PyBytes_FromString("system")); - PyModule_AddObject(m, "NS_TRUSTED", PyBytes_FromString("trusted")); - PyModule_AddObject(m, "NS_USER", PyBytes_FromString("user")); + if((ns_security = PyBytes_FromString("security")) == NULL) + goto err_out; + if((ns_system = PyBytes_FromString("system")) == NULL) + goto err_out; + if((ns_trusted = PyBytes_FromString("trusted")) == NULL) + goto err_out; + if((ns_user = PyBytes_FromString("user")) == NULL) + goto err_out; + if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0) + goto err_out; + ns_security = NULL; + if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0) + goto err_out; + ns_system = NULL; + if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0) + goto err_out; + ns_trusted = NULL; + if(PyModule_AddObject(m, "NS_USER", ns_user) < 0) + goto err_out; + ns_user = NULL; #ifdef IS_PY3K return m; +#else + return; #endif + + err_out: + Py_XDECREF(ns_user); + Py_XDECREF(ns_trusted); + Py_XDECREF(ns_system); + Py_XDECREF(ns_security); + INITERROR; } -- 2.39.2 From 10e19cc64c2fe54f9bf2febd07af01eb3736a402 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 21:23:20 +0200 Subject: [PATCH 15/16] Remove use of deprecated fail* test functions --- test/test_xattr.py | 246 +++++++++++++++++++++------------------------ 1 file changed, 114 insertions(+), 132 deletions(-) diff --git a/test/test_xattr.py b/test/test_xattr.py index cd25594..a1ad52f 100644 --- a/test/test_xattr.py +++ b/test/test_xattr.py @@ -72,10 +72,10 @@ class xattrTest(unittest.TestCase): def _checkDeprecated(self, item, symlink=False): """check deprecated list, set, get operations against an item""" - self.failUnlessEqual(xattr.listxattr(item, symlink), []) - self.failUnlessRaises(EnvironmentError, xattr.setxattr, item, - self.USER_ATTR, self.USER_VAL, - XATTR_REPLACE) + self.assertEqual(xattr.listxattr(item, symlink), []) + self.assertRaises(EnvironmentError, xattr.setxattr, item, + self.USER_ATTR, self.USER_VAL, + XATTR_REPLACE) try: xattr.setxattr(item, self.USER_ATTR, self.USER_VAL, 0, symlink) except IOError: @@ -85,30 +85,27 @@ class xattrTest(unittest.TestCase): # of the test for this case return raise - self.failUnlessRaises(EnvironmentError, xattr.setxattr, item, - self.USER_ATTR, self.USER_VAL, - XATTR_CREATE) - self.failUnlessEqual(xattr.listxattr(item, symlink), [self.USER_ATTR]) - self.failUnlessEqual(xattr.getxattr(item, self.USER_ATTR, symlink), - self.USER_VAL) - self.failUnlessEqual(xattr.get_all(item, nofollow=symlink), - [(self.USER_ATTR, self.USER_VAL)]) + self.assertRaises(EnvironmentError, xattr.setxattr, item, + self.USER_ATTR, self.USER_VAL, XATTR_CREATE) + self.assertEqual(xattr.listxattr(item, symlink), [self.USER_ATTR]) + self.assertEqual(xattr.getxattr(item, self.USER_ATTR, symlink), + self.USER_VAL) + self.assertEqual(xattr.get_all(item, nofollow=symlink), + [(self.USER_ATTR, self.USER_VAL)]) xattr.removexattr(item, self.USER_ATTR) - self.failUnlessEqual(xattr.listxattr(item, symlink), []) - self.failUnlessEqual(xattr.get_all(item, nofollow=symlink), []) - self.failUnlessRaises(EnvironmentError, xattr.removexattr, - item, self.USER_ATTR) + self.assertEqual(xattr.listxattr(item, symlink), []) + self.assertEqual(xattr.get_all(item, nofollow=symlink), []) + self.assertRaises(EnvironmentError, xattr.removexattr, + item, self.USER_ATTR) def _checkListSetGet(self, item, symlink=False, use_ns=False): """check list, set, get operations against an item""" - self.failUnlessEqual(xattr.list(item, symlink), []) - self.failUnlessRaises(EnvironmentError, xattr.set, item, - self.USER_ATTR, self.USER_VAL, - flags=XATTR_REPLACE) - self.failUnlessRaises(EnvironmentError, xattr.set, item, - self.USER_NN, self.USER_VAL, - flags=XATTR_REPLACE, - namespace=NS_USER) + self.assertEqual(xattr.list(item, symlink), []) + self.assertRaises(EnvironmentError, xattr.set, item, + self.USER_ATTR, self.USER_VAL, flags=XATTR_REPLACE) + self.assertRaises(EnvironmentError, xattr.set, item, + self.USER_NN, self.USER_VAL, flags=XATTR_REPLACE, + namespace=NS_USER) try: if use_ns: xattr.set(item, self.USER_NN, self.USER_VAL, @@ -124,70 +121,64 @@ class xattrTest(unittest.TestCase): # of the test for this case return raise - self.failUnlessRaises(EnvironmentError, xattr.set, item, - self.USER_ATTR, self.USER_VAL, - flags=XATTR_CREATE) - self.failUnlessRaises(EnvironmentError, xattr.set, item, - self.USER_NN, self.USER_VAL, - flags=XATTR_CREATE, - namespace=NS_USER) - self.failUnlessEqual(xattr.list(item, nofollow=symlink), - [self.USER_ATTR]) - self.failUnlessEqual(xattr.list(item, namespace=NS_USER, - nofollow=symlink), - [self.USER_NN]) - self.failUnlessEqual(xattr.get(item, self.USER_ATTR, nofollow=symlink), - self.USER_VAL) - self.failUnlessEqual(xattr.get(item, self.USER_NN, nofollow=symlink, + self.assertRaises(EnvironmentError, xattr.set, item, + self.USER_ATTR, self.USER_VAL, flags=XATTR_CREATE) + self.assertRaises(EnvironmentError, xattr.set, item, + self.USER_NN, self.USER_VAL, + flags=XATTR_CREATE, namespace=NS_USER) + self.assertEqual(xattr.list(item, nofollow=symlink), [self.USER_ATTR]) + self.assertEqual(xattr.list(item, namespace=NS_USER, nofollow=symlink), + [self.USER_NN]) + self.assertEqual(xattr.get(item, self.USER_ATTR, nofollow=symlink), + self.USER_VAL) + self.assertEqual(xattr.get(item, self.USER_NN, nofollow=symlink, + namespace=NS_USER), self.USER_VAL) + self.assertEqual(xattr.get_all(item, nofollow=symlink), + [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.get_all(item, nofollow=symlink, namespace=NS_USER), - self.USER_VAL) - self.failUnlessEqual(xattr.get_all(item, nofollow=symlink), - [(self.USER_ATTR, self.USER_VAL)]) - self.failUnlessEqual(xattr.get_all(item, nofollow=symlink, - namespace=NS_USER), - [(self.USER_NN, self.USER_VAL)]) + [(self.USER_NN, self.USER_VAL)]) if use_ns: xattr.remove(item, self.USER_NN, namespace=NS_USER) else: xattr.remove(item, self.USER_ATTR) - self.failUnlessEqual(xattr.list(item, symlink), []) - self.failUnlessEqual(xattr.get_all(item, nofollow=symlink), []) - self.failUnlessRaises(EnvironmentError, xattr.remove, - item, self.USER_ATTR, nofollow=symlink) - self.failUnlessRaises(EnvironmentError, xattr.remove, - item, self.USER_NN, namespace=NS_USER, - nofollow=symlink) + self.assertEqual(xattr.list(item, symlink), []) + self.assertEqual(xattr.get_all(item, nofollow=symlink), []) + self.assertRaises(EnvironmentError, xattr.remove, + item, self.USER_ATTR, nofollow=symlink) + self.assertRaises(EnvironmentError, xattr.remove, item, + self.USER_NN, namespace=NS_USER, nofollow=symlink) def testNoXattrDeprecated(self): """test no attributes (deprecated functions)""" fh, fname = self._getfile() - self.failUnlessEqual(xattr.listxattr(fname), []) - self.failUnlessEqual(xattr.get_all(fname), []) + self.assertEqual(xattr.listxattr(fname), []) + self.assertEqual(xattr.get_all(fname), []) dname = self._getdir() - self.failUnlessEqual(xattr.listxattr(dname), []) - self.failUnlessEqual(xattr.get_all(dname), []) + self.assertEqual(xattr.listxattr(dname), []) + self.assertEqual(xattr.get_all(dname), []) _, sname = self._getsymlink() - self.failUnlessEqual(xattr.listxattr(sname, True), []) - self.failUnlessEqual(xattr.get_all(sname, nofollow=True), []) + self.assertEqual(xattr.listxattr(sname, True), []) + self.assertEqual(xattr.get_all(sname, nofollow=True), []) def testNoXattr(self): """test no attributes""" fh, fname = self._getfile() - self.failUnlessEqual(xattr.list(fname), []) - self.failUnlessEqual(xattr.list(fname, namespace=NS_USER), []) - self.failUnlessEqual(xattr.get_all(fname), []) - self.failUnlessEqual(xattr.get_all(fname, namespace=NS_USER), []) + self.assertEqual(xattr.list(fname), []) + self.assertEqual(xattr.list(fname, namespace=NS_USER), []) + self.assertEqual(xattr.get_all(fname), []) + self.assertEqual(xattr.get_all(fname, namespace=NS_USER), []) dname = self._getdir() - self.failUnlessEqual(xattr.list(dname), []) - self.failUnlessEqual(xattr.list(dname, namespace=NS_USER), []) - self.failUnlessEqual(xattr.get_all(dname), []) - self.failUnlessEqual(xattr.get_all(dname, namespace=NS_USER), []) + self.assertEqual(xattr.list(dname), []) + self.assertEqual(xattr.list(dname, namespace=NS_USER), []) + self.assertEqual(xattr.get_all(dname), []) + self.assertEqual(xattr.get_all(dname, namespace=NS_USER), []) _, sname = self._getsymlink() - self.failUnlessEqual(xattr.list(sname, nofollow=True), []) - self.failUnlessEqual(xattr.list(sname, nofollow=True, + self.assertEqual(xattr.list(sname, nofollow=True), []) + self.assertEqual(xattr.list(sname, nofollow=True, namespace=NS_USER), []) - self.failUnlessEqual(xattr.get_all(sname, nofollow=True), []) - self.failUnlessEqual(xattr.get_all(sname, nofollow=True, + self.assertEqual(xattr.get_all(sname, nofollow=True), []) + self.assertEqual(xattr.get_all(sname, nofollow=True, namespace=NS_USER), []) def testFileByNameDeprecated(self): @@ -235,37 +226,32 @@ class xattrTest(unittest.TestCase): """test mixed access to file (deprecated functions)""" fh, fname = self._getfile() fo = os.fdopen(fh) - self.failUnlessEqual(xattr.listxattr(fname), []) + self.assertEqual(xattr.listxattr(fname), []) xattr.setxattr(fname, self.USER_ATTR, self.USER_VAL) - self.failUnlessEqual(xattr.listxattr(fh), [self.USER_ATTR]) - self.failUnlessEqual(xattr.getxattr(fo, self.USER_ATTR), - self.USER_VAL) - self.failUnlessEqual(xattr.get_all(fo), - [(self.USER_ATTR, self.USER_VAL)]) - self.failUnlessEqual(xattr.get_all(fname), - [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.listxattr(fh), [self.USER_ATTR]) + self.assertEqual(xattr.getxattr(fo, self.USER_ATTR), self.USER_VAL) + self.assertEqual(xattr.get_all(fo), [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fname), + [(self.USER_ATTR, self.USER_VAL)]) def testMixedAccess(self): """test mixed access to file""" fh, fname = self._getfile() fo = os.fdopen(fh) - self.failUnlessEqual(xattr.list(fname), []) + self.assertEqual(xattr.list(fname), []) xattr.set(fname, self.USER_ATTR, self.USER_VAL) - self.failUnlessEqual(xattr.list(fh), [self.USER_ATTR]) - self.failUnlessEqual(xattr.list(fh, namespace=NS_USER), - [self.USER_NN]) - self.failUnlessEqual(xattr.get(fo, self.USER_ATTR), - self.USER_VAL) - self.failUnlessEqual(xattr.get(fo, self.USER_NN, namespace=NS_USER), - self.USER_VAL) - self.failUnlessEqual(xattr.get_all(fo), - [(self.USER_ATTR, self.USER_VAL)]) - self.failUnlessEqual(xattr.get_all(fo, namespace=NS_USER), - [(self.USER_NN, self.USER_VAL)]) - self.failUnlessEqual(xattr.get_all(fname), - [(self.USER_ATTR, self.USER_VAL)]) - self.failUnlessEqual(xattr.get_all(fname, namespace=NS_USER), - [(self.USER_NN, self.USER_VAL)]) + self.assertEqual(xattr.list(fh), [self.USER_ATTR]) + self.assertEqual(xattr.list(fh, namespace=NS_USER), [self.USER_NN]) + self.assertEqual(xattr.get(fo, self.USER_ATTR), self.USER_VAL) + self.assertEqual(xattr.get(fo, self.USER_NN, namespace=NS_USER), + self.USER_VAL) + self.assertEqual(xattr.get_all(fo), [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fo, namespace=NS_USER), + [(self.USER_NN, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fname), + [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fname, namespace=NS_USER), + [(self.USER_NN, self.USER_VAL)]) def testDirOpsDeprecated(self): """test attribute setting on directories (deprecated functions)""" @@ -281,28 +267,28 @@ class xattrTest(unittest.TestCase): def testSymlinkOpsDeprecated(self): """test symlink operations (deprecated functions)""" _, sname = self._getsymlink() - self.failUnlessRaises(EnvironmentError, xattr.listxattr, sname) + self.assertRaises(EnvironmentError, xattr.listxattr, sname) self._checkDeprecated(sname, symlink=True) target, sname = self._getsymlink(dangling=False) xattr.setxattr(target, self.USER_ATTR, self.USER_VAL) - self.failUnlessEqual(xattr.listxattr(target), [self.USER_ATTR]) - self.failUnlessEqual(xattr.listxattr(sname, True), []) - self.failUnlessRaises(EnvironmentError, xattr.removexattr, sname, - self.USER_ATTR, True) + self.assertEqual(xattr.listxattr(target), [self.USER_ATTR]) + self.assertEqual(xattr.listxattr(sname, True), []) + self.assertRaises(EnvironmentError, xattr.removexattr, sname, + self.USER_ATTR, True) xattr.removexattr(sname, self.USER_ATTR, False) def testSymlinkOps(self): """test symlink operations""" _, sname = self._getsymlink() - self.failUnlessRaises(EnvironmentError, xattr.list, sname) + self.assertRaises(EnvironmentError, xattr.list, sname) self._checkListSetGet(sname, symlink=True) self._checkListSetGet(sname, symlink=True, use_ns=True) target, sname = self._getsymlink(dangling=False) xattr.set(target, self.USER_ATTR, self.USER_VAL) - self.failUnlessEqual(xattr.list(target), [self.USER_ATTR]) - self.failUnlessEqual(xattr.list(sname, nofollow=True), []) - self.failUnlessRaises(EnvironmentError, xattr.remove, sname, - self.USER_ATTR, nofollow=True) + self.assertEqual(xattr.list(target), [self.USER_ATTR]) + self.assertEqual(xattr.list(sname, nofollow=True), []) + self.assertRaises(EnvironmentError, xattr.remove, sname, + self.USER_ATTR, nofollow=True) xattr.remove(sname, self.USER_ATTR, nofollow=False) def testBinaryPayloadDeprecated(self): @@ -313,9 +299,9 @@ class xattrTest(unittest.TestCase): if PY3K: BINVAL = BINVAL.encode() xattr.setxattr(fname, self.USER_ATTR, BINVAL) - self.failUnlessEqual(xattr.listxattr(fname), [self.USER_ATTR]) - self.failUnlessEqual(xattr.getxattr(fname, self.USER_ATTR), BINVAL) - self.failUnlessEqual(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)]) + self.assertEqual(xattr.listxattr(fname), [self.USER_ATTR]) + self.assertEqual(xattr.getxattr(fname, self.USER_ATTR), BINVAL) + self.assertEqual(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)]) xattr.removexattr(fname, self.USER_ATTR) def testBinaryPayload(self): @@ -326,15 +312,14 @@ class xattrTest(unittest.TestCase): if PY3K: BINVAL = BINVAL.encode() xattr.set(fname, self.USER_ATTR, BINVAL) - self.failUnlessEqual(xattr.list(fname), [self.USER_ATTR]) - self.failUnlessEqual(xattr.list(fname, namespace=NS_USER), - [self.USER_NN]) - self.failUnlessEqual(xattr.get(fname, self.USER_ATTR), BINVAL) - self.failUnlessEqual(xattr.get(fname, self.USER_NN, - namespace=NS_USER), BINVAL) - self.failUnlessEqual(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)]) - self.failUnlessEqual(xattr.get_all(fname, namespace=NS_USER), - [(self.USER_NN, BINVAL)]) + self.assertEqual(xattr.list(fname), [self.USER_ATTR]) + self.assertEqual(xattr.list(fname, namespace=NS_USER), [self.USER_NN]) + self.assertEqual(xattr.get(fname, self.USER_ATTR), BINVAL) + self.assertEqual(xattr.get(fname, self.USER_NN, + namespace=NS_USER), BINVAL) + self.assertEqual(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)]) + self.assertEqual(xattr.get_all(fname, namespace=NS_USER), + [(self.USER_NN, BINVAL)]) xattr.remove(fname, self.USER_ATTR) def testManyOpsDeprecated(self): @@ -343,13 +328,12 @@ class xattrTest(unittest.TestCase): xattr.setxattr(fh, self.USER_ATTR, self.USER_VAL) VL = [self.USER_ATTR] for i in range(self.MANYOPS_COUNT): - self.failUnlessEqual(xattr.listxattr(fh), VL) + self.assertEqual(xattr.listxattr(fh), VL) for i in range(self.MANYOPS_COUNT): - self.failUnlessEqual(xattr.getxattr(fh, self.USER_ATTR), - self.USER_VAL) + self.assertEqual(xattr.getxattr(fh, self.USER_ATTR), self.USER_VAL) for i in range(self.MANYOPS_COUNT): - self.failUnlessEqual(xattr.get_all(fh), - [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fh), + [(self.USER_ATTR, self.USER_VAL)]) def testManyOps(self): """test many ops""" @@ -358,19 +342,17 @@ class xattrTest(unittest.TestCase): VL = [self.USER_ATTR] VN = [self.USER_NN] for i in range(self.MANYOPS_COUNT): - self.failUnlessEqual(xattr.list(fh), VL) - self.failUnlessEqual(xattr.list(fh, namespace=NS_USER), VN) + self.assertEqual(xattr.list(fh), VL) + self.assertEqual(xattr.list(fh, namespace=NS_USER), VN) for i in range(self.MANYOPS_COUNT): - self.failUnlessEqual(xattr.get(fh, self.USER_ATTR), - self.USER_VAL) - self.failUnlessEqual(xattr.get(fh, self.USER_NN, - namespace=NS_USER), - self.USER_VAL) + self.assertEqual(xattr.get(fh, self.USER_ATTR), self.USER_VAL) + self.assertEqual(xattr.get(fh, self.USER_NN, namespace=NS_USER), + self.USER_VAL) for i in range(self.MANYOPS_COUNT): - self.failUnlessEqual(xattr.get_all(fh), - [(self.USER_ATTR, self.USER_VAL)]) - self.failUnlessEqual(xattr.get_all(fh, namespace=NS_USER), - [(self.USER_NN, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fh), + [(self.USER_ATTR, self.USER_VAL)]) + self.assertEqual(xattr.get_all(fh, namespace=NS_USER), + [(self.USER_NN, self.USER_VAL)]) if __name__ == "__main__": unittest.main() -- 2.39.2 From 0125c3983f317cfe9e45d0ad30e93d24cee02c10 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 15 May 2012 21:24:04 +0200 Subject: [PATCH 16/16] Rework parsing of the namespace argument In Python 3, we cannot accept (easily) bytes or None, so we have to change how we accept the namespace argument. Previously, if the argument was not passed or it was None, it was considered missing. Since the None option is no longer possible, we change it so that if not passed or passed as an empty string, it is considered missing. This changes the behaviour somewhat, but I hope that empty namespaces are not used (that's what I understand from reading various pages on the internet). --- xattr.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/xattr.c b/xattr.c index c1bd080..b8f77cd 100644 --- a/xattr.c +++ b/xattr.c @@ -34,7 +34,9 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define IS_PY3K +#define BYTES_CHAR "y" #else +#define BYTES_CHAR "z" #define PyBytes_Check PyString_Check #define PyBytes_AS_STRING PyString_AS_STRING #define PyBytes_FromStringAndSize PyString_FromStringAndSize @@ -113,7 +115,7 @@ static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) { fully-qualified name */ static int merge_ns(const char *ns, const char *name, const char **result, char **buf) { - if(ns != NULL) { + if(ns != NULL && *ns != '\0') { int cnt; size_t new_size = strlen(ns) + 1 + strlen(name) + 1; if((*buf = PyMem_Malloc(new_size)) == NULL) { @@ -308,7 +310,7 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL}; /* Parse the arguments */ - if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist, &myarg, NULL, &attrname, &nofollow, &ns)) return NULL; if(convertObj(myarg, &tgt, nofollow) < 0) { @@ -408,7 +410,7 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) static char *kwlist[] = {"item", "nofollow", "namespace", NULL}; /* Parse the arguments */ - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist, &myarg, &nofollow, &ns)) return NULL; if(convertObj(myarg, &tgt, nofollow) < 0) @@ -650,8 +652,8 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) "nofollow", "namespace", NULL}; /* Parse the arguments */ - if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|iiz", kwlist, - &myarg, NULL, &attrname, NULL, + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR, + kwlist, &myarg, NULL, &attrname, NULL, &buf, &bufsize, &flags, &nofollow, &ns)) return NULL; if(convertObj(myarg, &tgt, nofollow) < 0) { @@ -783,7 +785,7 @@ xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL}; /* Parse the arguments */ - if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|iz", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oet|i" BYTES_CHAR, kwlist, &myarg, NULL, &attrname, &nofollow, &ns)) return NULL; @@ -941,15 +943,15 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) ssize_t nalloc, nret; PyObject *myarg; PyObject *res; - char *ns = NULL; + const char *ns = NULL; Py_ssize_t nattrs; char *s; target_t tgt; static char *kwlist[] = {"item", "nofollow", "namespace", NULL}; /* Parse the arguments */ - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iet", kwlist, - &myarg, &nofollow, NULL, &ns)) + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i" BYTES_CHAR, kwlist, + &myarg, &nofollow, &ns)) return NULL; if(convertObj(myarg, &tgt, nofollow) < 0) { res = NULL; @@ -1006,7 +1008,6 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) freetgt: free_tgt(&tgt); freearg: - PyMem_Free(ns); /* Return the result */ return res; -- 2.39.2