mirror of
https://github.com/kdave/btrfs-progs
synced 2024-12-09 16:07:03 +00:00
23c01b3c1b
The C libbtrfsutil library isn't very useful for scripting, so we also want bindings for Python. Writing unit tests in Python is also much easier than doing so in C. Only Python 3 is supported; if someone really wants Python 2 support, they can write their own bindings. This commit is just the scaffolding. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
203 lines
5.8 KiB
C
203 lines
5.8 KiB
C
/*
|
|
* Copyright (C) 2018 Facebook
|
|
*
|
|
* This file is part of libbtrfsutil.
|
|
*
|
|
* libbtrfsutil is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* libbtrfsutil is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with libbtrfsutil. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "btrfsutilpy.h"
|
|
|
|
typedef struct {
|
|
PyOSErrorObject os_error;
|
|
PyObject *btrfsutilerror;
|
|
} BtrfsUtilError;
|
|
|
|
void SetFromBtrfsUtilError(enum btrfs_util_error err)
|
|
{
|
|
SetFromBtrfsUtilErrorWithPaths(err, NULL, NULL);
|
|
}
|
|
|
|
void SetFromBtrfsUtilErrorWithPath(enum btrfs_util_error err,
|
|
struct path_arg *path1)
|
|
{
|
|
SetFromBtrfsUtilErrorWithPaths(err, path1, NULL);
|
|
}
|
|
|
|
void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err,
|
|
struct path_arg *path1,
|
|
struct path_arg *path2)
|
|
{
|
|
PyObject *strobj, *args, *exc;
|
|
int i = errno;
|
|
const char *str1 = btrfs_util_strerror(err), *str2 = strerror(i);
|
|
|
|
if (str1 && str2 && strcmp(str1, str2) != 0) {
|
|
strobj = PyUnicode_FromFormat("%s: %s", str1, str2);
|
|
} else if (str1) {
|
|
strobj = PyUnicode_FromString(str1);
|
|
} else if (str2) {
|
|
strobj = PyUnicode_FromString(str2);
|
|
} else {
|
|
Py_INCREF(Py_None);
|
|
strobj = Py_None;
|
|
}
|
|
if (strobj == NULL)
|
|
return;
|
|
|
|
args = Py_BuildValue("iOOOOi", i, strobj,
|
|
path1 ? path1->object : Py_None, Py_None,
|
|
path2 ? path2->object : Py_None, (int)err);
|
|
Py_DECREF(strobj);
|
|
if (args == NULL)
|
|
return;
|
|
|
|
exc = PyObject_CallObject((PyObject *)&BtrfsUtilError_type, args);
|
|
Py_DECREF(args);
|
|
if (exc == NULL)
|
|
return;
|
|
|
|
PyErr_SetObject((PyObject *)&BtrfsUtilError_type, exc);
|
|
Py_DECREF(exc);
|
|
}
|
|
|
|
static int BtrfsUtilError_clear(BtrfsUtilError *self)
|
|
{
|
|
Py_CLEAR(self->btrfsutilerror);
|
|
return Py_TYPE(self)->tp_base->tp_clear((PyObject *)self);
|
|
}
|
|
|
|
static void BtrfsUtilError_dealloc(BtrfsUtilError *self)
|
|
{
|
|
PyObject_GC_UnTrack(self);
|
|
BtrfsUtilError_clear(self);
|
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
}
|
|
|
|
static int BtrfsUtilError_traverse(BtrfsUtilError *self, visitproc visit,
|
|
void *arg)
|
|
{
|
|
Py_VISIT(self->btrfsutilerror);
|
|
return Py_TYPE(self)->tp_base->tp_traverse((PyObject *)self, visit, arg);
|
|
}
|
|
|
|
static PyObject *BtrfsUtilError_new(PyTypeObject *type, PyObject *args,
|
|
PyObject *kwds)
|
|
{
|
|
BtrfsUtilError *self;
|
|
PyObject *oserror_args = args;
|
|
|
|
if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 6) {
|
|
oserror_args = PyTuple_GetSlice(args, 0, 5);
|
|
if (oserror_args == NULL)
|
|
return NULL;
|
|
}
|
|
|
|
self = (BtrfsUtilError *)type->tp_base->tp_new(type, oserror_args,
|
|
kwds);
|
|
if (oserror_args != args)
|
|
Py_DECREF(oserror_args);
|
|
if (self == NULL)
|
|
return NULL;
|
|
|
|
if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 6) {
|
|
self->btrfsutilerror = PyTuple_GET_ITEM(args, 5);
|
|
Py_INCREF(self->btrfsutilerror);
|
|
}
|
|
|
|
return (PyObject *)self;
|
|
}
|
|
|
|
static PyObject *BtrfsUtilError_str(BtrfsUtilError *self)
|
|
{
|
|
#define OR_NONE(x) ((x) ? (x) : Py_None)
|
|
if (self->btrfsutilerror) {
|
|
if (self->os_error.filename) {
|
|
if (self->os_error.filename2) {
|
|
return PyUnicode_FromFormat("[BtrfsUtilError %S Errno %S] %S: %R -> %R",
|
|
OR_NONE(self->btrfsutilerror),
|
|
OR_NONE(self->os_error.myerrno),
|
|
OR_NONE(self->os_error.strerror),
|
|
self->os_error.filename,
|
|
self->os_error.filename2);
|
|
} else {
|
|
return PyUnicode_FromFormat("[BtrfsUtilError %S Errno %S] %S: %R",
|
|
OR_NONE(self->btrfsutilerror),
|
|
OR_NONE(self->os_error.myerrno),
|
|
OR_NONE(self->os_error.strerror),
|
|
self->os_error.filename);
|
|
}
|
|
}
|
|
if (self->os_error.myerrno && self->os_error.strerror) {
|
|
return PyUnicode_FromFormat("[BtrfsUtilError %S Errno %S] %S",
|
|
self->btrfsutilerror,
|
|
self->os_error.myerrno,
|
|
self->os_error.strerror);
|
|
}
|
|
}
|
|
return Py_TYPE(self)->tp_base->tp_str((PyObject *)self);
|
|
#undef OR_NONE
|
|
}
|
|
|
|
static PyMemberDef BtrfsUtilError_members[] = {
|
|
{"btrfsutilerror", T_OBJECT,
|
|
offsetof(BtrfsUtilError, btrfsutilerror), 0,
|
|
"btrfsutil error code"},
|
|
{},
|
|
};
|
|
|
|
#define BtrfsUtilError_DOC \
|
|
"Btrfs operation error."
|
|
|
|
PyTypeObject BtrfsUtilError_type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"btrfsutil.BtrfsUtilError", /* tp_name */
|
|
sizeof(BtrfsUtilError), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)BtrfsUtilError_dealloc, /* tp_dealloc */
|
|
NULL, /* tp_print */
|
|
NULL, /* tp_getattr */
|
|
NULL, /* tp_setattr */
|
|
NULL, /* tp_as_async */
|
|
NULL, /* tp_repr */
|
|
NULL, /* tp_as_number */
|
|
NULL, /* tp_as_sequence */
|
|
NULL, /* tp_as_mapping */
|
|
NULL, /* tp_hash */
|
|
NULL, /* tp_call */
|
|
(reprfunc)BtrfsUtilError_str, /* tp_str */
|
|
NULL, /* tp_getattro */
|
|
NULL, /* tp_setattro */
|
|
NULL, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
|
BtrfsUtilError_DOC, /* tp_doc */
|
|
(traverseproc)BtrfsUtilError_traverse, /* tp_traverse */
|
|
(inquiry)BtrfsUtilError_clear, /* tp_clear */
|
|
NULL, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
NULL, /* tp_iter */
|
|
NULL, /* tp_iternext */
|
|
NULL, /* tp_methods */
|
|
BtrfsUtilError_members, /* tp_members */
|
|
NULL, /* tp_getset */
|
|
NULL, /* tp_base */
|
|
NULL, /* tp_dict */
|
|
NULL, /* tp_descr_get */
|
|
NULL, /* tp_descr_set */
|
|
offsetof(BtrfsUtilError, os_error.dict), /* tp_dictoffset */
|
|
NULL, /* tp_init */
|
|
NULL, /* tp_alloc */
|
|
BtrfsUtilError_new, /* tp_new */
|
|
};
|