dcantrell / pyparted

Python bindings for GNU parted (libparted)
GNU General Public License v2.0
86 stars 43 forks source link

Strange disc.commit() behavior #73

Open marcel-behlau-elfin opened 4 years ago

marcel-behlau-elfin commented 4 years ago

Hi,

i observed a strange behavior of the disc.commit() function.

I would expect, that i have to perform a commit after applying all necessary operations.

For reproducing, i created a simple test application:

#!/usr/bin/env python
#
# Requirements:
# - python
# - python-dev
# - pyparted

import parted

# Create a disk image then attach it to a loopback device (e.g. /dev/loop0)
'''
dd if=/dev/zero of=disk.img bs=512 count=2097152
losetup -f disk.img
'''

alwaysCommit = False
commitBeforeExtended = True
lengthModifier = 0

devicePath = '/dev/loop0'
device = parted.getDevice(devicePath)
disk = parted.freshDisk(device, "msdos")

# create partition 1
geometry1 = parted.Geometry(device=device, start=1, length=parted.sizeToSectors(16, 'MiB', device.sectorSize))
filesystem1 = parted.FileSystem(type='fat32', geometry=geometry1)
partition1 = parted.Partition(disk=disk,
                              type=parted.PARTITION_NORMAL,
                              fs=filesystem1,
                              geometry=geometry1)
disk.addPartition(partition1, constraint=device.optimalAlignedConstraint)
if alwaysCommit:
    disk.commit()

# partition 2
geometry2 = parted.Geometry(device=device, start=partition1.geometry.end + 1,
        length=parted.sizeToSectors(512, 'MiB', device.sectorSize))
filesystem2 = parted.FileSystem(type='ext4', geometry=geometry2)
partition2 = parted.Partition(disk=disk,
                              type=parted.PARTITION_NORMAL,
                              fs=filesystem2,
                              geometry=geometry2)
disk.addPartition(partition2, constraint=device.optimalAlignedConstraint)
if alwaysCommit:
    disk.commit()

# partition 3
geometry3 = parted.Geometry(device=device, start=partition2.geometry.end + 1,
        length=parted.sizeToSectors(512, 'MiB', device.sectorSize))
filesystem3 = parted.FileSystem(type='ext4', geometry=geometry3)
partition3 = parted.Partition(disk=disk,
                              type=parted.PARTITION_NORMAL,
                              fs=filesystem3,
                              geometry=geometry3)
disk.addPartition(partition3, constraint=device.optimalAlignedConstraint)
if alwaysCommit or commitBeforeExtended:
    disk.commit()

# partition 4: Extended
geometry4 = parted.Geometry(device=device, start=partition3.geometry.end + 1,
                            end=device.length-lengthModifier)
partition4 = parted.Partition(disk=disk,
                              type=parted.PARTITION_EXTENDED,
                              geometry=geometry4)
disk.addPartition(partition4, constraint=device.optimalAlignedConstraint)
if alwaysCommit:
    disk.commit()

# partition 5: Logical
geometry5 = parted.Geometry(device=device, start=partition4.geometry.start + 1,
                            length=parted.sizeToSectors(256, 'MiB', device.sectorSize))
filesystem5 = parted.FileSystem(type='ext4', geometry=geometry5)
partition5 = parted.Partition(disk=disk,
                              type=parted.PARTITION_LOGICAL,
                              fs=filesystem5,
                              geometry=geometry5)
disk.addPartition(partition5, constraint=device.optimalAlignedConstraint)
if alwaysCommit:
    disk.commit()

# partition 6: Logical
geometry6 = parted.Geometry(device=device, start=partition5.geometry.end + 1,
                            length=parted.sizeToSectors(256, 'MiB', device.sectorSize))
filesystem6 = parted.FileSystem(type='ext4', geometry=geometry6)
partition6 = parted.Partition(disk=disk,
                              type=parted.PARTITION_LOGICAL,
                              fs=filesystem6,
                              geometry=geometry6)
disk.addPartition(partition6, constraint=device.optimalAlignedConstraint)

disk.commit()

My first thought was to use the options as follows, but the operation fails

alwaysCommit = False
commitBeforeExtended = False
lengthModifier = 0
[marcel@elfin-behlau pat]$ sudo ./test.py 
Traceback (most recent call last):
  File "./test.py", line 67, in <module>
    disk.addPartition(partition4, constraint=device.optimalAlignedConstraint)
  File "/usr/lib/python3.8/site-packages/parted/decorators.py", line 42, in new
    ret = fn(*args, **kwds)
  File "/usr/lib/python3.8/site-packages/parted/disk.py", line 244, in addPartition
    result = self.__disk.add_partition(partition.getPedPartition(),
_ped.PartitionException: Can't have a partition outside the disk!

This can be fixed by using an length modifier, but the "hack" fails with an assert.

alwaysCommit = False
commitBeforeExtended = False
lengthModifier = 1
Backtrace has 20 calls on stack:
  20: /usr/lib/libparted.so.2(ped_assert+0x46) [0x7fdc917e6476]
  19: /usr/lib/libparted.so.2(+0x259da) [0x7fdc917fd9da]
  18: /usr/lib/libparted.so.2(+0x1307a) [0x7fdc917eb07a]
  17: /usr/lib/libparted.so.2(ped_disk_add_partition+0x1ce) [0x7fdc917eb8fe]
  16: /usr/lib/python3.8/site-packages/_ped.cpython-38-x86_64-linux-gnu.so(py_ped_disk_add_partition+0xcc) [0x7fdc918c259c]
  15: /usr/lib/libpython3.8.so.1.0(+0x16eb07) [0x7fdc91dd1b07]
  14: /usr/lib/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x7de) [0x7fdc91e520ce]
  13: /usr/lib/libpython3.8.so.1.0(_PyEval_EvalCodeWithName+0x3cb) [0x7fdc91e3ee3b]
  12: /usr/lib/libpython3.8.so.1.0(_PyFunction_Vectorcall+0x39b) [0x7fdc91e4024b]
  11: /usr/lib/libpython3.8.so.1.0(PyObject_Call+0x2f8) [0x7fdc91d91418]
  10: /usr/lib/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x2413) [0x7fdc91e53d03]
  9: /usr/lib/libpython3.8.so.1.0(_PyEval_EvalCodeWithName+0x3cb) [0x7fdc91e3ee3b]
  8: /usr/lib/libpython3.8.so.1.0(+0x1dd892) [0x7fdc91e40892]
  7: /usr/lib/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x11ac) [0x7fdc91e52a9c]
  6: /usr/lib/libpython3.8.so.1.0(_PyEval_EvalCodeWithName+0x3cb) [0x7fdc91e3ee3b]
  5: /usr/lib/libpython3.8.so.1.0(PyEval_EvalCode+0x23) [0x7fdc91ec83d3]
  4: /usr/lib/libpython3.8.so.1.0(+0x265428) [0x7fdc91ec8428]
  3: /usr/lib/libpython3.8.so.1.0(+0x269623) [0x7fdc91ecc623]
  2: /usr/lib/libpython3.8.so.1.0(PyRun_FileExFlags+0x97) [0x7fdc91d673e7]
  1: /usr/lib/libpython3.8.so.1.0(PyRun_SimpleFileExFlags+0x390) [0x7fdc91d71f4a]
Aborted

Committing after adding an partition, results in strange partition size ( loop0p2 is only 255M instead of 512M, /dev/loop0p3 is 510M)

alwaysCommit = True
commitBeforeExtended = False
lengthModifier = 0
Disk /dev/loop0: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb80d081d

Device       Boot   Start     End Sectors  Size Id Type
/dev/loop0p1            1   32768   32768   16M  b W95 FAT32
/dev/loop0p2       522240 1044479  522240  255M 83 Linux
/dev/loop0p3      1044480 2088959 1044480  510M 83 Linux
/dev/loop0p4      2088960 8355839 6266880    3G  5 Extended
/dev/loop0p5      2091008 2611199  520192  254M 83 Linux
/dev/loop0p6      2613248 3133439  520192  254M 83 Linux

Only if i commit before creating the extended partion, everything works as expected:

alwaysCommit = False
commitBeforeExtended = False
lengthModifier = 1
Disk /dev/loop0: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x265e0c9c

Device       Boot   Start     End Sectors  Size Id Type
/dev/loop0p1            1   32768   32768   16M  b W95 FAT32
/dev/loop0p2        32769 1081344 1048576  512M 83 Linux
/dev/loop0p3      1081345 2129920 1048576  512M 83 Linux
/dev/loop0p4      2611200 8355839 5744640  2.8G  5 Extended
/dev/loop0p5      2613248 3133439  520192  254M 83 Linux
/dev/loop0p6      3135488 3655679  520192  254M 83 Linux