Atarium: Acht plus drei ist zu wenig

Seitdem klar ist, daß der Unterbau von MultiTOS (von einigen Erweiterungen abgesehen) mit dem Freeware-Projekt MiNT identisch ist, hat das Interesse an dem neuen Betriebssystemkern massiv zugenommen.

Wie schon in den vergangenen Monaten [1] erwähnt, macht MiNT im Grunde genommen den Versuch, GEMDOS um bisher fehlende Unix-artige Eigenschaften zu erweitern. Dabei hat MiNT-Autor Eric Smith offensichtlich eine möglichst hohe Kompatibilität zu existierenden- Unix-Versionen und somit auch automatisch zum POSIX-Betriebssystemstandard [2] angestrebt. In mancher Hinsicht kann man MultiTOS/MiNT also als Unix-artiges Betriebssystem mit GEMDOS-Kompatibilität betrachten.

Neue Dateibehandlung

Ein beträchtlicher Anteil der Entwickler von Atari-Software besteht aus Studenten, die meist sowieso im Rahmen ihres Studiums mit Unix-Systemen in Kontakt kommen. Ihnen braucht man kaum zu erklären, wie die neuen MiNT-Funktionen anzusprechen sind. Anders bei Programmierern, die vorher nur Atari- oder auch MSDOS-Erfahrungen sammeln konnten. Gerade für diese Gruppe möchten wir uns in dieser Ausgabe mit den Neuerungen auf dem Gebiet der Dateibehandlung auseinandersetzen.

Beginnen wir mit einigen Eigenschaften von Dateinamen, die bisher unter GEMDOS für immer und ewig festgelegt schienen, sich nun jedoch unter MiNT geändert haben.

Da wäre zunächst einmal das Format eines Dateinamens. Alle Zugriffe auf Verzeichnisinformationen werden über die sog. DTA abgewickelt (s. Abb. 1). Jeder GEMDOS-Prozeß verfügt über eine DTA, die intern über einen (dokumentierten) Zeiger in der Basepage-Struktur angesprochen wird.

Die DTA verfügt über 14 Byte Platz für den eigentlichen Dateinamen. Damit sind prinzipiell (unter Verzicht auf die abschließende, überflüssige) 0 bis zu 14 Zeichen lange Dateinamen möglich. GEMDOS (oder vielmehr das Vorbild MSDOS) legen diesen Dateinamen jedoch mehrere Beschränkungen auf, die uns allen nur allzu vertraut sind:

Eine andere wichtige Eigenschaft des GEMDOS-Dateisystems ist weniger offensichtlich: Jeder Verzeichniseintrag kann für insgesamt drei verschiedene Dateitypen stehen:

Im GEMDOS-Dateisystem (bzw. MS-DOS-Dateisystem) werden die Dateiinformationen vom eigentliche Dateiinhalt getrennt verwaltet. Der Verzeichniseintrag (s. Abb. 3 oder in [4]) enthält die auch in der DTA vorzufindenden Informationen, sowie einen Verweis auf den Cluster, in dem der eigentliche Dateiinhalt beginnt. Die genaue Funktionsweise der FAT (File Allocation Table) und der Cluster-Verkettung braucht uns an dieser Stelle nicht zu interessieren.

Wurzel- und Unterverzeichnisse unterscheiden sich aber nicht nur in ihrer sichtbaren Erscheinungsform, sondern auch in der Implementation: Während das Wurzelverzeichnis ein fester, reservierter Bereich auf dem Medium ist (der daher nur eine, einmal bei der Einrichtung zu wählende Anzahl von Dateien, faßt), werden die Unterverzeichnisse intern wie ganz normale Dateien verwaltet (daher ist ihre Größe nur durch den freien Speicherplatz auf dem Medium beschränkt). Diese aufgepropft erscheinende Unterscheidung beruht auf der Tatsache, daß die hierarchische Organisation von »Microsoft« erst nachträglich eingeführt wurde.

Die meisten der Dateisystembeschränkungen sind direkte Folgen der Herkunft von GEMDOS und MS-DOS: Die Beschränkung auf 8+3 Zeichen gab es schließlich schon Ende der siebziger Jahre in CP/M [5].

Um die neue MiNT-Funktionalität zu verstehen, ist es nützlich, sich mit einigen Unix-Grundlagen zu bewaffnen. Eine besonders geeignete Informationsquelle zu diesem Thema ist das Buch »The Design of the UNIX Operating System« von Maurice J. Bach [6], das jüngst auch deutschsprachig erschienen ist. Bach gelingt es, auf gerade mal 460 Seiten alle grundlegenden Interna eines vollständigen Unix-Systems gleichermaßen präzise wie lesbar zusammenzufassen (die uns vorliegende Fassung bezieht sich auf »AT&T Unix System V Release 2«). Viele Informationen in diesem Buch können direkt auf MiNT übertragen werden. Eine andere, für das Verständnis von MiNT wertvolle Informationsquelle, sind naturgemäß die Quelltexte, die ebenso wie MiNT frei verfügbar sind.

Kommen wir also zu Unix und dessen Handhabung des Dateisystems. Ohne Anspruch auf Vollständigkeit seien einige offensichtliche Unterschiede genannt:

Dateien und Verzeichnisse werden vollständig gleichbehandelt. Was im GEMDOS-Dateisystem nur angedeutet ist, wurde hier (viel früher!) konsequent implementiert. Verzeichniszugriffe werden über die normalen Funktionen zum Öffnen, Lesen und Schließen von Dateien durchgeführt.

Verzeichniseinträge enthalten nur den Namen der Datei sowie einen Verweis auf den »inode«, der alle übrigen Informationen sowie den Rest der Datei enthält.

Die volle Länge des Namensfeldes kann für den Dateinamen benutzt werden künstliche Einschränkungen werden nicht gemacht. Unter System V Release 2 sind z.B. 14 Zeichen erlaubt, egal ob groß oder klein, mit keinem oder vier Punkten usw. Lediglich das Nullbyte sowie der »Slash« (das Unix-Pfadtrennzeichen /) dürfen nicht im Dateinamen auftauchen. Andere Zeichen, wie z.B. das Leerzeichen, werden nur per Konvention vermieden, sind aber rein technisch problemlos möglich. Neuere Unix-Dateisysteme wie das »UFS« im »BSD-Unix« (erlauben schließlich auch erheblich längere Dateinamen (bis zu 255 Zeichen).

Im Inode der Datei werden sämtliche Dateiinformationen mit Ausnahme des Dateinamens aufbewahrt. Jede Datei hat also genau einen Inode, kann aber mehrere Dateinamen haben. Das heißt, daß die Datei an verschiedenen Stellen des Dateisystems mit unterschiedlichen Namen auftauchen kann. Konsequent spricht man normalerweise auch nicht vom »Dateinamen«, sondern von »einem Link« auf den Dateinamen. Die Informationen aus dem Inode werden mit der Systemfunktion »stat()« ermittelt.

Im Gegensatz zu GEMDOS sind zum vollständigen Lesen eines Verzeichnisses also pro Datei zwei Schritte nötig: Auslesen des Dateinamens aus der Verzeichnisdatei und Abfrage der Inode-Daten per stat().

Wozu, wird jetzt so mancher fragen. Da wäre einmal das Standardbeispiel der Unix-Programme, die ihr Verhalten davon abhängig machen, unter welchem Namen sie gestartet werden. »compress« und »uncompress« sind beispielsweise normalerweise beides Links auf die gleiche Programmdatei (die, je nach Namen, Dateien komprimiert oder wieder auspackt).

Eine weniger offensichtliche Anwendung sind aber die speziellen Verzeichnisnamen ».« und »..«, die man ja auch unter GEMDOS kennt. ».« ist ein Link auf dasselbe Verzeichnis, in dem der Link auftaucht, »..« zeigt auf das übergeordnete Verzeichnis.

Damit diese so nützlichen Eigenschaften funktionieren, dürfen Informationen über Länge, Datum oder Zugriffsrechte natürlich nicht in jedem einzelnen Verzeichniseintrag (wie sollten dann alle Informationen immer auf dem gleichen Stand gehalten werden?), sondern eben im Inode gespeichert werden. Der enthält zusätzlich einen » Reference Counter«, der die Anzahl der Links auf den Inode mitprotokolliert. Beim Entfernen eines Verzeichniseintrags (der Unix-Systemaufruf heißt nicht umsonst »unlink()« wird der Referenzzähler um Eins vermindert. Erst wenn er Null erreicht, wird der Inode (und die daran hängende Datei) tatsächlich gelöscht.

Natürlich birgt das Inode-Konzept auch Gefahren: So kann man natürlich auch für Verzeichnisse mehrere Links anlegen und damit, wenn man unvorsichtig ist, zirkuläre Verzeichnisketten erzeugen.

Jede Datei innerhalb eines Dateisystems ist natürlich durch ihre Inode-Nummer exakt identifiziert. Nur durch die Möglichkeit, für jeden Verzeichniseintrag diese Inode-Nummer abzufragen, hat man die theoretische Möglichkeit, Fälle wie den oben angesprochenen in Programmen zu entdecken. Unter GEMDOS findet die Inode-Nummer im Start-Cluster der Datei ihre ungefähre Entsprechung (leider läßt sich diese sehr nützliche Information nicht mit GEMDOSAufrufen ermitteln).

Neben den Verzeichniseinträgen, die Links auf Inodes sind (also Dateien und Unterverzeichnisse), gibt es noch mindestens drei weitere Dateitypen:

Eine für Unix-Verhältnisse relativ neue Erfindung sind »Symbolische Links«, die ähnliche Aufgaben wie die echten Links erfüllen, jedoch völlig anders funktionieren. Eine Einschränkung der echten Links (die man zur Unterscheidung zu symbolischen Links auch »Hard-Links« nennt) ist, daß sie eben immer nur innerhalb eines Dateisystems eingesetzt werden können. Doch auch auf Unix-Systemen kennt man das Konzept mehrerer »Partitionen«, die innerhalb einer Festplatte eingerichtet werden. Und schließlich muß man ja auch damit zurechtkommen, daß mehr als ein Massenspeicher an einem System angeschlossen ist.

Für diese Fälle hat man die symbolischen Links erfunden. Für normale Anwendungsprogramme ergeben sich kaum Unterschiede: Es sieht einfach so aus, als wäre die gelinkte Datei (oder häufiger: das gelinkte Verzeichnis) wirklich auf dem ursprünglich benutzten Dateisystem. Intern ist ein symbolischer Link eine ganz normale Datei, die den Zugriffspfad auf die anzusprechende Datei enthält. Dies ist natürlich eine Bastellösung, die leider nicht die gut definierten Eigenschaften eines Hard-Links hat. So kann es ohne weiteres passieren, daß ein symbolischer Link auf eine Datei verweist, die es gar nicht mehr gibt. Symbolische Links verursachen noch einige andere vertrackte Nebeneffekte, die man auch bei der Programmierung unter MiNT beachten sollte (mehr dazu im nächsten Monat).

Eine wichtige Folgerung aus der Existenz spezieller Dateitypen ist natürlich, daß man nicht mehr ohne jede Vorsichtsmaßnahme auf jede Datei zugreifen kann. Daher sollte man sich im Zweifel vergewissern, daß es sich bei der anzusprechenden Datei auch wirklich um eine reguläre handelt. Doch zurück zu den Verzeichnisfunktionen: Die Einfachheit des ursprünglichen Unix-Konzepts (Verzeichnisse einfach wie Dateien zu behandeln) hat leider auch einige schwerwiegende Einschränkungen zur Folge:

Abhilfe schafft eine neue stardardisierte Methode zum Zugriff auf die Verzeichnisdateien, die die implementations- und dateisystem-typischen Eigenheiten verbirgt. Dabei dienen »opendir()« und »closedir()« zum Öffnen bzw. Schließen des Verzeichnisses. »readdir()« liefert jeweils den folgenden Eintrag. Alle weiteren Informationen muß man dann über »stat()« erfragen. Dieses neue Interface tauchte zum ersten Mal in BSD-Unix auf, wurde später von AT&T System V Release 3 übernommen und schließlich vom Posix-Komitee genormt.

Auch einer anderen Frage nahm sich das Posix-Komitee an: Verschiedene gleichzeitig benutzbare Dateisysteme bedeuten natürlich auch unterschiedliche Einschränkungen im Hinblick auf die Länge von Datei- und Pfadnamen und ähnlichem. Daher wurden die Auskunftsfunktionen »pathconf()« und »fpathconf()« in den Posix-Standard aufgenommen: Mit ihnen kann man die dateisystemspezifischen Informationen gezielt abfragen.

Nachdem nun viel von AT&T-Unix, BSD-Unix und Posix die Rede war, ist es Zeit, auf MiNT zurückzukommen. Im großen und ganzen könnte man sagen: Durch die Möglichkeit, externe Dateisystemtreiber einzubinden, fallen praktisch auch alle durch GEMDOS auferlegten Einschränkungen.

Zum Zugriff auf die neuen Informationen (neue Attribute, längere Namen etc.) gibt es die Posix-ähnlichen Funktionen »Dopendir()«, »Dreaddir()«, »Dclosedir()« und »Fxattr()« (für »stat()«). Auch »pathconf()« findet sein MiNT-Äquivalent in »Dpathconf()«. Im kommenden Monat werden wir diese Funktionen betrachten und noch auf ihre praktische Anwendung detailliert eingehen.

(uw)

Quellennachweis:

[1] Julian F. Reschke: »MiNT - Frischzellenkur für GEMDOS«, ST-Magazin 3/1992, Seite 37

[2] The Institute of Electrical und Electronics Engineers, Inc. (IEEE): »Information technology Portable Operating System Interface (POSIX) - Part 1: System Application Program Interface (API) [C Language]«, IEEE Std 1003.1-1990, ISO/IEC 9945-1, ISBN 1-55937-061-0

[3] Atari Corporation: »Atari GEMDOS Reference Manual«, 4.4.1986

[4] Jankowski/Rabich/Reschke: »ATARI Profibuch ST-STE-TT«, 12. Auflage, Sybex Düsseldorf 1992, ISBN 3-88745-888-5

[5] Rodnay Zaks: »CP/M Handbuch«, Sybex, Düsseldorf 1984, ISBN 3-88745-053-1

[6] Maurice J. Bach: »The Design of the UNIX Operating Systern«, Prentice-Hall Inc, New Jersey, 1986, ISBN 0-13-201799-7

typedef struct
{
 char dir_name[11]; /* Name inkl. Erweiterung ohne Punkt */
 BYTE dir_attr; /* Attribut */
 BYTE dir_dummy[10]; /* unbenutzt */
 UWORD dir_time; /* Erstellungszeit */
 UWORD dir_date; /* Erstellungsdatum */
 UWORD dir_stcl; /* erster Cluster */
 ULONG dir_flen; /* Länge der Datei */
} DIR;

Abb 1: GEMDOS-Funktionen und -Strukturen zur Directory-Verwaltung

A bis Z, a bis z, 0 bis 9, _!@#$%^&()+-=~`;´",<>|[]{}

Abb. 2. Unter GEMDOS erlaubte Zeichen in Dateinamen

typedef struct
{
 BYTE d_reserved[21]; /* fürs GEMDOS reserviert */
 BYTE d_attrib, /* Datei-Attribut */
 UWORD d_time; /* Uhrzeit */
 UWORD d_date; /* Datum */
 LONG d_length; /* Dateilänge */
 char d_fname; /* Dateiname */
} DTA;

DTA *Fgetdta (void);
void Fsetdta (DTA *ptr);
WORD Fsfirst (const char *fspec, WORD attribs);
WORD Fsnext (void);

Abb. 3. Struktur eines Verzeichniseintrags unter GEMDOS


Julian F. Reschke
Aus: ST-Magazin 07 / 1992, Seite

Links

Copyright-Bestimmungen: siehe Über diese Seite