Skip to content

Commit babad09

Browse files
committed
feat(p3-204): posix schreibt bis in die Datei - und die Mutationsmatrix fand eine stille Umwandlung (MF-1119)
`posix_write_track()` ruft jetzt `uft_posix_write()` und schreibt bis in die Datei. Neunter der elf aus MF-930. Merkmalstafel `Write` von UNSUPPORTED auf SUPPORTED, `.capabilities` um `UFT_FORMAT_CAP_WRITE` ergaenzt. Damit ist die Sechserliste aus MF-1111 abgearbeitet. WARUM DAS KEINE ZEILE WAR. `uft_posix_write()` rechnet mit `uft_logical_offset(c, h, nummer, &lg)`, und `lg` folgt aus `g.sides` - der Schreiber KANN seit MF-1034 alle drei Spielarten. Aber ohne uebergebene Geometrie faellt er auf `UFT_LOGI_SIDES_ALT` zurueck, und `posix_open()` behielt nur den Bildzeiger; `disk->geometry` hat kein Anordnungsfeld. Eine naive Verdrahtung haette also IMMER `alt` geschrieben - woertlich der Befund, den MF-1034 auf der LESESEITE behoben hat, wo bei `acorn640` (80 x 2, OUTOUT) 158 von 160 Spuren an anderer Stelle lagen. Derselbe Fehler auf der Schreibseite waere die naechste Wiederholung von MF-519/MF-529. `plugin_data` traegt deshalb jetzt eine eigene Struktur mit der vom LESER benutzten `posix_geometry_t`, aus `posix_read_result_t.geometry`. Sie neu aus der `.geom` zu lesen waere NICHT dasselbe: zwischen Oeffnen und Schreiben koennte die Nachbardatei sich geaendert haben, und dann schriebe der Schreiber eine andere Anordnung als der Leser gelesen hat. MF-931 Regel 4 ist genau das. Vier Fundstellen angepasst (`open`, `close`, `read_track`, `write_track`). ABNAHME: 57 gruen / 0 rot (vorher 48). Der neue Pruefling ist `posix-outback`, 80 x 2 x 9 x 512 - dieselbe Geometrie wie libdsks `ibm720`, an dem MF-1032 die OUTBACK-Regel abgenommen hat. `outback` und nicht `alt`, und das ist der Punkt: eine `alt`-Probe waere auch bei einem Schreiber gruen, der die Anordnung gar nicht kennt - dieselbe Aussagelosigkeit wie die Fuellbyte-Diskette aus MF-1021. `posix` ist dabei der erste Pruefling mit einer NACHBARDATEI: seine Sonde prueft kein Magic, sondern nur, ob eine `.geom` daneben liegt. Die Probe legt sie selbst an und raeumt sie wieder ab. DER EIGENTLICHE BEFUND, UND ER KAM AUS DER MATRIX, NICHT AUS DEM NACHDENKEN. Mutation M1 ersetzte `&pd->geometry` durch `NULL` - also genau die naive Verdrahtung. Die Probe blieb GRUEN, 56 von 56. Der Grund ist kein Messfehler: `uft_posix_write()` schreibt die `.geom` NEU, mit seiner eigenen Annahme. Danach stand dort `alt`, das Neu-Oeffnen las `alt`, und der Ruecklesevergleich stimmte mit dem ueberein, was `alt` geschrieben hatte. Ein geschlossener Kreis - dieselbe Gestalt wie die gruenen Rundlauftests von `apridisk` (MF-1009) und `qrst` (MF-1028), wo Packer und Entpacker Spiegelbilder derselben Erfindung waren. Und die Diskette war dabei still von `outback` auf `alt` VERWANDELT: genau das, was das Leitprinzip verbietet. Ein Sektorvergleich kann das grundsaetzlich nicht sehen, wenn die IDENTITAET des Abbilds in einer Nachbardatei steht und der Schreiber sie mitschreibt. Die Probe prueft sie deshalb byteweise, und die Mutation faellt: Matrix 4 von 5 statt 3 von 5. Damit ist auch mein eigener Kommentar im Test berichtigt. Er sagte, an `outback` falle ein immer-`alt`-Schreiber sofort auf. Das war FALSCH, solange die Nachbardatei mitgeschrieben wird - die Messung hat die Behauptung widerlegt und die fehlende Zusage geliefert. Die fuenfte Mutation ist gemessen redundant, nicht weggeredet: Pfadpruefung entfernt rutscht durch, weil `uft_posix_write()` selbst `if (!disk || !path) return UFT_ERR_INVALID_PARAM;` traegt - dieselbe Lage wie bei `hardsector` (MF-1117), Gestalt von MF-1031. Die Pruefung bleibt, weil sie den Versuch nicht unternimmt und den genaueren Code `UFT_ERR_INVALID_STATE` liefert. WAS OFFEN BLEIBT: neu als P3-381 - darf ein Schreiber die Nachbardatei ueberschreiben, in der die Identitaet des Abbilds steht? Fuer einen Export ist das richtig, fuer eine Aenderung an Ort und Stelle ist es eine stille Umwandlung. Der Weg ueber `write_track` ist abgesichert; jeder andere Aufrufer mit `geometry == NULL` ist es nicht. Drei Wege benannt, keiner gewaehlt - Eigentuemer-Entscheidung. Berichtigt im Dateikopf: dort stand "Er bleibt ohne Aufrufer (P3-204, MF-930)". Das gilt nicht mehr. Stand der dreizehn Schreiber: 9 verdrahtet, 1 offen (`logical` an P3-337), 2 Absicht (`ibm3740`, `rcpmfs`), 1 mit eigenem Blocker (`atx`, P3-380). Kennzahl: keine der vier direkt - aber die `Write`-Zusage der posix-Merkmalstafel geht von UNSUPPORTED auf SUPPORTED, und Tor 57 nimmt sie an. DAZU EIN ZWEITER OFFENER PUNKT, GEMESSEN BEIM WEITERGEHEN: P3-382. Naechster Posten auf der Hardware-Seite war Applesauce M3.3 („serial I/O pending"). Vor dem Bauen gemessen: von `uft_as_open`, `uft_as_close`, `uft_as_read_track`, `uft_as_read_disk`, `uft_as_write_track` und `uft_as_identify` hat KEINE einen Produktions-Aufrufer. Die einzige Fundstelle ausserhalb der eigenen Datei und der Header ist `src/hal/uft_hal_unified.c:1280` - und das ist eine HINWEISZEICHENKETTE in einer Fehlermeldung, kein Aufruf. Der benutzte Weg ist ein anderer und verdrahtet: `src/hardwaretab.cpp:863-884` oeffnet einen echten `QSerialPortApplesauceTransport` und baut daraus sieben Laeufer; `applesauce_serial_runners.cpp` treibt das dokumentierte Textprotokoll Schritt fuer Schritt. Die Serien-E/A der C-HAL zu implementieren waere damit dreifach fragwuerdig: eine ZWEITE Umsetzung desselben Protokolls (die Klasse „GCR-Tafel sechsfach", MF-1015, MF-1026), UNERREICHBAR (kein Aufrufer, also ein selbstgemachter P3-204-Fall), und ohne Geraet nicht abnehmbar (MF-310). Das wird deshalb NICHT stillschweigend gemacht, sondern als P3-382 mit drei Wegen aufgeschrieben - Eigentuemer-Entscheidung. Nebenbei eine eigene Vermutung verworfen: ich war dabei, `CLAUDE.md` fuer veraltet zu erklaeren (MF-1045-Klasse, wo „runner pending" stand, waehrend der Laeufer seit MF-256 existierte). Sie hat RECHT - sie spricht von der HAL, und die HAL ist wirklich gestummelt. Zwei getrennte Wege, und die Doku unterscheidet sie. Erfuellte Aufgaben: P3-204 (posix, letzter der loesbaren Teilmenge), P3-381 und P3-382 eroeffnet. Claude-Session: https://claude.ai/code/session_01BHdqfaZ5RFb1HPcw7NYoEY
1 parent 1e284d0 commit babad09

7 files changed

Lines changed: 286 additions & 22 deletions

File tree

docs/OPEN_ITEMS.md

Lines changed: 3 additions & 1 deletion
Large diffs are not rendered by default.

docs/STAND.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
## Was offen ist
4141

42-
`docs/OPEN_ITEMS.md` führt **7716** Zeilen in **82** Abschnitten.
42+
`docs/OPEN_ITEMS.md` führt **7718** Zeilen in **82** Abschnitten.
4343

4444
**erledigt** (1):
4545
- GCR-1 — der 6-and-2-Dekoder steht, 560 von 560 Sektoren belegt (MF-715)

docs/VERIFICATION_TIERS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Ein T3 mit Test-Eintrag bedeutet: es existiert ein synthetischer Test, aber die
8989
**(1) Der Datenanfang lag 256 Byte zu weit.** `JV3_HEADER_SIZE` war `0x2300`, mit dem Kommentar „dir + writeprot + padding“, und der Dateikopf setzte das Schreibschutz-Byte auf 0x2200. Wirklich ist es das **letzte** Byte des Kopfbereichs (0x21FF), und `2901*3 + 1` ergibt **0x2200** — keine Polsterung. MAME woertlich: `const uint32_t header_size = entries * 3 + 1;`, und sein `identify()` prueft das Schreibschutz-Byte bei `data[0x21ff]`. Klasse MF-796 (`edsk` meldete „9 Sektoren“ und lieferte keinen) und MF-794 (`sad` las 158 von 160 Spuren an der falschen Stelle). **(2) Der Verzeichnislauf brach beim ersten freien Satz ab.** MAMEs Beschreibung sagt ausdruecklich das Gegenteil: „Unused descriptors are FF FF (FC | size). **These can be intermixed with valid descriptors.**“ Sein `identify()` laeuft alle 2901 Saetze ab, ueberspringt die freien und schiebt den Datenzeiger um deren Groesse weiter — freie Saetze belegen Datenraum, und ihre Groesse verrechnet sich mit **2** statt mit 1. Der alte Lauf verlor alles hinter der ersten Luecke. **(3) Der Freimarker ist die SPUR allein.** Geprueft wurde `trk == 0xFF && sid == 0xFF`; MAME prueft `if (track < 0xff)`. Ein Satz mit Spur 0xFF und einer Sektornummer ungleich 0xFF galt als benutzt und lieferte einen Sektor der Spur 255. **(4) Die Sektornummern kippten zusammen.** `uint8_t sec_num = e->sector_id; if (sec_num > 0) sec_num--;` vor einem `uft_format_add_sector()`, das 1 addiert — die Schranke `> 0` machte die Gegenrechnung fuer Sektor **0** unwirksam: 0 blieb 0, plus 1 ergab **1**. Sektor 0 und Sektor 1 landeten beide auf ID 1, genau wie in der Messung oben. **(5) Dichte und DAM standen in falschen Bits.** Der Dateikopf sagte „bit 5 = double density, bit 6 = deleted address mark“; MAME und Tim Mann sagen **Bit 7 = Dichte** und **Bits 5-6 = DAM-Kode** (0xF8 deleted = 0x60 in Einzel-, 0x20 in Doppeldichte; 0xF9 = 0x40; 0xFB normal = 0x00). Der Code las `flags & 0x40` als „deleted“ — das trifft in Einzeldichte die **0xF9** und in Doppeldichte einen ungueltigen Wert; die Dichte wurde **nie** gelesen. **Und ein zweiter gruener Test hat einen Defekt bewacht:** `tests/test_register_all_formats.c` schrieb `0x2300` als Kopfgroesse fest (`const size_t total = 0x2300 + 20 * 256;`). Nach der Reparatur fiel er sofort. Das ist der **zweite Fall in derselben Runde** nach `test_plugin_probe_real.c`/MF-1016 — die Tests, die je ein Loch geschlossen haben, hielten das Nachbarloch fuer richtig. Gestalt von MF-992. **Zusaetzlich uebernommen, was das Orakel wirklich prueft:** Schreibschutz-Byte 0x00/0xFF, DMK-Unterscheidung (Bytes 5..15 alle null), Spur < 96, Sektor < 19, keine Doppelvergabe von (Seite, Spur, Sektor), `last_data <= Dateigroesse`, und das non-IBM-Bit wird **benannt abgewiesen** (MAME: „it's impossible to support it“) statt geraten. Ein zweiter Satzblock wird ebenfalls nicht angenommen — MAME: „no TRS-80 disks need this extra area, so it's unsupported“. **Mutationsmatrix 6 von 6**: Datenanfang zurueck auf 0x2300 (faellt 5) · beim ersten freien Satz abbrechen (3) · Freimarker wieder Spur UND Sektor (**genau 1**) · Sektornummer wieder dekrementieren (3) · „deleted“ wieder als Bit 6 allein (**genau 1**, und die Meldung zeigt woertlich `0x40=1`) · freie Saetze mit XOR 1 statt XOR 2 verrechnen (2, und Sektor 2 bekommt die Bytes des freien Blocks). **T2 und nicht T1b:** kein JV3 von fremder Hand im Korpus, kein Orakel-Binary verfuegbar. Die Pruefdatei ist nach der Arithmetik des Orakels gebaut — nicht nach UFTs Code — und der freie Satz ist mit Absicht **512** Byte gross (flags&3 = 0, XOR 2), damit die XOR-2-Regel wirklich geprueft ist: mit XOR 1 waeren es 256, und der Sektor dahinter laege falsch. | 1 |
9090
| `jvc` | **T1b** | `test_corpus_gw_geometrie`, `test_schranken_die_nie_greifen` ||| 1 |
9191
| `kfx` | **T1b** | `test_apple_moof_a2r_no_door`, `test_fremde_hand_liest`, `test_kfx_probe_overclaims`, `test_kfx_sonde_sagt_nein` ||| 2 |
92-
| `logical` | **T1b** | `test_logical_gegen_libdsk`, `test_posix_gegen_libdsk` | libdsk **1.5.12** (John Elliott, **LGPL-2+**; Quelltext **nur gelesen**, Kanal *Spec* nach MF-695, `dsktrans` **ausgefuehrt**). Vier Dateien: `lib/drvlogi.c` (Z. 24-26 der Kopfkommentar, Z. 67-85 `logical_open()` prueft nichts, Z. 124-147 `logical_read()`, Z. 150-165 Loecher mit 0xE5), `lib/dsklphys.c` (Z. 91-118 `dg_pt2lt()` — die vier Gesetze, Z. 28-48 `dg_ps2ls()`), `lib/dsksgeom.c` (die Geometrietafel samt Sidedness und `dg_secbase`), `lib/drvposix.c` (Z. 24 die Abgrenzung: dort ist die Sidedness die des TREIBERS, hier die der GEOMETRIE). | MF-1032 — **UFT konnte keine echte Logical-Datei lesen, und die Anordnung, die das Format AUSMACHT, war gar nicht umgesetzt.**
92+
| `logical` | **T1b** | `test_durchschreibprobe`, `test_logical_gegen_libdsk`, `test_posix_gegen_libdsk` | libdsk **1.5.12** (John Elliott, **LGPL-2+**; Quelltext **nur gelesen**, Kanal *Spec* nach MF-695, `dsktrans` **ausgefuehrt**). Vier Dateien: `lib/drvlogi.c` (Z. 24-26 der Kopfkommentar, Z. 67-85 `logical_open()` prueft nichts, Z. 124-147 `logical_read()`, Z. 150-165 Loecher mit 0xE5), `lib/dsklphys.c` (Z. 91-118 `dg_pt2lt()` — die vier Gesetze, Z. 28-48 `dg_ps2ls()`), `lib/dsksgeom.c` (die Geometrietafel samt Sidedness und `dg_secbase`), `lib/drvposix.c` (Z. 24 die Abgrenzung: dort ist die Sidedness die des TREIBERS, hier die der GEOMETRIE). | MF-1032 — **UFT konnte keine echte Logical-Datei lesen, und die Anordnung, die das Format AUSMACHT, war gar nicht umgesetzt.**
9393

9494
**(1) Kennung und Kopf waren erfunden.** Verlangt wurden `"LGD\0"` und ein **32-Byte-Kopf** mit `cylinders/heads/sectors/sector_size/first_sector/encoding/data_rate`. libdsks `logical_open()` (`lib/drvlogi.c` Z. 67-85) prueft **nichts** — es gibt keine Kennung und keinen Kopf, die Datei beginnt mit dem ersten Sektor. Klasse von **MF-961** (`86f`), **MF-1022** (`sap`), **MF-1029** (`myz80`) und **MF-1030** (`nanowasp`) — zum **fuenften** Mal.
9595

@@ -151,7 +151,7 @@ Die Konfidenz steht bei **40** (MF-729: „nur die Groesse“) und darf nicht ho
151151
| `opus` | **T1b** | `test_kopflose_sonden_sind_erreichbar`, `test_opd_geometrie`, `test_opus_gegen_floptool`, `test_schreibzusage_erreicht_die_datei`, `test_zx_und_pc98_echte_abbilder` | MF-905 Geometrie aus dem Bootsektor: src/samdisk/opd.h (struct OPD_BOOT) und src/samdisk/opd.cpp — ReadOPD() UND WriteOPD() werten identisch aus (cyls, sectors, heads = flags & 0x10, Groessencode = flags >> 6). SAMdisk ist im Baum vendort unter MIT (src/samdisk/License.txt). Loest die frueher genannte, ausdruecklich UNVERIFIZIERTE Referenz libdsk drvopus.c ab (MF-651). | MF-905 || MF-1074 — **dieselbe Falle wie bei `mgt` daneben, an derselben Zeile.** `opus_probe_plugin()` begann mit `(void)file_size;`, und `uft_opus_probe()` verlangt seit MF-905, dass die im Bootsektor angesagte Geometrie die **Dateigroesse** restlos erklaert (`cyls * heads * sectors * ssize == size`). Bekommen hat es 4096 — eine Zahl, die keine Opus-Geometrie ergibt; die Sonde konnte **nie** zustimmen. Gemessen an zwei echten Discovery-Abbildern: `probe` = 0 bei `open` = 0 mit 160 bzw. 40 Spuren und 2880 bzw. 720 Sektoren. **Der Sondenrumpf selbst ist richtig** — anders als bei `mgt`: `data[0] != OPUS_JR_OPCODE` weist einen Nullpuffer in der ersten Zeile ab, die MF-729-Eichung blieb also gewahrt. Und diese Pruefung ist **nur** an einer Datei mit gueltigen Geometriefeldern ohne Sprungbefehl isolierbar (am Nullpuffer greift schon `cyls == 0`) — nachgemessen statt behauptet, wie MF-1031 es vorgemacht hat. Mutationsmatrix **8 von 8**, Grundlauf zuerst. **T2 bleibt T2**: die Abbilder stammen aus einem Paket ohne Lizenztext, P3-359 || MF-1075 — **T2 bleibt T2, und das ist eine Messung, keine Vorsicht.** Die zwei echten Opus-Discovery-Abbilder aus dem Archiv sind zu ~100 % mit dem Formatier-Fuellbyte **0xE5** belegt; ausser dem Etikett „SpeccyPL“ steht nichts darauf. Nach MF-1021 ist ein Abbild erst dann ein Beleg, wenn sein INHALT nachgewiesen ist — sie stehen deshalb als `derived` im Manifest und heben keine Stufe. **Was sie trotzdem belegen:** der Bootsektor ist echt, und seine Geometrie kommt durch. Gemessen `18 05 50 12 50` (80 Zylinder, 18 Sektoren, zwei Koepfe, 256 Byte) und `18 05 28 12 40` (40 Zylinder, EIN Kopf) — Byte fuer Byte die Form, die MF-1074 aus der Beschreibung **erzeugt** hatte, bevor eines dieser Abbilder gelesen war | 1 |
152152
| `pdp` | **T1b** | `test_corpus_gw_geometrie` ||| 1 |
153153
| `po` | **T1b** | `test_apple_do_po_bounds`, `test_corpus_gw_geometrie`, `test_do_po_probe_ignores_content`, `test_durchschreibprobe`, `test_format_probe_fuzz`, `test_plugin_probe_real`, `test_po_write_roundtrip` ||| 1 |
154-
| `posix` | **T1b** | `test_posix_gegen_libdsk` | libdsk **1.5.12** (John Elliott, **LGPL-2+**; Quelltext **nur gelesen**, Kanal *Spec* nach MF-695, `dsktrans` **ausgefuehrt**). `lib/drvposix.c` Z. 23-24 (der Kopfkommentar), Z. 38-98 (die drei Treiberklassen), Z. 232-254 (`posix_offset()` samt der Abgrenzung gegen `logical`), Z. 150-165 (Loecher mit 0xE5); `lib/dsklphys.c` Z. 91-118 (`dg_pt2lt()`). Die `.geom`-Nachbardatei ist **nicht** von dort — sie ist UFT-eigen, siehe Q1. | MF-1034 — vier Befunde, und der zweite hiess: **von den drei Spielarten war nur eine umgesetzt**.
154+
| `posix` | **T1b** | `test_durchschreibprobe`, `test_posix_gegen_libdsk` | libdsk **1.5.12** (John Elliott, **LGPL-2+**; Quelltext **nur gelesen**, Kanal *Spec* nach MF-695, `dsktrans` **ausgefuehrt**). `lib/drvposix.c` Z. 23-24 (der Kopfkommentar), Z. 38-98 (die drei Treiberklassen), Z. 232-254 (`posix_offset()` samt der Abgrenzung gegen `logical`), Z. 150-165 (Loecher mit 0xE5); `lib/dsklphys.c` Z. 91-118 (`dg_pt2lt()`). Die `.geom`-Nachbardatei ist **nicht** von dort — sie ist UFT-eigen, siehe Q1. | MF-1034 — vier Befunde, und der zweite hiess: **von den drei Spielarten war nur eine umgesetzt**.
155155

156156
**(Q1) Die Attribution trug nicht.** Der Dateikopf sagte „Reference: libdsk drvposix.c (LGPL-2.0-or-later; Fassung 1.5.12 geprueft)“. Die Zeichenfolge `.geom` kommt im **ganzen** libdsk-Baum nicht vor (gemessen ueber `lib/`, `include/`, `tools/`, `doc/`); libdsk loest die Geometriefrage, indem der Aufrufer sie **nennt** (`dsktrans -itype raw -format acorn640`). Die Sidecar-Datei ist **UFTs eigene Konvention** und wird jetzt so geführt. Eine Attribution ist eine rechtliche Aussage (MF-636), ein Pruefvermerk eine gemessene — dieselbe Berichtigung wie bei `logical` (MF-1032).
157157

docs/WAISEN_ROLL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Fortschritt (MF-1077, G2).
9494
| `uft_myz80_write` | schreiber | verdrahtet | MF-1112 |
9595
| `uft_qrst_write` | schreiber | verdrahtet | MF-1112 |
9696
| `uft_logical_write` | schreiber | offen | P3-204 |
97-
| `uft_posix_write` | schreiber | offen | P3-204 |
97+
| `uft_posix_write` | schreiber | verdrahtet | MF-1119 |
9898
| `uft_hardsector_write` | schreiber | verdrahtet | MF-1117 |
9999
| `uft_ibm3740_write` | schreiber | absicht | MF-1117 |
100100
| `uft_atx_write` | schreiber | offen | P3-380 |

0 commit comments

Comments
 (0)