File diff 000000000000 → f3f4cf108453
floppyemu/__init__.py
Show inline comments
 
new file 100644
 
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