#!/usr/bin/env python3 """Упаковщик FAT12-дискеты Sprinter. Образ принадлежит вызывающему проекту.""" import struct import sys import os def create_floppy_image(output_file, files_to_add): """Создаёт FAT12 образ дискеты 1.44MB и добавляет файлы""" # Размер дискеты 1.44MB SECTOR_SIZE = 512 TOTAL_SECTORS = 2880 FAT_SIZE = 9 ROOT_DIR_ENTRIES = 224 # Проверяем весь набор до открытия выходного файла: ошибочная упаковка # не должна уничтожать предыдущий пригодный носитель приложения. capacity = TOTAL_SECTORS - 1 - 2 * FAT_SIZE - ROOT_DIR_ENTRIES * 32 // SECTOR_SIZE needed = 0 names = set() if len(files_to_add) > ROOT_DIR_ENTRIES: raise ValueError("слишком много файлов для корневого каталога FAT12") for filename, src_path in files_to_add: name, ext = os.path.splitext(filename) short_name = (name[:8].upper(), ext[1:4].upper()) # Исторические тесты SDK могут иметь длинное имя; на носителе оно # сокращается до 8.3. Коллизия после сокращения — настоящая ошибка. if not name or short_name in names: raise ValueError(f"пустое или повторное имя FAT 8.3: {filename}") short_name[0].encode('ascii') short_name[1].encode('ascii') names.add(short_name) needed += max(1, (os.path.getsize(src_path) + SECTOR_SIZE - 1) // SECTOR_SIZE) if needed > capacity: raise ValueError(f"данные не помещаются на дискету: {needed} > {capacity} секторов") os.makedirs(os.path.dirname(os.path.abspath(output_file)), exist_ok=True) # Создаём пустой образ with open(output_file, 'wb') as f: f.write(b'\x00' * (TOTAL_SECTORS * SECTOR_SIZE)) # Читаем и модифицируем образ with open(output_file, 'r+b') as f: # BPB (BIOS Parameter Block) - начинаем с смещения 0 # Jump instruction f.seek(0) f.write(b'\xEB\x3C\x90') # OEM name f.write(b'MSDOS5.0') # Bytes per sector f.write(struct.pack('