Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added all the good stuff, still a lot of tweaks need to be made. The …

…conversion file needs to be sorted out. You can add partitions and delete them as well as specifying the filesystem code blocks, type and name. By default it will snap partitions to the nearest boundaries intersecting sectors according to device constraint, you can also choose between minimal and optimal alignment. Missing all documentation.
  • Loading branch information...
commit 649318a1990b55afc6ca0404e2b0e2faf284237b 1 parent 29e5e76
@xzased authored
Showing with 544 additions and 0 deletions.
  1. +10 −0 __init__.py
  2. +248 −0 conversion.py
  3. +46 −0 device.py
  4. +240 −0 disk.py
View
10 __init__.py
@@ -0,0 +1,10 @@
+from ctypes.util import find_library
+from ctypes import *
+
+lib = find_library("parted")
+
+if not lib:
+ raise Exception("It's not a toomah!")
+
+parted = CDLL("/usr/local/lib/libparted.so.1.0.0")
+
View
248 conversion.py
@@ -0,0 +1,248 @@
+from ctypes import *
+from reparted import *
+
+# No enum data type in ctypes, just assign values.
+# PedDiskFlag
+PED_DISK_CYLINDER_ALIGNMENT = 1
+
+# PedPartitionFlag
+PED_PARTITION_BOOT = 1
+PED_PARTITION_ROOT = 2
+PED_PARTITION_SWAP = 3
+PED_PARTITION_HIDDEN = 4
+PED_PARTITION_RAID = 5
+PED_PARTITION_LVM = 6
+PED_PARTITION_LBA = 7
+PED_PARTITION_HPSERVICE = 8
+PED_PARTITION_PALO = 9
+PED_PARTITION_PREP = 10
+PED_PARTITION_MSFT_RESERVED = 11
+PED_PARTITION_BIOS_GRUB = 12
+PED_PARTITION_APPLE_TV_RECOVERY = 13
+PED_PARTITION_DIAG = 14
+PED_PARTITION_LEGACY_BOOT = 15
+
+# PedDiskTypeFeature
+PED_DISK_TYPE_EXTENDED = 1
+PED_DISK_TYPE_PARTITION_NAME = 2
+
+class PedCHSGeometry(Structure):
+ _fields_ = [
+ ('cylinders', c_int),
+ ('heads', c_int),
+ ('sectors', c_int),
+ ]
+
+PedSector = c_longlong
+
+class PedAlignment(Structure):
+ _fields_ = [
+ ('offset', PedSector),
+ ('grain_size', PedSector),
+ ]
+
+class PedDevice(Structure):
+ pass
+
+PedDevice._fields_ = [
+ ('next', POINTER(PedDevice)),
+ ('model', c_char_p),
+ ('path', c_char_p),
+ ('type', c_int),
+ ('sector_size', c_longlong),
+ ('phys_sector_size', c_longlong),
+ ('length', PedSector),
+ ('open_count', c_int),
+ ('read_only', c_int),
+ ('external_mode', c_int),
+ ('dirty', c_int),
+ ('boot_dirty', c_int),
+ ('hw_geom', PedCHSGeometry),
+ ('bios_geom', PedCHSGeometry),
+ ('host', c_short),
+ ('did', c_short),
+ ('arch_specific', c_void_p),
+]
+
+# Geometry stuff starts here
+class PedGeometry(Structure):
+ _fields_ = [
+ ('dev', POINTER(PedDevice)),
+ ('start', PedSector),
+ ('length', PedSector),
+ ('end', PedSector),
+ ]
+# Geometry stuff ends here
+
+class PedPartition(Structure):
+ pass
+
+class PedDiskType(Structure):
+ pass
+
+class PedFileSystemType(Structure):
+ pass
+
+class PedDisk(Structure):
+ _fields_ = [
+ ('dev', POINTER(PedDevice)),
+ ('type', POINTER(PedDiskType)),
+ ('block_sizes', c_int),
+ ('part_list', POINTER(PedPartition)),
+ ('disk_specific', c_void_p),
+ ('needs_clobber', c_int),
+ ('update_mode', c_int),
+ ]
+ #def __init__(self):
+ #name = self.type.contents.name
+ #ops = self.type.contents.ops
+ #ops.contents.alloc_metadata = c_char_p(name + '_alloc_metadata')
+
+class PedDiskOps(Structure):
+ _fields_ = [
+ ('probe', c_int),
+ ('clobber', c_int),
+ ('alloc', POINTER(PedDisk)),
+ ('duplicate', POINTER(PedDisk)),
+ ('free', c_void_p),
+ ('read', c_int),
+ ('write', c_int),
+ ('disk_set_flag', c_int),
+ ('disk_get_flag', c_int),
+ ('disk_is_flag_available', c_int),
+ ('partition_new', POINTER(PedPartition)),
+ ('partition_duplicate', POINTER(PedPartition)),
+ ('partition_destroy', c_void_p),
+ ('partition_set_system', c_int),
+ ('partition_set_flag', c_int),
+ ('partition_get_flag', c_int),
+ ('partition_is_flag_available', c_int),
+ ('partition_set_name', c_void_p),
+ ('partition_get_name', c_char_p),
+ ('partition_align', c_int),
+ ('partition_enumerate', c_int),
+ ('partition_check', c_bool),
+ ('alloc_metadata', c_int),
+ ('get_max_primary_partition_count', c_int),
+ ('get_max_supported_partition_count', c_bool),
+ ('get_partition_alignment', POINTER(PedAlignment)),
+ ('max_length', PedSector),
+ ('max_start_sector', PedSector)
+ ]
+
+PedDiskType._fields_ = [
+ ('next', POINTER(PedDiskType)),
+ ('name', c_char_p),
+ ('ops', POINTER(PedDiskOps)),
+ ('features', c_int)
+]
+
+PedFileSystemType._fields_ = [
+ ('next', POINTER(PedFileSystemType)),
+ ('name', c_char_p),
+ ('block_sizes', c_int),
+ ('ops', POINTER(PedDiskOps)),
+]
+
+PedPartition._fields_ = [
+ ('prev', POINTER(PedPartition)),
+ ('next', POINTER(PedPartition)),
+ ('disk', POINTER(PedDisk)),
+ ('geom', PedGeometry),
+ ('num', c_int),
+ ('type', c_long),
+ ('fs_type', POINTER(PedFileSystemType)),
+ ('part_list', POINTER(PedPartition)),
+ ('disk_specific', c_void_p),
+]
+
+# Start of Alignment/Constraint stuff
+
+class PedConstraint(Structure):
+ _fields_ = [
+ ('start_align', POINTER(PedAlignment)),
+ ('end_align', POINTER(PedAlignment)),
+ ('start_range', POINTER(PedGeometry)),
+ ('end_range', POINTER(PedGeometry)),
+ ('min_size', PedSector),
+ ('max_size', PedSector),
+ ]
+# End of Alignment/Constraint stuff
+
+# Devices
+device_get = parted.ped_device_get
+device_get.restype = POINTER(PedDevice)
+device_get_constraint = parted.ped_device_get_constraint
+device_get_constraint.restype = POINTER(PedConstraint)
+devices = POINTER(PedDevice)
+
+# Disks
+disk_probe = parted.ped_disk_probe
+disk_probe.restype = POINTER(PedDiskType)
+disk_new = parted.ped_disk_new
+disk_new.restype = POINTER(PedDisk)
+disk_new_fresh = parted.ped_disk_new_fresh
+disk_new_fresh.argtypes = [POINTER(PedDevice), POINTER(PedDiskType)]
+disk_new_fresh.restype = POINTER(PedDisk)
+disk_add_partition = parted.ped_disk_add_partition
+disk_add_partition.argtypes = [POINTER(PedDisk), POINTER(PedPartition), POINTER(PedConstraint)]
+disk_next_partition = parted.ped_disk_next_partition
+disk_next_partition.argtypes = [POINTER(PedDisk), POINTER(PedPartition)]
+disk_next_partition.restype = POINTER(PedPartition)
+disk_get_last_partition_num = parted.ped_disk_get_last_partition_num
+disk_get_last_partition_num.argtypes = [POINTER(PedDisk)]
+disk_get_partition = parted.ped_disk_get_partition
+disk_get_partition.argtypes = [POINTER(PedDisk), c_int]
+disk_get_partition.restype = POINTER(PedPartition)
+disk_delete_partition = parted.ped_disk_delete_partition
+disk_delete_partition.argtypes = [POINTER(PedDisk), POINTER(PedPartition)]
+disk_delete_all = parted.ped_disk_delete_all
+disk_delete_all.argtypes = [POINTER(PedDisk)]
+# I would rather call commit_to_dev and commit_to_os manually
+#parted.ped_disk_commit.argtypes = [POINTER(PedDisk)]
+disk_commit_to_os = parted.ped_disk_commit_to_os
+disk_commit_to_os.argtypes = [POINTER(PedDisk)]
+disk_commit_to_dev = parted.ped_disk_commit_to_dev
+disk_commit_to_dev.argtypes = [POINTER(PedDisk)]
+disk_destroy = parted.ped_disk_destroy
+disk_destroy.argtypes = [POINTER(PedDisk)]
+disk_destroy.restype = None
+disk_print = parted.ped_disk_print
+disk_print.argtypes = [POINTER(PedDisk)]
+partition_new = parted.ped_partition_new
+partition_new.argtypes = [POINTER(PedDisk), c_int, POINTER(PedFileSystemType), PedSector, PedSector]
+partition_new.restype = POINTER(PedPartition)
+partition_is_busy = parted.ped_partition_is_busy
+partition_is_busy.argtypes = [POINTER(PedPartition)]
+get_type = parted.ped_disk_type_get
+get_type.restype = POINTER(PedDiskType)
+constraint_new = parted.ped_constraint_new
+constraint_new.argtypes = [POINTER(PedAlignment), POINTER(PedAlignment), POINTER(PedGeometry), POINTER(PedGeometry), PedSector, PedSector]
+constraint_new.restype = POINTER(PedConstraint)
+geometry_new = parted.ped_geometry_new
+geometry_new.argtypes = [POINTER(PedDevice), PedSector, PedSector]
+geometry_new.restype = POINTER(PedGeometry)
+device_get_optimal_aligned_constraint = parted.ped_device_get_optimal_aligned_constraint
+device_get_optimal_aligned_constraint.argtypes = [POINTER(PedDevice)]
+device_get_optimal_aligned_constraint.restype = POINTER(PedConstraint)
+device_get_minimal_aligned_constraint = parted.ped_device_get_minimal_aligned_constraint
+device_get_minimal_aligned_constraint.argtypes = [POINTER(PedDevice)]
+device_get_minimal_aligned_constraint.restype = POINTER(PedConstraint)
+device_get__constraint = parted.ped_device_get_constraint
+device_get_constraint.argtypes = [POINTER(PedDevice)]
+device_get_constraint.restype = POINTER(PedConstraint)
+constraint_intersect = parted.ped_constraint_intersect
+constraint_intersect.argtypes = [POINTER(PedConstraint), POINTER(PedConstraint)]
+constraint_intersect.restype = POINTER(PedConstraint)
+constraint_destroy = parted.ped_constraint_destroy
+constraint_destroy.argtypes = [POINTER(PedConstraint)]
+disk_remove_partition = parted.ped_disk_remove_partition
+disk_remove_partition.argtypes = [POINTER(PedDisk), POINTER(PedPartition)]
+partition_get_name = parted.ped_partition_get_name
+partition_get_name.argtypes = [POINTER(PedPartition)]
+partition_get_name.restype = c_char_p
+partition_set_name = parted.ped_partition_set_name
+partition_set_name.argtypes = [POINTER(PedPartition), c_char_p]
+file_system_type_get = parted.ped_file_system_type_get
+file_system_type_get.argtypes = [c_char_p]
+file_system_type_get.restype = POINTER(PedFileSystemType)
View
46 device.py
@@ -0,0 +1,46 @@
+from conversion import *
+from disk import *
+import os
+
+device_type = {
+ 0 : 'UNKNOWN',
+ 1 : 'SCSI',
+ 2 : 'IDE',
+ 3 : 'DAC960',
+ 4 : 'CPQARRAY',
+ 5 : 'FILE',
+ 6 : 'ATARAID',
+ 7 : 'I20',
+ 8 : 'UBD',
+ 9 : 'DASD',
+ 10 : 'VIODASD',
+ 11 : 'SX8',
+ 12 : 'DM',
+ 13 : 'XVD',
+ 14 : 'SDMMC',
+ 15 : 'VIRTBLK',
+ 16 : 'AOE',
+ 17 : 'MD',
+}
+
+class Device(object):
+ def __init__(self, path=None, dev=None):
+ if path:
+ if not os.path.exists(path):
+ raise Exception("%s does not exist" % path)
+ self.__device = device_get(path)
+ elif dev:
+ self.__device = dev
+ else:
+ raise Exception("Dude WTF?")
+
+ self.path = self.__device.contents.path
+ self.model = self.__device.contents.model
+ self.type = device_type[self.__device.contents.type]
+ self.sector_size = self.__device.contents.sector_size
+
+ def disk(self):
+ return Disk(self, None)
+
+
+
View
240 disk.py
@@ -0,0 +1,240 @@
+from conversion import *
+#from partition import *
+import os
+
+alignment_any = PedAlignment(0, 1)
+
+class DiskError(Exception):
+ pass
+
+class Disk(object):
+ def __init__(self, device=None, disk=None):
+ if device:
+ self.__device = device._Device__device
+ self.__disk = disk_new(self.__device)
+ elif disk:
+ self.__disk = disk
+ self.__device = self.__disk.contents.dev
+ else:
+ raise Exception("Dude WTF?")
+
+ @property
+ def type(self):
+ return self.__disk.contents.type.contents.name
+
+ @property
+ def block_sizes(self):
+ return self.__disk.contents.block_sizes
+
+ @property
+ def needs_clobber(self):
+ return bool(self.__disk.contents.needs_clobber)
+
+ @property
+ def update_mode(self):
+ return bool(self.__disk.contents.update_mode)
+
+ def partitions(self):
+ partitions = []
+ part = disk_next_partition(self.__disk, None)
+
+ while part:
+ if part.contents.type == 4 or \
+ part.contents.type == 8 or \
+ part.contents.type == 10:
+ part = disk_next_partition(self.__disk, part)
+ continue
+ p = Partition(part=part)
+ partitions.append(p)
+ part = disk_next_partition(self.__disk, part)
+
+ return partitions
+
+ def add_partition(self, part, alignment=None):
+ try:
+ p = self.get_partition(part.num)
+ if p.geom.start == part.geom.start and p.geom.length == part.geom.length:
+ raise DiskError
+ except DiskError:
+ raise ValueError("This partition already exists in the disk... And yeah, my english sucks.")
+ except ValueError:
+ pass
+ partition = part._Partition__partition
+ disk = self.__disk
+ range_start = geometry_new(self.__device, partition.contents.geom.start, 1)
+ range_end = geometry_new(self.__device, partition.contents.geom.end, 1)
+ user_constraint = constraint_new(alignment_any, alignment_any, range_start, range_end, 1, part.geom.length)
+ if not bool(user_constraint):
+ raise Exception("Could not set user defined constraint.")
+ if alignment == 'optimal':
+ dev_constraint = device_get_optimal_aligned_constraint(self.__device)
+ elif alignment == 'minimal':
+ dev_constraint = device_get_optimal_aligned_constraint(self.__device)
+ elif alignment == None:
+ dev_constraint = device_get_constraint(self.__device)
+ else:
+ raise ValueError("Alignment '%s' is not valid" % str(alignment))
+ if not bool(dev_constraint):
+ raise Exception("Could not set user defined constraint.")
+ final_constraint = constraint_intersect(user_constraint, dev_constraint)
+ constraint_destroy(user_constraint)
+ constraint_destroy(dev_constraint)
+ if not bool(final_constraint):
+ raise Exception("Could not set device constraint.")
+ added = disk_add_partition(disk, partition, final_constraint)
+ print "Added val is:\n"
+ print added
+ constraint_destroy(final_constraint)
+ if not added:
+ disk_remove_partition(disk, partition)
+ raise Exception("Failed to add partition")
+ if part.name:
+ set_name = partition_set_name(partition, part.name)
+ if not set_name:
+ disk_remove_partition(disk, partition)
+ raise Exception("Failed to set partition name.")
+
+ def delete_partition(self, part=None, part_num=None):
+ if part and isinstance(part, Partition):
+ partition = part._Partition__partition
+ elif part_num:
+ partition = self._get_ped_partition(part_num)
+ else:
+ raise ValueError("You must specify a Partition instance or a partition number.")
+ if partition_is_busy(partition):
+ raise Exception("Partition is busy, no sexy time for you!")
+ disk_delete_partition(self.__disk, partition)
+ self.commit()
+ disk_destroy(self.__disk)
+ self.__disk = disk_new(self.__device)
+
+ def delete_all(self):
+ disk_delete_all(self.__disk)
+ return
+
+ def commit(self):
+ to_dev = disk_commit_to_dev(self.__disk)
+ if not to_dev:
+ raise Exception("Failed to commit disk changes to device.")
+ to_os = disk_commit_to_os(self.__disk)
+ if not to_os:
+ raise Exception("Failed to commit disk changes to OS.")
+
+ def _get_ped_partition(self, part_num):
+ partition = disk_get_partition(self.__disk, part_num)
+ if not bool(partition):
+ raise ValueError("Partition number %i does not exist." % part_num)
+ return partition
+
+ def get_partition(self, part_num):
+ partition = Partition(part=self._get_ped_partition(part_num))
+ return partition
+
+partition_type = {
+ 0 : 'NORMAL',
+ 1 : 'LOGICAL',
+ 2 : 'EXTENDED',
+ 4 : 'FREESPACE',
+ 8 : 'METADATA',
+ 10 : 'PROTECTED'
+}
+
+size_units = {
+ "B": 1, # byte
+ "KB": 1000**1, # kilobyte
+ "MB": 1000**2, # megabyte
+ "GB": 1000**3, # gigabyte
+ "TB": 1000**4, # terabyte
+ "PB": 1000**5, # petabyte
+ "EB": 1000**6, # exabyte
+ "ZB": 1000**7, # zettabyte
+ "YB": 1000**8, # yottabyte
+ "KiB": 1024**1, # kibibyte
+ "MiB": 1024**2, # mebibyte
+ "GiB": 1024**3, # gibibyte
+ "TiB": 1024**4, # tebibyte
+ "PiB": 1024**5, # pebibyte
+ "EiB": 1024**6, # exbibyte
+ "ZiB": 1024**7, # zebibyte
+ "YiB": 1024**8, # yobibyte
+ "%": 1 # Fuck you pyparted, we've got percents!!!
+}
+
+class Size(object):
+ def __init__(self, length, units="MB"):
+ self.__length = length
+ if units == "%":
+ self.sectors = None
+ else:
+ self.sectors = (size_units[units] * length) / 512
+ self.units = units
+
+ def convert(self, units):
+ return (size_units[units] * length) / 512
+
+class FSType(object):
+ def __init__(self, fs=None,
+
+class Partition(object):
+ def __init__(self, disk=None, size=None, type=0, fs=None,
+ name=None, start=None, end=None, part=None):
+ self.__name = name
+ self.__fs = fs
+ if part:
+ self.__partition = part
+ elif disk and size:
+ if start:
+ if not end:
+ end = start + size.sectors - 1
+ if (end - start) != (size.sectors - 1):
+ raise ValueError("Dude, your geometry is messed up.")
+ else:
+ last_part_num = disk_get_last_partition_num(disk._Disk__disk)
+ last_part = disk_get_partition(disk._Disk__disk, last_part_num)
+ last_end_sector = last_part.contents.geom.end
+ start = last_end_sector + 1
+ end = start + size.sectors - 1
+ if fs:
+ filesystem = file_system_type_get(fs)
+ else:
+ filesystem = None
+ self.__partition = partition_new(disk._Disk__disk, type, filesystem, start, end)
+ else:
+ raise Exception("Dude WTF?")
+
+ @property
+ def disk(self):
+ return Disk(None, self.__partition.contents.disk)
+
+ @property
+ def geom(self):
+ return self.__partition.contents.geom
+
+ @property
+ def num(self):
+ return self.__partition.contents.num
+
+ @property
+ def type(self):
+ return partition_type[self.__partition.contents.type]
+
+ @property
+ def fs_type(self):
+ try:
+ fs = self.__partition.contents.fs_type.contents.name
+ except ValueError:
+ fs = None
+ return fs
+
+ @property
+ def name(self):
+ return self.__name
+
+ @property
+ def fs(self):
+ return self.__fs
+
+ #@property
+ #def size(self, units="MB"):
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.