Forum: Mikrocontroller und Digitale Elektronik FAT32 - wo anfangen?


von Ralf (Gast)


Lesenswert?

Halo Leuts,
ich will grade auf meinem Mikrocontrollerboard, welches einen LPC2468 
hat, FAT32 implementieren, um von der SD-Karte Dateien zu lesen und zu 
schreiben.
Ich weiss, das gab es schon 5646546533412 mal, und es gibt ungefähr 
10000000 fertige Libs, aber ich will etwas lernen und es deshalb selber 
machen.
Mein Problem ist jetzt nicht, dass es mir an Infos mangelt, sondern das 
Gegenteil ist der Fall. Ich habe zu viel, teilweise leicht 
widersprüchliche Angaben. fatgen103.doc  von Microsoft hilft auch nicht 
viel, die Datenstrukturen sind zwar schön beschrieben, aber es ist nicht 
wirklich übersichtlich. Meine Frage: Wenn ich ein solches FS 
implementieren will - wo fange ich am besten an? Sektoren lesen und 
schreiben kann ich schon, daran soll es also nicht scheitern. Wie geht 
es weiter? Ich scheitere schon nur an der Frage, wie ich jetzt ein File 
lese. Ich weiss zwar, dass man irgendwie den Startcluster einer Datei 
berechnen kann, und dann daraus die Sektornummer, aber irgendwie kriege 
ich bis jetzt noch keinen funktionierenden Code zustande. Könnt ihr mir 
ein bisschen auf die Sprünge helfen?

Was ich vor allem möchte:
Die FAT-Implementation soll möglichst ähnlich sein, wie die auf dem PC 
(also was das File-Handling im Programm angeht mit fopen, fwrite und so 
weiter). Ich will mehrere Dateien gleichzeitig öffnen, lesen und 
schreiben. RAM ist genug da (128M).

von Soeren A. (abraxa)


Lesenswert?

http://www.pjrc.com/tech/8051/ide/fat32.html fand ich hilfreich, schau's 
dir mal an.

von holger (Gast)


Lesenswert?

@Ralf
>Ich weiss, das gab es schon 5646546533412 mal, und es gibt ungefähr
>10000000 fertige Libs, aber ich will etwas lernen und es deshalb selber
>machen.

Von den 1000000 Libs funktioniert nur eine handvoll wirlich gut.

>Ich habe zu viel, teilweise leicht
>widersprüchliche Angaben. fatgen103.doc

Die Doku von MS ist ausreichend. Wenn du damit nicht klarkommst
ist das dein Problem.

>Wenn ich ein solches FS
>implementieren will - wo fange ich am besten an?

Verstehen was ein MBR ist, was ein Bootsektor ist,
was eine Partition ist. Wie sieht eine FAT aus?
Was wird dort wie eingetragen? Wie groß sind die Cluster?
Wie groß ist der Eintrag in der FAT für einen Cluster?

>Ich scheitere schon nur an der Frage, wie ich jetzt ein File
>lese.

Folge der Clusterchain!

>Ich will mehrere Dateien gleichzeitig öffnen,

Versuch es erstmal mit einer Datei.
Mehrere ist dann für die Fortgeschrittenen.

Ein eigenes FAT Dateisystem zu programmieren und zu
entwanzen dauert schon ein paar Monate/Jahre.

von Ralf (Gast)


Lesenswert?

Also,
ich habe beim Googeln noch ein interessantes Dokument gefunden, wo das 
ganze einigermassen leicht verständlich erklärt wird.
Sehe ich das richtig so:
Ich lese erst den Sektor 0 vom Medium, um den BPB (Bios Parameter Block) 
zu kriegen. Mit den Infos, die dort drin stehen, kann ich dann 
berechnen, wo die FAT beginnt, und wo die Directory Table sich befindet. 
Richtig?
Um ein File zu suchen, muss ich im Directory Table-Bereich nach dem 
gewünschten Namen suchen. Dort finde ich dann eine Struktur, wo 
Dateinamen, Datum, Attribute sowie der Startcluster drin stehen. 
Richtig?
Anhand der Nummer des Startclusters kann ich den Startsektor der Datei 
berechnen. Wenn ich unter der Nummer dieses Startclusters in der FAT 
nachschaue, dann sehe ich da, welches die Nummer des nächsten Clusters 
ist. Wenn als nächster Cluster 0x0FFFFFFF eingetragen ist, dann ist die 
Cluster Chain zu Ende.
Ist mein Vorgehen grundsätzlich richtig?

Nun habe ich nur noch ein Problem:
Ich wollte das mit der Directory Table als struct lösen. Sprich: ich 
definiere ein struct, das genau einen Dir-Eintrag repräsentiert. Nun 
habe ich aber festgestellt, dass die Dir-Einträge unterschiedlich lang 
sein können :-( wie löst man dieses Problem?
Lange Dateinamen würde ich nämlich auch gerne Verwenden. 8.3 ist leider 
unbrauchbar....

von Zwirbeljupp (Gast)


Lesenswert?

Grundsätzlich klingt das Vorgehen schon mal gut, aber...

> ich definiere ein struct, das genau einen Dir-Eintrag repräsentiert. Nun
> habe ich aber festgestellt, dass die Dir-Einträge unterschiedlich lang
> sein können :-( wie löst man dieses Problem?
...das ist Blödsinn, die Dir-Einträge sind alle exakt 32 Bytes lang. Es 
gibt nur zwei unterschiedliche Typen.

> Lange Dateinamen würde ich nämlich auch gerne Verwenden. 8.3 ist leider
> unbrauchbar....
Tja, lange Dateinamen ist ebenfalls für Fortgeschrittene. Wenn Dein FAT 
mit 8.3 läuft und Du dann tatsächlich noch Lust haben solltest, lange 
Dateinamen einzubauen, kannst Du das immer noch machen.

von Martin (Gast)


Lesenswert?

Die Widersprüche in der fatgen103.doc interessieren mich. Hast du ein 
paar Beispiele?

von Ralf (Gast)


Lesenswert?

> ...das ist Blödsinn, die Dir-Einträge sind alle exakt 32 Bytes lang. Es
> gibt nur zwei unterschiedliche Typen.

Also, das ist ja super.
Nun habe ich nur noch folgendes Problem:
Bei einem langen Dateinamen kommt erst der Dateiname, anschliessend der 
eigentliche Directory Eintrag. Woher weiss ich denn nun im Voraus, ob es 
sich bei dem folgenden File um eines mit oder ohne langen Namen handelt?
Wenn ich meinen FAT-Treiber so schreibe, dass er mit 8.3 funktioniert, 
das Medium dann in Windows bearbeite und dadurch lange Dateinamen 
entstehen - kann ich das Medium dann trotzdem noch lesen?

von Zwirbeljupp (Gast)


Lesenswert?

> Wenn ich meinen FAT-Treiber so schreibe, dass er mit 8.3 funktioniert,
> das Medium dann in Windows bearbeite und dadurch lange Dateinamen
> entstehen - kann ich das Medium dann trotzdem noch lesen?
Ja, natürlich. Nur die Dateinamen werden halt verkürzt dargestellt. 
Diese Abwärtskompatibilität ist ja gerade der Grund, warum man sich bei 
der Implementierung von LongFileName-Unterstützung so dermaßen einen 
abbrechen muss...

> Woher weiss ich denn nun im Voraus, ob es
> sich bei dem folgenden File um eines mit oder ohne langen Namen handelt?
Die Dir-Einträge, welche den langen Dateinamen enthalten sind nummeriert 
und liegen IMMER direkt vor dem eigentlichen Dir-Eintrag der 
entsprechenden Datei. Wenn Du also das Directory Eintrag für Eintrag von 
oben nach unten durchgehst, stolperst Du also zwangsläufig zuerst über 
die LongFileName-Einträge.

von Karl H. (kbuchegg)


Lesenswert?

Ralf schrieb:
> Meine Frage: Wenn ich ein solches FS
> implementieren will - wo fange ich am besten an?

Meine Startegie bei solchen Sachen war immer (auf diesen konkreten Fall 
angewendet):
Lass dir von Windows eine SD-Karte neu formatieren, schreibe eine(!) 
kleine Datei drauf und dann sieh in den Sektoren nach, was da alles wo 
eingetragen wurde. Wenn du Doku dazu hast, sieh nach ob die Doku mit der 
Realität übereinstimmt, bzw nimm Papier und Bleistift und werte die 
Bytes mit der Hand aus und sieh zu, dass du gedanklich einen Filezugriff 
durchspielst. Welches Byte kommt woher, welche Info kriege ich davon, 
wie führt mich dieses Byte weiter. Solange bis ich bei den Datenbytes 
des Files bin.
Gehts mit einer kleinen Datei, dann eine größere von Windows schreiben 
lassen. Welche Bytes haben sich verändert, etc.
Hab ich verstanden, wie das mit einer Datei geht, überprüfe ich mein 
Wissen, indem ich mehrere Dateien auf die Karte schreiben lasse. Gelingt 
es mir immer noch die Datenbytes zu finden?
Was ist wenn eine Datei gelöscht wird, wie ändern sich dann die 
Einträge?

Langer Rede, kurzer Sinn:
Die Strategie ist nicht, da jetzt tagelang Doku zu studieren und rein 
anhand der Doku ein Programm zu bauen, sondern Doku studieren und anhand 
der realen Daten (welche ein anderes Pgm geschrieben hat, in deinem Fall 
Windows) überprüfen ob ich die Doku richtig verstanden habe. Dazu gehört 
auch sich zu überlegen, wie ich Windows dazu bringen kann, das in der 
Doku gelesene auch zu realisieren. Also: Wenn in der Doku steht, dieses 
Bit zeigt das ReadOnly Flag an, dann lass ich mir von Windows eine 
ReadOnly Datei schreiben und sehe nach. Hat sich ausser diesem einen Bit 
noch etwas verändert? (Dazu ist es notwendig, dass man zb auch überlegt, 
wie man reproduzierbare Sektordaten auf der Karte mit Windows erzeugen 
kann).
Und erst dann geht es los und ich fange mit einer Implementierung an, 
wobei auch das ein Wechselspiel ist. Ich implementiere nicht alles in 
einem Rutsch, sondern teile das so auf, dass ich einzelne Schritte 
testen kann. Testen, lange bevor alles fertig ist.

Ob das jetzt ein Filesystem ist, oder die Ansteuerung eines Plotters, 
oder eines Spektrometers oder eines Terminals, oder .... Das Prinzip ist 
immer das Gleiche: Ein Wechselspiel aus Doku lesen und sich das Gelesene 
in Natura am Objekt ansehen.

Oh. Ganz wichtig. Am Anfang kleine Brötchen backen! Du hast schon 
tausend Pläne, wie toll dein FS sein soll und welche Features es können 
soll, etc. Fang erst mal klein an. Sieh zu dass du 8.3 lesen/schreiben 
kannst. Es ist auch nicht ungewöhnlich bei derartigen Dingen, dass man 2 
oder 3 Anläufe benötigt, bis die interne Programmstruktur so ist, dass 
sie vernünftig ist. Also keine Angst davor, dass du nach Tagen 
draufkommst, dass du ungeschickt angefangen hast. "Failure is not an 
option" ist kein Hindernis für dich. Aus dem gescheiterten Versuch hast 
du etwas sehr Wichtiges gelernt. Nämlich, dass es so nicht geht und vor 
allen Dingen: warum es so nicht geht und in welche Probleme dieser 
spezielle Ansatz führt. Und dieses Wissen ist unbezahlbar!

von Ralf (Gast)


Lesenswert?

Hallo Leuts,
also ich habe mich nochmals hin gesetzt und vor allem fatgen103.pdf 
genau studiert. Mittels Disk-Editor habe ich dann meinen 
FAT32-formatierten Memory Stick auseinander genommen, und mittlerweile 
bin ich so weit, dass ich anhand des BPB den Beginn der FAT bzw. der 
Directory-Einträge bestimmen kann. Auch das durchlaufen der Cluster 
chain geht. (bis jetzt habe ich das auf dem PC getestet, indem ich 
einfach ein Image meines Memory Stick gemacht habe und dieses dann als 
virtuelles Speichermedium verwende). Somit kann ich nun also eine Datei 
lesen, wenn ich deren Anfangscluster kenne.
Das einzige, was mir jetzt noch Kopfzerbrechen bereitet, sind diese 
Directory-Einträge. Mir ist nicht ganz klar, wie ich die finden soll - 
klar, ich kenne den Startsektor, wo die Dir-Einträge liegen, aber damit 
kenne ich ja erst die Position des 1. Eintrags. Die Position des 
nächsten Eintrags könnte ich zwar berechnen, wenn ich weiss, ob es sich 
beim 1. File um eines mit oder ohne langem Namen handelt. Das geht aber 
nicht, da ich das im Voraus nicht wissen kann! Also, meine Frage 
deshalb:
Ich kenne den aller ersten Directory-Eintrag. Wie finde ich den 
nächsten?
Was ich schon weiss: wenn der Name eines Directory-Eintrags mit 0x00 
oder 0xE5 beginnt, dann ist dies entweder ein gelöschtes File (0xE5) 
oder es ist ein leerer Platz und es folgen keine weiteren Eintrage 
(0x00).

Klar heisst es in fatgen103, dass FAT32 mit oder ohne lange Namen voll 
kompatibel sind, und die langen Namen einfach ignoriert werden, wenn das 
System sie nicht unterstützt. Aber irgendwo her muss das System ja 
wissen, welche Daten es ignorieren soll und welche nicht ;-)


Das ist also das Einzige, womit ich noch Mühe habe. Ansonsten glaube 
ich, habe ich FAT32 einigermassen verstanden....

von holger (Gast)


Lesenswert?

>Ich kenne den aller ersten Directory-Eintrag. Wie finde ich den
>nächsten?

Alle Directory Einträge (gelöschte Dateien, LFN Einträge) abklappern
bis du den nächsten gefunden hast.

von Ralf (Gast)


Lesenswert?

Also, da jeder Eintrag 32 Bytes umfasst, gehe ich einfach 32 Bytes 
weiter bis zum nächsten Eintrag. Richtig?

von holger (Gast)


Lesenswert?

>Also, da jeder Eintrag 32 Bytes umfasst, gehe ich einfach 32 Bytes
>weiter bis zum nächsten Eintrag. Richtig?

Jo.

von Peter R. (gelb)


Lesenswert?

Ralf schrieb:
> nächsten Eintrags könnte ich zwar berechnen, wenn ich weiss, ob es sich
> beim 1. File um eines mit oder ohne langem Namen handelt. Das geht aber

Ob ein Directory-Eitrag ein LFN ist, kann am Attribut festgestellt 
werden:
Die Bits ATTR_READ_ONLY, ATTR_HIDDEN, ATTR_SYSTEM und ATTR_VOLUME_ID 
sind gesetzt. Ein 8.3-System ignoriert solche Einträge. Du solltest sie 
erstmal ebenfalls ignorieren.

Steht in fatgen103.doc, Seite 26.

Grüße, Peter

von Ralf (Gast)


Lesenswert?

Danke Peter, ich hab es auch grade gesehen!
Super Sache, so langsam wird einiges klarer.
Aber ich habe noch etwas weiteres festgestellt:
Nehmen wir an, ich habe einen leeren Datenträger. Den bearbeite ich 
jetzt mit Windows (da mein eigener FAT-Treiber ja noch nicht läuft).
Jetzt erstelle ich also da drauf ein File - kein Problem, das File ist 
sofort auffindbar, es wird nämlich durch den ersten Eintrag im Directory 
Table repräsentiert. So, und jetzt erstelle ich einen Ordner. Der Ordner 
wird korrekterweise im Directory Table abgebildet - es ist der Eintrag, 
der gleich auf mein erstes File folgt. Schön und gut, aber dummerweise 
müssen jetzt irgendwo noch die . und .. Einträge erstellt werden - und 
die platziert Windows zu beginnn des nächsten Clusters. Das wäre ansich 
auch kein Problem, aber wenn mein Directory Table jetzt wächst, stösst 
es irgendwann an die Cluster-Grenze. Und dann verstehe ich nicht mehr, 
was passiert - wo kommen denn jetzt neue Einträge rein, wenn das 
Directory Table weiter wachsen soll? Irgendwie wird es fragmentiert 
durch das Vorhandensein von Dateien und Ordnern :-(

von holger (Gast)


Lesenswert?

>Und dann verstehe ich nicht mehr,
>was passiert - wo kommen denn jetzt neue Einträge rein, wenn das
>Directory Table weiter wachsen soll?

Du suchst dir einen freien Cluster und hängst ihn
ans Ende der Clusterchain des Directorys.

>Irgendwie wird es fragmentiert
>durch das Vorhandensein von Dateien und Ordnern :-(

Das lässt sich nicht vermeiden.

von Simon K. (simon) Benutzerseite


Lesenswert?

Bist du dir sicher, dass du dem Projekt gewachsen bist?

von Ralf (Gast)


Lesenswert?

holger,
okay klar soweit - neuen Cluster suchen und dann in der Cluster chain 
einfügen.
Dummerweise kenne ich ja aber die Clusternummer des Directory Table 
nicht - ich mache die Ausfindig über die Formel, die in fatgen103 
angegeben ist. Irgendwie so: (Anzahl der FATs * Grösse der FAT) + 
Reservierte Sektoren oder irgendwie etwas in der Art (habe den Code grad 
nicht parat).
Ist das also nicht richtig so? Irgendwo her muss ich ja die 
Clusternummer des Directory Table kennen, damit ich bestimmen kann, wo 
ich den neuen Cluster einfügen muss....

von holger (Gast)


Lesenswert?

@Simon

>Bist du dir sicher, dass du dem Projekt gewachsen bist?

Nun lass ihn mal machen, das fängt doch schon ganz gut an.
Ich bin gespannt wie weit er kommt! Vieleicht wächst hier
gerade ein neues selfmade FAT System.

von Peter R. (gelb)


Lesenswert?

Ralf schrieb:

> auch kein Problem, aber wenn mein Directory Table jetzt wächst, stösst
> es irgendwann an die Cluster-Grenze. Und dann verstehe ich nicht mehr,
> was passiert - wo kommen denn jetzt neue Einträge rein, wenn das
> Directory Table weiter wachsen soll? Irgendwie wird es fragmentiert
> durch das Vorhandensein von Dateien und Ordnern :-(

Die Root-Directory ist auf jeden Fall begrenzt. Meines Wissens ist die 
Anzahl der dafür reservierten Sektoren bei FAT32 nicht angegeben.

Aber sowohl der Anfang der Root-Directory als auch der Beginn der Daten 
ist angegeben, dazwischen liegt die Root, die Anzahl Sektoren muss man 
wohl selbst ausrechnen.

Grüße, Peter

von holger (Gast)


Lesenswert?

>Dummerweise kenne ich ja aber die Clusternummer des Directory Table
>nicht

Doch, das steht bei einem Unterverzeichnis im Directory Eintrag
für das Unterverzeichnis. Für das Rootdirectory ist es ein fester
Wert. Schaun wir mal ob du rausfindest welcher das ist ;)

von holger (Gast)


Lesenswert?

>Die Root-Directory ist auf jeden Fall begrenzt. Meines Wissens ist die
>Anzahl der dafür reservierten Sektoren bei FAT32 nicht angegeben.

Bei FAT32 ist das Rootdirectory in der FAT eingetragen und kann
beliebig vergrößert werden. Nur bei FAT12 und FAT16 ist die Größe
des Rootdirectory fix.

von Ralf (Gast)


Lesenswert?

Peter,
so wie ich das verstanden habe, ist bei FAT32 die Anzahl der Einträge im 
Root Directory nicht begrenzt.
Bei FAT12 und 16 war sie es, ich glaube auf 512 Einträge.


Simon:
Ja, ich denke schon dass ich dem Projekt gewachsen bin. Ich bin nicht 
dumm, meine Stärke liegt halt eher auf der Hardware-Seite. Ausserdem 
beschäftige ich mich auch erst seit etwa gestern ernsthaft mit dem 
Thema, da finde ich es normal, dass man zu beginn einige Fragen hat bzw. 
einiges unklar ist. Dass du FAT32 von Beginn an gleich durchschaut hast, 
und es für dich ein leichtes war, das zu Programmieren, glaube ich gern, 
aber ich für meinen Teil tue mir damit etwas schwerer. Zumal die Doku 
von MS zwar ausreichend, aber nicht wirklich toll ist; was die Sache 
nicht unbedingt vereinfacht.

holger:
ich hoffe sehr, dass ich mein Programm irgendwann mal zum Laufen kriege.
Man findet zwar im Netz zahllose Libraries für FAT, aber keine ist so 
richtig toll (für meinen Geschmack).
Ich  will was bauen, was vor allem auf Performance ausgelegt ist (da es 
auf einem ARM laufen soll, spare ich auch nicht unbedingt an RAM oder 
dergleichen). Es soll möglichst schnell sein, und soweit es geht 
PC-Kompatibel (was glaube ich nicht bei allen erhältlichen FAT Libs zu 
100% der Fall ist).
Wenn ihr wollt kann ich ja dann, wenn ich fertig bin, den Code hier 
reinstellen (als Dankeschön sozusagen für eure Hilfe ;-)).

von Ralf (Gast)


Lesenswert?

holger,

> Doch, das steht bei einem Unterverzeichnis im Directory Eintrag
> für das Unterverzeichnis. Für das Rootdirectory ist es ein fester
> Wert. Schaun wir mal ob du rausfindest welcher das ist ;)

Meinst du Cluster Nr. 2? Die FAT-Einträge 0 und 1 sind ja reserviert. 
Dann nehme ich mal an, beginnt das Root-Directory bei Cluster Nr. 2.

von Simon K. (simon) Benutzerseite


Lesenswert?

holger schrieb:
> @Simon
>
>>Bist du dir sicher, dass du dem Projekt gewachsen bist?
>
> Nun lass ihn mal machen, das fängt doch schon ganz gut an.
> Ich bin gespannt wie weit er kommt! Vieleicht wächst hier
> gerade ein neues selfmade FAT System.

;) Ja vielleicht. Ich meine nur, so oft wie er hier nachfragt und was 
nicht versteht. Erster Schritt wäre vielleicht: Selber herausfinden und 
das Posten im Forum als letzten Ausweg sehen, so mache ich das nämlich 
immer. Wo bleibt die Herausforderung. Es gibt sooo viel Infos zu FAT im 
Internet und auch in diesem Forum.
Notfalls guckt man mal in andere Sourcen rein und lässt sich 
inspirieren.
Stattdessen herrscht hier eher eine Schüler-Nachhilfelehrer Situation.

von holger (Gast)


Lesenswert?

>Dann nehme ich mal an, beginnt das Root-Directory bei Cluster Nr. 2.

Muss nicht 2 sein. Kleiner Tip:

BPB_RootClus

von holger (Gast)


Lesenswert?

>Stattdessen herrscht hier eher eine Schüler-Nachhilfelehrer Situation.

Ich finde er hat sich schon ganz gut informiert
und ein wenig Nachhilfe verdient ;)

von Ralf (Gast)


Lesenswert?

Simon,
ich werde versuchen mich zu Bessern.
Du sagst, man findet viele Infos zu FAT. Das ist richtig. Und genau das 
ist mein Problem! Für meinen Geschmack sind es eben zu viele Infos. Ich 
weiss gar nicht, wo ich beginnen soll! Oder wusste es bis jetzt nicht. 
Mittlerweile habe ich eine ungefähre Vorstellung davon, wie man von 
einem Datenträger liest, die Cluster ausfindig macht usw. Mein Problem 
ist, dass die fatgen103 Doku zwar alles beinhaltet, was man braucht, 
aber es werden halt nur die Strukturen beschrieben - welche Felder sie 
beinhalten, wie breit diese sind und so weiter. Aber was ich jetzt mit 
einer FSInfoStruct anfangen soll, das steht nicht drin, das muss man 
irgendwie rein interpretieren - und das kann ich nicht so gut.

von Ralf (Gast)


Lesenswert?

holger,
Danke! das passt. In meinem Fall ist BPB_RootClus 2, wie wohl in den 
meisten Fällen.
Das bedeutet also: Um mein Medium nach Dateien und Ordnern zu 
durchsuchen, muss ich BPB_RootClus auswerten, um den Anfang der DirTable 
zu bestimmen. In der FAT kann ich nachschauen, in welchen Clustern die 
DirTable sich befindet. Und innerhalb dieser DirTable ist es dann - mehr 
oder weniger - ein Kindespiel, die Files bzw. Ordner heraus zu 
pfriemeln.
Danke!

Ich habe bei mir das gleich so implementiert. Ich lese jetzt einen 
Cluster der DirTable, lege den im Memory ab und betrachte das nachher 
als Array von DirEntry-Structs (und eine DirEntry-Struct sieht natürlich 
genau so aus wie in fatgen103 beschrieben).
Denkst du, das ist ein sinnvolles Vorgehen, um schnell arbeiten zu 
können? Es ist natürlich zum Programmieren sehr einfach; der Code wird 
leichter lesbar, als wenn man da solche Akrobatik mit x Pointern macht 
und mit den Offsets irgendwas herum rechnet, wie man das in vielen 
FAT-implementationen sieht.
Ich denke mal, auch bei PCs wird man niemals die komplette DirTable oder 
die komplette FAT im Memory haben. Oder täusche ich mich da? Wie machen 
die das, dass der File-Zugriff möglichst einfach und schnell wird?
Wichtig ist: ich will mich nicht mit irgendwelchen Pointern und 
dergleichen abplagen. Das ist unübersichtlich, und wie ich finde, 
irgendwie Murks. Genau dazu gibt es doch stucts ;-) Mittlerweile habe 
ich einen ungefähren Durchblick. Lange Dateinamen ist mittlerweile auch 
klar.

Dieses Forum hier ist echt geil :-) Aus der Doku, die man im Internet 
findet, hätte ich solches Zeug niemals raus lesen können!

von holger (Gast)


Lesenswert?

>Ich lese jetzt einen Cluster der DirTable,

Du scheinst aber eine Menge RM zu haben.
So ein Cluster kann schon mal 64Kb haben.

>als Array von DirEntry-Structs

Schön aufpassen das das struct "packed" ist.
Bei Big Endian Maschinen bekommst du trotzdem Ärger.

>Ich denke mal, auch bei PCs wird man niemals die komplette DirTable oder
>die komplette FAT im Memory haben. Oder täusche ich mich da? Wie machen
>die das, dass der File-Zugriff möglichst einfach und schnell wird?

Die komplette FAT wird nicht im Speicher gehalten.
Viel zu groß. Ein kleiner Teil beschleunigt auch schon.
Ein Sektor z.B. Wenn du Platz für einen Cluster hast, umso besser.

von Ralf (Gast)


Lesenswert?

holger,
Also mein Rechner ist ein Little Endian (ein LPC2000). Das passt also 
perfekt :-)
Und ja, ich habe eine Menge RAM. Dank dem SDRAM-Interface kann ich 256M 
benutzen; im Moment sind zwar nur 64 auf meinem Bastel-Board, aber 
besser als gar nichts ;-) Und damit es noch ein bisschen besser wird, 
ist das ganze 32 Bit breit angebunden.
Ich habe mir dazu auch einen eigenen Memory-Manager geschrieben (ich 
will die ganze Software da drauf selber machen), sodass ich mittels 
malloc und free den grossen Speicher schön bequem verwalten kann. Ich 
denke, ich werde das so lösen:
Ich bestimme, wie viele Sektoren ein Cluster hat, und reserviere dann so 
viel Memory. In dieses kommt dann ein Teil der FAT; in einen anderen 
(ebenso grossen Bereich) kommen die DirTables rein. Damit ich mich in 
der FAT zurecht finde, nehme ich eine Variable, die mir den Offset 
angibt, also welcher Teil der FAT sich im Memory befindet. Bevor ich 
dann einen bestimmten Cluster suchen kann, muss ich prüfen, ob er in dem 
bereits im Memory befindlichen FAT-Bereich liegt; wenn nicht wird 
berechnet, welche Sektoren nachgeladen werden müssen.
Ich denke das sollte so funktionieren, nicht? Klingt das plausibel und 
einigermassen performant? Ansonsten muss ich mir überlegen, wie man es 
noch schneller machen könnte. Der Rechner wird wohl nicht das Problem 
sein, der kann seine Daten meinetwegen per DMA aus dem Medium holen. 
Ausserdem läuft er mit 72 MHz, wovon ich mir eine einigermassen gute 
Leistung verspreche. Mal schauen :-)

von holger (Gast)


Lesenswert?

>Ich denke das sollte so funktionieren, nicht? Klingt das plausibel und
>einigermassen performant?

Perfekt! Wie gesagt, ich bin gespannt was dabei raus kommt.

von zerrome (Gast)


Lesenswert?

Hallo,
um den FAT Teil zu puffern musst du nicht rausfinden wieviele Sektoren 
einen Cluster bilden, da nur der Daten Bereich in Clustern zusammen 
gefasst wird...

Interessehalber mach dir mal ein paar Daten klar.
Wenn du einen FAT Sektor zwischen pufferst, und das Dateisystem mit z.B. 
8 Sektoren/Cluster Formatiert ist kannst du 512*8*128 = 524288 Bytes am 
Stück lesen, WENN alle FAT Einträge in dem gepufferten Sektor zusammen 
gehören. Das ist schonmal nicht schlecht :)

Sagen wir mal du spendierst einen Puffer für 128 FAT Einträge, also 
Cluster Nummern, dann ist die Optimale Vorgehensweise:

1. Annahme Idealfall (FAT unfragmentiert):
Merk dir den 1. Cluster und gehe durch die FAT-Chain bis du beim letzten 
Cluster angekommen bist, so kannst du mit 8 Gespeicherten Bytes (Start 
und End Cluster) Dateien mit beliebiger Größe lesen.

2. Annahme nicht Idealfall (FAT fragmentiert):
Wieder 1. Cluster merken, jetzt wird es ungemütlicher, weil die FAT 
Kette nicht am Stück ist sondern in einzelne kleine Ketten aufgeteilt 
ist. Jetzt muss man sich immer Paare von Anfang und Ende merken. Da ist 
jetzt nur die Frage, wieviele dieser Kettenpaare man sich merken möchte 
:)

Hoffe das ist verständlich^^

Ach ja, diese Überlegungen gelten so nur für lesenden Zugriff..

von Ralf (Gast)


Lesenswert?

holger,
Okay, super Sache. Ich habe das gleich so implementiert in der Software; 
heute Abend werde ich dann wieder Zeit zum Basteln haben und testen, ob 
das so gut funktioniert.
Nur eine Unschönheit habe ich festgestellt: Wenn bereits einige 
FAT-Einträge im Puffer liegen, und ich Zwecks Erstellen einer neuen 
Datei nach freien Clustern suche, dann muss ich erst den Puffer leeren, 
dann die FAT von Beginn an neu laden und von vorne alle Einträge 
abklappern, bis ich einen freien Cluster gefunden habe. Klar könnte ich 
auch gleich den Puffer durchsuchen, der im Memory liegt, aber so würde 
ich vielleicht gewisse FAT-Bereiche gar nie nutzen... das selbe beim 
Directory Puffer.
Was natürlich auch doof ist - lese ich eine Datei, und merke, dass der 
nächste Cluster nicht mehr in meinem Puffer ist, dann muss ich erst 
prüfen, ob der Inhalt des Puffers verändert wurde, wenn ja diesen auf 
dem Medium speichern, und dann den nächsten Bereich in den Puffer laden. 
Das ist etwas hässlich, und sicher auch langsam, aber mir fällt keine 
Lösung ein, wie sich das vermeiden liesse. Ich nehme an, auf PCs wird 
das genauso gehandhabt - einen Teil der FAT in den Puffer laden, und 
wenn man Daten benötigt, die nicht im Puffer vorhanden sind den Puffer 
speichern und neu laden.
Oder hast du dazu auch irgend eine kluge Idee?

zerrome,
Ich weiss dass nur der Datenbereich in Clustern unterteilt ist. Der 
Einfachheit halber will ich aber die Puffer sowohl für die FAT als auch 
für die Dir Table so gross wie ein einzelner Cluster machen, das hat den 
Vorteil, dass die Funktion zum Lesen und Schreiben der Puffer nur auf 
eine bestimmte Grösse eingestellt werden muss. Ausserdem verspreche ich 
mir dadurch einen Geschwindigkeitsvorteil - mehr FAT-Einträge im Puffer 
= grössere Geschwindigkeit.
Dass ich 524288 Bytes lesen kann mit einem solchen Puffer ist mir klar; 
ich sehe aber ein Problem, wenn die FAT fragmentiert wird. Dann kann ich 
immer weniger Bytes auf einmal lesen, was nicht so dolle ist.... Aber 
ich werde sicher prüfen, wie viel FAT sinnvoll zu puffern ist.

von Karl H. (kbuchegg)


Lesenswert?

Ralf schrieb:
> Was natürlich auch doof ist - lese ich eine Datei, und merke, dass
> der nächste Cluster nicht mehr in meinem Puffer ist, dann muss ich
> erst prüfen, ob der Inhalt des Puffers verändert wurde, wenn ja
> diesen auf dem Medium speichern, und dann den nächsten Bereich
> in den Puffer laden.
> Das ist etwas hässlich, und sicher auch langsam, aber mir fällt
> keine Lösung ein, wie sich das vermeiden liesse. Ich nehme an,
> auf PCs wird das genauso gehandhabt - einen Teil der FAT in den
> Puffer laden, und wenn man Daten benötigt, die nicht im Puffer
> vorhanden sind den Puffer speichern und neu laden.
> Oder hast du dazu auch irgend eine kluge Idee?

Ganz genau so wird das gemacht.
Sieh zu, dass du diese Cache-Logik (denn genau darum handelt es sich), 
in ein paar Funktionen auslagerst. Für die Codeteile, die darüber 
liegen, sieht es so aus, als ob alles im Speicher liegt. Die braucht 
nicht zu interessieren, dass du da im Hintergrund 
speichern/lesen/verwerfen musst.

Der Knackpunkt am ganze ist, dass du im Code nicht Wildwuchs betreibst 
und jeder dahergelaufene Code überall einfach zugreift, wie er lustig 
ist, sondern dass das alles geordnet geht. Du brauchst den Dir-Eintrag 
Nr.5? Dann rufe die Funktion auf, die dafür zuständig ist, einen 
bestimmten Eintrag zu besorgen. Selbst dann wenn du bereits einen 
Pointer auf den Dir Eintrag Nr 0 hast und dir die Position selber 
ausrechnen könntest. Denn irgendwann benötigst du dann den Eintrag 2087. 
Kein Problem: Die Funktion weiß, wie man das macht. Aber der Code der 
nur den Pointer auf den 0-ten Eintrag hat nicht. Und der soll das auch 
gar nicht wissen.

Module bauen!
Und diese ganzen speziellen Lade/Nachlade/Speichern - Cache-Logiken in 
diese Module einbauen.

von Ralf (Gast)


Lesenswert?

Hallo Karl heinz,
so ähnlich habe ich mir das vorgestellt.
ICh habe eine Funktion GetNextCluster - die liest aus der FAT heraus, 
welches der nächste Cluster ist. Dazu prüft sie, ob der gewünschte 
Cluster bereits im Puffer is, ansonsten lädt sie den Puffer neu und 
speichert den alten, falls geändert.
Ganz ähnlich funktioniert GetNextFreeCluster. Die gibt einfach die 
Nummer des nächsten freien Clusters zurück. Da weiss ich jetzt noch 
nicht, in wie weit es Sinn macht, die FAT von Offset 0 an nach freien 
Clustern zu durchsuchen, oder einfach den ersten freien Cluster im 
aktuellen Puffer zu suchen. Letzteres wäre sicherlich schneller, aber in 
Bezug auf die Fragmentierung suboptimal.
Module habe ich in dem Sinne einfach gemacht, in dem ich ein Modul 
fat.c/fat.h habe, wo das ganze Zeug mit Sektoren und Clustern und 
Puffern gehandhabt wird. Im Modul file.c/file.h werden dann Funktionen 
drin sein, die mittels fat.c/fat.h Dateien bearbeiten (also öffnen mit 
fopen und schreiben mit fwrite und dergleichen).
Ein eigenes Cache-Modul gibt es nicht. Meinst du, das wäre erforderlich 
oder sinnvoll?

von holger (Gast)


Lesenswert?

>die FAT von Offset 0 an nach freien
>Clustern zu durchsuchen, oder einfach den ersten freien Cluster im
>aktuellen Puffer zu suchen. Letzteres wäre sicherlich schneller, aber in
>Bezug auf die Fragmentierung suboptimal.

Fragmentierung kann dir in beiden Fällen passieren. Nimm einfach
erst den Puffer. Es ist (gefühlt) wahrscheinlicher das du eher
freie Cluster findest wenn du von deinem aktuellen Puffer ausgehst.
Am Anfang der FAT sind doch eher belegte Cluster zu erwarten.
Vom Puffer aus bis ans Ende der FAT suchen. Falls bis zum Ende
nix gefunden wird vom Anfang bis zum aktuellen Puffer. Wieder
nix gefunden: Disk full.

Oder schreib dir der Einfachheit halber erst einen Code
der tatsächlich immer bei 0 anfängt. Optimieren machst du später.

von Ralf (Gast)


Lesenswert?

also, ich werde das jetzt aus Performance-Gründen wie folgt machen:
Wenn ich einen neuen Cluster brauche, dann wird in dem Teil der FAT 
gesucht, der aktuell gepuffert ist. Sind dort keine neuen Cluster 
vorhanden, dann muss der nächste Part der FAT geladen werden usw.
Ich habe bis jetzt noch keine speziellen Dateifunktionen eingebaut, aber 
offensichtlich scheint meine bisherige Software zu funktionieren. Die 
ist durchtbar dumm - sie kann nichts anderes, als einen FAT-Datenträger 
mounten, BPB auslesen, die entsprechenden Puffergrössen berechnen und 
die gewünschten Datenbereiche (also FAT und Directory Table) in 
ebendiese Puffer laden.
Ausserdem kann man mittels GetNextCluster die Cluster chain durchlaufen, 
bzw. man kann mit GetNextFreeCluster nach neuen, leeren Clustern suchen. 
Beides klappt schon, und die Puffer werden korrekt geladen und wieder 
auf das Speichermedium geschrieben.
Das heisst: jetzt müssen nur noch die Directory Table Einträge 
interpretiert werden, dann kann ich erst Dateien und Ordner lesen. Aber 
es ist tatsächlich nicht so schwierig, wie ich es mir Vorgestellt habe! 
Super Sache.

Noch eine Frage:
Angenommen, ich will eine 72 MB grosse Datei bearbeiten (in Wirklichkeit 
habe ich keine so grossen Dateien, das dient nur als Beispiel). Ich habe 
aber nur 64 MB RAM. Also kann ich nicht die komplette Datei im Memory 
halten, sie dort bearbeiten und anschliessend zurück schreiben.
Wie wird das denn professionell gemacht? Angenommen, ich füge an 
Position 23 ein Byte ein. Dann muss ich ja den ganzen Datei-Inhalt um 1 
Byte nach 'hinten' verschieben.... das beisst sich irgendwie mit der 
Memory-Grösse. Also bin ich grade am überlegen, wie viel Memory ich 
sinnvoll reservieren soll, wenn der Benutzer eine Datei öffnet. Wieder 
ein Cluster? Das ergäbe Sinn, aber ist auch doof, wenn die Datei > 1 
Cluster ist. Andererseits habe ich nicht beliebig viel Speicher....

von holger (Gast)


Lesenswert?

>Wie wird das denn professionell gemacht? Angenommen, ich füge an
>Position 23 ein Byte ein. Dann muss ich ja den ganzen Datei-Inhalt um 1
>Byte nach 'hinten' verschieben.... das beisst sich irgendwie mit der
>Memory-Grösse.

Temporäre Datei anlegen. Bis Byte 22 Originaldaten reinkopieren.
Byte 23 anfügen. Rest von Originaldaten dranhängen. Original
löschen, Temp Datei umbenennen.

von Ralf (Gast)


Lesenswert?

holger,
Das mit der temporären Datei ergibt Sinn. Auf die Idee bin ich noch gar 
nicht gekommen! Das erklärt auch, warum Windows immer diesen doofen 
TEMP-Ordner hat, wo allerlei Mist drin landet ;)
Also, mittlerweile sind mehr oder weniger alle meine Fragen geklärt. Das 
FS läuft zwar noch nicht, aber das wird schon. Hoffentlich ;) Bis jetzt 
schaut es aber gut aus. Einziges Problem bereitet mir noch die 
kompatibilität - eigentlich wollte ich ein einziges Programm, welches 
sowohl FAT32 als auch FAT16 und FAT12 kann. Aber das geht offenbar nicht 
mit meiner Vorgehensweise, da werde ich mir wohl noch was einfallen 
lassen müssen....

von holger (Gast)


Lesenswert?

>Das mit der temporären Datei ergibt Sinn.

Das war nur eine schnelle Lösung.

>eigentlich wollte ich ein einziges Programm, welches
>sowohl FAT32 als auch FAT16 und FAT12 kann.

Vergiss FAT12. FAT16 ist auch bald tot weil es keine
kleinen Karten (<4GB) mehr zu kaufen gibt. FAT32 wird uns
noch ein wenig begleiten. Die Frage ist wie lange?

von Ralf (Gast)


Lesenswert?

Naja, so lange wohl, wie es diese Karten gibt. Denn NTFS lässt sich da 
nicht s einfach einsetzen, nicht ohne Grund kann man Karten damit nicht 
formatieren.
Oder denkst du, es wird ma ein neues FS kommen, extra für Karten?
Nee, ich glaube FAT32 wird schon noch ne Weile leben. Man könnte 
allerdings mal darüber nachdenken, die Struktur ein bisschen zu 
modernisieren. Sprich: Alles nur noch mit langen Dateinamen, dafür eine 
einfachere Struktur für die Dir-Einträge z.B. Halt solche alten Zöpfe 
vergessen; ebenso, wie die Clusternummern nur bis 0x0fffffff gehen 
dürfen.

von holger (Gast)


Lesenswert?

>Oder denkst du, es wird ma ein neues FS kommen, extra für Karten?

Wer weiss ;) Aber vergiss FAT12. FAT16 einzubinden ist nicht schwer
wenn du es unbedingt brauchst.

>Nee, ich glaube FAT32 wird schon noch ne Weile leben. Man könnte
>allerdings mal darüber nachdenken, die Struktur ein bisschen zu
>modernisieren. Sprich: Alles nur noch mit langen Dateinamen, dafür eine
>einfachere Struktur für die Dir-Einträge z.B. Halt solche alten Zöpfe
>vergessen; ebenso, wie die Clusternummern nur bis 0x0fffffff gehen
>dürfen.

Ich hab mal irgendwo was über ExtFAT32? gelesen.
64Bit für die Dateilänge möglich, also auch Dateien mit mehr
als 4GB auf FAT. Theoretisch geht FAT32 bis 8TB ;)

von holger (Gast)


Lesenswert?

>Theoretisch geht FAT32 bis 8TB)

Autsch, verrechnet ;)
FAT32 benutzt 32Bit Werte für Sektornummern. 4GB * 512 = 2TB.

von zerrome (Gast)


Lesenswert?

Das ist nicht das einzige Problem, es werden auch 32 Bit für die 
Dateilänge im 32 Byte Dateieintrag benutzt... und da ist nicht mehr 
Platz.

Eigentlich werden Cluster Nummern in der FAT mit 32 Bit gespeichert. 
Jetzt setzen sich Cluster aber aus mehreren Sektoren zusammen....Bei 8 
Sektoren/Cluster würde das 8*512*2^32 geben also 1,7 * 10^13 Bytes, was 
definitiv nicht mehr in 32 Bit Dateigröße passt, es gibt aber 
extFat,welches aber noch nicht ganz offen ist.

http://de.wikipedia.org/wiki/File_Allocation_Table#exFAT

von Ralf (Gast)


Lesenswert?

Hallo,
falls es jemanden interessiert:
ich hab jetzt meine eigene FAT32-Implementierung am Laufen!
Inclusive langer Dateinamen etc.
Man kann Dateien öffnen, indem man entweder den langen oder den kurzen 
Namen verwendet. Ausserdem ist mein Code voll PC-kompatibel, d.h. ich 
kann alles lesen, was mittels PC auf die Karte gepackt wurde.
Der Speicherverbrauch hängt vom Dateisystem ab: es werden immer ganze 
Cluster gepuffert; ich habe dazu einen Memory-Manager programmiert, der 
ähnlich wie malloc funktioniert und mit dem sich auf dem Heap dynamisch 
Memory allozieren und freigeben lässt. Beim Initialisieren werden dann 
die ersten paar Einträge der FAT gepuffert sowie ein paar Directory 
Entries; Danach kann man bereits auf das Dateisystem zugreifen. Beliebig 
viele Dateien gleichzeitig offen zu haben ist möglich.
Im Moment bin ich noch dabei, eine komplette File-API zu implementieren; 
momentan lassen sich Dateien nur Byteweise lesen, aber es wird natürlich 
alle anderen Funktionen auch geben, wie sie in stdio.h auch existieren.
Soweit der Stand.
Wie schnell der Code ist, habe ich noch nicht genau gemessen, aber ich 
kann sagen dass bis jetzt alles wirklich sehr flüssig läuft.
Bei interesse lade ich den Kram dann mal hoch, wenn ich fertig bin.

Gruss

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.