gfx gfx
gfx
homegfxgaestebuchgfxforumgfxkontaktgfximpressum
gfx
QBasic
  1. QB-Forum
  2. QB-Forum
  QB-MonsterFAQ
  Tutorials
AK-LIB
  Download
  Archiv
  Hilfe
  TroubleFAQ
  Tools
Projekte
  DosFont
Extras
  Links
Statistik
Tutorials
Festplatte & Diskette
Autor: Andre Klein

         Vorwort   letzte Aktualisierung: 10.08.2003
In diesem Tutorial besprechen wir, wie Disketten und Festplatten aufgebaut sind, wie man sie direkt lesen und beschreiben kann und wie das Dateisystem aufgebaut ist.

       Abschnitt 1   Aufbau von Disketten und Festplatten
Eine Diskette oder Festplatte ist eigentlich nur eine Ansammlung von sich drehenden Scheiben die übereinander liegen und auf der die Daten abgespeichert sind.
Eine Diskette hat meistens nur 1 oder 2 Scheiben, wobei eine Festplatte mehrere Scheiben haben kann.
Damit der PC aber auch was mit den Scheiben anfangen kann, müssen wir da erstmal eine Ordnung reinbringen.
Und zwar ist es so das eine Disk in sogenannte Köpfe, Zylinder und Sektoren aufgeteilt ist.
Der Kopf (HEAD) bezeichnet einfach nur auf welcher Scheibe sich die momentanen Daten befinden.
Jede einzelne Scheibe wird in Ringe unterteilt, das sind die Zylinder (Cylinder)
Und zum Schluß ist jeder einzelne Ring in Sektoren (Sector) unterteilt.
Der Sektor ist also die kleinste ansprechbare Einheit, und besteht (fast) immer aus 512 Byte!

Mit dieser Einteilung kann man dann immer einen bestimmten Sektor von der Disk lesen oder schreiben.

Der allererste Sektor jeder Disk liegt bei der Adresse CHS 0,0,1.
Das C steht für Cylinder, das H für Head und das S für Sector.
Cylinder und Head werden immer ab 0 gezählt. Die Sectoren werden ab 1 gezählt!

Wenn der Computer jetzt startet liest er zuerst diesen Sektor (CHS 0,0,1) von der Disk. Denn das ist der BOOT-RECORD bei Disketten und der MASTER-BOOT-RECORD bei Festplatten. In diesem Sektor steht alles drinne was man über die Diskette oder Festplatte wissen muß.

       Abschnitt 2   der BOOT-RECORD
hier die Tabelle eines BOOT-RECORD's für eine Diskette:
Byte-Nummer Bedeutung
1-3 3 Byte JMP zum Boot-Code
4-11 Herstellerkennung
12-13 Bytes pro Sektor
14 Sektoren pro Cluster
15-16 Anzahl der Sektoren für BOOT-RECORD
17 Anzahl der FAT's
18-19 Anzahl der Verzeichnisse im ROOT
20-21 Anzahl aller Sektoren der Disk
22 Mediadiskriptor
- F0 = 3,5", High Density
- F8 = Harddisk
- F9 = 3,5", doppelseitig
- FA = RAM-Disk
- FC = 5,25" einseitig (9 SEK/CYL)
- FD = 5,25" doppelseitig (9 SEK/CYL)
- FE = 5,25" einseitig (8 SEK/CYL)
- FF = 5,25" doppelseitig (8 SEK/CYL)
23-24 Größe einer FAT in Sektoren
25-26 Sektoren pro Kopf
27-28 Anzahl der Köpfe
29-30 Sektor-Offset
31-512 Boot-Code

Und da wir schon dabei sind, hier der MASTER-BOOT-RECORD den nur die Festplatten besitzen. Dieser wird auch als MBR bezeichnet.
Byte-Nummer Bedeutung
1-446 Boot-Code
447-510 Partitionstabelle. In dieser Tabelle gibt es immer 4 Partitionseinträge mit einer Länge von jeweils 16 Byte. Dieser Eintrag sieht wie folgt aus:
Byte 1: - Boot-Indicator (&H80 = Aktive Partition, &H00 inaktive Partition)
Byte 2: - Start-Head
Byte 3: - Start-Sector
Byte 4: - Start-Cylinder
Byte 5: - Betriebssystem-Indicator (Beispiele folgen)
Byte 6: - End-Head
Byte 7: - End-Sector
Byte 8: - End-Cylinder
Byte 9-12: - Sektor-Offset
Byte 13-16: - Länge der Partition in Sektoren
511-512 &H55AA

In der Partitions-Tabelle siehst du ja, das jede Partition eine Startadresse bekommt. An der Startadresse befindet sich jetzt nochmal ein ganz normaler BOOT-RECORD, wie du ihn von der Diskette kennst.

       Abschnitt 3   Diskettenparameter ermitteln
Wir schreiben uns jetzt ein Programm mit dem wir die Diskettenparameter ermitteln können. Dazu benutzen wir den Befehl INTERRUPTX. Damit man mit ihm arbeiten kann, mußt du mindestens QB 4.0 haben und mußt QB mit der Option /L starten.
Für weitere Informationen: Bibliotheken in QB

Das erste was wir an den Anfang der Datei schreiben ist folgendes
TYPE regtypex
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
ds AS INTEGER
es AS INTEGER
END TYPE
DIM SHARED reg AS regtypex

In Programmen die ich hier beschreibe, gehe ich davon aus das dieses Teilprogramm schon existiert!

So, jetzt lesen wir mal den ersten Sektor einer Diskette aus. Dazu mußt du jetzt eine beliebige Diskette einlegen.
Fürs Lesen benutzen wir den BIOS-INT &H13 mit der Unterfunktion AH = 2.
AL = Anzahl der Sektoren die gelesen werden sollen
DL = Nummer des Laufwerks (0 = 1. Floppy, 1 = 2. Floppy, &H80 = 1. Harddisk, &H81 = 2. Harddisk...)
DH = Kopfnummer
CH = Bit 0-7 des Cylinders
CL = Bit 0-5 = Startsektor / Bit 6-7 = Bit 8 und 9 des Cylinders
ES:BX = Adresse unseres Puffers (dat$) in dem der Sektor gespeichert wird.

WICHTIG: Ab hier probierst du die Programme auf eigene Gefahr aus. Deshalb übernehme ich keine Haftung für evtl. Schäden. Wenn du die Programme richtig abschreibst dann kann nichts passieren. Ich wollte dich nur darauf hinweisen.

Hier das Programm:
'Grundparameter festlegen
head% = 0
cylinder% = 0
sector% = 1
anzahlsectoren% = 1
disk% = 0
-----------------------------------------------------
'Sektor lesen
dat$ = STRING$(512, CHR$(0))
reg.ax = &H200 + (anzahlsectoren% AND 255)
zs# = (disk% AND 255#) + ((head% AND 255#) * 256#)
reg.dx = CVI(MID$(MKL$(zs#),1,2))
zs# = (sector% AND 63#) + ((cylinder% \ 256#) * 64#) + (cylinder% AND 255#) * 256#
reg.cx = CVI(MID$(MKL$(zs#),1,2))
reg.es = VARSEG(dat$)
reg.bx = SADD(dat$)
CALL INTERRUPTX(&H13, reg, reg)
-----------------------------------------------------
'Daten rausfiltern
PRINT "Hersteller : "; MID$(dat$, 4, 8)
PRINT "Bytes pro Sektor :"; CVI(MID$(dat$, 12, 2))
PRINT "Sektoren pro Cluster:"; ASC(MID$(dat$, 14, 1))
PRINT "Boot-Sektoren :"; CVI(MID$(dat$, 15, 2))
PRINT "Anzahl der FAT's :"; ASC(MID$(dat$, 17, 1))
PRINT "Anzahl Files im ROOT:"; CVI(MID$(dat$, 18, 2))
PRINT "Sektoren gesamt :"; CVI(MID$(dat$, 20, 2))
PRINT "Media-Diskriptor : "; HEX$(ASC(MID$(dat$, 22, 1)))
PRINT "Sektoren pro FAT :"; CVI(MID$(dat$, 23, 2))
PRINT "Sektoren pro HEAD :"; CVI(MID$(dat$, 25, 2))
PRINT "Anzahl der HEAD's :"; CVI(MID$(dat$, 27, 2))
PRINT "Sektor-Offset :"; CVI(MID$(dat$, 29, 2))

Jetzt haben wir den ersten Sektor (den Boot-Sektor) einer Diskette ausgelesen. Da es sich um eine Diskette handelt ist es ein normaler BOOT-RECORD.
Als nächstes lesen wir den MASTER-BOOT-RECORD unserer Festplatte aus und lassen uns die Daten anzeigen. Dazu können wir die gleichen Grund-Parameter benutzen wie im vorherigen Beispielprogramm. Das einzige was wir jetzt ändern müssen ist die Variable -> disk%. Diese ändern wir von 0 auf &H80. Denn das bedeutet das es sich um unsere 1. Harddisk handelt.
Den Programm-Teil mit dem wir unseren Sektor lesen, übernehmen wir 1:1.
Das einzige was wir jetzt noch ändern müssen ist das "Daten Rausfiltern". Da ja der MBR anders aufgebaut ist als unser normaler BOOT-RECORD!

WICHTIG: Bei WIN NT und XP kann es vorkommen das das folgende Programm eine Fehlermeldung hervorruft. Das hat damit zu tun das diese beiden Versionen manchmal kein direktes Zugreifen auf Festplatten erlauben.

Das ganze Programm sieht dann folgendermaßen aus:
'Grundparameter festlegen
head% = 0
cylinder% = 0
sector% = 1
anzahlsectoren% = 1
disk% = &H80
-----------------------------------------------------
'Sektor lesen
dat$ = STRING$(512, CHR$(0))
reg.ax = &H200 + (anzahlsectoren% AND 255)
zs# = (disk% AND 255#) + ((head% AND 255#) * 256#)
reg.dx = CVI(MID$(MKL$(zs#),1,2))
zs# = (sector% AND 63#) + ((cylinder% \ 256#) * 64#) + (cylinder% AND 255#) * 256#
reg.cx = CVI(MID$(MKL$(zs#),1,2))
reg.es = VARSEG(dat$)
reg.bx = SADD(dat$)
CALL INTERRUPTX(&H13, reg, reg)
-----------------------------------------------------
'Daten rausfiltern
'Partitionen rausfiltern
p1$ = MID$(dat$, 447, 16)
p2$ = MID$(dat$, 463, 16)
p3$ = MID$(dat$, 479, 16)
p4$ = MID$(dat$, 495, 16)
'Boot-Indikatoren auslesen
bi1% = ASC(MID$(p1$, 1, 1))
bi2% = ASC(MID$(p2$, 1, 1))
bi3% = ASC(MID$(p3$, 1, 1))
bi4% = ASC(MID$(p4$, 1, 1))
'Start-Head's auslesen
sh1% = ASC(MID$(p1$, 2, 1))
sh2% = ASC(MID$(p2$, 2, 1))
sh3% = ASC(MID$(p3$, 2, 1))
sh4% = ASC(MID$(p4$, 2, 1))
'Start-Sector's auslesen
ss1% = ASC(MID$(p1$, 3, 1))
ss2% = ASC(MID$(p2$, 3, 1))
ss3% = ASC(MID$(p3$, 3, 1))
ss4% = ASC(MID$(p4$, 3, 1))
'Start-Cylinder auslesen
sc1% = ASC(MID$(p1$, 4, 1))
sc2% = ASC(MID$(p2$, 4, 1))
sc3% = ASC(MID$(p3$, 4, 1))
sc4% = ASC(MID$(p4$, 4, 1))
'Betriebssystem-Indicator auslesen
os1% = ASC(MID$(p1$, 5, 1))
os2% = ASC(MID$(p2$, 5, 1))
os3% = ASC(MID$(p3$, 5, 1))
os4% = ASC(MID$(p4$, 5, 1))
'End-Head's auslesen
eh1% = ASC(MID$(p1$, 6, 1))
eh2% = ASC(MID$(p2$, 6, 1))
eh3% = ASC(MID$(p3$, 6, 1))
eh4% = ASC(MID$(p4$, 6, 1))
'End-Sector's auslesen
es1% = ASC(MID$(p1$, 7, 1))
es2% = ASC(MID$(p2$, 7, 1))
es3% = ASC(MID$(p3$, 7, 1))
es4% = ASC(MID$(p4$, 7, 1))
'End-Cylinder auslesen
ec1% = ASC(MID$(p1$, 8, 1))
ec2% = ASC(MID$(p2$, 8, 1))
ec3% = ASC(MID$(p3$, 8, 1))
ec4% = ASC(MID$(p4$, 8, 1))
'Sektor-Offset's auslesen
so1# = CVL(MID$(p1$, 9, 4))
so2# = CVL(MID$(p2$, 9, 4))
so3# = CVL(MID$(p3$, 9, 4))
so4# = CVL(MID$(p4$, 9, 4))
'Gesamt-Zahl der Sektoren auslesen
as1# = CVL(MID$(p1$, 13, 4))
as2# = CVL(MID$(p2$, 13, 4))
as3# = CVL(MID$(p3$, 13, 4))
as4# = CVL(MID$(p4$, 13, 4))
CLS
PRINT " Boot-Indicator / Start-CHS / End-CHS / OS / Sek-Off / alle Sektoren"
PRINT "1."
PRINT "2."
PRINT "3."
PRINT "4."
'Boot-Indikatoren anzeigen
LOCATE 2, 10: PRINT HEX$(bi1%)
LOCATE 3, 10: PRINT HEX$(bi2%)
LOCATE 4, 10: PRINT HEX$(bi3%)
LOCATE 5, 10: PRINT HEX$(bi4%)
'Start-Adressen anzeigen
LOCATE 2, 20: PRINT sc1%; ","; sh1%; ","; ss1%
LOCATE 3, 20: PRINT sc2%; ","; sh2%; ","; ss2%
LOCATE 4, 20: PRINT sc3%; ","; sh3%; ","; ss3%
LOCATE 5, 20: PRINT sc4%; ","; sh4%; ","; ss4%
'End-Adressen anzeigen
LOCATE 2, 36: PRINT ec1%; ","; eh1%; ","; es1%
LOCATE 3, 36: PRINT ec2%; ","; eh2%; ","; es2%
LOCATE 4, 36: PRINT ec3%; ","; eh3%; ","; es3%
LOCATE 5, 36: PRINT ec4%; ","; eh4%; ","; es4%
'Betriebssystemindikatoren anzeigen
LOCATE 2, 52: PRINT os1%
LOCATE 3, 52: PRINT os2%
LOCATE 4, 52: PRINT os3%
LOCATE 5, 52: PRINT os4%
'Sektoroffset's anzeigen
LOCATE 2, 57: PRINT so1#
LOCATE 3, 57: PRINT so2#
LOCATE 4, 57: PRINT so3#
LOCATE 5, 57: PRINT so4#
'Gesamtzahl der Sektoren anzeigen
LOCATE 2, 67: PRINT as1#
LOCATE 3, 67: PRINT as2#
LOCATE 4, 67: PRINT as3#
LOCATE 5, 67: PRINT as4#

Damit haben wir jetzt auch mal einen MBR ausgelesen. Wenn man jetzt noch weitere Informationen über die Partition haben möchte, dann liest man den Start-Sector aus mit den dazugehörigen CHS-Werten. Dieser Sector ist dann wieder ein ganz normaler BOOT-RECORD.
Hier eine englische Liste für den Betriebsystemindicator:
00h empty
01h DOS 12-bit FAT
02h XENIX root file system
03h XENIX /usr file system (obsolete)
04h DOS 16-bit FAT (up to 32M)
05h DOS 3.3+ extended partition
06h DOS 3.31+ Large File System (16-bit FAT, over 32M)
07h QNX
07h OS/2 HPFS
07h Windows NT NTFS
07h Advanced Unix
08h AIX bootable partition, SplitDrive
09h AIX data partition
09h Coherent filesystem
0Ah OS/2 Boot Manager
0Ah OPUS
0Ah Coherent swap partition
10h OPUS
11h OS/2 Boot Manager hidden 12-bit FAT partition
12h Compaq Diagnostics partition
14h (resulted from using Novell DOS 7.0 FDISK to delete Linux Native part)
14h OS/2 Boot Manager hidden sub-32M 16-bit FAT partition
16h OS/2 Boot Manager hidden over-32M 16-bit FAT partition
17h OS/2 Boot Manager hidden HPFS partition
18h AST special Windows swap file
24h NEC MS-DOS 3.x
3Ch PowerQuest PartitionMagic recovery partition
40h VENIX 80286
42h SFS (Secure File System) by Peter Gutmann
50h Disk Manager, read-only partition
51h Disk Manager, read/write partition
51h Novell???
52h CP/M
52h Microport System V/386
56h GoldenBow VFeature
61h SpeedStor
63h Unix SysV/386, 386/ix
63h Mach, MtXinu BSD 4.3 on Mach
63h GNU HURD
64h Novell NetWare
65h Novell NetWare (3.11)
70h DiskSecure Multi-Boot
75h PC/IX
80h Minix v1.1 - 1.4a
81h Minix v1.4b+
81h Linux
81h Mitac Advanced Disk Manager
82h Linux Swap partition
83h Linux native file system (ext2fs/xiafs)
84h OS/2-renumbered type 04h partition (related to hiding DOS C: drive)
93h Amoeba file system
94h Amoeba bad block table
A5h FreeBSD
B7h BSDI file system (secondarily swap)
B8h BSDI swap partition (secondarily file system)
C1h DR-DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition
C4h DR-DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition
C6h DR-DOS 6.0 LOGIN.EXE-secured Huge partition
C7h Cyrnix Boot
DBh CP/M, Concurrent CP/M, Concurrent DOS
DBh CTOS (Convergent Technologies OS)
E1h SpeedStor 12-bit FAT extended partition
E4h SpeedStor 16-bit FAT extended partition
F2h DOS 3.3+ secondary
F4h SpeedStor
FEh LANstep
FFh Xenix bad block table

Damit wissen wir jetzt alles über MBR, BR, Partitionen, CHS und dem direkten Lesen.

Jetzt beschäftigen wir uns mal mit dem Dateisystem.

       Abschnitt 4   Was sind FAT und Cluster?
FAT ist die englische Abkürzung für File-Aloccation-Table. Was auf deutsch Datei-Zuordnungs-Tabelle heißt.
Die FAT ist dazu da, um auf der Festplatte eine Ordnung herzustellen, damit man ein Datei-System benutzen kann. Denn in dieser Tabelle ist angegeben wo auf der Festplatte sich eine Datei erstreckt.
Aber damit ich das erklären kann, müssen wir uns erstmal mit dem Begriff CLUSTER auseinander setzen.
Dafür nehmen wir jetzt mal eine Beispiel-Festplatte.
1. Wir lesen den MBR aus
2. Durch den Betriebssystem-Indicator wissen wir das es sich um FAT 16 handelt.
3. Unsere einzige Partition hat eine Größe von 1038300 Sektoren.
4. Daraus folgt (Sektoren * 512) das es sich um eine 530 MB-Platte handelt.
5. Die Startadresse liegt bei CHS 0,1,1
6. Wir lesen den BOOT-RECORD an Adresse CHS 0,1,1 aus.
7. sektorenprocluster% = ASC(MID$(dat$,14,1))
8 Jetzt wissen wir das ein Cluster auf unsere Platte immer 16 Sektoren hat.
9. Da ein Cluster 16 Sektoren hat, haben wir eine jeweilige Größe von 8192 Byte
Der Cluster ist damit die kleinste adressierbare Einheit in unserem Dateisystem.

Was passiert jetzt wenn wir eine Datei abspeichern?
1. Es wird ein freier Cluster gesucht.
2. Dieser Cluster wird durch die Datei belegt.
3. Der Cluster wird als belegt markiert. Also durch einen entsprechenden Eintrag in die FAT.

In unserem Beispiel haben wir ja eine Cluster-Größe von 8192 Byte (16 Sektoren).
Wenn wir jetzt eine Datei haben die nur 1 Byte groß ist dann wird dieser Cluster trotzdem als komplett belegt markiert.
Das würde dann heißen das wir in diesem Fall 8191 Byte verschenkt haben! Das ist der große Nachteil von FAT!!!
Wenn wir jetzt eine Datei haben die eine Größe von z.B. 10192 hat, dann reicht 1 Cluster ja nicht aus um sie abzuspeichern. Da nimmt man einfach einen 2. Cluster dazu. Im ersten Cluster werden die ersten 8192 Byte der Datei gespeichert und im 2. Cluster werden die restlichen 2000 Byte gespeichert. Diese beiden Cluster können jeweils an ganz verschiedenen Stellen der Festplatte gespeichert sein.
Aber woher weiß das Betriebssystem jetzt welche Cluster zusammengehören?
Dazu ist dann die FAT da. Wenn wir den ersten Cluster gespeichert haben, dann wird ja dieser Cluster als belegt in der FAT markiert. Aber das ist nicht alles, denn dieser Eintrag in die FAT ist einfach nur die Nummer des nächsten Clusters. Wenn es keinen nächsten Cluster gibt, dann wird das auch entsprechend vermerkt.
Für jeden Eintrag bei FAT16 sind 2Byte reserviert. 2 hoch 16 = 65536. Diese Zahl kann man mit 2 Byte darstellen (Integer).
Hier nun die Einträge in Hex:
- 0000 nicht belegt
- 0001 - FFEF belegt, nächste Clusternummer
- FFF7 - defekt
- FFF8 - FFFF - Ende der Clusterkette

Fassen wir noch mal zusammen: In der FAT sind alle Cluster entweder als frei, belegt mit Clusternummer, defekt, oder als End-Cluster markiert. Daraus ergeben sich für größere Dateien Clusterketten. Dabei braucht man nur zu wissen, welches der erste Cluster ist und kann dann durch die FAT diese Kette verfolgen. Das wird dir in späteren Beispielprogrammen noch verständlicher werden.
Desweiteren ist dir evtl. schon aufgefallen, das es 2 FAT's gibt. Das dient zur Sicherheit. Falls die erste FAT mal kaputt geht, kann man theoretisch die 2. FAT auf die 1. FAT kopieren. In der Praxis ist das aber etwas, was nie gemacht, und deshalb brauchen wir uns darum nicht zu kümmern!
Jetzt wollen wir wissen wie viele Sektoren denn eine FAT einnimmt. Dazu nehmen wir das 23. und 24. Byte aus unserem BOOT-RECORD. fatsectors% = CVI(MID$(dat$, 23, 2)). Damit wissen wir wieviele Sektoren eine FAT benötigt. In unserem Beispiel sind es 254. Da wir 2 FAT's haben, multiplizieren wir diese Zahl jetzt noch mit 2. Also haben wir für beide FAT's eine Gesamtgröße von 508 Sektoren (260096 Byte). Das müssen wir wissen damit wir später noch Dateien auslesen können. Denn es gibt eine bestimmte Reihenfolge in einer Partition.
1. BOOT-RECORD
2. FAT1
3. FAT2
4. ROOT
5. Daten (in Cluster aufgeteilt)

Da wir die FAT jetzt kennen, schauen wir uns mal ROOT an. Dieser Abschnitt wird auch als ROOT-Verzeichnis bezeichnet. Dort stehen alle Verzeichnisse und Dateien drin die du direkt auf C:\ hast. Also das Grund-Verzeichnis.
Die Maximalzahl der Dateien und Verzeichnisse stehen an Byte 18 und 19 des BOOT-RECORD's. Also anzahlfiles% = CVI(MID$(dat$,18,2)).
Für jedes Verzeichnis und für jede Datei gibt es genau einen 32 Byte Eintrag. Der sieht wie folgt aus:
Byte-Nummer Bedeutung
1-8 Dateiname
9-11 Dateinamens-Erweiterung
12 Attribut
00h - normales File, Lesen und Schreiben erlaubt
01h - nur Lesen erlaubt
02h - versteckt
04h - System-Datei
08h - Volume-Label (z.B. Laufwerkbezeichnung)
10h - Verzeichnis
20h - Archiv
13-22 Reserviert (für Windows z.B. letzter Zugriff...
23-24 Zeit des letzten Schreibzugriffs
Bits 0-4 Sekunden
Bits 5-10 Minuten
Bits 11-15 Stunden
25-26 Datum des letzten Schreibzugriffs
Bits 0-4 Tag
Bits 5-8 Monat
Bits 9-15 Jahr ( + 1980)
27-28 Nummer des ersten Clusters
29-32 Größe der Datei in Byte

Da es in unserem Beispiel insgesamt 512 Verzeichnisse sind im ROOT ergibt das eine Sektorzahl von 32.
Damit wissen wir jetzt erstmal genug und schreiben uns ein paar Routinen mit denen es sich gut arbeiten lässt.

Als erstes schreiben wir uns ein Programm das alle Sektoren-Offset ausliest und berechnet und zwar im Bezug auf den Festplatten-Anfang.
Dabei gehe ich davon aus das wir schon den BOOT-RECORD ausgelesen haben und die Daten in dat$ stehen.
DIM SHARED sectorprocluster#, fatoffset#, rootoffset#, datenoffset#
----------------------------------------------------------------
Sektoren pro Cluster merken
sectorprocluster# = ASC(MID$(dat$,14,1))
----------------------------------------------------------------
Sektoroffset der 1. FAT
fatoffset# = CVI(MID$(dat$,29,2)) + CVI(MID$(dat$,15,2))
----------------------------------------------------------------
Sektoroffset des ROOT
rootoffset# = fatoffset# + (CVI(MID$(dat$,23,2))*2)
----------------------------------------------------------------
Sektoroffset des ersten Daten-Clusters
datenoffset# = rootoffset# + ((CVI(MID$(dat$,18,2)) * 32) / CVI(MID$(dat$,12,2)) )

Damit haben wir alle Offsets die wir brauchen um Daten von der Festplatte zu lesen
Das was wir jetzt noch brauchen ist ein Programm das uns die jeweiligen Sektor-Werte in CHS-Werte umwandelt, damit wir INT 13 benutzen können.

Dazu schreiben wir uns ein SUB:
Hauptprogramm:
DIM SHARED mul1#, mul2#
mul1# = CVI(MID$(dat$,25,2)) * CVI(MID$(dat$,27,2))
mul2# = CVI(MID$(dat$,25,2))
------------------------------------------------
SUB Sector2CHS (sektor#, cylinder%, head%, sector%)
sektor2# = sektor#
cylinder2# = sektor2# \ mul1#
sektor2# = sektor2# - (mul1# * cylinder2#)
head2# = sektor2# \ mul2#
sektor2# = sektor2# - (mul2# * head2#)
sektor2# = sektor2# + 1
sector% = sektor2#
head% = head2#
cylinder% = cylinder2#
END SUB

Jetzt lesen wir mal den ersten ROOT-Sektor aus. Dafür nehmen wir das Sektoroffset rootoffset# und lesen ihn mittels unserer LeseRoutine ein. Das ganze sieht dann so aus:
CALL Sector2CHS (rootoffset#, cylinder%, head%, sector%)
disk% = &H80
anzahlsectoren% = 1
-----------------------------------------------------
'Sektor lesen
dat$ = STRING$(512, CHR$(0))
reg.ax = &H200 + (anzahlsectoren% AND 255)
zs# = (disk% AND 255#) + ((head% AND 255#) * 256#)
reg.dx = CVI(MID$(MKL$(zs#),1,2))
zs# = (sector% AND 63#) + ((cylinder% \ 256#) * 64#) + (cylinder% AND 255#) * 256#
reg.cx = CVI(MID$(MKL$(zs#),1,2))
reg.es = VARSEG(dat$)
reg.bx = SADD(dat$)
CALL INTERRUPTX(&H13, reg, reg)

Jetzt haben wir in dat$ unsere ersten 16 Verzeichnisse aus dem ROOT-Verzeichnis. Und diese schlüsseln wir jetzt mit folgendem Programm mal auf.
CLS
PRINT "Dateiname Attribut Zeit Datum Größe Start-Cluster"
FOR i% = 1 TO LEN(dat$) STEP 32
'-----------------------------------------------------------
dateiname$ = MID$(dat$, i%, 8) + " " + MID$(dat$, i% + 8, 3)
'-----------------------------------------------------------
attribut$ = HEX$(ASC(MID$(dat$, i% + 11, 1)))
IF LEN(attribut$) = 1 THEN attribut$ = "0" + attribut$
'-----------------------------------------------------------
zeit# = CVL(MID$(dat$, i% + 22, 2) + MKI$(0))
'-----------------------------------------------------------
sekunde$ = LTRIM$(STR$(zeit# AND 31))
IF LEN(sekunde$) = 1 THEN sekunde$ = "0" + sekunde$
'-----------------------------------------------------------
minute$ = LTRIM$(STR$((zeit# \ 32) AND 63))
IF LEN(minute$) = 1 THEN minute$ = "0" + minute$
'-----------------------------------------------------------
stunde$ = LTRIM$(STR$((zeit# \ 2048) AND 31))
IF LEN(stunde$) = 1 THEN stunde$ = "0" + stunde$
'-----------------------------------------------------------
z$ = stunde$ + ":" + minute$ + "." + sekunde$
'-----------------------------------------------------------
datum# = CVL(MID$(dat$, i% + 24, 2) + MKI$(0))
'-----------------------------------------------------------
tag$ = LTRIM$(STR$(datum# AND 31))
IF LEN(tag$) = 1 THEN tag$ = "0" + tag$
'-----------------------------------------------------------
monat$ = LTRIM$(STR$((datum# \ 32) AND 7))
IF LEN(monat$) = 1 THEN monat$ = "0" + monat$
'-----------------------------------------------------------
jahr$ = LTRIM$(STR$(((datum# \ 512) AND 127) + 1980))
'-----------------------------------------------------------
d$ = tag$ + "." + monat$ + "." + jahr$
'-----------------------------------------------------------
gr$ = LTRIM$(STR$(CVL(MID$(dat$, i% + 28, 4))))
gr$ = STRING$(10 - LEN(gr$), " ") + gr$
'-----------------------------------------------------------
start$ = LTRIM$(HEX$(CVI(MID$(dat$, i% + 26, 2))))
start$ = STRING$(4 - LEN(start$), "0") + start$
'-----------------------------------------------------------
PRINT dateiname$; " "; attribut$; " " + z$ + " " + d$ + " " + gr$ + " " + start$
'-----------------------------------------------------------
NEXT i%

Wenn jetzt alles geklappt hat, dann müßtest du an der ersten Stelle dein Laufwerkslabel sehen und danach einige Dateien und Verzeichnisse wo die angezeigten Werte auch richtig und sinnvoll sind. Um jetzt das ganze ROOT-Verzeichnis auszulesen (es sind ja immerhin 32 Sektoren) nimmst du anstatt rootoffset# -> rootoffset# + 1, +2,...,+31. und liest die Sektoren erneut aus.

Wie du evtl gesehen hast gibt es einen Wert für den Start-Cluster. Dieser bedeutet das die jeweilige Datei dort mit den Daten anfängt, oder bei Verzeichnissen befindet sich dort das Unterverzeichnis, welches datentechnisch genauso augebaut ist wie das ROOT. Nur das jedes Unterverzeichnis immer nur 1 Cluster belegt.
Desweiteren ist dieser Start-Cluster-Wert ein Integer-Wert. Das heißt das er die Zahlen von 0-65535 annehmen kann. Was automatisch bedeutet das wir in diesem Fall mit maximal FAT16 arbeiten können. Da ich die Beispielprogramme nur an FAT16 ausprobieren konnte, werden die jetzt folgenden Programme nur bis FAT16 funktionieren.
Dazu suchst du dir jetzt ein beliebiges Verzeichnis aus (Attribut 10) und merkst dir mal den Start-Cluster.
Jetzt schreiben wir uns ein Programm das einen Cluster in ein Sektoroffset umwandelt.
SUB Cluster2Sektor (cluster#, sektor#)
IF cluster# < 0 THEN cluster# = cluster# + 65536
sektor# = datenoffset# + (cluster# - 2) * sectorprocluster
END SUB

Danach rufen wir unser SUB Sector2CHS mit sektor# auf, und schon haben wir unsere gewünschten CHS-Werte. Jetzt lesen wir den Sektor aus. Da es sich um ein Unterverzeichnis handelt, kannst du den gelesenen Sektor jetzt auch wie ein Verzeichnissektor aufschlüsseln. So wie wir es schon gemacht haben.

Als nächstes suchst du dir mal eine größere Datei aus dem ROOT-Verzeichnis aus. Am idealsten wäre eine Text-Datei.
Dann machen wir wieder das gleiche wie ebend. Also erstmal den Cluster in Sektor umwandeln, dann den Sektor in CHS-Werte umwandeln und dann den ersten Sektor der Datei auslesen. Wenn du eine Text-Datei genommen hast kannst du ja mal PRINT dat$ ausführen. Wenn es klappt, dann kannst du jetzt den Text sehen der in dieser datei steht. Um natürlich den ganzen Cluster auszulesen mußt du auch noch die anderen Sektoren lesen. Wie das geht weißt du ja. Die Gesamtzahl der Sektoren in einem Cluster ist in der Variable sectorprocluster gespeichert.

Jetzt kommen wir zu dem Fall, wenn eine Datei mehr als einen Cluster belegt. Dazu müssen wir nämlich in die FAT schauen. Denn dort steht ja der jeweils nächste Cluster der Datei.
Das folgende SUB liest den nächsten Cluster aus der FAT aus.
SUB GET.FAT.CLUSTER (cluster#, nextcluster#)
IF cluster# < 0 THEN cluster# = cluster# + 65536
cluster2# = cluster#
sektor2# = fatoffset# + (cluster2# \ 256)
cluster2# = (cluster2# - ((sektor2# - fatoffset#) * 256)) * 2
CALL Sector2CHS (sektor2#, cylinder%, head%, sector%)
disk% = &H80
anzahlsectoren% = 1
-----------------------------------------------------
'Sektor lesen
dat$ = STRING$(512, CHR$(0))
reg.ax = &H200 + (anzahlsectoren% AND 255)
zs# = (disk% AND 255#) + ((head% AND 255#) * 256#)
reg.dx = CVI(MID$(MKL$(zs#),1,2))
zs# = (sector% AND 63#) + ((cylinder% \ 256#) * 64#) + (cylinder% AND 255#) * 256#
reg.cx = CVI(MID$(MKL$(zs#),1,2))
reg.es = VARSEG(dat$)
reg.bx = SADD(dat$)
CALL INTERRUPTX(&H13, reg, reg)
nextcluster# = CVI(MID$(dat$, cluster2# + 1,2))
IF nextcluster# < 0 THEN nextcluster# = nextcluster# + 65536
END SUB

So, damit können wir jetzt auch eine Cluster-Kette verfolgen.
Was noch wichtig ist, ist das Disketten FAT12 benutzen. Das heißt das ein Eintrag in die FAT nicht 2 Byte hat(wie bei FAT16) sondern nur 1.5 Byte. Da müßtest du das Sub dementsprechend umschreiben.

         Abschluss   letzte Aktualisierung: 10.08.2003
Das war es auch schon wieder. Wenn du weitere Fragen hast oder ich irgend etwas falsch beschrieben habe, dann Mail an Webmaster.




Werbung
Partner