Files
rippy/rippy-windows/src/kern/laufwerk/codes.ts
T
HitonabiandClaude Fable 5 a45069af5e
Ampel / ampel (push) Successful in 1m21s
feat(v5): Etappe W-1 — Laufwerk: Wache, Typ, Auswerfen mit Nachsehen
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>
2026-08-30 17:28:46 +02:00

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
}