/* * Copyright (C) 2020 Red Hat, Inc. * * This library 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. * * This library 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 this library; if not, see . * */ #include "partitions.h" #include #define UNUSED __attribute__((unused)) /*********************** PARTLIST ***********************/ PyObject *Partlist_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { PartlistObject *self = (PartlistObject*) type->tp_alloc (type, 0); if (self) self->Parttable_object = NULL; return (PyObject *) self; } int Partlist_init (PartlistObject *self UNUSED, PyObject *args UNUSED, PyObject *kwargs UNUSED) { return 0; } void Partlist_dealloc (PartlistObject *self) { if (self->Parttable_object) Py_DECREF (self->Parttable_object); Py_TYPE (self)->tp_free ((PyObject *) self); } PyObject *_Partlist_get_partlist_object (blkid_probe probe) { PartlistObject *result = NULL; blkid_partlist partlist = NULL; if (!probe) { PyErr_SetString (PyExc_RuntimeError, "internal error"); return NULL; } partlist = blkid_probe_get_partitions (probe); if (!partlist) { PyErr_SetString (PyExc_RuntimeError, "Failed to get partitions"); return NULL; } result = PyObject_New (PartlistObject, &PartlistType); if (!result) { PyErr_SetString (PyExc_MemoryError, "Failed to create a new Partlist object"); return NULL; } Py_INCREF (result); result->partlist = partlist; result->Parttable_object = NULL; return (PyObject *) result; } PyDoc_STRVAR(Partlist_get_partition__doc__, "get_partition (number)\n\n" "Get partition by number.\n\n" "It's possible that the list of partitions is *empty*, but there is a valid partition table on the disk.\n" "This happen when on-disk details about partitions are unknown or the partition table is empty."); static PyObject *Partlist_get_partition (PartlistObject *self, PyObject *args, PyObject *kwargs) { char *kwlist[] = { "number", NULL }; int partnum = 0; int numof = 0; blkid_partition blkid_part = NULL; PartitionObject *result = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "i", kwlist, &partnum)) { return NULL; } numof = blkid_partlist_numof_partitions (self->partlist); if (numof < 0) { PyErr_SetString (PyExc_RuntimeError, "Failed to get number of partitions"); return NULL; } if (partnum > numof) { PyErr_Format (PyExc_RuntimeError, "Cannot get partition %d, partition table has only %d partitions", partnum, numof); return NULL; } blkid_part = blkid_partlist_get_partition (self->partlist, partnum); if (!blkid_part) { PyErr_Format (PyExc_RuntimeError, "Failed to get partition %d", partnum); return NULL; } result = PyObject_New (PartitionObject, &PartitionType); if (!result) { PyErr_SetString (PyExc_MemoryError, "Failed to create a new Partition object"); return NULL; } result->number = partnum; result->partition = blkid_part; result->Parttable_object = NULL; return (PyObject *) result; } #ifdef HAVE_BLKID_2_25 PyDoc_STRVAR(Partlist_get_partition_by_partno__doc__, "get_partition_by_partno(number)\n\n" "Get partition by partition number.\n\n" "This does not assume any order of partitions and correctly handles \"out of order\" " "partition tables. partition N is located after partition N+1 on the disk."); static PyObject *Partlist_get_partition_by_partno (PartlistObject *self, PyObject *args, PyObject *kwargs) { char *kwlist[] = { "number", NULL }; int partno = 0; blkid_partition blkid_part = NULL; PartitionObject *result = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "i", kwlist, &partno)) { return NULL; } blkid_part = blkid_partlist_get_partition_by_partno (self->partlist, partno); if (!blkid_part) { PyErr_Format (PyExc_RuntimeError, "Failed to get partition %d", partno); return NULL; } result = PyObject_New (PartitionObject, &PartitionType); if (!result) { PyErr_NoMemory (); return NULL; } result->number = partno; result->partition = blkid_part; result->Parttable_object = NULL; return (PyObject *) result; } #endif static int _Py_Dev_Converter (PyObject *obj, void *p) { #ifdef HAVE_LONG_LONG *((dev_t *)p) = PyLong_AsUnsignedLongLong (obj); #else *((dev_t *)p) = PyLong_AsUnsignedLong (obj); #endif if (PyErr_Occurred ()) return 0; return 1; } #ifdef HAVE_LONG_LONG #define _PyLong_FromDev PyLong_FromLongLong #else #define _PyLong_FromDev PyLong_FromLong #endif PyDoc_STRVAR(Partlist_devno_to_partition__doc__, "devno_to_partition (devno)\n\n" "Get partition by devno.\n"); static PyObject *Partlist_devno_to_partition (PartlistObject *self, PyObject *args, PyObject *kwargs) { dev_t devno = 0; char *kwlist[] = { "devno", NULL }; blkid_partition blkid_part = NULL; PartitionObject *result = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O&:devno_to_devname", kwlist, _Py_Dev_Converter, &devno)) return NULL; blkid_part = blkid_partlist_devno_to_partition (self->partlist, devno); if (!blkid_part) { PyErr_Format (PyExc_RuntimeError, "Failed to get partition %zu", devno); return NULL; } result = PyObject_New (PartitionObject, &PartitionType); if (!result) { PyErr_NoMemory (); return NULL; } result->number = blkid_partition_get_partno (blkid_part); result->partition = blkid_part; result->Parttable_object = NULL; return (PyObject *) result; } static PyMethodDef Partlist_methods[] = { {"get_partition", (PyCFunction)(void(*)(void)) Partlist_get_partition, METH_VARARGS|METH_KEYWORDS, Partlist_get_partition__doc__}, #ifdef HAVE_BLKID_2_25 {"get_partition_by_partno", (PyCFunction)(void(*)(void)) Partlist_get_partition_by_partno, METH_VARARGS|METH_KEYWORDS, Partlist_get_partition_by_partno__doc__}, #endif {"devno_to_partition", (PyCFunction)(void(*)(void)) Partlist_devno_to_partition, METH_VARARGS|METH_KEYWORDS, Partlist_devno_to_partition__doc__}, {NULL, NULL, 0, NULL}, }; static PyObject *Partlist_get_table (PartlistObject *self, PyObject *Py_UNUSED (ignored)) { if (self->Parttable_object) { Py_INCREF (self->Parttable_object); return self->Parttable_object; } self->Parttable_object = _Parttable_get_parttable_object (self->partlist); return self->Parttable_object; } static PyObject *Partlist_get_numof_partitions (PartlistObject *self, PyObject *Py_UNUSED (ignored)) { int ret = 0; ret = blkid_partlist_numof_partitions (self->partlist); if (ret < 0) { PyErr_SetString (PyExc_MemoryError, "Failed to get number of partitions"); return NULL; } return PyLong_FromLong (ret); } static PyGetSetDef Partlist_getseters[] = { {"table", (getter) Partlist_get_table, NULL, "binary interface for partition table on the device", NULL}, {"numof_partitions", (getter) Partlist_get_numof_partitions, NULL, "number of partitions in the list", NULL}, {NULL, NULL, NULL, NULL, NULL} }; PyTypeObject PartlistType = { PyVarObject_HEAD_INIT (NULL, 0) .tp_name = "blkid.Partlist", .tp_basicsize = sizeof (PartlistObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = Partlist_new, .tp_dealloc = (destructor) Partlist_dealloc, .tp_init = (initproc) Partlist_init, .tp_methods = Partlist_methods, .tp_getset = Partlist_getseters, }; /*********************** PARTTABLE ***********************/ PyObject *Parttable_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { ParttableObject *self = (ParttableObject*) type->tp_alloc (type, 0); return (PyObject *) self; } int Parttable_init (ParttableObject *self UNUSED, PyObject *args UNUSED, PyObject *kwargs UNUSED) { return 0; } void Parttable_dealloc (ParttableObject *self) { Py_TYPE (self)->tp_free ((PyObject *) self); } PyObject *_Parttable_get_parttable_object (blkid_partlist partlist) { ParttableObject *result = NULL; blkid_parttable table = NULL; if (!partlist) { PyErr_SetString(PyExc_RuntimeError, "internal error"); return NULL; } table = blkid_partlist_get_table (partlist); if (!table) { PyErr_SetString (PyExc_RuntimeError, "Failed to get partitions"); return NULL; } result = PyObject_New (ParttableObject, &ParttableType); if (!result) { PyErr_SetString (PyExc_MemoryError, "Failed to create a new Parttable object"); return NULL; } Py_INCREF (result); result->table = table; return (PyObject *) result; } PyDoc_STRVAR(Parttable_get_parent__doc__, "get_parent ()\n\n" "Parent for nested partition tables."); static PyObject *Parttable_get_parent (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { blkid_partition blkid_part = NULL; PartitionObject *result = NULL; blkid_part = blkid_parttable_get_parent (self->table); if (!blkid_part) Py_RETURN_NONE; result = PyObject_New (PartitionObject, &PartitionType); if (!result) { PyErr_SetString (PyExc_MemoryError, "Failed to create a new Partition object"); return NULL; } result->number = 0; result->partition = blkid_part; return (PyObject *) result; } static PyMethodDef Parttable_methods[] = { {"get_parent", (PyCFunction)(void(*)(void)) Parttable_get_parent, METH_NOARGS, Parttable_get_parent__doc__}, {NULL, NULL, 0, NULL}, }; static PyObject *Parrtable_get_type (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { const char *pttype = blkid_parttable_get_type (self->table); return PyUnicode_FromString (pttype); } static PyObject *Parrtable_get_id (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { const char *ptid = blkid_parttable_get_id (self->table); return PyUnicode_FromString (ptid); } static PyObject *Parrtable_get_offset (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { blkid_loff_t offset = blkid_parttable_get_offset (self->table); return PyLong_FromLongLong (offset); } static PyGetSetDef Parttable_getseters[] = { {"type", (getter) Parrtable_get_type, NULL, "partition table type (type name, e.g. 'dos', 'gpt', ...)", NULL}, {"id", (getter) Parrtable_get_id, NULL, "GPT disk UUID or DOS disk ID (in hex format)", NULL}, {"offset", (getter) Parrtable_get_offset, NULL, "position (in bytes) of the partition table", NULL}, {NULL, NULL, NULL, NULL, NULL} }; PyTypeObject ParttableType = { PyVarObject_HEAD_INIT (NULL, 0) .tp_name = "blkid.Parttable", .tp_basicsize = sizeof (ParttableObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = Parttable_new, .tp_dealloc = (destructor) Parttable_dealloc, .tp_init = (initproc) Parttable_init, .tp_methods = Parttable_methods, .tp_getset = Parttable_getseters, }; /*********************** PARTITION ***********************/ PyObject *Partition_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { PartitionObject *self = (PartitionObject*) type->tp_alloc (type, 0); if (self) self->Parttable_object = NULL; return (PyObject *) self; } int Partition_init (PartitionObject *self, PyObject *args, PyObject *kwargs) { char *kwlist[] = { "number", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "i", kwlist, &(self->number))) { return -1; } self->partition = NULL; return 0; } void Partition_dealloc (PartitionObject *self) { if (self->Parttable_object) Py_DECREF (self->Parttable_object); Py_TYPE (self)->tp_free ((PyObject *) self); } static PyObject *Partition_get_type (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { int type = blkid_partition_get_type (self->partition); return PyLong_FromLong (type); } static PyObject *Partition_get_type_string (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { const char *type = blkid_partition_get_type_string (self->partition); return PyUnicode_FromString (type); } static PyObject *Partition_get_uuid (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { const char *uuid = blkid_partition_get_uuid (self->partition); return PyUnicode_FromString (uuid); } static PyObject *Partition_get_is_extended (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { int extended = blkid_partition_is_extended (self->partition); if (extended == 1) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject *Partition_get_is_logical (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { int logical = blkid_partition_is_logical (self->partition); if (logical == 1) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject *Partition_get_is_primary (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { int primary = blkid_partition_is_primary (self->partition); if (primary == 1) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject *Partition_get_name (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { const char *name = blkid_partition_get_name (self->partition); return PyUnicode_FromString (name); } static PyObject *Partition_get_flags (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { unsigned long long flags = blkid_partition_get_flags (self->partition); return PyLong_FromUnsignedLongLong (flags); } static PyObject *Partition_get_partno (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { int partno = blkid_partition_get_partno (self->partition); return PyLong_FromLong (partno); } static PyObject *Partition_get_size (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { blkid_loff_t size = blkid_partition_get_size (self->partition); return PyLong_FromLongLong (size); } static PyObject *Partition_get_start (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { blkid_loff_t start = blkid_partition_get_start (self->partition); return PyLong_FromLongLong (start); } PyObject *_Partition_get_parttable_object (blkid_partition partition) { ParttableObject *result = NULL; blkid_parttable table = NULL; if (!partition) { PyErr_SetString(PyExc_RuntimeError, "internal error"); return NULL; } table = blkid_partition_get_table (partition); if (!table) { PyErr_SetString (PyExc_RuntimeError, "Failed to get partition table"); return NULL; } result = PyObject_New (ParttableObject, &ParttableType); if (!result) { PyErr_SetString (PyExc_MemoryError, "Failed to create a new Parttable object"); return NULL; } Py_INCREF (result); result->table = table; return (PyObject *) result; } static PyObject *Partition_get_table (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { if (self->Parttable_object) { Py_INCREF (self->Parttable_object); return self->Parttable_object; } self->Parttable_object = _Partition_get_parttable_object (self->partition); return self->Parttable_object; } static PyGetSetDef Partition_getseters[] = { {"type", (getter) Partition_get_type, NULL, "partition type", NULL}, {"type_string", (getter) Partition_get_type_string, NULL, "partition type string, note the type string is supported by a small subset of partition tables (e.g Mac and EFI GPT)", NULL}, {"uuid", (getter) Partition_get_uuid, NULL, "partition UUID string if supported by PT (e.g. GPT)", NULL}, {"is_extended", (getter) Partition_get_is_extended, NULL, "returns whether the partition is extendedor not ", NULL}, {"is_logical", (getter) Partition_get_is_logical, NULL, "returns whether the partition is logical or not", NULL}, {"is_primary", (getter) Partition_get_is_primary, NULL, "returns whether the partition is primary or not", NULL}, {"name", (getter) Partition_get_name, NULL, "partition name string if supported by PT (e.g. Mac)", NULL}, {"flags", (getter) Partition_get_flags, NULL, "partition flags (or attributes for gpt)", NULL}, {"partno", (getter) Partition_get_partno, NULL, "proposed partition number (e.g. 'N' from sda'N') or -1 in case of error", NULL}, {"size", (getter) Partition_get_size, NULL, "size of the partition (in 512-sectors)", NULL}, {"start", (getter) Partition_get_start, NULL, "start of the partition (in 512-sectors)", NULL}, {"table", (getter) Partition_get_table, NULL, "partition table object (usually the same for all partitions, except nested partition tables)", NULL}, {NULL, NULL, NULL, NULL, NULL} }; PyTypeObject PartitionType = { PyVarObject_HEAD_INIT (NULL, 0) .tp_name = "blkid.Partition", .tp_basicsize = sizeof (PartitionObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = Partition_new, .tp_dealloc = (destructor) Partition_dealloc, .tp_init = (initproc) Partition_init, .tp_getset = Partition_getseters, };