mirror of
https://github.com/kdave/btrfs-progs
synced 2025-03-02 17:01:25 +00:00
libbtrfsutil: add Python bindings
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>
This commit is contained in:
parent
d51e8b128f
commit
23c01b3c1b
4
INSTALL
4
INSTALL
@ -41,6 +41,10 @@ To build from the released tarballs:
|
||||
$ make
|
||||
$ make install
|
||||
|
||||
To install the libbtrfsutil Python bindings:
|
||||
|
||||
$ make install_python
|
||||
|
||||
You may disable building some parts like documentation, btrfs-convert or
|
||||
backtrace support. See ./configure --help for more.
|
||||
|
||||
|
36
Makefile
36
Makefile
@ -154,8 +154,10 @@ endif
|
||||
|
||||
ifeq ($(BUILD_VERBOSE),1)
|
||||
Q =
|
||||
SETUP_PY_Q =
|
||||
else
|
||||
Q = @
|
||||
SETUP_PY_Q = -q
|
||||
endif
|
||||
|
||||
ifeq ("$(origin D)", "command line")
|
||||
@ -302,6 +304,9 @@ endif
|
||||
$($(subst -,_,btrfs-$(@:%/$(notdir $@)=%)-cflags))
|
||||
|
||||
all: $(progs) $(libs) $(lib_links) $(BUILDDIRS)
|
||||
ifeq ($(PYTHON_BINDINGS),1)
|
||||
all: libbtrfsutil_python
|
||||
endif
|
||||
$(SUBDIRS): $(BUILDDIRS)
|
||||
$(BUILDDIRS):
|
||||
@echo "Making all in $(patsubst build-%,%,$@)"
|
||||
@ -349,6 +354,16 @@ testsuite: btrfs-corrupt-block fssum
|
||||
@echo "Export tests as a package"
|
||||
$(Q)cd tests && ./export-testsuite.sh
|
||||
|
||||
ifeq ($(PYTHON_BINDINGS),1)
|
||||
test-libbtrfsutil: libbtrfsutil_python
|
||||
$(Q)cd libbtrfsutil/python; \
|
||||
LD_LIBRARY_PATH=../.. $(PYTHON) -m unittest discover -v tests
|
||||
|
||||
.PHONY: test-libbtrfsutil
|
||||
|
||||
test: test-libbtrfsutil
|
||||
endif
|
||||
|
||||
#
|
||||
# NOTE: For static compiles, you need to have all the required libs
|
||||
# static equivalent available
|
||||
@ -399,6 +414,15 @@ libbtrfsutil.so.$(libbtrfsutil_major) libbtrfsutil.so: libbtrfsutil.so.$(libbtrf
|
||||
@echo " [LN] $@"
|
||||
$(Q)$(LN_S) -f $< $@
|
||||
|
||||
ifeq ($(PYTHON_BINDINGS),1)
|
||||
libbtrfsutil_python: libbtrfsutil.so libbtrfsutil/btrfsutil.h
|
||||
@echo " [PY] libbtrfsutil"
|
||||
$(Q)cd libbtrfsutil/python; \
|
||||
CFLAGS= LDFLAGS= $(PYTHON) setup.py $(SETUP_PY_Q) build_ext -i build
|
||||
|
||||
.PHONY: libbtrfsutil_python
|
||||
endif
|
||||
|
||||
# keep intermediate files from the below implicit rules around
|
||||
.PRECIOUS: $(addsuffix .o,$(progs))
|
||||
|
||||
@ -582,6 +606,10 @@ clean: $(CLEANDIRS)
|
||||
$(libs) $(lib_links) \
|
||||
$(progs_static) $(progs_extra) \
|
||||
libbtrfsutil/*.o libbtrfsutil/*.o.d
|
||||
ifeq ($(PYTHON_BINDINGS),1)
|
||||
$(Q)cd libbtrfsutil/python; \
|
||||
$(PYTHON) setup.py $(SETUP_PY_Q) clean -a
|
||||
endif
|
||||
|
||||
clean-doc:
|
||||
@echo "Cleaning Documentation"
|
||||
@ -617,6 +645,14 @@ ifneq ($(udevdir),)
|
||||
$(INSTALL) -m644 $(udev_rules) $(DESTDIR)$(udevruledir)
|
||||
endif
|
||||
|
||||
ifeq ($(PYTHON_BINDINGS),1)
|
||||
install_python: libbtrfsutil_python
|
||||
$(Q)cd libbtrfsutil/python; \
|
||||
$(PYTHON) setup.py install --skip-build $(if $(DESTDIR),--root $(DESTDIR)) --prefix $(prefix)
|
||||
|
||||
.PHONY: install_python
|
||||
endif
|
||||
|
||||
install-static: $(progs_static) $(INSTALLDIRS)
|
||||
$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $(progs_static) $(DESTDIR)$(bindir)
|
||||
|
@ -14,6 +14,8 @@ DISABLE_BTRFSCONVERT = @DISABLE_BTRFSCONVERT@
|
||||
BTRFSCONVERT_EXT2 = @BTRFSCONVERT_EXT2@
|
||||
BTRFSCONVERT_REISERFS = @BTRFSCONVERT_REISERFS@
|
||||
BTRFSRESTORE_ZSTD = @BTRFSRESTORE_ZSTD@
|
||||
PYTHON_BINDINGS = @PYTHON_BINDINGS@
|
||||
PYTHON = @PYTHON@
|
||||
|
||||
SUBST_CFLAGS = @CFLAGS@
|
||||
SUBST_LDFLAGS = @LDFLAGS@
|
||||
|
15
configure.ac
15
configure.ac
@ -210,6 +210,19 @@ fi
|
||||
AS_IF([test "x$enable_zstd" = xyes], [BTRFSRESTORE_ZSTD=1], [BTRFSRESTORE_ZSTD=0])
|
||||
AC_SUBST(BTRFSRESTORE_ZSTD)
|
||||
|
||||
AC_ARG_ENABLE([python],
|
||||
AS_HELP_STRING([--disable-python], [do not build libbtrfsutil Python bindings]),
|
||||
[], [enable_python=yes]
|
||||
)
|
||||
|
||||
if test "x$enable_python" = xyes; then
|
||||
AM_PATH_PYTHON([3.4])
|
||||
fi
|
||||
|
||||
AS_IF([test "x$enable_python" = xyes], [PYTHON_BINDINGS=1], [PYTHON_BINDINGS=0])
|
||||
AC_SUBST(PYTHON_BINDINGS)
|
||||
AC_SUBST(PYTHON)
|
||||
|
||||
# udev v190 introduced the btrfs builtin and a udev rule to use it.
|
||||
# Our udev rule gives us the friendly dm names but isn't required (or valid)
|
||||
# on earlier releases.
|
||||
@ -265,6 +278,8 @@ AC_MSG_RESULT([
|
||||
backtrace support: ${enable_backtrace}
|
||||
btrfs-convert: ${enable_convert} ${convertfs:+($convertfs)}
|
||||
btrfs-restore zstd: ${enable_zstd}
|
||||
Python bindings: ${enable_python}
|
||||
Python interpreter: ${PYTHON}
|
||||
|
||||
Type 'make' to compile.
|
||||
])
|
||||
|
@ -3,7 +3,8 @@ libbtrfsutil
|
||||
|
||||
libbtrfsutil is a library for managing Btrfs filesystems. It is licensed under
|
||||
the LGPL. libbtrfsutil provides interfaces for a subset of the operations
|
||||
offered by the `btrfs` command line utility.
|
||||
offered by the `btrfs` command line utility. It also includes official Python
|
||||
bindings (Python 3 only).
|
||||
|
||||
Development
|
||||
-----------
|
||||
@ -33,3 +34,5 @@ A few guidelines:
|
||||
type specific to `libbtrfsutil`)
|
||||
* Preserve API and ABI compatability at all times (i.e., we don't want to bump
|
||||
the library major version if we don't have to)
|
||||
* Include Python bindings for all interfaces
|
||||
* Write tests for all interfaces
|
||||
|
7
libbtrfsutil/python/.gitignore
vendored
Normal file
7
libbtrfsutil/python/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
__pycache__
|
||||
*.pyc
|
||||
/btrfsutil.egg-info
|
||||
/btrfsutil*.so
|
||||
/build
|
||||
/constants.c
|
||||
/dist
|
57
libbtrfsutil/python/btrfsutilpy.h
Normal file
57
libbtrfsutil/python/btrfsutilpy.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef BTRFSUTILPY_H
|
||||
#define BTRFSUTILPY_H
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include <btrfsutil.h>
|
||||
|
||||
extern PyTypeObject BtrfsUtilError_type;
|
||||
|
||||
/*
|
||||
* Helpers for path arguments based on posixmodule.c in CPython.
|
||||
*/
|
||||
struct path_arg {
|
||||
bool allow_fd;
|
||||
char *path;
|
||||
int fd;
|
||||
Py_ssize_t length;
|
||||
PyObject *object;
|
||||
PyObject *cleanup;
|
||||
};
|
||||
int path_converter(PyObject *o, void *p);
|
||||
void path_cleanup(struct path_arg *path);
|
||||
|
||||
void SetFromBtrfsUtilError(enum btrfs_util_error err);
|
||||
void SetFromBtrfsUtilErrorWithPath(enum btrfs_util_error err,
|
||||
struct path_arg *path);
|
||||
void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err,
|
||||
struct path_arg *path1,
|
||||
struct path_arg *path2);
|
||||
|
||||
void add_module_constants(PyObject *m);
|
||||
|
||||
#endif /* BTRFSUTILPY_H */
|
202
libbtrfsutil/python/error.c
Normal file
202
libbtrfsutil/python/error.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 */
|
||||
};
|
166
libbtrfsutil/python/module.c
Normal file
166
libbtrfsutil/python/module.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
static int fd_converter(PyObject *o, void *p)
|
||||
{
|
||||
int *fd = p;
|
||||
long tmp;
|
||||
int overflow;
|
||||
|
||||
tmp = PyLong_AsLongAndOverflow(o, &overflow);
|
||||
if (tmp == -1 && PyErr_Occurred())
|
||||
return 0;
|
||||
if (overflow > 0 || tmp > INT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"fd is greater than maximum");
|
||||
return 0;
|
||||
}
|
||||
if (overflow < 0 || tmp < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "fd is negative");
|
||||
return 0;
|
||||
}
|
||||
*fd = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
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;
|
||||
path->object = o;
|
||||
return Py_CLEANUP_SUPPORTED;
|
||||
|
||||
err:
|
||||
Py_XDECREF(o);
|
||||
Py_XDECREF(bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void path_cleanup(struct path_arg *path)
|
||||
{
|
||||
Py_CLEAR(path->object);
|
||||
Py_CLEAR(path->cleanup);
|
||||
}
|
||||
|
||||
static PyMethodDef btrfsutil_methods[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static struct PyModuleDef btrfsutilmodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"btrfsutil",
|
||||
"Library for managing Btrfs filesystems",
|
||||
-1,
|
||||
btrfsutil_methods,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_btrfsutil(void)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
BtrfsUtilError_type.tp_base = (PyTypeObject *)PyExc_OSError;
|
||||
if (PyType_Ready(&BtrfsUtilError_type) < 0)
|
||||
return NULL;
|
||||
|
||||
m = PyModule_Create(&btrfsutilmodule);
|
||||
if (!m)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(&BtrfsUtilError_type);
|
||||
PyModule_AddObject(m, "BtrfsUtilError",
|
||||
(PyObject *)&BtrfsUtilError_type);
|
||||
|
||||
add_module_constants(m);
|
||||
|
||||
return m;
|
||||
}
|
108
libbtrfsutil/python/setup.py
Executable file
108
libbtrfsutil/python/setup.py
Executable file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# 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/>.
|
||||
|
||||
import re
|
||||
import os
|
||||
import os.path
|
||||
from setuptools import setup, Extension
|
||||
from setuptools.command.build_ext import build_ext
|
||||
import subprocess
|
||||
|
||||
|
||||
def get_version():
|
||||
with open('../btrfsutil.h', 'r') as f:
|
||||
btrfsutil_h = f.read()
|
||||
major = re.search(r'^#define BTRFS_UTIL_VERSION_MAJOR ([0-9]+)$',
|
||||
btrfsutil_h, flags=re.MULTILINE).group(1)
|
||||
minor = re.search(r'^#define BTRFS_UTIL_VERSION_MINOR ([0-9]+)$',
|
||||
btrfsutil_h, flags=re.MULTILINE).group(1)
|
||||
patch = re.search(r'^#define BTRFS_UTIL_VERSION_PATCH ([0-9]+)$',
|
||||
btrfsutil_h, flags=re.MULTILINE).group(1)
|
||||
return major + '.' + minor + '.' + patch
|
||||
|
||||
|
||||
def out_of_date(dependencies, target):
|
||||
dependency_mtimes = [os.path.getmtime(dependency) for dependency in dependencies]
|
||||
try:
|
||||
target_mtime = os.path.getmtime(target)
|
||||
except OSError:
|
||||
return True
|
||||
return any(dependency_mtime >= target_mtime for dependency_mtime in dependency_mtimes)
|
||||
|
||||
|
||||
def gen_constants():
|
||||
with open('../btrfsutil.h', 'r') as f:
|
||||
btrfsutil_h = f.read()
|
||||
|
||||
constants = re.findall(
|
||||
r'^\s*(BTRFS_UTIL_ERROR_[a-zA-Z0-9_]+)',
|
||||
btrfsutil_h, flags=re.MULTILINE)
|
||||
|
||||
with open('constants.c', 'w') as f:
|
||||
f.write("""\
|
||||
#include <btrfsutil.h>
|
||||
#include "btrfsutilpy.h"
|
||||
|
||||
void add_module_constants(PyObject *m)
|
||||
{
|
||||
""")
|
||||
for constant in constants:
|
||||
assert constant.startswith('BTRFS_UTIL_')
|
||||
name = constant[len('BTRFS_UTIL_'):]
|
||||
f.write('\tPyModule_AddIntConstant(m, "{}", {});\n'.format(name, constant))
|
||||
f.write("""\
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
class my_build_ext(build_ext):
|
||||
def run(self):
|
||||
if out_of_date(['../btrfsutil.h'], 'constants.c'):
|
||||
try:
|
||||
gen_constants()
|
||||
except Exception as e:
|
||||
try:
|
||||
os.remove('constants.c')
|
||||
except OSError:
|
||||
pass
|
||||
raise e
|
||||
super().run()
|
||||
|
||||
|
||||
module = Extension(
|
||||
name='btrfsutil',
|
||||
sources=[
|
||||
'constants.c',
|
||||
'error.c',
|
||||
'module.c',
|
||||
],
|
||||
include_dirs=['..'],
|
||||
library_dirs=['../..'],
|
||||
libraries=['btrfsutil'],
|
||||
)
|
||||
|
||||
setup(
|
||||
name='btrfsutil',
|
||||
version=get_version(),
|
||||
description='Library for managing Btrfs filesystems',
|
||||
url='https://github.com/kdave/btrfs-progs',
|
||||
license='LGPLv3',
|
||||
cmdclass={'build_ext': my_build_ext},
|
||||
ext_modules=[module],
|
||||
)
|
0
libbtrfsutil/python/tests/__init__.py
Normal file
0
libbtrfsutil/python/tests/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user