Revision 25cdca3e snf-image-helper/disklabel.py

b/snf-image-helper/disklabel.py
171 171
                    d.seek(BLOCKSIZE * self.mbr.part[i].first_sector)
172 172
                    self.part_num = i
173 173
                    if ptype == 0xa5:  # FreeBSD
174
                        self.disklabel = BSDDisklabel(d)
174
                        self.disklabel = FreeBSDDisklabel(d)
175 175
                    elif ptype == 0xa6:  # OpenBSD
176 176
                        self.disklabel = OpenBSDDisklabel(d)
177 177
                    else:  # NetBSD
178
                        self.disklabel = BSDDisklabel(d)
178
                        self.disklabel = NetBSDDisklabel(d)
179 179
                    break
180 180

  
181 181
        assert self.disklabel is not None, "No *BSD partition found"
......
303 303
        return (cylinder, header, sector)
304 304

  
305 305
    @abc.abstractmethod
306
    def enlarge(self, new_size):
307
        """Enlarge the disk and return the last usable sector"""
308
        pass
309

  
310
    @abc.abstractmethod
311
    def enlarge_last_partition(self):
312
        """Enlarge the last partition to consume all the usable space"""
313
        pass
314

  
315
    @abc.abstractmethod
316 306
    def get_last_partition_id(self):
317 307
        """Get the ID of the last partition"""
318 308
        pass
......
322 312
        """Print the Disklabel"""
323 313
        pass
324 314

  
315
    def enlarge(self, new_size):
316
        """Enlarge the disk and return the last usable sector"""
317
        raise NotImplementedError
318

  
319
    def enlarge_last_partition(self):
320
        """Enlarge the last partition to consume all the usable space"""
321
        raise NotImplementedError
322

  
323

  
325 324

  
326 325
class PartitionTableBase(object):
327 326
    """Base Class for disklabel partition tables"""
......
391 390
                'cpg'       # 14      2      File system cylinders per group
392 391
                ]
393 392

  
393
        def setsize(self, i, size):
394
            """Set size for partition i"""
395
            tmp = self.part[i]
396
            self.part[i] = self.Partition(size, tmp.offset, tmp.fsize,
397
                                          tmp.fstype, tmp.frag, tmp.cpg)
398

  
394 399
    @property
395 400
    def fmt(self):
396 401
        return "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
......
440 445
        self.field = d_
441 446

  
442 447
    def enlarge(self, new_size):
448
        """Enlarge the disk and return the last usable sector"""
443 449
        raise NotImplementedError
444 450

  
445 451
    def enlarge_last_partition(self):
446 452
        raise NotImplementedError
447 453

  
448 454
    def get_last_partition_id(self):
449
        raise NotImplementedError
450

  
451
    def lba2chs(self, lba, hpc=None, spt=None):
452
        """Return the CHS address for a given LBA address"""
453

  
454
        # NetBSD uses LBA-Assisted translation. The sectors per track (spt)
455
        # value is always 63 and the heads per cylinder (hpc) value depends on
456
        # the size of the disk
457

  
458
        disk_size = self.field['secperunit']
459

  
460
        # Maximum disk size that can be addressed is 1024 * HPC* SPT
461
        spt = 63
462
        for hpc in 16, 32, 64, 128, 255:
463
            if disk_size <= 1024 * hpc * spt:
464
                break
455
        """Returns the id of the last partition"""
456
        end = 0
465 457

  
466
        chs = super(BSDDisklabel, self).lba2chs(lba, hpc, spt)
458
        # Exclude partition 'c' which describes the whole disk
459
        for i in [n for n in range(len(self.ptable.part)) if n != 2]:
460
            current_end = self.ptable.part[i].size + self.ptable.part[i].offset
461
            if end < current_end:
462
                end = current_end
463
                part = i
467 464

  
468
        if chs[0] > 1023:  # Cylinders overflowed
469
            assert hpc == 255  # Cylinders may overflow only for large disks
470
            return (1023, chs[1], chs[2])
465
        assert end > 0, "No partition found"
471 466

  
472
        return chs
467
        return part
473 468

  
474 469
    def __str__(self):
475 470
        """Print the Disklabel"""
......
513 508
            "%s" % self.ptable
514 509

  
515 510

  
511
class FreeBSDDisklabel(BSDDisklabel):
512
    """Represents a FreeBSD Disklabel"""
513
    pass
514

  
515

  
516
class NetBSDDisklabel(BSDDisklabel):
517
    """Represents a NetBSD Disklabel"""
518

  
519
    def lba2chs(self, lba, hpc=None, spt=None):
520
        """Return the CHS address for a given LBA address"""
521

  
522
        # NetBSD uses LBA-Assisted translation. The sectors per track (spt)
523
        # value is always 63 and the heads per cylinder (hpc) value depends on
524
        # the size of the disk
525

  
526
        disk_size = self.field['secperunit']
527

  
528
        # Maximum disk size that can be addressed is 1024 * HPC* SPT
529
        spt = 63
530
        for hpc in 16, 32, 64, 128, 255:
531
            if disk_size <= 1024 * hpc * spt:
532
                break
533

  
534
        chs = super(NetBSDDisklabel, self).lba2chs(lba, hpc, spt)
535

  
536
        if chs[0] > 1023:  # Cylinders overflowed
537
            assert hpc == 255  # Cylinders may overflow only for large disks
538
            return (1023, chs[1], chs[2])
539

  
540
        return chs
541

  
542
    def enlarge(self, new_size):
543
        """Enlarge the disk and return the last usable sector"""
544

  
545
        assert new_size >= self.field['secperunit'], \
546
            "New size cannot be smaller than %d" % self.field['secperunit']
547

  
548
        self.field['secperunit'] = new_size
549

  
550
        # According to the ATA specifications, "If the content of words (61:60)
551
        # is greater than or equal to 16,514,064 then the content of word 1
552
        # [the number of logical cylinders] shall be equal to 16,383."
553
        # NetBSD respects this.
554
        self.field['ncylinders'] = 16383 if new_size >= 16514064 else \
555
            new_size // self.field['secpercyl']
556

  
557
        # Partition 'c' describes the NetBSD MBR partition
558
        self.ptable.setsize(2, new_size - self.ptable.part[2].offset)
559

  
560
        # Partition 'd' describes the entire disk
561
        self.ptable.setsize(3, new_size)
562

  
563
        # Update the checksum
564
        self.field['checksum'] = self.compute_checksum()
565

  
566
        return new_size - 1
567

  
568
    def enlarge_last_partition(self):
569
        """Enlarge the last partition to cover up all the free space"""
570

  
571
        last = self.get_last_partition_id()
572
        size = self.field['secperunit'] - self.ptable.part[last].offset
573
        self.ptable.setsize(last, size)
574

  
575
        self.field['checksum'] = self.compute_checksum()
576

  
577
    def get_last_partition_id(self):
578
        """Returns the id of the last partition"""
579
        end = 0
580

  
581
        # Exclude partition 'c' which describes the NetBSD MBR partition and
582
        # partition 'd' which describes the whole disk
583
        for i in [n for n in range(len(self.ptable.part)) if n not in (2, 3)]:
584
            current_end = self.ptable.part[i].size + self.ptable.part[i].offset
585
            if end < current_end:
586
                end = current_end
587
                part = i
588

  
589
        assert end > 0, "No partition found"
590

  
591
        return part
592

  
593

  
516 594
class OpenBSDDisklabel(DisklabelBase):
517 595
    """Represents an OpenBSD Disklabel"""
518 596

  
......
642 720
        """Enlarge the disk and return the last usable sector"""
643 721

  
644 722
        assert new_size >= self.dsize, \
645
            "New size cannot be smaller that %s" % self.dsize
723
            "New size cannot be smaller than %d" % self.dsize
646 724

  
647 725
        # Fix the disklabel
648 726
        self.dsize = new_size
......
651 729
        self.bend = (self.field['ncylinders'] * self.field['nsectors'] *
652 730
                     self.field['ntracks'])
653 731

  
654
        # Partition 'c' descriptes the entire disk
732
        # Partition 'c' describes the entire disk
655 733
        self.ptable.setpsize(2, new_size)
656 734

  
657 735
        # Update the checksum
......
662 740

  
663 741
    def get_last_partition_id(self):
664 742
        """Returns the id of the last partition"""
665
        part = 0
666 743
        end = 0
667 744
        # Don't check partition 'c' which is the whole disk
668
        for i in filter(lambda x: x != 2, range(len(self.ptable.part))):
745
        for i in [n for n in range(len(self.ptable.part)) if n != 2]:
669 746
            curr_end = self.ptable.getpsize(i) + self.ptable.getpoffset(i)
670 747
            if end < curr_end:
671 748
                end = curr_end

Also available in: Unified diff