/* * 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 2.1 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 . */ #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) .tp_name = "btrfsutil.BtrfsUtilError", .tp_basicsize = sizeof(BtrfsUtilError), .tp_dealloc = (destructor)BtrfsUtilError_dealloc, .tp_str = (reprfunc)BtrfsUtilError_str, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, .tp_doc = BtrfsUtilError_DOC, .tp_traverse = (traverseproc)BtrfsUtilError_traverse, .tp_clear = (inquiry)BtrfsUtilError_clear, .tp_members = BtrfsUtilError_members, .tp_dictoffset = offsetof(BtrfsUtilError, os_error.dict), .tp_new = BtrfsUtilError_new, };