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).
@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.
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....
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.
Die Widersprüche in der fatgen103.doc interessieren mich. Hast du ein paar Beispiele?
> ...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?
> 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.
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!
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....
>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.
Also, da jeder Eintrag 32 Bytes umfasst, gehe ich einfach 32 Bytes weiter bis zum nächsten Eintrag. Richtig?
>Also, da jeder Eintrag 32 Bytes umfasst, gehe ich einfach 32 Bytes >weiter bis zum nächsten Eintrag. Richtig? Jo.
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
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 :-(
>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.
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....
@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.
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
>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 ;)
>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.
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 ;-)).
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.
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.
>Dann nehme ich mal an, beginnt das Root-Directory bei Cluster Nr. 2.
Muss nicht 2 sein. Kleiner Tip:
BPB_RootClus
>Stattdessen herrscht hier eher eine Schüler-Nachhilfelehrer Situation.
Ich finde er hat sich schon ganz gut informiert
und ein wenig Nachhilfe verdient ;)
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.
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!
>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.
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 :-)
>Ich denke das sollte so funktionieren, nicht? Klingt das plausibel und >einigermassen performant? Perfekt! Wie gesagt, ich bin gespannt was dabei raus kommt.
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..
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.
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.
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?
>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.
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....
>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.
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....
>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?
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.
>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 ;)
>Theoretisch geht FAT32 bis 8TB)
Autsch, verrechnet ;)
FAT32 benutzt 32Bit Werte für Sektornummern. 4GB * 512 = 2TB.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.