Heute geht es um die Anwendung der im ersten Teil besprochenen Grundlagen der Directory-Verwaltung. HauptsĂ€chlich handelt es sich dabei um das Suchen (und hoffentlich auch Finden) von Dateien, einem der KernstĂŒcke von GEMDOS. FĂŒr diese Aufgabe werden die wichtigen Routinen âd srcnameâ und âd getdir' (Namen sind wie ĂŒblich frei erfunden, Ăhnlichkeiten mit lebenden Routinen wĂ€ren rein zufĂ€llig) benötigt, die schon im ersten Teil erwĂ€hnt wurden. Bevor wir ans Eingemachte gehen, möchte ich aber noch einige allgemeine Dinge vorausschicken.
Ein Name - zwei Teile
GEMDOS-Dateinamen bestehen aus zwei Teilen: Der Hauptname besteht aus bis zu 8 Zeichen, die Namenserweiterung (Extender) aus bis zu 3 Zeichen. Bei dem dem Benutzer bekannten Namensformat sind beide Teile durch einen V getrennt. Fehlt der Extender, so kann der â. â weggelassen werden (GEMDOS selbst macht dies bei âRĂŒckgabeâ von Dateinamen wie bei âDgetpath' und âFsfirstâ/âFsnextâ immer).
Das GEMDOS-interne Format kennt nur genau 11 Zeichen lange Dateinamen. Zu kurze Namensteile werden mit Leerzeichen auf die 8 bzw. 3 Zeichen aufgefĂŒllt. Daher ist auch kein Trennzeichen zwischen den beiden Teilen notwendig. Ein Beispiel: Die Datei âDATEI.Câ wird im internen Format durch âDATEI C â reprĂ€sentiert.
Ersetzungszeichen
Bei der Spezifikation von Dateinamen, nach denen gesucht werden soll, können die Ersetzungszeichen (Wildcards) '*â und '?â verwendet werden.
Ein '?' zeigt an, daĂ an seiner Stelle ein beliebiges Zeichen stehen darf. So wird bei einem Suchnamen âH?LLO' sowohl die Datei âHALLO' als auch âHELLOâ gefunden.
Bei einem '' sind alle weiteren Zeichen bis zum Ende des Namensteils, in dem das '' vorkommt, beliebig. Der Suchname âH*.Câ lĂ€Ăt GEMDOS z.B. 'HALLO.Câ oder âHXXX.Câ, nicht aber âHALLO.Sâ finden.
Weitere Zeichen nach dem '*' (bis zum Ende des Namensteils) werden ignoriert.
Intern wird ĂŒbrigens das '*' in '?' umgewandelt, indem der betreffende Namensteil bis zu seiner maximalen LĂ€nge von 8 bzw. 3 Zeichen mit â?' aufgefĂŒllt wird.
Die Ersetzungszeichen können immer dann verwendet werden, wenn nach einer schon vorhandenen Datei gesucht werden soll (z.B. bei âFopenâ oder dem Quellnamen von âFrenameâ). Alle GEMDOS-Funktionen auĂer âFsfirstâ/âFsnextâ arbeiten jedoch immer nur auf einer Datei. Dies ist stets die im Directory am âweitesten vorneâ, also bei niedriger Dateiposition stehende.
Wenn alle Dateien, die das Suchkriterium erfĂŒllen, angesprochen werden sollen, so muĂ dies entweder durch wiederholte Anwendung (z.B. bei âFdeleteâ) oder durch âFsfirstâ/âFsnextâ (s.u.) geschehen. Bei Dateipfaden darf nur der eigentliche Dateiname Ersetzungszeichen enthalten. Die Directories mĂŒssen immer vollstĂ€ndig angegeben werden.
Dateiattribut
Bisher habe ich mich immer um das Dateiattribut gedrĂŒckt, das schon des öfteren erwĂ€hnt wurde. Aber das dĂŒrfte wohl ganz im Sinne des GEMDOS liegen, da es sich auch nicht sonderlich darum kĂŒmmert. Das Attribut ist nĂ€mlich zu weit weniger zu gebrauchen, als es im ersten Moment scheint. Jede in einem Directory verzeichnete Datei hat also ein sogenanntes Dateiattribut, durch das ihre Verwendung und bestimmte Eigenschaften charakterisiert werden. Das Attribut wird durch einen Byte-Wert reprĂ€sentiert, wobei bestimmten Bits eine Eigenschaft zugewiesen wird. In einigen FĂ€llen ist ihre Kombination möglich. Die Bedeutung dieser Bits ist in Tab. 1 zusammengestellt.
Der âread onlyâ-Modus soll ein softwaremĂ€Ăiger Schreibschutz einzelner Dateien sein. Er verhindert das Ăffnen einer Datei mit âFopenâ im Modus âschreibenâ oder "lesen und schreibenâ. Weiterhin wird er bei âFdeleteâ und âFcreateâ berĂŒcksichtigt.
'Fwriteâ kĂŒmmert sich jedoch herzlich wenig um den Zugriffsmodus, so daĂ nur zum Lesen geöffnete Dateien trotzdem beschrieben werden können (s. Juni-Ausgabe).
Versteckte Dateien (âhiddenâ oder âSystemâ) sollten normalerweise bei der Anzeige von Directories nicht erscheinen. Der Desktop berĂŒcksichtigt dies sogar, d.h. versteckte Dateien werden einfach nicht angezeigt (s. auch âSuchattributâ). Der Begriff âSystem-Dateiâ hat weiter keine tiefschĂŒrfende Bedeutung, er klingt geheimnisvoller als er ist.
Das Diskettennamen-Bit kennzeichnet einen besonderen Eintrag, der fĂŒr GEMDOS keine spezielle Bedeutung hat und a1s Diskettenname verwendet werden kann. Er ist in Directories normalerweise unsichtbar. Er wird im allgemeinen beim Formatieren festgelegt und vom Desktop beim âDisk-Infoâ angezeigt.
Das Ordner-Bit zeigt an, daĂ es sich bei er Datei um ein Directory handelt. Da Directories in einigen Punkten anders behandelt werden, sollte man es tunlichst unterlassen, mit âFattribâ eine ânormaleâ Datei in einen Ordner umzuwandeln oder umgekehrt (GEMDOS fĂ€ngt dies nicht ab!). Gleiches gilt auch fĂŒr den Diskettennamen.
Das Archiv-Bit hat unter GEMDOS keinerlei Funktion. Normalerweise sollte es dazu dienen, verĂ€nderte Dateien zu erkennen. Backup-Programme oder Ă€hnliches wĂŒrden bei jedem Backup das Bit (bei den Quelldateien) löschen. Wenn die Datei verĂ€ndert wird, mĂŒĂte es gesetzt werden. Beim nĂ€chsten Backup könnte man erkennen, ob die Datei inzwischen verĂ€ndert oder neu angelegt wurde.
Ein paar Worte zu den Kombinationsmöglichkeiten der einzelnen Bits sind vielleicht auch ganz angebracht. Bei Diskettennamen und Ordnern werden alle anderen Bits ignoriert, was ihre Funktion angeht. Allerdings dĂŒrfen Schreibschutz-und Archiv-Bit trotzdem nicht gesetzt sein, da Ordner sonst nicht nur als Ordner sondern auch als normale Dateien gefunden werden, was zu Konflikten fĂŒhren kann.
Atari-Dokumentationen verlangen sogar, daĂ bei Directories und Diskettennamen keinerlei weitere Bits gesetzt werden. Bei versteckten Dateien dĂŒrfen zwar das Schreibschutz- und das Archiv-Bit gesetzt sein, doch sind dann die Dateien nicht mehr unsichtbar! System- und Ver-steckt-Bit dĂŒrfen miteinander kombiniert werden. Dann wird die Datei sowohl als System- als auch als versteckte Datei gefunden. Sie sehen also, daĂ das Dateiattribut keine allzu aufregende Sache ist.
Bit |
Bedeutung, wenn gesetzt |
engl. Kurzbezeichnung |
0 |
Datei ist schreibgeschĂŒtzt |
read only |
1 |
Datei ist versteckt |
hidden |
2 |
Datei ist (versteckte) Systemdatei |
System |
3 |
Dateieintrag ist der Diskettenname volume label |
|
4 |
Datei ist ein Ordner |
subdirectory |
5 |
Datei ist âarchiviertâ |
archive |
6,7 |
reserviert (sollten gelöscht sein) |
|
Tab. 1: Das Dateiattribut
Suchattribute
Die Directory-Suchfunktionen bekommen ein âSuchattributâ ĂŒbergeben, das festlegt, unter welchen Bedingungen Dateien als gefunden gemeldet werden. Intern verwendet GEMDOS allerdings ein Suchattribut etwas anderer Form. Es wird von der Suchroutine "d_srcname" wie folgt ausgewertet:
- Dateien mit dem Attribut 0 werden immer gefunden (unabhĂ€ngig vom internen Suchattribut), auĂer wenn das interne Suchattribut 8 ist.
- Dateien, bei deren Attribut mindestens ein Bit gesetzt ist, das auch im internen Suchattribut gesetzt ist, werden gefunden.
Der Programmierer hat mit Suchattributen nur bei âFsfirstâ zu tun. Das dort ĂŒbergebene Suchattribut wird in das interne Suchattribut umgewandelt, indem die Bits 0 und 5 gesetzt werden, auĂer wenn das Suchattribut 8 ist. In diesem Fall ist das interne Suchattribut ebenfalls 8. Dies fĂŒhrt zu folgender ErgĂ€nzung:
- ZusÀtzlich zu den obigen Möglichkeiten wird eine Datei auch dann gefunden, wenn Bit 0 oder 5 seines Attributs gesetzt sind, unabhÀngig vom Suchattribut.
Diese Suchregeln sind allerdings nicht immer die vernĂŒnftigsten. Ein paar Beispiele fĂŒr das, was so alles gefunden wird.
Suchattribut 0:
- alle ânormalenâ Dateien, ob mit oder ohne Schreibschutz oder Archiv-Flag
- versteckte und System-Dateien, Ordner oder Diskettenname mit Schreibschutz oder Archiv-Flag
Suchattribut $08:
- alle Arten von Diskettennamen
Suchattribut $10:
- alle Arten von "normalenâ Dateien
- alle Arten von Ordnern
Suchattribut $11:
- alle Ordner und alle Dateien mit oder ohne Schreibschutz (nicht etwa alle âschreibgeschĂŒtzten Ordnerâ!)
Suchattribut $02:
- alle normalen Dateien, versteckte Dateien
- Systemdateien, die zusÀtzlich noch versteckt sind
- versteckte Ordner
UngĂŒnstig ist vor allem die Mixtur aus verschiedenen Arten von Dateien (normal, Directory, Diskettenname, Systemdatei) und ihren Eigenschaften (Schreibschutz, versteckt, archiviert). Hier gĂ€be es sinnvollere Regeln, die es erlauben wĂŒrden, gezielt nach einzelnen Dateitypen mit bestimmten Eigenschaften zu suchen. Im allgemeinen wird man daher mit Suchattribut 0 oder $ 10 arbeiten.
Interessant ist es noch zu wissen, mit welchen Suchattributen die verschiedenen Teile des TOS arbeiten. GEMDOS verwendet bei allen Dateifunktionen, die âd_srcnameâ benutzen (z.B. âFopenâ usw.), das Suchattribut $27. Damit werden sĂ€mtliche ânormalenâ' Dateien gefunden. Es ist daher meistens möglich, lĂ€stige Zusatzdateien zu âversteckenâ. Das rĂ€umt so manches Directory auf. Ein gutes Beispiel ist der Auto-Boot-Harddisk-Treiber âSH204DVR.SYSâ, den man so elegant "loswerdenâ kann. Bei der Suche nach Directories benutzt GEMDOS Suchattribut $10, wie nicht anders zu erwarten.
âFrenameâ ĂŒberprĂŒft mit âFsfirstâ, ob der gewĂŒnschte Zielname schon existiert. Dabei wird Suchattribut 0 verwendet, was zu Problemen fĂŒhrt (s. âFrenameâ in Teil 1).
Das AES sucht Accessories mit âFsfirstâ und Suchattribut 0. âVersteckteâ Accessories werden daher nicht gefunden.
Das DESKTOP.INF dagegen wird mit âFopenâ angesprochen und kann daher âverstecktâ werden (und wieder wird ein Directory etwas ĂŒbersichtlicher).
Beim Suchen von Resource Dateien wird Suchattribut 5 genommen (findet auch âSysten""-Dateien). Also können auch die oft lĂ€stigen Resources unsichtbar gemacht werden.
Beim Arbeiten mit Command Line-Interpretern gibt es manchmal eine Option, wirklich alle (also auch die versteckten) Dateien aufzulisten. Der Desktop kann dies nicht, daher ist es zu empfehlen, das Verstecken auf wenige Directories zu beschrĂ€nken (z.B. auf die Root-Directo-ries der Harddisk), damit man nicht den Ăberblick verliert.
Ermitteln eines Directories mit d_getdir
Kommen wir nun zur Routine âd_getdirâ, die von den meisten GEMDOS-TRAP1-Funktionen benutzt wird. Sie ermittelt aus einem Dateipfad den DD des zugehörigen Directories und eventuell den aus dem Pfad isolierten eigentlichen Dateinamen.
Der grobe Ablauf ist wie folgt: Der Pfadname wird in einzelne Directory-Namen zerlegt, wobei sich GEMDOS im DD-Baum von den oberen zu den unteren Ebenen hangelt. Doch nun zu den Details.
Zuerst wird das Start-Directory bestimmt, auf das sich der restliche Pfad bezieht. Dazu wird als allererstes das Laufwerk festgelegt. Wenn es im Dateipfad nicht explizit angegeben ist, wird das aktuelle Laufwerk (âpdefdrvâ im PD) ausgewĂ€hlt. Wie im Teil 1 beschrieben, ĂŒbernimmt âd_chkdrvâ die ĂberprĂŒfung des Laufwerks und sorgt fĂŒr die Existenz eines Standardpfades. Beginnt der Pfad mit einem â', so ist das Root-Directory das Start-Directory, ansonsten das Ende des Standardpfads. Das so festgelegte Start-Directory ist ersteinmal das âaktuelle Directoryâ.
Nun wird die nĂ€chste Komponente des Pfades extrahiert und in das GEMDOS-interne Format konvertiert. Die Spezial-Dateinamen '.' und '..' werden hier separat ausgewertet. â.â wird ignoriert, bei '..' wird das Parent-Directory des aktuellen Directories ĂŒber den âdd_parddâ-Zeiger ermittelt. Unschönerweise erfolgt hier keine Sicherheitsabfrage ob man sich nicht schon im Root-Directory befindet. Da dessen âdd_parddâ NIL ist, gibt es gleich darauf einen Bus-Error.
Ansonsten muĂ das gewĂŒnschte Subdirectory im aktuellen Directory gesucht werden. Wenn GEMDOS in seinem âDD-Baumâ (s. Teil 1) hier noch ĂŒberhaupt kein Child kennt, muĂ auf jeden Fall im Directory selbst gesucht werden. Dies erledigt âd_srcnameâ (s.u.). Wenn im aktuellen Directory kein weiteres Directory ist, ist die Suche auf jeden Fall fehlgeschlagen und wird abgebrochen.
Wenn schon mindestens ein Child bekannt ist oder von âd_srcnameâ eins gefunden wurde, wird die Child-Liste des DD durchsucht. Falls das gewĂŒnschte Directory hier nicht gefunden werden kann, besteht noch die Möglichkeit, daĂ noch nicht alle Child-Directories in der Child-Liste eingetragen sind. Dies wird am âfd_dirchâ-Flag des Directory-FD erkannt (s.u.). In diesem Fall wird nochmals âd srcnameâ aufgerufen. SchlĂ€gt dies auch fehl, so existiert das Directory nicht und es wird abgebrochen.
Nun wird das ermittelte Child zum aktuellen Directory und das Spiel beginnt von vorne, bis der ganze Pfad durchgearbeitet ist.
Je nach Aufruf (bestimmt durch ein Flag) wird dabei der ganze String (âDsetpathâ) oder alles bis auf den letzten Namen (âFopenâ) als Pfadname angesehen. Im zweiten Fall wird der letzte Name als Dateiname interpretiert und der ĂŒbergeordneten Routine zur VerfĂŒgung gestellt.
Letztendlich erhĂ€lt man also den DD des gewĂŒnschten Directories am Pfadende, wobei alle Directories auf dem Weg dorthin automatisch im DD-Baum angelegt werden.
Suchen von Dateien mit d_srcname
Doch nun zur internen Funktion âd_srcnameâ, die die Drecksarbeit, sprich das Suchen im Directory, erledigt und so nebenbei den DD-Baum aufbaut. âd_srcnameâ wird fĂŒr alle Sucharbeiten (Dateinamen, Directories oder freie EintrĂ€ge) verwendet und bekommt daher auch das âinterne Suchattributâ ĂŒbergeben.
Da hier mit den ĂŒblichen Dateioperationen auf das Directory zugegriffen wird, muĂ ersteinmal ein FD fĂŒr das Directory erzeugt werden, falls noch keiner vorhanden ist.
âd_srcnameâ kann eine Anfangs-Dateiposition ĂŒbergeben werden, ab der gesucht werden soll. Dies ist wichtig, wenn erst ab einer bestimmten Stelle gesucht werden soll (wie bei âFsnextâ).
âd_getdirâ lĂ€Ăt dagegen immer ab der letzten Suchposition (âdd_lposâ) suchen, da hier ja nur die Child-Liste verlĂ€ngert werden soll, und âdd_lposâ gerade angibt, bis wohin die Subdirectories schon erfaĂt wurden.
Das Directory wird nun ab dieser Anfangsposition Eintrag fĂŒr Eintrag gelesen, bis das Ende erreicht wird oder bis die gesuchte Datei gefunden wurde. Das Ende eines Directories wird von GEMDOS nicht nur an seiner tatsĂ€chlichen LĂ€nge in Sektoren bzw. Clustern erkannt. Schon der erste Eintrag, der mit einem Nullbyte beginnt, fĂŒhrt bei Directory-Suchoperationen zum Abbruch. Dies spart vor allem beim Root-Directory erheblich an Zeit.
Zuerst wird ĂŒberprĂŒft, ob der gerade untersuchte Eintrag ein geeigneter Kandidat fĂŒr die automatische Aufnahme in den DD-Baum ist. Dazu muĂ es sich natĂŒrlich um einen Directory-Namen (auĂer '.' und '..â) handeln. AuĂerdem muĂ die aktuelle Dateiposition hinter âdd_lposâ liegen, da das Directory sonst schon im Baum vorhanden ist. Desweiteren wird ĂŒberprĂŒft, ob nicht ĂŒberhaupt schon frĂŒher einmal das gesamte Directory durchsucht wurde (âfd_dirchâ-Flag gesetzt, s.u.). Wenn nach einem Directory (nicht nach einer normalen Datei) gesucht wird, soll eine letzte Abfrage nochmals sicherstellen, daĂ der Ordner nicht schon in der Child-Liste vorhanden ist.
Nachdem alle Klippen ĂŒberwunden sind und âd_srcnameâ der Meinung ist, das Directory mĂŒsse in die Child-Liste des durchsuchten Directories aufgenommen werden, wird ein DD eingerichtet. Die benötigten Daten werden dem Directory-Eintrag bzw. dem DD des Parents entnommen. Der neue DD wird immer vorne in die Child-Liste eingehĂ€ngt.
Nun erfolgt der Vergleich des Directory-Eintrags mit den Suchkriterien. Eine Datei gilt als gefunden, wenn ihr Name unter BerĂŒcksichtigung der Ersetzungszeichen und ihr Attribut im Rahmen der Suchregeln ĂŒbereinstimmt.
Bei der Suche nach einem freien Eintrag (z.B. von âFcreateâ aus) wird âd_srcnameâ fĂŒndig, wenn es auf $00 oder $E5 im ersten Byte des Dateinamens stöĂt.
Nach Abbruch der Suche (egal ob erfolgreich oder nicht) wird âdd_lposâ auf den neuesten Stand gebracht, aber nur, wenn âd_srcnameâ von 'd_ getdir' aus aufgerufen wurde. Dies fĂŒhrt zu einem fatalen Fehler, wie unten noch beschrieben wird.
Wenn die gewĂŒnschte Datei nicht gefunden werden konnte und auch nicht gerade nach einem freien Eintrag gesucht wurde, so wird das Bit 1 von âfd_dirchâ im FD des Suchdirectories gesetzt. Es zeigt somit an, daĂ das Directory einmal komplett gelesen wurde und dieser Zweig des DD-Baums vollstĂ€ndig aufgebaut ist.
Je nach Aufruf von âd_srcnameâ wird ein Zeiger auf den Directory-Eintrag der gefundenen Datei oder einer auf den DD des gefundenen oder in die DD-Liste aufgenommenen Directories (NIL zeigt Fehlschlag an) zurĂŒckgegeben.
Fehler in der Directory-Verwaltung
Diese Routine beinhaltet einen der schwerwiegendsten Fehler des ganzen GEMDOS. Er kann dazu fĂŒhren, daĂ ein Directory mehrmals in die Child-Liste seines Parents aufgenommen wird.
Zum einen fĂŒhrt dies dazu, daĂ zuviel âinterner Speicherâ fĂŒr die DDs und eventuell deren FDs verbraucht wird. Dadurch findet eine zusĂ€tzliche Begrenzung der ansprechbaren Ordner statt (das berĂŒhmtberĂŒchtigte â40-Ordner-Problemâ). In vielen FĂ€llen tritt dieses Problem ĂŒberhaupt nur auf Grund dieses Fehlers auf und nicht, weil zu viele Ordner geöffnet wurden o.Ă€!
Es sind aber noch weitere merkwĂŒrdige Effekte möglich. Es kann passieren, daĂ sich ein Directory nicht mehr löschen lĂ€Ăt, obwohl es keine Dateien mehr enthĂ€lt, denn beim âDdeleteâ wird ĂŒberprĂŒft, ob die Child-Liste des zu löschenden Directories auch wirklich leer ist (s. Teil 1).
Doch nun zur Ursache des Fehlers. Beim Aufruf von âd_srcnameâ fĂŒr ânormaleâ Suchoperationen (wie etwa von âFopenâ, âFcreateâ usw.) werden ebenfalls âzufĂ€lligâ entdeckte Directories in den DD-Baum integriert. Im Gegensatz zu der von âd_getdirâ initiierten Suche wird aber âdd_lposâ nicht auf die Endposition der Suche gesetzt, so daĂ GEMDOS bei der nĂ€chsten Suchoperation nicht merkt, daĂ das Directory schon in der Child-Liste hĂ€ngt und es erneut einfĂŒgt.
Warum, so werden Sie sich vielleicht fragen, merkt man dann normalerweise nicht viel von diesem Fehler? Er mĂŒĂte sich doch eigentlich stĂ€ndig bemerkbar machen.
Dies liegt daran, daĂ die Child-Liste nicht mehr erweitert wird, wenn das âfd_dirchâ-Bit 1 gesetzt ist. Das ist aber der Fall, sobald das Directory einmal komplett durchsucht wurde, weil eine Suchoperation fehlgeschlagen ist. Das ist aber genau das, was beim Arbeiten mit dem Desktop stĂ€ndig passiert. Meistens macht man einen Ordner auf, bevor man mit ihm arbeitet. Dabei liest der Desktop das Directory komplett, um es im Fenster darzustellen.
Auch bei Command Line-Interpretem listet man die meisten Directories irgendwann einmal, oft ebenfalls bevor man sie anspricht.
GefĂ€hrlich wird es bei Programmen, die in einem Directory stĂ€ndig ganz bestimmte Dateien bearbeiten. Da dabei i.allg. keine Suchoperation fehlschlĂ€gt, weil das Programm ja âgezieltâ sucht, geht bei jedem Datei-Offnen interner Speicher verloren. Da dieser Effekt keine Begrenzung kennt, kommt es irgendwann zum Zusammenbruch der internen Speicherverwaltung, da hilft dann kein noch so groĂzĂŒgiges âMehr-Ordner-Programmâ.
Ein schönes Beispiel findet sich in Listing 1. Vor Ablauf des Programms sind allerdings einige Vorbereitungen notwendig. Legen Sie in dem Directory, in dem sich das Programm befindet, einen Ordner âTEST.ORDâ an. Ăffnen Sie ihn nun und erzeugen Sie zuerst einen weiteren Ordner mit beliebigem Namen. AuĂerdem muĂ danach irgendeine Datei in den Ordner "TEST.ORD" kopiert und in âTESTâ umbenannt werden. Initialisieren Sie das System mittels RESET-Knopf neu und starten Sie das Demo-Programm, ohne vorher "TEST.ORDâ geöffnet zu haben. Nach einiger Zeit meldet das Programm einen Fehler und gibt an, wie oft es die Datei âTESTâ öffnen und wieder schlieĂen konnte. Dieser Wert hĂ€ngt vom verwendeten TOS (âaltes TOSâ oder âBlitter-TOSâ) und eventuell vorhandenen "Mehr-Ordner-Programmenâ ab.
Nun ist der GEMDOS-Speicher fast restlos aufgebraucht, und Sie werden dies am merkwĂŒrdigen Verhalten des Desktops bemerken. Ordner sind scheinbar leer, es gibt ungewohnte Fehlermeldungen bei harmlosen Operationen, AbstĂŒrze oder einen selbstausgelösten RESET.
Warnung: FĂŒhren Sie keinesfalls irgendwelche Schreibzugriffe durch (wie Kopieren), da sonst die Gefahr von ungewollten Datenverlusten besteht.
Am besten machen Sie einen RESET, dann normalisiert sich wieder alles. Wenn âTEST.ORD" vor dem Start des Demos einmal geöffnet wurde, geht alles gut und das Programm bricht ohne Fehler nach 1000 âFopenâ-âFcloseâ-Sequenzen ab.
Die âDisk Transfer Areaâ (DTA)
GEMDOS stellt dem Programmierer zwei Funktionen zur VerfĂŒgung, mit denen ein Directory nach bestimmten EintrĂ€gen durchsucht werden kann. Im einfachsten Fall dienen sie dem Einlesen des kompletten Directories, was z.B. der Desktop macht, um es dann in einem Fenster darzustellen.
âFsfirstâ fĂŒhrt dabei die erste Suche aus, die am Anfang des Directories beginnt, und hinterlegt die im Directory gespeicherten Informationen ĂŒber die gefundene Datei in der DTA.
âFsnextâ ist in der Lage, ab der Stelle weiterzusuchen, wo âFsfirstâ bzw. ein vorheriges âFsnextâ aufgehört hat. Durch wiederholte Aufrufe ist es damit möglich, ein Directory komplett nach Dateien, die bestimmten Kriterien genĂŒgen, zu durchsuchen.
Die DTA enthĂ€lt daher auch alle Daten, die GEMDOS braucht, um die Suche am alten Abbruch-Punkt aufsetzen zu lassen. Speicherplatz fĂŒr die DTA kann vom Anwender selbst bereitgestellt werden (s. âFsetdtaâ und âFgetdtaâ). Eine genaue Beschreibung dieser Funktionen findet sich im Abschnitt âGEMDOS-Funktionenâ.
Hier geht es in erster Linie um den Aufbau der DTA (Abb. 1). Beginnen wir hinten, ja dort die fĂŒr den Programmierer wichtigeren Daten abgelegt sind.
tvpedef struct
{ char dta_sname[12]; /* Suchname (von Fsfirst) */
char dta_sattr; /* Suchattribut (von Fsfirst) */
char dta_dpos[4]; /* letzte Suchposition im Suchdirectory */
char dta_dd[4]; /* Zeiger auf DD des Suchdirectories */
char dta_attr; /* gefundenes Attribut */
unsigned int dta_time; /* gefundene Zeit */
unsigned int dta_date; /* gefundenes Datum */
long dta len; /* gefundene Laenge */
char dta_name[14]; /* gefundener Name */
} DTA;
Abb. 1: Struktur der âDisk Transfer Areaâ (DTA)
'dta_nameâ ist der Name der gefundenen Datei in der dem Anwender bekannten Darstellung (nicht im internen Format). dta_nameâ ist mit 14 Zeichen groĂzĂŒgig dimensioniert (13 hĂ€tten auch gelangt). Desweiteren findet man hier die DateilĂ€nge in Bytes (âdta_lenâ), Erstellungszeit dta_timeâ) und -datum (âdta_dateâ) sowie das Dateiattribut (âdta_attr') der gefundenen Datei. Diese Komponenten sind alle von Atari dokumentiert, anders wĂ€re die Nutzung von 'Fsfirstâ/âFsnextâ wohl auch kaum möglich.
Der Rest der DTA ist offiziell als âreserviert fĂŒr interne Zweckeâ ausgewiesen, daher kann (und nach neuesten Informationen soll) sich die Belegung in spĂ€teren TOS-Versionen durchaus Ă€ndern. Man sollte daher die Kenntnis hiervon nicht beim Programmieren ausnutzen.
Der bei âFsfirstâ ĂŒbergebene Suchname (abgetrennt vom zugehörigen Suchpfad), wird in âdta_snameâ abgelegt. Dieser Name liegt im GEMDOS-internen Format vor. Das bei âFsfirstâ festgelegte Suchattribut wird in âdta_attrâ aufbewahrt. âdta_ddâ zeigt auf den DD des Directories, in dem die Suche stattfindet.
Die aktuelle Dateiposition der Suche ist in dta_dposâ zu finden. âdta_dposâ zeigt dabei auf den Eintrag nach dem zuletzt gefundenen, also auf den, bei dem die nĂ€chste Suche beginnen soll.
Bei âdta_ddâ und âdta_dposâ fĂ€llt die merkwĂŒrdige Definition als âchar-Arrayâ in der Struktur auf. Etwas besseres fiel mir nicht ein, da es sich offensichtlich um 32-Bit-Werte auf ungeraden Adressen handelt. So etwas erzeugt kein C-Compiler, daher muĂ die Original-Definition von Digital Research wohl Ă€hnlich merkwĂŒrdig aussehen. Der Zugriff auf diesen Teil der DTA geschieht ohnehin nur mit Byte-Kopierroutinen.
Das Problem wĂ€re bei anderer Anordnung der Komponenten oder VerkĂŒrzung von âdta_snameâ (11 Zeichen reichen auch) nicht aufgetreten.
Mit Hilfe von âdta_ddâ kommt man ĂŒbrigens an die internen Datenstrukturen der Dateiverwaltung heran. Hier findet sich nĂ€mlich unter anderem ein Zeiger auf den DMD, von dem aus alle DDs und FDs erreichbar sind. Dies kann als eine âhalblegaleâ Methode angesehen werden, da zwar nicht die Kenntnis von verĂ€nderlichen Systemadressen, aber die der internen Strukturen vorausgesetzt wird.
Der DMD ist auch ĂŒber die Sektorpuffer-Listen (âbufT) erreichbar, doch kann man oft nicht wissen, ob ein solcher Puffer fĂŒr das gewĂŒnschte Laufwerk existiert.
GEMDOS-Funktionen (TRAP #1)
Hier sind die vier GEMDOS-Funktionen zusammengestellt, die mit Suchoperationen zu tun haben.
Funktion $1A Fsetdta
void Fsetdta(DTA *new_dta)
Die Adresse der aktiven DTA wird auf ânew_dtaâ gesetzt. Die DTA wird von âFsfirstâ/âFsnextâ benutzt. Vor dem Start jedes Prozesses wird eine Default-DTA definiert. Sie liegt bei der aktuellen GEMDOS-Version im ProzeĂdescriptor unmittelbar am Beginn der Kommandozeile.
In vielen FĂ€llen muĂ man daher keinen eigenen Speicherbereich mit âFsetdtaâ zur VerfĂŒgung stellen. Man muĂ aber Konflikte mit der Kommandozeile berĂŒcksichtigen. Das bedeutet, die Kommandozeile muĂ vordem ersten âFsfirstâ ausgewertet sein, wenn keine eigene DTA verwendet wird.
Arbeitsweise
Hierbei handelt es sich um einen âCâ-Einzeiler. ânew_dtaâ wird direkt in den PD des aktiven Prozesses nach âp_dtaâ ĂŒbertragen.
Funktion $2F Fgetdta
DTA *Fgetdta()
Die Adresse der aktiven DTA wird zurĂŒckgegeben. Es ist immer eine DTA definiert (s. âFsetdtaâ).
Arbeitsweise
Noch ein Einzeiler: Der RĂŒckgabewert ist einfach âp_dtaâ des aktiven Prozesses.
Funktion $4E Fsfirst
long Fsfirst(char *path, int attr)
Das durch den Directory-Anteil von âpathâ ausgewĂ€hlte Directory wird nach Dateien durchsucht, deren Namen durch den von âpathâ abgetrennten Suchnamen und das Suchattribut âattrâ bestimmt werden.
Beispiel: Bei einem âpathâ von âORDNERVLDOCâ wird im Directory âORDNERâ, das sich im aktuellen Directory des Standardlaufwerks befindet, nach allen Dateien gesucht, die die Endung â.DOCâ haben, und mit dem Suchattribut vereinbar sind.
Die Suche wird beim Anfang des Directories begonnen und bricht beim ersten die Suchanfrage erfĂŒllenden Dateinamen ab. Sie kann mit âFsnextâ fortgefĂŒhrt werden. Der Suchname kann die ĂŒblichen Ersetzungszeichen â?â und '' enthalten, insbesondere sucht â.*â nach allem. Das Suchattribut ist oben schon erklĂ€rt worden.
RĂŒckgabewerte:
-1 ..-31 BIOS-Fehlermeldung bei Diskzugriff
-33L (EFILNF) Pfad oder keine Datei gefunden, Laufwerk existiert nicht, interner Fehler (keine Pfad-Handles, zu wenig interner Speicher)
0L alles ok.
Arbeitsweise
Das Suchattribut wird in das interne Suchattribut konvertiert, wie oben beschrieben.
âd_getdirâ ermittelt das Suchdirectory und mit âd_srcnameâ wird ab dem Directory-Anfang wie gewĂŒnscht gesucht. Wenn eine Datei gefundenen wurde, die die Suchanfrage erfĂŒllt, wird die DTA komplett gefĂŒllt (Teile fĂŒr Anwender und interne Zwecke).
Funktion $4F Fsnext
lang Fsnext()
Eine vorher mit âFsfirstâ begonnene Suche wird fortgesetzt. Die Suche wird ab dem Eintrag fortgefĂŒhrt, der dem letzten gefundenen folgt. âFsnextâ ist mehrmals hintereinander anwendbar, bis das ganze Directory durchsucht ist.
Andere Dateioperationen âzwischendurchâ sind durchaus erlaubt. Fatal ist dagegen ein Mediumwechsel. Er sorgt fĂŒr die Freigabe aller internen Strukturen. Bei âFsnextâ wird auf diese zugegriffen, obwohl sie nicht mehr definiert sind. Dies kann zur Suche in einem ganz anderen Directory oder zum Absturz fĂŒhren. Ebenfalls tödlich ist ein âFsnextâ ohne vorhergehendes âFsfirstâ, da die DTA dann Undefiniert ist.
RĂŒckgabewerte:
-1..-31 BIOS-Fehlermeldung bei Diskzugriff
-49L (ENMFIL) keine Datei gefunden, interner Fehler (zu wenig interner Speicher)
0L alles ok.
Arbeitsweise
Mit den in der DTA gespeicherten Daten wird âd_srcnameâ aufgerufen. Wenn die Suche erfolgreich war, wird der Anwender-Teil der DTA und âdta_dposâ neu gesetzt.
Anwendungsbespiel
Ein Beispiel fĂŒr die Verwendung dieser vier GEMDOS-Funktionen ist in Listing 2 gegeben.
Die Funktion âsearchâ sucht in einem bestimmten Directory nach sĂ€mtlichen Dateien (auĂer dem Diskettennamen). Dabei werden auch alle Subdirectories sowie deren Subdirectories usw. durchsucht. Bei jeder gefundenen Datei wird âfoundâ aufgerufen, das in diesem Beispiel nichts weiter macht, als den Pfad und das Dateiattribut der gewĂŒnschten Datei auszugeben. Aufgerufen wird âsearchâ von âmainâ, wobei das aktuelle Directory als zu durchsuchendes festgelegt wird. Die Einzelheiten können dem Listing entnommen werden.
Mit Vorsicht ist dieses Programm im Root-Directory einer Harddisk anzuwenden. Da dabei sĂ€mtliche Ordner geöffnet werden, tritt ein erheblicher Verbrauch an âinternem Speicherâ auf, womit wir wieder beim â40-Ordner-Problemâ angelangt wĂ€ren.
Ausblick
Das Gröbste hĂ€tten wir nun hinter uns. Zur Datei- und Directory-Verwaltung wissen Sie nun alles wesentliche. Was noch bleibt, sind vor allem die I/O-Umlei-tung und die I/O-Funktionen fĂŒr die zeichenorientierten GerĂ€te, womit wir uns als nĂ€chstes beschĂ€ftigen werden.
/* Demo-Programm f .TOS-Fehler d. Directory-Verwaltung */
#include <osbind.h>
main ()
{ int err;
int i;
/* maximal 1000 DurchlÀufe oder Abbruch durch Fehler */
for (i=0,err=0; err==0 && i<1000; i++)
{
err = Fopen("test.ord\\test", 0);
if (err > 0)
err = Fclose(err);
}
printf("Abbruch nach %d DurchlÀufen mit Fehler %d.\n",i,err);
Cnecin();
}
Listing 1: Demo-Programm fĂŒr TOS-Fehler
/* Rekursives Durchsuchen eines Directories
by A.Esser
13.6.1988
*/
#include <osbind.h>
#define E_OK 0
#define ERROR 1
#define MAX_RECUR 10 /* max. Rekursionstiefe */
typedef struct
{ char dta_reserved[21];
char dta_attr;
unsigned int dta_time;
unsigned int dta_date;
long dta_len;
char dta_name [14];
} DTA;
/* Rekursiv durch Directory-Hierarchie durcharbeiten */
/* 'path' ist Start-Pfad (ohne abschliePendes '\') */
/* Erst-Aufruf erfolgt mit 'level'=0 */
int search(level,path)
int level; /* Rekursionstiefe */
char *path;
{ DTA dta; /* lokale DTA */
DTA *olddta; /* DTA-Adresse der höheren Ebene */
int err;
char *name; /* Zeiger auf Dateinamen in 'path' */
olddta = (DTA *)Fgetdta(); /* alte DTA-Adresse merken */
Fsetdta(&dta); /* lokale DTA definieren */
name = path + strlen (path) + 1;
strcpy(name-1,"\\*.*") ; /* alles suchen */
err = Fsfirst(path,0x37);
while (err == E_OK) /* suchen bis nichts mehr da oder Fehler */
{
strcpy(name,dta.dta_name); /* gefundenen Namen an Pfad anhÀngen */
found(path,&dta); /* gewĂŒnschte Aktion ausfĂŒhren */
if (dta.dta_attr & 0x10 && *name != '.')
if (level < MAX_RECUR) /* ab in die nÀchste Ebene */
err = search(level+1,path);
else
err = ERROR; /* Rekursion zu tief:Abbruch */
if (err == E_OK)
err = Fsnext(); /* weiter suchen wenn kein Abbruch */
}
Fsetdta(olddta); /* DTA der letzten Ebene zurĂŒck */
if (err < 0) /* keine Datei mehr gefunden */
err =0; /* weiter in letzter Ebene */
return err; /* sonst Abbruch */
}
/* Aufruf bei jeder gefundenen Datei einschl. Ordner */
/* Beispiel: Ausgabe des Pfades und des Attributs */
found(path,dta)
char *path;
DTA *dta;
{
printf("$%02x %s\n",dta->dta_attr,path);
}
/* Beispiel fĂŒr Aufruf */
main()
{
char cpath[128];
Dgetpath(cpath,0); /* los geht's ab akt. Directory */
search(0,cpath);
}
Listing 2: Anwendung der Datei-Suchfunktionen