# Sprinter Commander: сохранение метаданных F5 0.2/P18 Дата: 10 сентября 2026 года. Статус: `PASS` в MAME 0.288 / BIOS 3.06 / DSS 1.71.57 на HDD `D:`. ## Контракт Одиночный, групповой и рекурсивный F5 сохраняют у каждого обычного файла: - FAT date/time, включая двухсекундную точность; - атрибуты readonly, hidden, system и archive. Date/time задаются вызовом DSS `PUT_D_T` на открытом temp-файле после последней записи и до `close()`. Атрибуты задаются через `ATTRIB` только после атомарного rename temp в конечное имя. Такой порядок не делает temp readonly до commit и сохраняет прежнюю защиту существующего target. Если ошибка происходит до rename, общий cleanup закрывает дескрипторы и удаляет temp. Если `ATTRIB` или восстановление CWD завершаются ошибкой уже после rename, `ScCopyJob.committed` не позволяет выдавать результат за отсутствующий файл: UI сообщает `File committed; finalization failed`. Метаданные каталогов на этом этапе не переносятся. ## Проверка Fixture создаёт `MSRC/META.BIN` размером 4097 байт с контролируемым payload, датой `2001-02-03`, временем `04:05:06` и набором атрибутов `R/H/S/A`. Подготовленный raw FAT проверяется до MAME, чтобы текущая дата сборки не могла дать ложный положительный результат. После F5 извлекается конечный CHD и собственным FAT16-reader проверяются обе 32-байтовые directory entries и цепочка кластеров: ```text PASS: F5 preserved exact FAT date/time and R/H/S/A attributes. ``` На экране обе панели показывают одинаковые размер, `RHSA` и `2001-02-03 04:05`; секунды и payload подтверждает raw-проверка. Контрольные кадры: - [исходные метаданные](../artifacts/mame-p18/metadata/source-metadata.png); - [файл скопирован с теми же полями](../artifacts/mame-p18/metadata/copied-metadata.png); - [пассивная панель после переключения](../artifacts/mame-p18/metadata/passive-metadata.png); - [чистый возврат в DSS](../artifacts/mame-p18/metadata/clean-dss-return.png). После P18 повторно пройдены: - P5 copy-fault matrix: `ALL PASS`, CHD-check `PASS`; - P16 recursive group F5: UI корректен, все выбранные деревья и файлы совпали побайтно. ## ABI DSS `sc_metadata_set_datetime()` раскрывает packed FAT date/time в поля `PUT_D_T $18`. Низкоуровневый leaf получает handle в `A`, near-указатель на семибайтовую структуру в `DE`, загружает год в `IX` и сохраняет caller IX. Для `ATTRIB $16` сгенерированный `.asm` подтвердил важную особенность `__sdcccall(1)`: второй однобайтовый аргумент banked-wrapper лежит на стеке, а `E` занят номером банка. Поэтому публичная banked-функция вызывает локальный raw-leaf с обычным ABI; leaf снимает однобайтовый аргумент и адрес возврата явно. Оба пути переводят `CF/A` в `errno`. ## Компоновка Сборка `--memory big --safe --max-allocs 3000` остаётся двухбанковой и не увеличивает EXE за счёт пустого третьего банка: ```text _CODE 9503; DATA 3531; heap 1814 BANK1 11011/16384; BANK2 16145/16384 SPRCMD.EXE 43080 ``` В BANK2 остаётся 239 байт. Следующий заметный UI/policy-модуль следует размещать с осмысленной перекладкой в BANK3. Межбанковый аудит чист. ## Воспроизведение ```sh make hdd-p18-metadata ALLOCS=3000 tests/run_mame_hdd.sh build/hdd/p18_metadata.chd \ tests/mame_p18_metadata.lua artifacts/mame-p18/local 48 tests/check_p18_metadata_hdd.sh build/hdd/p18_metadata.chd ```