|
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.
|
|
|