libbtrfsutil: python: fix build on Python 3.13

Python 3.13, currently in beta, removed the internal
_PyObject_LookupSpecial function. The libbtrfsutil Python bindings use
it in the path_converter() function because it was based on internal
path_converter() function in CPython [1]. This is causing build failures
on Fedora Rawhide [2] and Gentoo [3]. Replace path_converter() with a
version that only uses public functions based on the one in drgn [4].

1: d9efa45d74/Modules/posixmodule.c (L1253)
2: https://bugzilla.redhat.com/show_bug.cgi?id=2245650
3: https://github.com/kdave/btrfs-progs/issues/838
4: 9ad29fd864/libdrgn/python/util.c (L81)

Issue: #838
Reported-by: Neal Gompa <neal@gompa.dev>
Reported-by: Sam James <sam@gentoo.org>
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Omar Sandoval 2024-07-25 16:28:35 -07:00 committed by David Sterba
parent c5ee9301c6
commit d0ab8f55a5
2 changed files with 32 additions and 72 deletions

View File

@ -40,16 +40,13 @@ extern PyTypeObject SubvolumeInfo_type;
extern PyTypeObject SubvolumeIterator_type;
extern PyTypeObject QgroupInherit_type;
/*
* Helpers for path arguments based on posixmodule.c in CPython.
*/
struct path_arg {
bool allow_fd;
char *path;
int fd;
char *path;
Py_ssize_t length;
PyObject *object;
PyObject *cleanup;
PyObject *bytes;
};
int path_converter(PyObject *o, void *p);
void path_cleanup(struct path_arg *path);

View File

@ -44,85 +44,48 @@ static int fd_converter(PyObject *o, void *p)
int path_converter(PyObject *o, void *p)
{
struct path_arg *path = p;
int is_index, is_bytes, is_unicode;
PyObject *bytes = NULL;
Py_ssize_t length = 0;
char *tmp;
if (o == NULL) {
path_cleanup(p);
return 1;
}
path->object = path->cleanup = NULL;
Py_INCREF(o);
path->fd = -1;
path->path = NULL;
path->length = 0;
path->bytes = NULL;
if (path->allow_fd && PyIndex_Check(o)) {
PyObject *fd_obj;
int overflow;
long fd;
is_index = path->allow_fd && PyIndex_Check(o);
is_bytes = PyBytes_Check(o);
is_unicode = PyUnicode_Check(o);
if (!is_index && !is_bytes && !is_unicode) {
_Py_IDENTIFIER(__fspath__);
PyObject *func;
func = _PyObject_LookupSpecial(o, &PyId___fspath__);
if (func == NULL)
goto err_format;
Py_DECREF(o);
o = PyObject_CallFunctionObjArgs(func, NULL);
Py_DECREF(func);
if (o == NULL)
fd_obj = PyNumber_Index(o);
if (!fd_obj)
return 0;
is_bytes = PyBytes_Check(o);
is_unicode = PyUnicode_Check(o);
}
if (is_unicode) {
if (!PyUnicode_FSConverter(o, &bytes))
goto err;
} else if (is_bytes) {
bytes = o;
Py_INCREF(bytes);
} else if (is_index) {
if (!fd_converter(o, &path->fd))
goto err;
path->path = NULL;
goto out;
fd = PyLong_AsLongAndOverflow(fd_obj, &overflow);
Py_DECREF(fd_obj);
if (fd == -1 && PyErr_Occurred())
return 0;
if (overflow > 0 || fd > INT_MAX) {
PyErr_SetString(PyExc_OverflowError, "fd is greater than maximum");
return 0;
}
if (fd < 0) {
PyErr_SetString(PyExc_ValueError, "fd is negative");
return 0;
}
path->fd = fd;
} else {
err_format:
PyErr_Format(PyExc_TypeError, "expected %s, not %s",
path->allow_fd ? "string, bytes, os.PathLike, or integer" :
"string, bytes, or os.PathLike",
Py_TYPE(o)->tp_name);
goto err;
if (!PyUnicode_FSConverter(o, &path->bytes)) {
path->object = path->bytes = NULL;
return 0;
}
path->path = PyBytes_AS_STRING(path->bytes);
path->length = PyBytes_GET_SIZE(path->bytes);
}
length = PyBytes_GET_SIZE(bytes);
tmp = PyBytes_AS_STRING(bytes);
if ((size_t)length != strlen(tmp)) {
PyErr_SetString(PyExc_TypeError,
"path has embedded nul character");
goto err;
}
path->path = tmp;
if (bytes == o)
Py_DECREF(bytes);
else
path->cleanup = bytes;
path->fd = -1;
out:
path->length = length;
Py_INCREF(o);
path->object = o;
return Py_CLEANUP_SUPPORTED;
err:
Py_XDECREF(o);
Py_XDECREF(bytes);
return 0;
}
PyObject *list_from_uint64_array(const uint64_t *arr, size_t n)
@ -150,8 +113,8 @@ PyObject *list_from_uint64_array(const uint64_t *arr, size_t n)
void path_cleanup(struct path_arg *path)
{
Py_CLEAR(path->bytes);
Py_CLEAR(path->object);
Py_CLEAR(path->cleanup);
}
static PyMethodDef btrfsutil_methods[] = {