Ampel / ampel (push) Successful in 1m21s
kern/laufwerk in drei Schichten: codes.ts (Steuercodes HERGELEITET wie win_ioctl.py, gegen die Doku-Zahlen getestet), win32.ts (der einzige koffi-Ort im Kern, Muster aus beweise/laufwerk.js), disc.ts (Logik gegen die LaufwerkApi-Schnittstelle — classify mit den cdrom.py-Schwellen, Geraete-Info mit ready/empty/unknown + Klartext-Grund, Auswurf als entriegeln→auswerfen→NACHSEHEN mit injizierbarem Warten). Dazu wache.ts im 3-Sekunden-Takt (§ 5 Plan A): Uebergangslogik pur, gescheiterte Runde behaelt den Stand (R2) und meldet laut (R4). Fenster zeigt Laufwerke live (Modell, Typ, Groesse, Grund) mit Auswerfen-Knopf; Ereigniszeilen fuer Disc rein/raus und Fehler. Bündel-Falle gefunden und behoben: Ein woertliches require überlebt Rollup nicht — win32 wird per dynamischem import() als eigener Chunk gebaut; der Fehler war dank R4 im Fenster sichtbar statt still. Gemessen am echten BU40N (30.08.2026, RIPPY_MESSUNG=1): Laufwerk G: status=ready typ=bluray groesse=33759690752 modell=HL-DT-ST BD-RE BU40N 1.03 serial=0025114C0149 Der Auswurf-Beweis (messung.auswurf) folgt am Ende der Sitzung — der BU40N kann die Schublade nicht selbst einziehen. 52 Tests gruen (Steuercodes, classify, Auswurf-Ablauf, Geraete-Info, Wache, Smoke weiterhin gruen mit Laufwerks-Kachel im Bild). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
95 lines
4.4 KiB
TypeScript
95 lines
4.4 KiB
TypeScript
// Win32-Steuercodes und -Konstanten für optische Laufwerke — HERGELEITET,
|
|
// nicht abgeschrieben (Regel D). Bewusst OHNE koffi: disc.ts und die Tests
|
|
// brauchen die Zahlen, aber kein natives Modul. Die echten Aufrufe stehen
|
|
// allein in win32.ts (Wächter R1).
|
|
//
|
|
// Ein Zahlendreher liefert kein „unbekannter Befehl", sondern
|
|
// ERROR_INVALID_FUNCTION — das sieht aus wie „das Laufwerk kann das nicht";
|
|
// test/laufwerk.test.ts rechnet die Werte deshalb gegen die in der
|
|
// Microsoft-Dokumentation genannten Zahlen gegen.
|
|
//
|
|
// Fundstellen: CTL_CODE/FILE_DEVICE_*/METHOD_* — winioctl.h;
|
|
// IOCTL_STORAGE_* — learn.microsoft.com/windows/win32/api/winioctl;
|
|
// IOCTL_CDROM_* — ntddcdrm.h. Gemessen in beweise/laufwerk.js (30.08.2026),
|
|
// Herleitung identisch mit src/rippy/drives/win_ioctl.py (Docker-Zweig,
|
|
// dort an echter Hardware bewiesen).
|
|
|
|
// ── CTL_CODE aus winioctl.h, eins zu eins ───────────────────────────────
|
|
export function ctlCode(geraetetyp: number, funktion: number, methode: number, zugriff: number): number {
|
|
return ((geraetetyp << 16) | (zugriff << 14) | (funktion << 2) | methode) >>> 0
|
|
}
|
|
|
|
const FILE_DEVICE_CD_ROM = 0x02
|
|
const FILE_DEVICE_DISK = 0x07
|
|
const FILE_DEVICE_MASS_STORAGE = 0x2d
|
|
|
|
const METHOD_BUFFERED = 0
|
|
const METHOD_OUT_DIRECT = 2
|
|
|
|
const FILE_ANY_ACCESS = 0
|
|
const FILE_READ_ACCESS = 0x0001
|
|
|
|
export const IOCTL_STORAGE_CHECK_VERIFY2 = ctlCode(FILE_DEVICE_MASS_STORAGE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
|
export const IOCTL_STORAGE_MEDIA_REMOVAL = ctlCode(FILE_DEVICE_MASS_STORAGE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
|
|
export const IOCTL_STORAGE_EJECT_MEDIA = ctlCode(FILE_DEVICE_MASS_STORAGE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
|
|
// LOAD_MEDIA (Schublade einziehen) fehlt MIT ABSICHT: Am BU40N des
|
|
// Commanders antwortet es mit ERROR_INVALID_FUNCTION — bei flachen und
|
|
// externen Laufwerken die Regel. Ein Knopf, der auf der Hälfte aller
|
|
// Laufwerke still nichts tut, wäre ein Placebo (windows.py, 28.08.2026).
|
|
export const IOCTL_STORAGE_QUERY_PROPERTY = ctlCode(FILE_DEVICE_MASS_STORAGE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
|
export const IOCTL_CDROM_DISK_TYPE = ctlCode(FILE_DEVICE_CD_ROM, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
|
export const IOCTL_DISK_GET_LENGTH_INFO = ctlCode(FILE_DEVICE_DISK, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
|
|
|
|
// Audio-CD (W-7): TOC + rohe Sektoren. Herleitung wie win_ioctl.py.
|
|
export const IOCTL_CDROM_READ_TOC = ctlCode(FILE_DEVICE_CD_ROM, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
|
|
export const IOCTL_CDROM_RAW_READ = ctlCode(FILE_DEVICE_CD_ROM, 0x000f, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
|
|
export const CDROM_TOC_BYTES = 4 + 100 * 8
|
|
|
|
// STORAGE_DEVICE_DESCRIPTOR: Offsets der Zeichenketten-Verweise (winioctl.h).
|
|
export const SDD_VENDOR_ID_OFFSET = 12
|
|
export const SDD_PRODUCT_ID_OFFSET = 16
|
|
export const SDD_PRODUCT_REVISION_OFFSET = 20
|
|
export const SDD_SERIAL_NUMBER_OFFSET = 24
|
|
|
|
export const CDROM_DISK_AUDIO_TRACK = 0x01
|
|
export const CDROM_DISK_DATA_TRACK = 0x02
|
|
|
|
// GetLastError-Werte, an denen Zugriffe scheitern (winerror.h).
|
|
export const ERROR_INVALID_FUNCTION = 1
|
|
export const ERROR_FILE_NOT_FOUND = 2
|
|
export const ERROR_ACCESS_DENIED = 5
|
|
export const ERROR_NOT_READY = 21
|
|
export const ERROR_NOT_SUPPORTED = 50
|
|
export const ERROR_NO_MEDIA_IN_DRIVE = 1112
|
|
|
|
export const DRIVE_CDROM = 5
|
|
|
|
export const GENERIC_READ = 0x8000_0000
|
|
export const FILE_SHARE_READ = 0x01
|
|
export const FILE_SHARE_WRITE = 0x02
|
|
export const OPEN_EXISTING = 3
|
|
|
|
/** Ein fehlgeschlagener Win32-Aufruf, mit dem Code von GetLastError(). */
|
|
export class Win32Fehler extends Error {
|
|
constructor(
|
|
was: string,
|
|
readonly code: number,
|
|
) {
|
|
super(`${was} scheiterte (Win32-Fehler ${code})`)
|
|
this.name = 'Win32Fehler'
|
|
}
|
|
}
|
|
|
|
/** Die Schnittstelle, gegen die disc.ts arbeitet — in Tests nachgebildet. */
|
|
export interface LaufwerkApi {
|
|
laufwerksbuchstaben(): string[]
|
|
laufwerkstyp(buchstabe: string): number
|
|
/** Öffnet das Gerät. `zugriff` 0 fragt das GERÄT, GENERIC_READ das MEDIUM —
|
|
* bei gestörter Disc scheitert das zweite und das erste geht weiter
|
|
* (rc11-Befund, in beweise/laufwerk.js nachgemessen). Wirft Win32Fehler. */
|
|
oeffnen(geraetepfad: string, zugriff: number): unknown
|
|
schliessen(handle: unknown): void
|
|
/** DeviceIoControl. Wirft Win32Fehler, sonst die Antwort (ggf. leer). */
|
|
steuern(handle: unknown, code: number, eingabe?: Buffer | null, ausgabeBytes?: number): Buffer
|
|
}
|