Volkov: добавить Sprinter Commander

Реализовать двухпанельный Commander от платформенного PoC до этапов P6-P20: EMM-каталог, сортировку и выбор, операции с файлами и деревьями, транзакционное копирование, метаданные, политику конфликтов и предварительную проверку свободного места.

Добавить проектную документацию, HDD/MAME-сценарии и проверенные артефакты. Расширить libc операцией bank_write_page, исправлением режима O_RDONLY и связанными регрессионными проверками.
This commit is contained in:
2026-09-10 10:45:30 +03:00
parent 05bcd8197e
commit 8e389c03f8
870 changed files with 21310 additions and 25 deletions
@@ -0,0 +1,89 @@
# 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
```