From 45d93f4506ff70bcc151b0dc618e37e5da947199 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Fri, 13 May 2016 23:17:52 +0200 Subject: [PATCH] Imported Upstream version 0.5.5 --- MANIFEST.in | 2 +- Makefile | 2 +- NEWS | 36 ++++++ PKG-INFO | 2 +- README => README.rst | 2 +- doc/conf.py | 4 +- doc/index.rst | 2 +- pyxattr.egg-info/PKG-INFO | 2 +- pyxattr.egg-info/SOURCES.txt | 2 +- setup.py | 2 +- xattr.c | 207 +++++++++++++++++++++-------------- 11 files changed, 173 insertions(+), 90 deletions(-) rename README => README.rst (96%) diff --git a/MANIFEST.in b/MANIFEST.in index 9c2be4b..6c709af 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,6 @@ include COPYING include NEWS -include README +include README.rst include Makefile include doc/conf.py include doc/*.rst diff --git a/Makefile b/Makefile index 5a66261..a41a077 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ DOCTREES = $(DOCDIR)/doctrees ALLSPHINXOPTS = -d $(DOCTREES) $(SPHINXOPTS) $(DOCDIR) MODNAME = xattr.so -RSTFILES = doc/index.rst doc/module.rst NEWS README doc/conf.py +RSTFILES = doc/index.rst doc/module.rst NEWS README.rst doc/conf.py all: doc test diff --git a/NEWS b/NEWS index 5dfdf0a..b4a099b 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,37 @@ News ==== +Version 0.5.5 +------------- + +*released Fri, 01 May 2015* + +Bugfix release: + +* fixes some more memory leaks when handling out-of-memory in get_all() + function +* improve error reporting when an attribute disappears after we asked + for its length but before we managed to read it +* fix int/size_t issues found by RedHat/Fedora, + https://bugzilla.redhat.com/show_bug.cgi?id=1127310; the fix is + different than their fix, but it should accomplish the same thing +* convert all code to only do explicit casts after checking boundaries, + making the code `-Wconversion`-clean (although that warning is not + enabled by default) + Version 0.5.4 ------------- +*released Thu, 30 Apr 2015* + Fix memory leaks on some of the error-handling paths of the `get()` function. Version 0.5.3 ------------- +*released Fri, 23 May 2014* + Small optimisations release: * ari edelkind contributed a speed-up optimisation for handling of files @@ -27,6 +49,8 @@ Small optimisations release: Version 0.5.2 ------------- +*released Thu, 03 Jan 2013* + Bug-fix release. Thanks to Michał Górny, it looked like the library had problem running under pypy, but actually there was a bug in the PyArg_ParseTuple use of et# (signed vs. unsigned, and lack of compiler @@ -36,6 +60,8 @@ CPython versions and PyPy (version 1.9). Version 0.5.1 ------------- +*released Wed, 16 May 2012* + Bug-fix release. Thanks to Dave Malcolm and his cpychecker tool, a number of significant bugs (refcount leaks and potential NULL-pointer dereferences) have been fixed. @@ -53,12 +79,16 @@ the documentation has been converted from epydoc-based to sphinx. Version 0.5 ----------- +*released Sun, 27 Dec 2009* + Implemented support for Python 3. This required a significant change to the C module, hence the new version number. Version 0.4 ----------- +*released Mon, 30 Jun 2008* + API ~~~ @@ -89,6 +119,8 @@ Unittest coverage was improved. Version 0.3 ----------- +*released Sun, 09 Mar 2008* + * changed licence from GPL to LGPL (3 or later) * changed listxattr return type from tuple to a list * developer-related: added unittests @@ -96,11 +128,15 @@ Version 0.3 Version 0.2.2 ------------- +*released Sun, 01 Jul 2007* + * fixed listing symlink xattrs Version 0.2.1 ------------- +*released Sat, 11 Feb 2006* + * fixed a bug when reading symlink EAs (you weren't able to do it, actually) * fixed a possible memory leak when the actual read of the EA diff --git a/PKG-INFO b/PKG-INFO index 58725ce..191a253 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyxattr -Version: 0.5.4 +Version: 0.5.5 Summary: Filesystem extended attributes for python Home-page: http://pyxattr.k1024.org/ Author: Iustin Pop diff --git a/README b/README.rst similarity index 96% rename from README rename to README.rst index bf1472c..4d6aa5b 100644 --- a/README +++ b/README.rst @@ -6,7 +6,7 @@ to the extended attributes for filesystem objects available in some operating systems. Downloads: go to http://pyxattr.k1024.org/downloads/. Latest -version is 0.5.4. The source repository is either at +version is 0.5.5. The source repository is either at http://git.k1024.org/pyxattr.git or at https://github.com/iustin/pyxattr. diff --git a/doc/conf.py b/doc/conf.py index 060ab2a..fd9d7c0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,9 +48,9 @@ copyright = u'2002, 2003, 2006, 2008, 2012, 2013, 2014, 2015, Iustin Pop' # built documents. # # The short X.Y version. -version = '0.5.4' +version = '0.5.5' # The full version, including alpha/beta/rc tags. -release = '0.5.4' +release = '0.5.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/index.rst b/doc/index.rst index e639155..6032182 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -2,7 +2,7 @@ Welcome to pyxattr's documentation! ====================================== -.. include:: ../README +.. include:: ../README.rst :start-line: 2 Contents diff --git a/pyxattr.egg-info/PKG-INFO b/pyxattr.egg-info/PKG-INFO index 58725ce..191a253 100644 --- a/pyxattr.egg-info/PKG-INFO +++ b/pyxattr.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyxattr -Version: 0.5.4 +Version: 0.5.5 Summary: Filesystem extended attributes for python Home-page: http://pyxattr.k1024.org/ Author: Iustin Pop diff --git a/pyxattr.egg-info/SOURCES.txt b/pyxattr.egg-info/SOURCES.txt index 51b72e6..55eaa50 100644 --- a/pyxattr.egg-info/SOURCES.txt +++ b/pyxattr.egg-info/SOURCES.txt @@ -2,7 +2,7 @@ COPYING MANIFEST.in Makefile NEWS -README +README.rst setup.cfg setup.py xattr.c diff --git a/setup.py b/setup.py index e9bca09..edcf5ae 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ except ImportError: long_desc = """This is a C extension module for Python which implements extended attributes manipulation. It is a wrapper on top of the attr C library - see attr(5).""" -version = "0.5.4" +version = "0.5.5" author = "Iustin Pop" author_email = "iustin@k1024.org" macros = [ diff --git a/xattr.c b/xattr.c index 7c59090..7173922 100644 --- a/xattr.c +++ b/xattr.c @@ -276,7 +276,8 @@ pygetxattr(PyObject *self, PyObject *args) int nofollow = 0; char *attrname = NULL; char *buf; - ssize_t nalloc, nret; + ssize_t nalloc_s, nret; + size_t nalloc; PyObject *res; /* Parse the arguments */ @@ -284,36 +285,38 @@ pygetxattr(PyObject *self, PyObject *args) return NULL; if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } /* Find out the needed size of the buffer */ - if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) { + if((nalloc_s = _get_obj(&tgt, attrname, NULL, 0)) == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freetgt; + goto free_tgt; } + nalloc = (size_t) nalloc_s; + /* Try to allocate the memory, using Python's allocator */ if((buf = PyMem_Malloc(nalloc)) == NULL) { res = PyErr_NoMemory(); - goto freetgt; + goto free_tgt; } /* Now retrieve the attribute value */ if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freebuf; + goto free_buf; } /* Create the string which will hold the result */ res = PyBytes_FromStringAndSize(buf, nret); - freebuf: + free_buf: /* Free the buffer, now it is no longer needed */ PyMem_Free(buf); - freetgt: + free_tgt: free_tgt(&tgt); - freearg: + free_arg: PyMem_Free(attrname); /* Return the result */ @@ -353,7 +356,8 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) const char *fullname; char *buf; const char *ns = NULL; - ssize_t nalloc, nret; + ssize_t nalloc_s, nret; + size_t nalloc; PyObject *res; static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL}; @@ -363,43 +367,45 @@ xattr_get(PyObject *self, PyObject *args, PyObject *keywds) return NULL; if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) { res = NULL; - goto freetgt; + goto free_tgt; } /* Find out the needed size of the buffer */ - if((nalloc = _get_obj(&tgt, fullname, NULL, 0)) == -1) { + if((nalloc_s = _get_obj(&tgt, fullname, NULL, 0)) == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freenamebuf; + goto free_name_buf; } + nalloc = (size_t) nalloc_s; + /* Try to allocate the memory, using Python's allocator */ if((buf = PyMem_Malloc(nalloc)) == NULL) { res = PyErr_NoMemory(); - goto freenamebuf; + goto free_name_buf; } /* Now retrieve the attribute value */ if((nret = _get_obj(&tgt, fullname, buf, nalloc)) == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freebuf; + goto free_buf; } /* Create the string which will hold the result */ res = PyBytes_FromStringAndSize(buf, nret); /* Free the buffers, they are no longer needed */ - freebuf: + free_buf: PyMem_Free(buf); - freenamebuf: + free_name_buf: PyMem_Free(namebuf); - freetgt: + free_tgt: free_tgt(&tgt); - freearg: + free_arg: PyMem_Free(attrname); /* Return the result */ @@ -450,9 +456,10 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) PyObject *myarg, *res; int nofollow=0; const char *ns = NULL; - char *buf_list, *buf_val; + char *buf_list, *buf_val, *buf_val_tmp; const char *s; - ssize_t nalloc, nlist, nval; + ssize_t nalloc_s, nlist, nval_s; + size_t nalloc, nval; PyObject *mylist; target_t tgt; static char *kwlist[] = {"item", "nofollow", "namespace", NULL}; @@ -467,22 +474,24 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) /* Compute first the list of attributes */ /* Find out the needed size of the buffer for the attribute list */ - nalloc = _list_obj(&tgt, NULL, 0); + nalloc_s = _list_obj(&tgt, NULL, 0); - if(nalloc == -1) { + if(nalloc_s == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freetgt; + goto free_tgt; } - if(nalloc == 0) { + if(nalloc_s == 0) { res = PyList_New(0); - goto freetgt; + goto free_tgt; } + nalloc = (size_t) nalloc_s; + /* Try to allocate the memory, using Python's allocator */ if((buf_list = PyMem_Malloc(nalloc)) == NULL) { res = PyErr_NoMemory(); - goto freetgt; + goto free_tgt; } /* Now retrieve the list of attributes */ @@ -518,17 +527,27 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) /* Now retrieve the attribute value */ missing = 0; while(1) { - nval = _get_obj(&tgt, s, buf_val, nalloc); + nval_s = _get_obj(&tgt, s, buf_val, nalloc); - if(nval == -1) { + if(nval_s == -1) { if(errno == ERANGE) { - nval = _get_obj(&tgt, s, NULL, 0); - if((buf_val = PyMem_Realloc(buf_val, nval)) == NULL) { + ssize_t realloc_size_s = _get_obj(&tgt, s, NULL, 0); + /* ERANGE + proper size should not fail, but it + still can, so let's check first */ + if(realloc_size_s == -1) { + res = PyErr_SetFromErrno(PyExc_IOError); + Py_DECREF(mylist); + goto free_buf_val; + } + size_t realloc_size = (size_t) realloc_size_s; + if((buf_val_tmp = PyMem_Realloc(buf_val, realloc_size)) + == NULL) { res = PyErr_NoMemory(); Py_DECREF(mylist); - goto free_buf_list; + goto free_buf_val; } - nalloc = nval; + buf_val = buf_val_tmp; + nalloc = realloc_size; continue; } else if(errno == ENODATA || errno == ENOATTR) { /* this attribute has gone away since we queried @@ -540,7 +559,9 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) don't know how to handle nicely, so we abort */ Py_DECREF(mylist); res = PyErr_SetFromErrno(PyExc_IOError); - goto freebufval; + goto free_buf_val; + } else { + nval = (size_t) nval_s; } break; } @@ -554,7 +575,7 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) if (my_tuple == NULL) { Py_DECREF(mylist); res = NULL; - goto freebufval; + goto free_buf_val; } PyList_Append(mylist, my_tuple); Py_DECREF(my_tuple); @@ -563,13 +584,13 @@ get_all(PyObject *self, PyObject *args, PyObject *keywds) /* Successful exit */ res = mylist; - freebufval: + free_buf_val: PyMem_Free(buf_val); free_buf_list: PyMem_Free(buf_list); - freetgt: + free_tgt: free_tgt(&tgt); /* Return the result */ @@ -605,18 +626,28 @@ pysetxattr(PyObject *self, PyObject *args) int nofollow = 0; char *attrname = NULL; char *buf = NULL; - int bufsize; + Py_ssize_t bufsize_s; + size_t bufsize; int nret; int flags = 0; target_t tgt; /* Parse the arguments */ if (!PyArg_ParseTuple(args, "Oetet#|ii", &myarg, NULL, &attrname, - NULL, &buf, &bufsize, &flags, &nofollow)) + NULL, &buf, &bufsize_s, &flags, &nofollow)) return NULL; + + if (bufsize_s < 0) { + PyErr_SetString(PyExc_ValueError, + "negative value size?!"); + res = NULL; + goto free_arg; + } + bufsize = (size_t) bufsize_s; + if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } /* Set the attribute's value */ @@ -626,13 +657,13 @@ pysetxattr(PyObject *self, PyObject *args) if(nret == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freearg; + goto free_arg; } Py_INCREF(Py_None); res = Py_None; - freearg: + free_arg: PyMem_Free(attrname); PyMem_Free(buf); @@ -671,7 +702,8 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) int nofollow = 0; char *attrname = NULL; char *buf = NULL; - int bufsize; + Py_ssize_t bufsize_s; + size_t bufsize; int nret; int flags = 0; target_t tgt; @@ -684,16 +716,25 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) /* Parse the arguments */ if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oetet#|ii" BYTES_CHAR, kwlist, &myarg, NULL, &attrname, NULL, - &buf, &bufsize, &flags, &nofollow, &ns)) + &buf, &bufsize_s, &flags, &nofollow, &ns)) return NULL; + + if (bufsize_s < 0) { + PyErr_SetString(PyExc_ValueError, + "negative value size?!"); + res = NULL; + goto free_arg; + } + bufsize = (size_t) bufsize_s; + if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } if(merge_ns(ns, attrname, &full_name, &newname) < 0) { res = NULL; - goto freearg; + goto free_arg; } /* Set the attribute's value */ @@ -705,13 +746,13 @@ xattr_set(PyObject *self, PyObject *args, PyObject *keywds) if(nret == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freearg; + goto free_arg; } Py_INCREF(Py_None); res = Py_None; - freearg: + free_arg: PyMem_Free(attrname); PyMem_Free(buf); @@ -748,7 +789,7 @@ pyremovexattr(PyObject *self, PyObject *args) if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } /* Remove the attribute */ @@ -758,13 +799,13 @@ pyremovexattr(PyObject *self, PyObject *args) if(nret == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freearg; + goto free_arg; } Py_INCREF(Py_None); res = Py_None; - freearg: + free_arg: PyMem_Free(attrname); /* Return the result */ @@ -810,12 +851,12 @@ xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) { res = NULL; - goto freearg; + goto free_arg; } /* Remove the attribute */ @@ -827,13 +868,13 @@ xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) if(nret == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freearg; + goto free_arg; } Py_INCREF(Py_None); res = Py_None; - freearg: + free_arg: PyMem_Free(attrname); /* Return the result */ @@ -857,7 +898,8 @@ pylistxattr(PyObject *self, PyObject *args) { char *buf; int nofollow=0; - ssize_t nalloc, nret; + ssize_t nalloc_s, nret; + size_t nalloc; PyObject *myarg; PyObject *mylist; Py_ssize_t nattrs; @@ -871,26 +913,28 @@ pylistxattr(PyObject *self, PyObject *args) return NULL; /* Find out the needed size of the buffer */ - if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) { + if((nalloc_s = _list_obj(&tgt, NULL, 0)) == -1) { mylist = PyErr_SetFromErrno(PyExc_IOError); - goto freetgt; + goto free_tgt; } - if(nalloc == 0) { + if(nalloc_s == 0) { mylist = PyList_New(0); - goto freetgt; + goto free_tgt; } + nalloc = (size_t) nalloc_s; + /* Try to allocate the memory, using Python's allocator */ if((buf = PyMem_Malloc(nalloc)) == NULL) { mylist = PyErr_NoMemory(); - goto freetgt; + goto free_tgt; } /* Now retrieve the list of attributes */ if((nret = _list_obj(&tgt, buf, nalloc)) == -1) { mylist = PyErr_SetFromErrno(PyExc_IOError); - goto freebuf; + goto free_buf; } /* Compute the number of attributes in the list */ @@ -901,7 +945,7 @@ pylistxattr(PyObject *self, PyObject *args) /* Create the list which will hold the result */ mylist = PyList_New(nattrs); if(mylist == NULL) - goto freebuf; + goto free_buf; /* Create and insert the attributes as strings in the list */ for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { @@ -909,17 +953,17 @@ pylistxattr(PyObject *self, PyObject *args) if(item == NULL) { Py_DECREF(mylist); mylist = NULL; - goto freebuf; + goto free_buf; } PyList_SET_ITEM(mylist, nattrs, item); nattrs++; } - freebuf: + free_buf: /* Free the buffer, now it is no longer needed */ PyMem_Free(buf); - freetgt: + free_tgt: free_tgt(&tgt); /* Return the result */ @@ -957,7 +1001,8 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) { char *buf; int nofollow = 0; - ssize_t nalloc, nret; + ssize_t nalloc_s, nret; + size_t nalloc; PyObject *myarg; PyObject *res; const char *ns = NULL; @@ -972,30 +1017,32 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) return NULL; if(convert_obj(myarg, &tgt, nofollow) < 0) { res = NULL; - goto freearg; + goto free_arg; } /* Find out the needed size of the buffer */ - if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) { + if((nalloc_s = _list_obj(&tgt, NULL, 0)) == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freetgt; + goto free_tgt; } - if(nalloc == 0) { + if(nalloc_s == 0) { res = PyList_New(0); - goto freetgt; + goto free_tgt; } + nalloc = (size_t) nalloc_s; + /* Try to allocate the memory, using Python's allocator */ if((buf = PyMem_Malloc(nalloc)) == NULL) { res = PyErr_NoMemory(); - goto freetgt; + goto free_tgt; } /* Now retrieve the list of attributes */ if((nret = _list_obj(&tgt, buf, nalloc)) == -1) { res = PyErr_SetFromErrno(PyExc_IOError); - goto freebuf; + goto free_buf; } /* Compute the number of attributes in the list */ @@ -1006,7 +1053,7 @@ 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; + goto free_buf; /* Create and insert the attributes as strings in the list */ for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { @@ -1016,20 +1063,20 @@ xattr_list(PyObject *self, PyObject *args, PyObject *keywds) if(item == NULL) { Py_DECREF(res); res = NULL; - goto freebuf; + goto free_buf; } PyList_SET_ITEM(res, nattrs, item); nattrs++; } } - freebuf: + free_buf: /* Free the buffer, now it is no longer needed */ PyMem_Free(buf); - freetgt: + free_tgt: free_tgt(&tgt); - freearg: + free_arg: /* Return the result */ return res; -- 2.39.2