summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore153
-rw-r--r--context.c237
-rw-r--r--fdisk.c59
-rw-r--r--fdisk.h40
-rw-r--r--label.c147
-rw-r--r--partition.c150
-rw-r--r--setup.py10
7 files changed, 796 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..06109db
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,153 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff --git a/context.c b/context.c
new file mode 100644
index 0000000..8c0d3fa
--- /dev/null
+++ b/context.c
@@ -0,0 +1,237 @@
+#include "fdisk.h"
+
+static PyMemberDef Context_members[] = {
+ { NULL }
+};
+
+
+static void Context_dealloc(ContextObject *self)
+{
+ if (!self->cxt) /* if init fails */
+ return;
+
+ fdisk_unref_context(self->cxt);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static PyObject *Context_new(PyTypeObject *type,
+ PyObject *args __attribute__((unused)),
+ PyObject *kwds __attribute__((unused)))
+{
+ ContextObject *self = (ContextObject*) type->tp_alloc(type, 0);
+
+ if (self) {
+ self->cxt = NULL;
+ self->lb = NULL;
+ self->tb = NULL;
+ }
+
+ return (PyObject *)self;
+}
+
+#define Context_HELP "Context(device=None, details=None)"
+static int Context_init(ContextObject *self, PyObject *args, PyObject *kwds)
+{
+ char *device = NULL;
+ int details, rc = 0;
+ char *kwlist[] = {
+ "device", "details",
+ NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,
+ kwds, "|sp", kwlist,
+ &device, &details)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+
+ if (self->cxt)
+ fdisk_unref_context(self->cxt);
+
+ self->cxt = fdisk_new_context();
+ if (!self->cxt) {
+ PyErr_SetString(PyExc_MemoryError, "Couldn't allocate context");
+ return -1;
+ }
+
+ /* XXX: always readonly */
+ if (device && (rc = fdisk_assign_device(self->cxt, device, 1)))
+ return -1;
+ if (details && (rc = fdisk_enable_details(self->cxt, details)))
+ return -1;
+
+ fdisk_get_partitions(self->cxt, &self->tb);
+
+ return 0;
+}
+
+
+#define Context_assign_device_HELP "assign_device(device)\n\n" \
+ "Open the device, discovery topology, geometry, detect disklabel " \
+ "and switch the current label driver to reflect the probing result. "
+static PyObject *Context_assign_device(ContextObject *self, PyObject *args, PyObject *kwds)
+{
+ char *fname;
+
+ if (!PyArg_ParseTuple(args, "s", &fname)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return NULL;
+ }
+
+ /* Assert self->cxt */
+
+ /* XXX: readonly */
+ fdisk_assign_device(self->cxt, fname, 1);
+
+ self->lb = fdisk_get_label(self->cxt, NULL);
+ fdisk_get_partitions(self->cxt, &self->tb);
+
+ /* XXX: check rc*/
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#define Context_partition_to_string_HELP "partition_to_string(pa, field)\n\n" \
+ "Retrieve partition field using fdisk_partition_to_string." \
+ "Field constants are available as FDISK_LABEL_*"
+static PyObject *Context_partition_to_string(ContextObject *self, PyObject *args, PyObject *kwds)
+{
+ struct fdisk_partition *pa;
+ enum fdisk_fieldtype field;
+ PartitionObject *part;
+ PyObject *ret;
+ char *data;
+
+ if (!PyArg_ParseTuple(args, "O!i", &PartitionType, &part, &field)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return NULL;
+ }
+
+ pa = part->pa;
+
+ fdisk_partition_to_string(pa, self->cxt, field, &data);
+ ret = Py_BuildValue("s", data);
+ free(data);
+
+ return ret;
+}
+static PyMethodDef Context_methods[] = {
+ {"assign_device", (PyCFunction)Context_assign_device, METH_VARARGS, Context_assign_device_HELP},
+ {"partition_to_string", (PyCFunction)Context_partition_to_string, METH_VARARGS, Context_partition_to_string_HELP},
+ {NULL}
+};
+
+
+static PyObject *Context_get_nsectors(ContextObject *self)
+{
+ return PyLong_FromUnsignedLong(fdisk_get_nsectors(self->cxt));
+}
+static PyObject *Context_get_sector_size(ContextObject *self)
+{
+ return PyLong_FromUnsignedLong(fdisk_get_sector_size(self->cxt));
+}
+static PyObject *Context_get_devname(ContextObject *self)
+{
+ return PyObjectResultStr(fdisk_get_devname(self->cxt));
+}
+static PyObject *Context_get_label(ContextObject *self)
+{
+ struct fdisk_context *cxt = self->cxt;
+
+ if (fdisk_has_label(cxt)) {
+ return PyObjectResultLabel(fdisk_get_label(cxt, NULL));
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+static PyObject *Context_get_nparts(ContextObject *self)
+{
+ return PyLong_FromLong(fdisk_table_get_nents(self->tb));
+}
+static PyObject *Context_get_parts(ContextObject *self)
+{
+ PyObject *p, *list = PyList_New(0); /* XXX: null if failed*/
+ struct fdisk_partition *pa;
+ struct fdisk_iter *itr;
+ struct fdisk_table *tb;
+ /* char *data; */
+
+ tb = self->tb;
+ itr = fdisk_new_iter(FDISK_ITER_FORWARD);
+
+ while(fdisk_table_next_partition(tb, itr, &pa) == 0) {
+ /* const char *name = fdisk_partition_get_name(pa);*/
+ p = PyObjectResultPartition(pa);
+ PyList_Append(list, p);
+ /*free(data);*/
+ }
+
+ fdisk_free_iter(itr);
+
+ return list;
+}
+static PyGetSetDef Context_getseters[] = {
+ {"nsectors", (getter)Context_get_nsectors, NULL, "context number of sectors", NULL},
+ {"sector_size", (getter)Context_get_sector_size, NULL, "context sector size", NULL},
+ {"devname", (getter)Context_get_devname, NULL, "context devname", NULL},
+ {"label", (getter)Context_get_label, NULL, "context label type", NULL},
+ {"nparts", (getter)Context_get_nparts, NULL, "context label number of existing partitions", NULL},
+ {"parts", (getter)Context_get_parts, NULL, "context partitions", NULL},
+ {NULL}
+};
+
+static PyObject *Context_repr(ContextObject *self)
+{
+ return PyUnicode_FromFormat("<libfdisk.Context object at %p, details=%s>",
+ self, fdisk_is_details(self->cxt) ? "True" : "False");
+}
+
+PyTypeObject ContextType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libfdisk.Context", /*tp_name*/
+ sizeof(ContextObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Context_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ NULL, /*tp_getattr*/
+ NULL, /*tp_setattr*/
+ NULL, /*tp_compare*/
+ (reprfunc) Context_repr,
+ NULL, /*tp_as_number*/
+ NULL, /*tp_as_sequence*/
+ NULL, /*tp_as_mapping*/
+ NULL, /*tp_hash */
+ NULL, /*tp_call*/
+ NULL, /*tp_str*/
+ NULL, /*tp_getattro*/
+ NULL, /*tp_setattro*/
+ NULL, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Context_HELP, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ Context_methods, /* tp_methods */
+ Context_members, /* tp_members */
+ Context_getseters, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Context_init, /* tp_init */
+ NULL, /* tp_alloc */
+ Context_new, /* tp_new */
+};
+
+void Context_AddModuleObject(PyObject *mod)
+{
+ if (PyType_Ready(&ContextType) < 0)
+ return;
+
+ Py_INCREF(&ContextType);
+ PyModule_AddObject(mod, "Context", (PyObject *)&ContextType);
+}
diff --git a/fdisk.c b/fdisk.c
new file mode 100644
index 0000000..5be7b66
--- /dev/null
+++ b/fdisk.c
@@ -0,0 +1,59 @@
+#include <dirent.h>
+
+#include "fdisk.h"
+
+PyObject *PyObjectResultStr(const char *s)
+{
+ PyObject *result;
+ if (!s)
+ /* TODO: maybe lie about it and return "":
+ * which would allow for
+ * fs = libmount.Fs()
+ * fs.comment += "comment"
+ return Py_BuildValue("s", ""); */
+ Py_RETURN_NONE;
+ result = Py_BuildValue("s", s);
+ if (!result)
+ PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
+ return result;
+}
+
+static PyMethodDef FdiskMethods[] = {
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+
+static struct PyModuleDef fdiskmodule = {
+ PyModuleDef_HEAD_INIT,
+ "fdisk", /* name of module */
+ NULL, /* module documentation, may be NULL */
+ -1, /* size of per-interpreter state of the module,
+ or -1 if the module keeps state in global variables. */
+ FdiskMethods
+};
+
+PyMODINIT_FUNC
+PyInit_fdisk(void)
+{
+ PyObject *m = PyModule_Create(&fdiskmodule);
+
+ PyModule_AddIntConstant(m, "FDISK_SIZEUNIT_BYTES", FDISK_SIZEUNIT_BYTES);
+ PyModule_AddIntConstant(m, "FDISK_SIZEUNIT_HUMAN", FDISK_SIZEUNIT_HUMAN);
+
+ PyModule_AddIntConstant(m, "FDISK_FIELD_DEVICE", FDISK_FIELD_DEVICE);
+ PyModule_AddIntConstant(m, "FDISK_FIELD_SIZE", FDISK_FIELD_SIZE);
+ PyModule_AddIntConstant(m, "FDISK_FIELD_TYPE", FDISK_FIELD_TYPE);
+ PyModule_AddIntConstant(m, "FDISK_FIELD_TYPEID", FDISK_FIELD_TYPEID);
+ PyModule_AddIntConstant(m, "FDISK_FIELD_FSTYPE", FDISK_FIELD_FSTYPE);
+
+ PyModule_AddIntConstant(m, "FDISK_DISKLABEL_DOS", FDISK_DISKLABEL_DOS);
+ PyModule_AddIntConstant(m, "FDISK_DISKLABEL_GPT", FDISK_DISKLABEL_GPT);
+ PyModule_AddIntConstant(m, "FDISK_ITER_FORWARD", FDISK_ITER_FORWARD);
+ PyModule_AddIntConstant(m, "FDISK_ITER_BACKWARD", FDISK_ITER_BACKWARD);
+
+ Context_AddModuleObject(m);
+ Label_AddModuleObject(m);
+
+
+ return m;
+}
diff --git a/fdisk.h b/fdisk.h
new file mode 100644
index 0000000..768a832
--- /dev/null
+++ b/fdisk.h
@@ -0,0 +1,40 @@
+#ifndef UTIL_LINUX_PYLIBFDISK_H
+#define UTIL_LINUX_PYLIBFDISK_H
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <structmember.h>
+
+#include <libfdisk/libfdisk.h>
+
+#define CONSTRUCT_ERR "Error during object construction"
+#define ARG_ERR "Invalid number or type of arguments"
+
+typedef struct {
+ PyObject_HEAD
+ struct fdisk_context *cxt;
+ struct fdisk_label *lb;
+ struct fdisk_table *tb;
+} ContextObject;
+
+typedef struct {
+ PyObject_HEAD
+ struct fdisk_label *lb;
+} LabelObject;
+
+typedef struct {
+ PyObject_HEAD
+ struct fdisk_partition *pa;
+} PartitionObject;
+
+extern PyTypeObject ContextType;
+extern PyTypeObject PartitionType;
+
+extern void Context_AddModuleObject(PyObject *mod);
+extern void Label_AddModuleObject(PyObject *mod);
+
+extern PyObject *PyObjectResultStr(const char *s);
+extern PyObject *PyObjectResultLabel(struct fdisk_label *lb);
+extern PyObject *PyObjectResultPartition(struct fdisk_partition *pa);
+
+#endif
diff --git a/label.c b/label.c
new file mode 100644
index 0000000..c41f59b
--- /dev/null
+++ b/label.c
@@ -0,0 +1,147 @@
+#include "fdisk.h"
+
+
+static PyMemberDef Label_members[] = {
+ { NULL }
+};
+
+
+static void Label_dealloc(LabelObject *self)
+{
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static PyObject *Label_new(PyTypeObject *type,
+ PyObject *args __attribute__((unused)),
+ PyObject *kwds __attribute__((unused)))
+{
+ LabelObject *self = (LabelObject*) type->tp_alloc(type, 0);
+
+ if (self) {
+ self->lb = NULL;
+ }
+
+ return (PyObject *)self;
+}
+
+#define Label_HELP "Label(context=None)"
+static int Label_init(LabelObject *self, PyObject *args, PyObject *kwds)
+{
+ ContextObject *cxt = NULL;
+ struct fdisk_label *lb;
+ char *kwlist[] = {
+ "context",
+ NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,
+ kwds, "|O!", kwlist,
+ &ContextType, &cxt)) {
+ PyErr_SetString(PyExc_TypeError, "Error");
+ return -1;
+ }
+
+ if (cxt && (lb = fdisk_get_label(cxt->cxt, NULL))) {
+ self->lb = lb;
+ }
+
+ return 0;
+}
+
+
+static PyMethodDef Label_methods[] = {
+ {NULL}
+};
+
+
+static PyObject *Label_get_type(LabelObject *self)
+{
+ return PyLong_FromLong(fdisk_label_get_type(self->lb));
+}
+static PyObject *Label_get_name(LabelObject *self)
+{
+ return PyObjectResultStr(fdisk_label_get_name(self->lb));
+}
+static PyGetSetDef Label_getseters[] = {
+ {"type", (getter)Label_get_type, NULL, "label type", NULL},
+ {"name", (getter)Label_get_name, NULL, "label name", NULL},
+ {NULL}
+};
+
+static PyObject *Label_repr(LabelObject *self)
+{
+ return PyUnicode_FromFormat("<libfdisk.Label object at %p, name=%s>",
+ self, fdisk_label_get_name(self->lb));
+}
+
+PyTypeObject LabelType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libfdisk.Label", /*tp_name*/
+ sizeof(LabelObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Label_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ NULL, /*tp_getattr*/
+ NULL, /*tp_setattr*/
+ NULL, /*tp_compare*/
+ (reprfunc) Label_repr,
+ NULL, /*tp_as_number*/
+ NULL, /*tp_as_sequence*/
+ NULL, /*tp_as_mapping*/
+ NULL, /*tp_hash */
+ NULL, /*tp_call*/
+ NULL, /*tp_str*/
+ NULL, /*tp_getattro*/
+ NULL, /*tp_setattro*/
+ NULL, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Label_HELP, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ Label_methods, /* tp_methods */
+ Label_members, /* tp_members */
+ Label_getseters, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Label_init, /* tp_init */
+ NULL, /* tp_alloc */
+ Label_new, /* tp_new */
+};
+
+PyObject *PyObjectResultLabel(struct fdisk_label *lb)
+{
+ LabelObject *result;
+
+ if (!lb) {
+ PyErr_SetString(PyExc_AssertionError, "lb assert failed");
+ return NULL;
+ }
+
+
+ result = PyObject_New(LabelObject, &LabelType);
+ if (!result) {
+ PyErr_SetString(PyExc_MemoryError, "Couldn't allocate Label object");
+ return NULL;
+ }
+
+ /* Py_INCREF(result); */
+
+ result->lb = lb;
+ return (PyObject *) result;
+}
+
+void Label_AddModuleObject(PyObject *mod)
+{
+ if (PyType_Ready(&LabelType) < 0)
+ return;
+
+ Py_INCREF(&LabelType);
+ PyModule_AddObject(mod, "Label", (PyObject *)&LabelType);
+}
diff --git a/partition.c b/partition.c
new file mode 100644
index 0000000..48f410a
--- /dev/null
+++ b/partition.c
@@ -0,0 +1,150 @@
+#include "fdisk.h"
+
+
+static PyMemberDef Partition_members[] = {
+ { NULL }
+};
+
+
+static void Partition_dealloc(PartitionObject *self)
+{
+ if (self->pa)
+ fdisk_unref_partition(self->pa);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static PyObject *Partition_new(PyTypeObject *type,
+ PyObject *args __attribute__((unused)),
+ PyObject *kwds __attribute__((unused)))
+{
+ PartitionObject *self = (PartitionObject*) type->tp_alloc(type, 0);
+
+ if (self)
+ self->pa = NULL;
+
+ return (PyObject *)self;
+}
+
+#define Partition_HELP "Partition()"
+static int Partition_init(PartitionObject *self, PyObject *args, PyObject *kwds)
+{
+ /*
+ char *kwlist[] = {
+ "context",
+ NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,
+ kwds, "|O!", kwlist,
+ &ContextType, &cxt)) {
+ PyErr_SetString(PyExc_TypeError, "Error");
+ return -1;
+ }
+ */
+
+ self->pa = fdisk_new_partition();
+
+ return 0;
+}
+
+
+static PyMethodDef Partition_methods[] = {
+ {NULL}
+};
+
+
+static PyObject *Partition_get_partno(PartitionObject *self)
+{
+ if (fdisk_partition_has_partno(self->pa)) {
+ return PyLong_FromSize_t(fdisk_partition_get_partno(self->pa));
+ }
+ // Py_RETURN_NONE;
+ return Py_BuildValue("%d", -1);
+}
+static PyObject *Partition_get_size(PartitionObject *self)
+{
+ if (fdisk_partition_has_size(self->pa)) {
+ return PyLong_FromUnsignedLongLong(fdisk_partition_get_size(self->pa));
+ }
+ Py_RETURN_NONE;
+}
+static PyGetSetDef Partition_getseters[] = {
+ {"partno", (getter)Partition_get_partno, NULL, "partition number", NULL},
+ {"size", (getter)Partition_get_size, NULL, "number of sectors", NULL},
+ {NULL}
+};
+
+static PyObject *Partition_repr(PartitionObject *self)
+{
+ return PyUnicode_FromFormat("<libfdisk.Partition object at %p>",
+ self);
+}
+
+PyTypeObject PartitionType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libfdisk.Partition", /*tp_name*/
+ sizeof(PartitionObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Partition_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ NULL, /*tp_getattr*/
+ NULL, /*tp_setattr*/
+ NULL, /*tp_compare*/
+ (reprfunc) Partition_repr,
+ NULL, /*tp_as_number*/
+ NULL, /*tp_as_sequence*/
+ NULL, /*tp_as_mapping*/
+ NULL, /*tp_hash */
+ NULL, /*tp_call*/
+ NULL, /*tp_str*/
+ NULL, /*tp_getattro*/
+ NULL, /*tp_setattro*/
+ NULL, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Partition_HELP, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ Partition_methods, /* tp_methods */
+ Partition_members, /* tp_members */
+ Partition_getseters, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Partition_init, /* tp_init */
+ NULL, /* tp_alloc */
+ Partition_new, /* tp_new */
+};
+
+PyObject *PyObjectResultPartition(struct fdisk_partition *pa)
+{
+ PartitionObject *result;
+
+ if (!pa) {
+ PyErr_SetString(PyExc_AssertionError, "pa assert failed");
+ return NULL;
+ }
+
+ result = PyObject_New(PartitionObject, &PartitionType);
+ if (!result) {
+ PyErr_SetString(PyExc_MemoryError, "Couldn't allocate Partition object");
+ return NULL;
+ }
+
+ result->pa = pa;
+ return (PyObject *) result;
+}
+
+void Partition_AddModuleObject(PyObject *mod)
+{
+ if (PyType_Ready(&PartitionType) < 0)
+ return;
+
+ Py_INCREF(&PartitionType);
+ PyModule_AddObject(mod, "Partition", (PyObject *)&PartitionType);
+}
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..aed3664
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,10 @@
+from setuptools import setup, Extension
+
+libfdisk = Extension('fdisk',
+ libraries = ['fdisk'],
+ sources = ['fdisk.c', 'context.c', 'label.c', 'partition.c'])
+
+setup (name = 'libfdisk',
+ version = '1.0',
+ description = 'Python bindings for libfdisk',
+ ext_modules = [libfdisk])