← ST-Computer 04 / 1988

Auf der Schwelle zum Licht: Laufwerksverwaltung

Grundlagen

Diesmal widmen wir uns der Verwaltung der Laufwerke unter GEMDOS. Dabei wird, wie versprochen, der Drive-Media-Descriptor erklĂ€rt. Außerdem ist das Thema “Cluster- und Sektornumerierung” vom letzten Mal auch noch nicht ausgeschöpft.

Nachtrag

Doch zuerst noch ein kleiner Nachtrag zur FAT-Verwaltung. Es ist vielleicht noch ganz interessant, den Algorithmus zu kennen, mit dem ein freier Sektor in der FAT ausgewÀhlt wird, wenn eine Datei verlÀngert wird.

Die Strategie ist eigentlich sehr einfach. Beim letzten Cluster der Datei beginnend, wird einfach der erste freie Cluster gesucht. Wenn dabei der letzte Cluster (nach Meinung des GEMDOS der letzte, eigentlich der drittletzte) erreicht wird, setzt man die Suche beim ersten Cluster (der Nummer 2) fort. Wenn ‘numcl’- EintrĂ€ge erfolglos untersucht wurden, ist das Speichermedium voll, und die Funktion bricht ab.

Nach dem Kreieren einer Datei beginnt die Suche fĂŒr den ersten Cluster von vorne.

Anmeldung von Laufwerken

Damit GEMDOS mit den verschiedenen Massenspeicher-Laufwerken Zusammenarbeiten kann, mĂŒssen diese bei ihm “angemeldet” sein. Dies geschieht aber nicht explizit dadurch, daß ein Treiberprogramm eine spezielle Funktion aufruft oder irgendwelche Systemvariablen manipuliert, sondern wird von GEMDOS automatisch durchgefĂŒhrt, wenn das Laufwerk zum ersten Mal mittels einer GEMDOS-Funktion angesprochen wird.

GEMDOS fĂŒhrt Buch darĂŒber, welche Laufwerke ihm schon bekannt sind. Dazu dient eine Bit-Maske (‘drvmap’), wobei ein gesetztes Bit bedeutet, daß das Laufwerk angemeldet ist. Bit 0 ist dabei Laufwerk A: zugeordnet, Bit 1 gehört zu Laufwerk B:, usw.

Bei jeder GEMDOS-Funktion, die auf ein Laufwerk zugreifen muß (insbesondere also die Datei- und Disk-Funktionen F... bzw. D...), wird von einer Routine ĂŒberprĂŒft, ob der Zugriff auf das gewĂŒnschte Laufwerk möglich ist. Diese Routine wird im folgenden ‘d_chkdrv’ genannt.

Wenn das Laufwerk schon bekannt ist, also das zugehörige Bit in ‘drvmap’ gesetzt ist, geht man davon aus, daß es auch ansprechbar ist. Man ĂŒberprĂŒft nur noch, ob fĂŒr das Laufwerk schon ein Standardpfad existiert. Ist dies nicht der Fall, wird das Root Directory als aktuelles Directory festgelegt (dazu kommen wir noch einmal in einer spĂ€teren Folge). Ist das Laufwerk dagegen GEMDOS noch unbekannt, wird das BIOS mit ‘Getbpb’ um Hilfe gefragt. Wenn hier ein Fehler zurĂŒckgeliefert wird, ist entweder kein Treiber fĂŒr das Laufwerk installiert oder es kann nicht an-, gesprochen werden (z.B. wenn der Boot-Sektor der Diskette einen Lesefehler hat).

Im Normalfall gibt ‘Getbpb’ die Adresse des “BIOS-Parameter-Blocks” (BPB) zurĂŒck, an dessen Aufbau Sie sich vielleicht noch aus der letzten Folge erinnern. Der BPB wird nun ausgewertet und der “Drive Media Descriptor” aufgebaut (siehe nĂ€chsten Abschnitt).

Anschließend definiert wie oben beschrieben, das Root-Directory als aktueller Pfad.

Interessant ist in diesem Zusammenhang noch, daß ‘d_chkdrv’, wenn alles geklappt hat, die Laufwerkskennung an den Aufrufer zurĂŒckgibt. ERROR (-1L) zeigt einen eventuellen Fehler an. Wenn die aufrufenden Routinen diese Kennung und nicht die, die sie ‘d_chkdrv’ ĂŒbergeben haben, fĂŒr die eigentlichen Operationen benutzen wĂŒrden, könnten in ‘d_chkdrv’ Laufwerke auf andere umgeleitet werden, bzw. es könnten “virtuelle Laufwerke” verwaltet werden.

An der Verwendung des Konjunktivs merken Sie schon, daß dies ein Wunschtraum bleibt, denn die RĂŒckgabe von ‘d_chkdrv’ wird nicht weiter beachtet (außer daß die Fehlermeldung abgefragt wird).

Dieser in ‘d_chkdrv’ auftretende interne Fehler, nĂ€mlich daß ein Laufwerk nicht angesprochen werden kann, ist die in der Januar-Folge als “Laufwerk unbekannt” bezeichnete Ursache von GEMDOS-Fehlermel-dungen (am besten nochmal nachlesen).

Der “Drive Media Descriptor”

Jeder eifrige Leser von Original ATARI-Dokumentationen ist schon ĂŒber die Bezeichnung “Drive Media Descriptor” gestolpert: Bei der Angabe (von Dokumentation kann man hier wohl kaum sprechen) des “Buffer Control Blocks” (BCB) taucht dieser Begriff auf, ohne daß ein weiteres Wort ĂŒber ihn verloren wird. Hier soll nun sein Geheimnis, das eigentlich gar keins ist, gelĂŒftet werden.

Sein Aufbau ist in Abb. 1 dargestellt. Die Komponenten lassen sich am besten erlÀutern, indem man die Initialisierung des DMD bei der Anmeldung eines Laufwerks betrachtet.

Wie der Name schon sagt, beschreibt der DMD ein Laufwerk bzw. das damit verbundene Speichermedium. Er erlaubt GEMDOS, die Kommunikation mit den unterschiedlichsten Laufwerken und Medien, da er recht flexibel ist. Wie letzten Monat schon deutlich wurde, ist dies aber alles nur graue Theorie, da hier so manches nicht funktioniert.

‘d_drive’ enthĂ€lt, wie man sich beinahe denken kann, die Kennung des Laufwerks, das der DMD beschreibt. Einige Werte im DMD werden direkt aus dem BPB ĂŒbernommen, was durch die Ă€hnliche Namensgebung angedeutet werden soll. So ist ‘d_clsiz’ die Cluster-GrĂ¶ĂŸe in Sektoren (wie ‘b_clsiz’), ‘d_clsizb’ gibt die Cluster-GrĂ¶ĂŸe in Bytes an (wie ‘b_clsizb’), ‘d_recsiz’ ist die Sektor-GrĂ¶ĂŸe in Bytes (wie ‘b_recsiz‘), ‘d_fsiz’ ist die FAT-GrĂ¶ĂŸe in Sektoren (wie ‘b_fsiz’) und ‘d_numcl’ ist die Anzahl der Daten-Cluster (wie ‘b_numcl’). ‘d_flag' enthĂ€lt eine Kopie des Bit 0 von ‘b_flags[0]\ gibt also Auskunft, ob eine 12-oder 16-Bit-FAT vorliegt. Die anderen Bits von ‘d_flag’ sind immer Null, unabhĂ€ngig von ‘b_flags[0]'

Bei der Berechnung von Datei-Positionen, Sektor-Nummern, usw. rechnet GEMDOS fleißig mit diesen Werten herum. Dabei ist es oft notwendig, durch sie zu dividieren bzw. bestimmte Bits auszublenden. Dies wird mit Shift-Operationen und Logisch-AND-Befehlen erreicht. Damit man die hierbei benötigten Shift-Operanden (Zweierlogarithmen) und Bit-Masken nicht jedesmal neu berechnen muß, merkt sich GEMDOS einige davon im DMD.

In ‘djclsiz’ wird der Zweierlogarithmus von ‘d_clsiz’ gespeichert, ‘d_mclsiz’ ist eine Bit-Maske zum Ausblenden niederwertiger Bits (Tab. 1). Die entsprechenden Werte fĂŒr ‘d_recsiz’ sind in ‘djrecsiz’ und ‘d_mrecsiz’ abgelegt (wer hĂ€tte das gedacht?). Die Bit-Masken sind zwar gerade die um eins verminderten Werte selbst, aber GEMDOS holt sie sich extra aus einer Tabelle ('f_masks’, s.u.)!

'clsiz' ’lclsiz' 'mclsiz' bzw. bzw. bzw. 'recsiz' ’lrecsiz' 'mrecsiz'

1 0 $0000 2 1 $0001 4 2 $0003 : : : 512 9 $01FF 1024 10 $03FF : : :

Tab. 1: Shift- und Maskier-Werte

typedef struct { int d_roff[3]; /* Sektornummer-Offsets fĂŒr FAT,DIR,DATA */ int d_drive; /* Laufwerkskennung 0..15 */ int d_fsiz; /* FAT-GrĂ¶ĂŸe in Sektoren */ int d_clsiz; /* Cluster-GrĂ¶ĂŸe in Sektoren */ int d_clsizb; /* Cluster-GrĂ¶ĂŸe in Bytes */ int d_recsiz; /* Sektor-GrĂ¶ĂŸe in Bytes */ int d_numcl; /* Zahl der Datencluster */ int d_lclsiz; /* 2er-Logarithmus von clsiz * */ int d_mclsiz; /* Bit-Maske fĂŒr clsiz */ int d_lrecsiz; /* 2er-Logarithmus von recsiz */ int d_mrecsiz; /* Bit-Maske fĂŒr recsiz */ int d_lclsizb; /* 2er-Logarithmus von clsizb */ FD *d_fatfd; /* Zeiger auf FD der FAT */ long d_dummy; /* unbenutzt */ DD *d_rdd; /* Zeiger auf DD des Root Directorys */ int d_flag; /* FAT-Typ: 0: 12-Bit, 1: 16-Bit */ } DMD;

Abb. 1 : Drive Media Descriptor (DMD)

  • | Standard-Diskette | fiktiv | fiktiv ------- | ---------- | ------- | ------- CLSIZ | 2 | 1 |4 datrec | 18 | 11 | 50 fatrec | 16 | 13 | 21 d_roff[2] | 14 | 9 | 42 RDLEN | 7 | 5 | 9 | RDCL | 4 | 5 |3 | RD-Clusternr. | -5.. -2 | -6.. -2 | -4.. -2 RD-Sektornr. | -10.. -4 | -6.. -2 | -16.. -6 d_roff[1] | 21 | 12 | 57 FSIZ | 5 | 3 | 20 FCL | 3 | 3 | 5 FAT-Clusternr. | -8.. -6 | -9.. -7 | -9.. -5 FAT-Sektornr. | -16..-12 | -9.. -7 | -36..-17 d_roff[0] | 22 | 12 | 57

Tab. 2 : Beispiele zur GEMDOS-Sektor-ZĂ€hlung

Zur Verwaltung von Dateien (einschl. Directories und FAT) gibt es weitere Strukturen (“File Descriptoren” und “Directory Descriptoren”), um die wir uns ein andermal kĂŒmmern. Hier sei nur erwĂ€hnt, daß sie zusammen mit dem DMD ein kompliziertes Netz bilden, welches vom DMD aus gut “aufgerollt” werden kann.

Beim Einrichten des DMD werden die File Descriptoren fĂŒr das Root Directory und die FAT sowie der Directory Descriptor des Root Directories ebenfalls initialisiert.

Übrig bleiben nun noch die "d_roff[0..2]’-Werte. Dabei handelt es sich um die letzten Monat erwĂ€hnen Sektornummer-Offsets fĂŒr FAT-, DIR- und DATA-Sektoren. Die GEMDOS-Sektornummer plus entsprechendem Offset ergibt die BIOS-Sektornummer.

In der letzten Folge waren die beiden ZĂ€hlweisen einander gegenĂŒbergestellt, wobei auffiel, daß die GEMDOS-Sektornummern nicht durchgehend waren, sondern daß es merkwĂŒrdige LĂŒcken in der Numerierung gab. Heute soll der Algorithmus erklĂ€rt werden, mit dem diese ZĂ€hlweise festgelegt wird.

Bisher habe ich Ihnen eine weitere Komplikation noch verschwiegen. Obwohl eigentlich nur Daten-Sektoren zu Clustern zusammengefaßt werden, gibt es auch Cluster-Nummern fĂŒr Root Directory (RD) und FAT. Das liegt daran, daß RD und FAT intern wie Dateien behandelt und daher bei der Berechnung von Dateipositionen (Seek-Funktion) wie bei Dateien Cluster in Sektoren umgerechnet werden. Da es in Wirklichkeit aber gar keine Cluster gibt, mĂŒssen Cluster- und Sektornumerierung so angelegt sein, daß die Pseudo-Cluster-Nummern eindeutig auf GEMDOS-Sektornummem abgebildet werden.

Zum besseren VerstĂ€ndnis der etwas komplizierten ZusammenhĂ€nge dient Tab. 2, wo Beispiele fĂŒr die nun folgenden ErklĂ€rungen angegeben sind. Aus der LĂ€nge des RD in Sektoren (‘b_rdlen’) errechnet sich seine LĂ€nge in Clustern (‘rdcl’). Da die Zahl der RD-Sektoren kein Vielfaches der ClustergrĂ¶ĂŸe sein muß, wird diese Clusterzahl aufgerundet. Die genaue Formel lautet:

rclcl_rdlen + clsiz - 1 clsiz

(Der bei der Division auftretende Rest wird ignoriert). Der erste “Cluster” des RD ist ‘rdsf:

rdst = - 1 - rdcl

Das RD belegt damit die Clusternummern ‘rdst’ bis -2; die Clusternummer -1 existiert nicht, ebenso die Cluster 0 und 1. Die erste GEMDOS-Sektornummer ergibt sich durch Multiplikation mit der Anzahl der Sektoren pro Cluster. Durch die Aufrundung bei der Berechnung von ‘rdcl’ ergeben sich in der “Ausnutzung” der GEMDOS-Sektornummern LĂŒcken (s. Beispiele in Tab. 2).

Entsprechend verfÀhrt man mit der FAT:

fl_fsiz + clsiz - 1 clsiz fst = rdst - fcl

Die FAT-Cluster liegen unmittelbar vor den RD-Clustem, denn sie haben die Nummern ‘fst’ bis ‘rdst’-1. Auch hier ergibt sich die erste GEMDOS-Sektornummer durch Multiplikation von ‘fst’ mit ‘clsiz’.

Nachdem nun festgelegt wurde, welchen Pseudo-Clustern die RD- und FAT-Sektoren zugeordnet werden, kann GEMDOS die gesamte Verwaltung wie bei User-Dateien erledigen. Beim tatsĂ€chlichen Zugriff werden nun die GEMDOS-Sektornummern, mit denen sich die Sektorpuffer-Verwaltung herumschlagen muß, mit den ‘d_roff’-Offsets zu BIOS-Nummern zurĂŒckgerechnet. Diese Offsets mĂŒssen nun so berechnet werden, daß diese RĂŒcktransformation klappt.

FĂŒr Daten-Sektoren:
d_roff[2] = datrec - (2 * clsiz)

‘datrec’ ist die aus dem BPB entnommene BIOS-Nummer des ersten Da-ten-Sektors. Da der erste Cluster immer die Nummer 2 hat, ergeben sich fĂŒr Daten-Sektoren die Nummern ab ‘datrec’ aufwĂ€rts.

FĂŒr FAT-Sektoren:
d_roff[0] = fatrec - (fst * clsiz)

‘fatrec’ ist die ebenfalls im BPB gefundene BIOS-Nummer des ersten Sektors der zweiten FAT, die, wie Sie seit einem Monat wissen, eigentlich die erste FAT ist. Zu beachten ist, daß ‘fst’ negativ ist, und damit ‘d_roff[0]’ grĂ¶ĂŸer als ‘fatrec’ wird. Dies ist aber korrekt, da die bei der Umrechnung addierten GEMDOS-Sektornummern negativ sind, so daß sich BIOS-Nummern ab ‘fatrec’ aufwĂ€rts ergeben.

FĂŒr RD-Sektoren:
d_roff[1] = fatrec + fsiz - (rdst * clsiz)

Das RD muß unmittelbar nach der zweiten FAT liegen, beginnt also bei ‘fatrec’ plus ‘fsiz’ (‘fsiz’ ist die Zahl der Sektoren pro FAT, zu finden im BPB - wo wohl sonst?). Der Rest ist wie bei der FAT.

So, nun wissen Sie hoffentlich alles, was man ĂŒber Sektor- und Clusternummern wissen muß. Bei den bisherigen Erfahrungen mit GEMDOS muß man sich wundern, daß das ganze Hin- und Hergerechne so reibungslos funktioniert; zumindest ist mir in dieser Hinsicht noch kein Fehler bekannt.

Noch eine ErgĂ€nzung fĂŒr diejenigen, die den Artikel ĂŒber die Speicherverwaltung kennen:

Die DMDs werden im “internen GEMDOS-Speicher” abgelegt. Da es hiervon aber nur relativ wenige gibt, ist die Anzahl der Laufwerke selbst nicht so entscheidend. Allerdings wird man bei vielen Laufwerken auch viele Ordner ansprechen, so daß die Chance, daß einem der GEMDOS-Speicher ausgeht, bei jedem neuen Laufwerk steigt (eine zweite Floppy wirkt hier schon Wunder).

Da ein DMD 42 Byte groß ist, was aufgerundet drei 8-Wort-Einheiten (382 = 48) sind, finden sich freigegebene DMDs in der ‘mifl’-Liste 3. Der DMD ist ĂŒbrigens die einzige Struktur, die ĂŒber die “3er-Liste” verwaltet wird.

Abmelden von Laufwerken

GEMDOS erkennt zwar selbstĂ€ndig neue Laufwerke und richtet dafĂŒr die internen Datenstrukturen ein, doch ist die Anmeldung eines Laufwerks nicht vorgesehen.

Aber auch hierfĂŒr gibt es einen “automatischen” Mechanismus, nĂ€mlich den Mediumwechsel. Bei einem durch das BIOS gemeldeten Mediumwechsel werden zuerst alle Datenstrukturen des betroffenen Laufwerks freigegeben. Dies sind der DMD, die File und die Directory-Descriptoren. Weiterhin werden alle Pfade zu Directories sowie die Sektor-Puffer fĂŒr ungĂŒltig erklĂ€rt (siehe hierzu auch die erste und zweite Folge).

Anschließend wird mit der BIOS-Funktion ‘Getbpb’ ĂŒberprĂŒft, ob das Laufwerk (mit einem anderen Medium) ĂŒberhaupt noch verfĂŒgbar ist. Ist dies der Fall, werden die Strukturen zur Disk-Verwaltung neu initialisiert, so daß das Laufwerk GEMDOS wieder bekannt ist.

Wenn das Laufwerk nicht mein ansprechbar ist, wird es fĂŒr GEMDOS abgemeldet, indem das entsprechende Bit von ‘drvmap’ gelöscht wird. Einer erneuten Anmeldung durch Zugriff steht nichts im Wege.

Dieses Verfahren kann man sich zu Nutze machen, wenn man gezielt einzelne Laufwerke abmelden will. Dies kann sinnvoll sein, wenn das Laufwerk unter verschiedenen Kennungen angesprochen werden soll. WĂŒrde die Abmeldung nicht erfolgen und der Treiber einfach auf seine alte Kennung nicht mehr reagieren, wĂŒrden die Datenstrukturen als “Leichen” im Speicher herumliegen und kostbaren internen Speicher verbrauchen.

Außerdem kann ein simulierter Mediumwechsel bei allen Laufwerken einfach dazu dienen, internen Speicher freizugeben, was nach ausgiebigem Öffnen von vielen Ordnern empfehlenswert ist. Dazu lĂ€ĂŸt sich eine solche Routine leicht in ein Accessory einbauen.

Listing 1 zeigt nun, wie man’s macht. In der Funktion ‘free=drv’ werden zunĂ€chst die Vektoren der elementaren Disk-Routinen ‘Mediach’, ‘Getbpb’ und ‘Rwabs’ auf eigene Routinen umgesetzt. Durch den Aufruf der GEMDOS-Funktion ‘Dffee’ (andere tun’s auch) wird GEMDOS zu einem Zugriff auf das Laufwerk gezwungen. Die eigenen Disk-Routinen geben nun Meldungen zurĂŒck, wie sie bei einem Diskettenwechsel auftreten.

Die Funktion ‘free_all’ generiert Diskettenwechsel fĂŒr alle 16 möglichen Laufwerke.

Da die Disk-Vektoren im geschĂŒtzten Speicherbereich liegen, darf auf sie nur im Supervisor-Mode zugegriffen werden. Da man dieses Problem als “Betriebssystem-Hacker” öfter hat, sind die allgemeinen "Peek & Poke”-Routinen fĂŒr solche Dinge ganz brauchbar. Wer erinnert sich hier nicht an seine alten 8-Bitter, bei denen die Kenntnis geheimnisvoller “Poke-Befehle” unerlĂ€ĂŸlich war?

Bei der Anwendung dieses kleinen Programms sollten Sie darauf achten, daß auf den betroffenen Laufwerken keine Dateien mehr geöffnet sind, da diese bei dem “Mediumwechsel” nicht mehr ordnungsgemĂ€ĂŸ geschlossen werden können, und daher Datenverlust droht. Ferner gehen alle Standardpfad-Einstellungen verloren.

Systemvariable ‘drvbits’

Wie wir nun wissen, steht in der GEMDOS-Variablen ‘drvmap’, welche Laufwerke bekannt sind. Andererseits gibt es noch die BlOS-Systemvariable ‘drvbits’ ($4C2). ‘drvbits’ ist ebenfalls eine Bit-Maske fĂŒr vorhandene Laufwerke (sogar 32 Bit!), hat aber nichts mit GEMDOS zu tun.

WĂ€hrend ‘drvmap’ angibt, welche Laufwerke schon einmal angesprochen wurden, steht in ‘drvbits’, ob das Laufwerk ĂŒberhaupt verfĂŒgbar ist. Massenspeicher-Treiber sollten allerdings die von ihnen belegten Laufwerkskennungen hier eintragen, ‘drvbits’ wird nĂ€mlich von der BIOS-Funktion ‘Drvmap’ zurĂŒckgeliefert, damit Anwenderprogramme feststellen können, welche Laufwerke ansprechbar sind. Vom AES wird diese Möglichkeit wĂ€hrend der Reset-Phase auch ausgiebig genutzt.

GEMDOS-Variablen fĂŒr Disk-Verwaltung

Die globalen GEMDOS-Variablen fĂŒr die Disk-Verwaltung sind in Abb. 2 dargestellt, zusammen mit denen fĂŒr die Sektor-Pufferung, die ich letztes Mal vergessen habe. Die erste Adresse gilt fĂŒr das alte TOS (6.2.1986), die zweite fĂŒr das Blitter-TOS. ÜberflĂŒssig zu erwĂ€hnen, daß diese Adressen nicht dokumentiert sind und nicht in Programmen verwendet werden sollten.

BCB bcbx[4]; /* $60a4/ $8846: BIOS: 4-Standard-BCBs */ char secbuf [4][512]; /* $4e22/ $75c4: BIOS: 4 Puffer fĂŒr je 1 Sektor */ int drvmap; /* $5fe2/ $8784: Bit-Map fĂŒr angemeldete Drives */ DMD *dmdx[16]; /* $5bde/ $8780: DMD-Zeiger fĂŒr alle Drives */ int f_masks[] /* $fd1bf6/$fd3022: Masken fĂŒr Datei-Operationen */ = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0xffff, 0x1fff, 0x3fff, 0x7fff };

Abb. 2 : GEMDOS-Variablen zur Puffer- und Disk-Verwaltung

‘bcbx’ und ‘secbuf’ sind die vom BIOS eingerichteten 4 BCBs mit den dazugehörigen Sektor-Puffern. Sie sind legal ĂŒber die Pufferlisten (‘bufl[]’) zugĂ€nglich.

‘drvmap’ wurde oben schon erlĂ€utert. GEMDOS hat eine Tabelle (‘dmdx’), in der fĂŒr jedes Laufwerk der Zeiger auf den DMD steht. Wenn ein Laufwerk unbekannt ist, enthĂ€lt die Tabelle einen Nullzeiger (OL). Gesetzt bzw. gelöscht werden diese Zeiger bei der automatischen An- und Abmeldung der Laufwerke.

‘f_masks’ ist eine Tabelle mit Bit-Masken, die fĂŒr Berechnungen verschiedenster Art benötigt werden. Bei der Anmeldung von Laufwerken ergeben sich die Werte fĂŒr ‘b_mrecsiz’ und ‘b_mclsiz’ aus dieser Tabelle durch Indizierung mit den log2-Werten (‘b_lrecsiz’, ‘bjclsiz’).

Im folgenden wird die Struktur des Prozeßdescriptors noch gebraucht werden, daher ist sie fĂŒr diejenigen unter Ihnen, die den Artikel “Programmverwaltung” nicht gelesen haben, in Abb. 3 noch einmal dargestellt. FĂŒr die genaue ErklĂ€rung muß ich jedoch leider wieder auf das ST-Extra-Heft verweisen.

Mehr als 16 Laufwerke?

GEMDOS kann in seiner derzeitigen Version entgegen sĂ€mtlicher GerĂŒchte maximal 16 Laufwerke verwalten. Dies scheint viel zu sein, doch gibt es Leute, denen das noch zu wenig ist. Die GrĂŒnde fĂŒr die BeschrĂ€nkung auf 16 Laufwerke sind die folgenden:

‘drvmap’ ist nur eine ‘int’-Variable (16 Bit). Durch eine einfache Änderung im GEMDOS-Quelltext könnte dies auf Tong’ (32 Bit) geĂ€ndert werden.

Das ‘dmdx’-Feld mĂŒĂŸte fĂŒr 32 Laufwerke erweitert werden (fĂŒr die Atari-Entwickler ebenfalls kein Problem). Das ‘p_drvx’-Feld im Prozeßdeskriptor (PD), in dem Handles fĂŒr die Standardpfade abgelegt sind (dazu kommen wir in einer spĂ€teren Folge), ist fĂŒr 16 Laufwerke dimensioniert. Da danach aber noch Platz im PD ist, wĂ€re eine Erweiterung auf 32 Laufwerke ohne Änderungen möglich. Allerdings gibt es Routinen, die alle Laufwerke aus ‘p_drvx’ in einer Schleife durchgehen (z.B. bei der Vererbung an Tochterprozesse). Hier mĂŒĂŸte ĂŒberall der Schleifenendwert auf 32 statt 16 gesetzt werden.

Bei Benutzung so vieler Laufwerke mĂŒĂŸte aber auch der interne Speicher nochmals vergrĂ¶ĂŸert werden, da GEMDOS hier ganz schön zuschlĂ€gt.

GEMDOS-Funktionen (TRAP #1)

Hier möchte ich noch kurz auf die GEMDOS-Funktionen eingehen, die mit der Disk-Verwaltung ZusammenhÀngen.

Funktion $0e Dsetdrv

long Dsetdrv(int drv)
Das Default-Laufwerk wird auf ‘drv’ gesetzt (0,1.. fĂŒr A:, B:, usw.). Dieses Laufwerk wird angesprochen, wenn in Pfadnamen keine Laufwerkskennung explizit angegeben ist.
RĂŒckgabewert
Es wird eine 32-Bit-Maske der angemeldeten Laufwerke zurĂŒckgegeben (Bit 0,1,.. fĂŒr A:,B:,..). Dabei handelt es sich jedoch nicht um die GEMDOS-Variable ‘drvmap’, sondern um die oben erwĂ€hnte BlOS-Systemvariable ‘drvbits’.

typedef struct { char *p_lowtpa; /* Zeiger auf Beginn des reservierten Bereichs */ char *p_hitpa; /* Zeiger auf Ende des reservierten Bereichs */ char *p_tbase; /* Zeiger auf TEXT-Segment */ long p_tlen; /* LĂ€nge TEXT-Segment */ char *p_dbase; /* Zeiger auf DATA-Segment */ long p_dlen; /* LĂ€nge DATA-Segment */ char *p_bbase; /* Zeiger auf BSS-Segment */ long p_blen; /* LĂ€nge BSS-Segment */ DTA *p_dta; /* Zeiger auf DTA-Puffer */ PD *p_parent; /* Zeiger auf PD des Parent-Prozesses */ long resl; /* nicht benutzt */ char *p_env; /* Zeiger auf Environment-String */ char p_devx[6]; /* Handles fĂŒr Standard-Devices */ char res2; /* nicht benutzt */ char p_defdrv; /* aktuelles Laufwerk (Default-Laufwerk) */ char res3[8]; /* nicht benutzt */ char p_drvx[16); /* Pfad_Handles fĂŒr alle Laufwerke */ char res4[0xl8]; /* nicht benutzt */ long p_d0; /* Prozessorregister DO */ long p_a3; /* Prozessorregister A3 */ long p_a4; /* Prozessorregister A4 */ long p_a5; /* Prozessorregister A5 */ long p_a6; /* Prozessorregister A6 */ long *p_reg; /* Zeiger auf restliche Prozessor-Register */ char p_cmdlin[128]; /* Kommando-Zeile (ĂŒbergebener Parameter) */ } PD;

Abb. 3: Der Prozeßdescriptor (PD)

typedef struct { long b_free; /* freie Cluster */ long b_total; /* Gesamtzahl der Cluster */ long b_secsiz; /* Sektor-GrĂ¶ĂŸe in Byte */ long b_clsiz; /* Cluster-GrĂ¶ĂŸe in Sektoren */ } DISKINFO;

Abb. 4: DISKINFO-Struktur

Arbeitsweise
GEMDOS merkt sich das aktuelle Laufwerk im PD als ‘p_defdrv’. Dies bedeutet, daß jeder Prozeß sein eigenes aktuelles Laufwerk hat.

Die Funktion ‘Dsetdrv’ besteht nur aus zwei ‘C’-Befehlen. ‘drv’ wird direkt nach ‘p_defdrv’ des PD kopiert. Dabei erfolgen keinerlei Kontrollen. Wenn das Laufwerk gar nicht existiert, wird dies frĂŒhestens beim versuchten Zugriff bemerkt (in der oben erlĂ€uterten Routine ‘d_chkdrv’). Als zweites wird die BIOS-Funktion ‘Drvmap’ aufgerufen, deren Ergebnis direkt an den Aufrufer von ‘Dsetdrv’ zurĂŒckgegeben wird.

Bei der Gelegenheit gleich noch ein Wort zu unerlaubten Laufwerkskennungen: GEMDOS bemerkt zwar frĂŒher oder spĂ€ter, wenn ein Laufwerk nicht ansprechbar ist. Es reagiert allerdings ausgesprochen allergisch auf Kennungen, die nicht zwischen 0 und 15 liegen. Da keine ÜberprĂŒfungen erfolgen, können unvorhersehbare Zugriffe erfolgen (durch Index-Überlauf in ‘p_drvx’). NatĂŒrlich gibt es auch Schwierigkeiten beim Abfragen des Laufwerk-Bits in ‘drvmap’.

Die GEMDOS-Programmierer waren sicherlich der Ansicht, daß es in Anwenderprogrammen keine Programmierfehler gibt, die illegale Kennungen erzeugen. Wie ĂŒblich muß der Anwender selbst nach den Bombenlegern im GEMDOS suchen. Bei Accessories ist wieder einmal zu beachten, daß diese unter dem PD der Hauptapplikation, also unter AES/ Desktop, laufen, wodurch sich Konflikte ergeben können.

Funktion $19 Degetdrv

int Dgetdrv()
Hiermit erhĂ€lt man die Kennung des fĂŒr den aktiven Prozeß gĂŒltigen aktuellen Laufwerks. Dies kann entweder die zuletzt mit ‘Dsetdrv* gesetzte oder die vom Parent-Prozeß “geerbte” Kennung sein.

Arbeitsweise
‘Dgetdrv’ ist ein Einzeiler. Es erfolgt direkt die RĂŒckgabe von ‘p_defdrv’ aus dem PD.

Funktion $36 Dfree

void Dfree
(DISKINFO *info, int drv)

Diese Funktion gibt Auskunft ĂŒber den freien Speicherplatz auf dem Laufwerk ‘drv’ (OfĂŒr aktuelles Laufwerk; 1,2,... fĂŒr A:,B:,..). ‘info’ muß dabei auf freien Speicherplatz zeigen, der von ‘Dfree’ mit einer DISKINFO-Struktur (Abb. 4) gefĂŒllt wird. Daraus kann der belegte und noch freie Speicherplatz in Bytes berechnet werden:

free = b_free * b_clsiz * b_secsiz used =(b_total - b_free)*b_clsiz *b_secsiz

Dabei ist zu berĂŒcksichtigen, daß‘Dfree’ nur die Informationen der FAT berĂŒcksichtigt, wo der Speicherplatz nach Clustern verbucht wird.

Arbeitsweise

Nach der Ermittlung des gewĂŒnschten Laufwerks (BerĂŒcksichtigung des aktuellen Laufwerks) und der ÜberprĂŒfung mit ‘d_chkdrv’ werden alle FAT-EintrĂ€ge (von 2 bis‘numcl’) gelesen. Alle EintrĂ€ge gleich Null werden als frei gezĂ€hlt (dies ergibt ‘b_free’).

Dann wird die DISKINFO-Struktur erzeugt. Die Werte ‘b_total\ ‘b_secsiz’ und ‘b_clsiz’ entnimmt man dabei dem DMD (‘d_numd\ 'd_recsiz\ ‘d_clsiz’).

FĂŒr das Lesen der FAT wurde keine große, programmtechnische MĂŒhe “vergeudet”. Dies erledigt nĂ€mlich die allgemeine FAT-Lese-Routine, die mit ‘f_seek’ (der internen Version von GEMDOS-Tseek’) und ‘f_read’ jeden Eintrag einzeln liest und auch noch gleich den Folge-Cluster bestimmt, was hier ja ĂŒberflĂŒssig ist. Dieser enorme Overhead erklĂ€rt, warum ‘Dfree’ so berĂŒchtigt langsam ist (gar nicht zu reden vom DESK-

TOP-”Disk-Info”, das auch noch sĂ€mtliche Directories liest!). Eine auf ‘Dfree’ zugeschnittene Routine, die effektiver arbeitet, wĂŒrde hier schon Wunder wirken.

Vorausschau

Das nĂ€chste Mal kehren wir wieder zur Dateiverwaltung zurĂŒck. Dabei geht es um die nĂ€chsthöhere Ebene -die Ebene der File-Descriptoren.

/* Routinen zum Abmelden von Laufwerken bzw. zur Freigabe internen GEMDOS-Speichers by A. Esser, Juni 1987 entwickelt mit MEGAMAX C */ #define pokeb(a,b) poke(0,(long)a,(int)b) #define pokew(a,b) poke(1, (long)a,(int)b) #define pokel(a,b) poke(3,(long)a,(long)b) #define peekb(a) ((int)peek(0,(long)a)) #define peekw(a) ((int)peek(1,(long)a)) #define peekl(a) peek(3,(long)a) /* allgemeine Funktionen zum Speicherzugriff ermöglicht Zugriff auf geschĂŒtzte Bereiche und auf ungerade Adressen */ asm { poke: pea spoke move.w #38,-(A7) ;XBIOS-Supexec trap #14 addq.w #6,A7 rts spoke: move.l 14(A7),A0 ;Poke-Adresse lea 18(A7),a1 ;Adresse des zu schreibenden Wertes move.w 12(A7),d1 ;Zahl der Bytes -1 (0,1,3) bne.s spokel ;-> int oder long addq.w #1,A1 ;char wurde als int ĂŒbergeben spokel: move.b (A1)+,(A0)+ dbf D1,spokel rts ; peek: pea speek move.w #38,-(A7) ;XBIOS-Supexec trap #14 addq.l #6,A7 rts speek: move.l 14(A7),A0 ;Peek-Adresse moveq #0,D0 move.w 12(A7),D1 ;Zahl der Bytes -1 (0,1,3) speekl: asl.l #8,D0 move.b (A0)+,D0 dbf D1,speekl rts } /* gesamten internen Speicher eines Laufwerks freigeben */ void free_drv(drive) register int drive; /* Laufwerks-Kennung 0..15 */ { long dummy[4]; /* Dfree-Puffer */ long old_bpb; /* Zwischenspeicher fĂŒr alte Vektoren */ long old_rw; long old_med; extern free_bpb(),free_rw(),free_med(); old_bpb = peekl(hdv_bpb); /* alte Vektoren merken */ old_rw = peekl(hdv_rw); old_med = peekl(hdv_mediach); pokel(hdv_bpb,free_bpb); /* auf Spezial-Routinen setzen */ pokel(hdv_rw,free_rw); pokel(hdv_mediach,free_med); Dfree(dummy, drive+1); /* Disk-Zugriff gibt Speicher frei */ pokel(hdv_bpb,old_bpb); /* Vektoren wieder zurĂŒckholen */ pokel(hdv_rw,old_rw); pokel(hdv_mediach,old_med); return; /* folgende hdv-Routinen sorgen indirekt fĂŒr Speicher-Freigabe */ asm { free_med: moveq #2,D0 ;"sicherer Medium-Wechsel" rts free_rw: moveq #-14,D0 ;"Medium-Wechsel" rts free_bpb: moveq #0,D0 ;Medium nicht vorhanden rts } } /* internen Speicher aller Laufwerke freigeben */ void free_all() { register int drive; /* ohne RĂŒcksicht auf Existenz */ for (drive = 0; drive < 16; drive++) free_drv(drive); }
Alex Esser