Files @ 2e3b9132fe02
Branch filter:

Location: linux-tools/kusbff/floppyemu/__init__.py

Silverwing
fix: properly show up to 1000 disks with proper indices
import subprocess
import os


SINGLE_DISK_OFFSET = 1572864
MAX_IMAGES_ON_DRIVE = 1000


def get_or_create_empty_image(index, temp_path, size=1440):
    filename = 'empty{}.ima'.format(index)
    filename = os.path.join(temp_path, filename)

    if os.path.isfile(filename):
        os.remove(filename)
    proc = subprocess.Popen(['mkfs.msdos', '-C', filename, str(size)])
    rval = proc.wait()
    if rval != 0:
        raise Exception('Not created')

    return filename


def format_images(device, indexes, temp_path, size=1440):
    for ipair in indexes:
        if isinstance(ipair, int):
            image = get_or_create_empty_image(ipair, temp_path, size)
            write_image(device, image, ipair)
        else:
            for i in range(ipair[0], ipair[1]):
                image = get_or_create_empty_image(i, temp_path, size)
                write_image(device, image, i)


def write_image(device, path, index=0):
    """
    Writes image from path to device at specified index
    :param device:
    :param index:
    :param path:
    :return:
    """
    with open(device, 'r+b') as dfile:
        offset = SINGLE_DISK_OFFSET * index
        dfile.seek(offset)
        with open(path, 'rb') as ifile:
            fdata = ifile.read()
            dfile.write(fdata)


def read_image(device, path, index=0):
    """
    Reads image at specified index from device into path
    :param device:
    :param path:
    :param index:
    :return:
    """
    with open(device, 'rb') as dfile:
        offset = SINGLE_DISK_OFFSET * index
        dfile.seek(offset)
        bootsector = dfile.read(512)
        if bootsector[-1] == 0xAA and bootsector[-2] == 0x55:
            # FAT12 image
            sectorsize = bootsector[0xB] + (bootsector[0xC] << 8)
            sectorcount = bootsector[0x13] + (bootsector[0x14] << 8)
            with open(path, 'xb') as ifile:
                dfile.seek(offset)
                fdata = dfile.read(sectorsize * sectorcount)
                ifile.write(fdata)


def list_images(device):
    """
    Reads device and lists all of images on it
    :param device:
    :return: (label, size)
    """
    rval = []
    with open(device, 'rb') as dfile:
        dfile.seek(0, 2)
        disks = min(dfile.tell() / SINGLE_DISK_OFFSET, MAX_IMAGES_ON_DRIVE)
        dfile.seek(0)
        while len(rval) < disks:
            bootsector = dfile.read(512)
            label = None
            if bootsector[0] == 0xEB or bootsector[0] == 0xE9:
                sectorsize = bootsector[0xB] + (bootsector[0xC] << 8)
                sectorcount = bootsector[0x13] + (bootsector[0x14] << 8)
                disksize = sectorsize * sectorcount
                if bootsector[0x26] == 0x29:
                    # label probably exists.
                    # As an additional precaution check fs type.
                    # If it's valid, then get label, otherwise consider disk unlabeled
                    if bootsector[0x36:0x3E] in (b'FAT12   ', b'FAT16   ', b'FAT     '):
                        label = bootsector[0x2B:0x36].decode(encoding='cp1251')
                dfile.seek(SINGLE_DISK_OFFSET - 512, 1)
            else:
                disksize = 0
                dfile.seek(SINGLE_DISK_OFFSET - 512, 1)
            rval.append((label, disksize))
    return rval