diff --git a/floppyemu/__init__.py b/floppyemu/__init__.py new file mode 100644 --- /dev/null +++ b/floppyemu/__init__.py @@ -0,0 +1,101 @@ +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