home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* FILEMAN.PAS *)
- (* objektorientierte Toolbox zum Zugriff auf Dateien *)
- (* (c) 1991 Gerd Cebulla & DMV-Verlag *)
- (* ------------------------------------------------------ *)
- UNIT FileMan;
- {$B-}
-
- INTERFACE
-
- USES
- Dos, DiskMan;
-
- CONST
- ClusListSize = $FFEE DIV 2;
-
- TYPE
- FileNameStr = STRING [12];
-
- PClusList = ^ClusList;
- ClusList = ARRAY [0..Pred(ClusListSize)] OF WORD;
- ClusTable = ARRAY [0..1] OF PClusList;
-
- PSecBuf = ^SecBuf;
- SecBuf = RECORD { Verwaltungs-Record für Dateipuffer }
- BufPtr : PDiskSector; { Zeiger auf den Sektor-Puffer }
- Prev, { vorhergehender Sektor }
- Next : PSecBuf; { nächster Sektor }
- Check : LONGINT; { Prüfsumme }
- END; { SecBuf }
-
- PFileManager = ^FileManager;
- FileManager = OBJECT(DiskInfo)
- Disk : PDiskManager;
- FileMask : DosNameStr; { Suchmaske }
- FileInfo : DirEntry; { Verzeichniseintrag }
- DirBuf : PDirSector;
- { Zeiger auf Verzeichnis-Puffer }
- DirCluster : WORD;
- { aktueller Verzeichnis-Cluster }
- DirSector : LONGINT;
- { absolute Nummer des aktuellen Verzeichnis-Sektors }
- DirOffset : BYTE; { Offset des aktuellen }
- { Verzeichnis-Sektors zum Beginn des Clusters }
- DirIndex : INTEGER;
- { Index des aktuellen Verzeichnis-Eintrags }
- ClusTab : ClusTable;
- { Tabelle für sämtliche Clusternummern einer Datei }
- FileClusters : WORD; { Dateigröße in Clusters }
- FileSectors : LONGINT; { Dateigröße in Sektoren }
- CurrPtr : PSecBuf;
- { Zeiger auf aktuellen Dateisektor }
- FirstSector, { erster Sektor im Dateipuffer }
- LastSector, { letzter Sektor im Dateipuffer }
- CurrSector : LONGINT; { aktueller Dateisektor }
- BufferedSectors : WORD; { Größe des Dateipuffers }
-
- CONSTRUCTOR Init(PDisk : PDiskManager);
- DESTRUCTOR Done; VIRTUAL;
- PROCEDURE ParseFileName( Dateiname : FileNameStr;
- VAR DosName : DosNameStr);
- VIRTUAL;
- FUNCTION Matching(Name,
- Suchmaske : DosNameStr) : BOOLEAN;
- VIRTUAL;
- FUNCTION GetFirstEntry(Dateiname : PathStr) :
- PDirEntry; VIRTUAL;
- FUNCTION GetNextEntry : PDirEntry; VIRTUAL;
- PROCEDURE Load(MinAvail : LONGINT); VIRTUAL;
- PROCEDURE Unload; VIRTUAL;
- FUNCTION GetCheckSum(BufPtr : PDiskSector) : LONGINT;
- VIRTUAL;
- FUNCTION TestCheckSum(Check : LONGINT;
- BufPtr : PDiskSector) :
- BOOLEAN; VIRTUAL;
- FUNCTION GetFileSize : LONGINT;
- FUNCTION GetBufSize : WORD;
- PROCEDURE WriteFileBuffer; VIRTUAL;
- PROCEDURE ReadFileSector( LogSektor : LONGINT;
- VAR Buffer); VIRTUAL;
- PROCEDURE WriteFileSector( LogSektor : LONGINT;
- VAR Buffer); VIRTUAL;
- FUNCTION GetFileSector(LogSektor : LONGINT) :
- PDiskSector; VIRTUAL;
- FUNCTION SaveFileSector(LogSektor : LONGINT) :
- BOOLEAN; VIRTUAL;
- FUNCTION AbsSector(LogSektor : LONGINT) : LONGINT;
- VIRTUAL;
- END; { FileManager }
-
- IMPLEMENTATION
-
- CONST
- Root = '\ ';
-
- CONSTRUCTOR FileManager.Init(PDisk : PDiskManager);
- { Initialisiert Variablen und legt einen }
- { Verzeichnispuffer an. }
- BEGIN
- CurrPtr := NIL;
- ClusTab[0] := NIL;
- DirSector := 0;
- FileSectors := 0;
- BufferedSectors := 0;
- Disk := PDisk;
- Disk^.GetDiskInfo(Self);
- GetMem(DirBuf, BytesPerSector);
- IF DirBuf = NIL THEN BEGIN
- DiskError := dskNoMemory;
- Done;
- Fail;
- END;
- END; { FileManager.Init }
-
- DESTRUCTOR FileManager.Done;
- { Schließt eine evtl. geöffnete Datei und gibt alle }
- { Puffer frei. }
- BEGIN
- Unload;
- IF DirBuf <> NIL THEN BEGIN
- FreeMem(DirBuf, BytesPerSector);
- DirBuf := NIL;
- END;
- END; { FileManager.Done }
-
- PROCEDURE FileManager.ParseFileName(Dateiname : FileNameStr;
- VAR DosName : DosNameStr);
- { Wandelt einen Dateinamen in der üblichen Form }
- { 'Filename.Ext' in das intern von DOS verwendete Format }
- { um: ein 11-elementiges Char-Array, bei dem die ersten }
- { 8 Byte für den Dateinamen, die letzten 3 Byte für die }
- { Erweiterung vorgesehen sind (beide jeweils mit }
- { Leerzeichen aufgefüllt). Jokerzeichen ('?' und '*') }
- { werden unterstützt. }
- VAR
- Punkt, Stelle : BYTE;
- BEGIN
- FillChar(DosName, SizeOf(DosNameStr), #32);
- Punkt := Pos('.', Dateiname);
- IF Punkt = 0 THEN
- Move(Dateiname[1], DosName[1], Length(Dateiname))
- ELSE BEGIN
- Move(Dateiname[1], DosName[1], Pred(Punkt));
- Move(Dateiname[Succ(Punkt)], DosName[9],
- Length(Dateiname)-Punkt);
- END;
- FOR Stelle := 1 TO SizeOf(DosNameStr) DO BEGIN
- IF DosName[Stelle] = '*' THEN BEGIN
- IF Stelle <= 8 THEN
- FillChar(DosName[Stelle], 9-Stelle, '?')
- ELSE
- FillChar(DosName[Stelle], 12-Stelle, '?');
- END;
- END;
- END; { FileManager.ParseFileName }
-
- FUNCTION FileManager.Matching(Name, Suchmaske : DosNameStr) : BOOLEAN;
- { Vergleicht einen Dateinamen im internen DOS-Format mit }
- { einer Suchmaske. Liefert True zurück, wenn der }
- { Vergleich positiv ausfällt. }
- VAR
- Stelle : BYTE;
- Gleich : BOOLEAN;
- BEGIN
- Stelle := 1;
- REPEAT
- Gleich := (Suchmaske[Stelle] = '?') OR
- (Suchmaske[Stelle] = Name[Stelle]);
- INC(Stelle);
- UNTIL NOT Gleich OR (Stelle > SizeOf(DosNameStr));
- Matching := Gleich;
- END; { FileManager.Matching }
-
- FUNCTION FileManager.GetFirstEntry(Dateiname : PathStr) :
- PDirEntry;
- { Sucht nach dem ersten Auftreten des angegebenen }
- { Dateinamens, der auch Jokerzeichen enthalten darf. }
- { Liefert im Erfolgsfall einen Zeiger auf den }
- { zugehörigen Verzeichniseintrag zurück, ansonsten den }
- { Wert nil. Entspricht in etwa Dos.FindFirst, bezieht }
- { sich aber immer auf das Stammverzeichnis (der }
- { Dateiname muß daher den vollständigen Suchpfad }
- { enthalten) und erwartet den Dateinamen in genau der }
- { Schreibweise, wie sie auch im Verzeichnis verwendet }
- { wird, d.h. in der Regel: in Großbuchstaben. Findet }
- { auch gelöschte Dateien; diese sind daran kenntlich, }
- { daß das erste Zeichen des Dateinamens Chr ($E5) ist. }
- VAR
- Suchmaske : DosNameStr;
- Stelle1,
- Stelle2 : BYTE;
- Gefunden : BOOLEAN;
- BEGIN
- DiskError := dskOk;
- Stelle1 := Succ(Pos(':', Dateiname));
- IF Dateiname[Stelle1] = '\' THEN
- INC(Stelle1);
- IF Stelle1 > Length(Dateiname) THEN BEGIN
- FileMask := Root;
- WITH FileInfo DO BEGIN
- Name := Root;
- Attribute := Directory;
- FillChar(Fill, SizeOf(FileInfo)-SizeOf(Name)-
- SizeOf(Attribute), 0);
- END;
- END ELSE BEGIN
- Stelle2 := Succ(Stelle1);
- WHILE (Dateiname[Stelle2] <> '\') AND
- (Stelle2 <= Length(Dateiname)) DO
- INC(Stelle2);
- ParseFileName(Copy(Dateiname, Stelle1,
- Stelle2-Stelle1), Suchmaske);
- IF DirSector <> RootDirStart THEN BEGIN
- DirSector := RootDirStart;
- Disk^.ReadSector(DirBuf^, DirSector, 1);
- END;
- DirCluster := 0;
- DirIndex := -1;
- REPEAT
- INC(DirIndex);
- IF DirIndex = DirEntriesPerSector THEN BEGIN
- INC(DirSector);
- IF DirSector-RootDirStart = RootDirSectors THEN BEGIN
- IF Stelle2 <= LENGTH(Dateiname) THEN
- DiskError := dskPathNotFound
- ELSE
- DiskError := dskNoMoreFiles;
- END ELSE BEGIN
- Disk^.ReadSector(DirBuf^, DirSector, 1);
- DirIndex := 0;
- END;
- END;
- WITH DirBuf^[DirIndex] DO BEGIN
- IF Stelle2 <= LENGTH(Dateiname) THEN
- Gefunden := (Attribute AND Directory <> 0) AND
- (Name = Suchmaske)
- ELSE
- Gefunden := Matching(Name, Suchmaske);
- END;
- UNTIL (DiskError <> dskOk) OR Gefunden;
- WHILE (DiskError = dskOk) AND
- (Stelle2 < Length(Dateiname)) DO BEGIN
- DirCluster := DirBuf^[DirIndex].FirstCluster;
- DirSector := LONGINT(DirCluster-2)*
- SectorsPerCluster+ClusterStart;
- DirOffset := 0;
- Disk^.ReadSector(DirBuf^, DirSector, 1);
- DirIndex := -1;
- Stelle1 := Succ(Stelle2);
- Stelle2 := Succ(Stelle1);
- WHILE (Dateiname[Stelle2] <> '\') AND
- (Stelle2 <= LENGTH(Dateiname)) DO
- INC(Stelle2);
- ParseFileName(Copy(Dateiname, Stelle1,
- Stelle2-Stelle1), Suchmaske);
- REPEAT
- INC(DirIndex);
- IF DirIndex = DirEntriesPerSector THEN BEGIN
- INC(DirOffset);
- IF DirOffset = SectorsPerCluster THEN BEGIN
- DirCluster := Disk^.GetFatEntry(DirCluster);
- IF DirCluster >= $FFF0 THEN BEGIN
- IF Stelle2 <= Length(Dateiname) THEN
- DiskError := dskPathNotFound
- ELSE
- DiskError := dskNoMoreFiles;
- END ELSE BEGIN
- DirSector := LONGINT(DirCluster-2)*
- SectorsPerCluster+ClusterStart;
- DirOffset := 0;
- END;
- END;
- IF DiskError = dskOk THEN BEGIN
- Disk^.ReadSector(DirBuf^,
- DirSector+DirOffset, 1);
- DirIndex := 0;
- END;
- END;
- WITH DirBuf^[DirIndex] DO BEGIN
- IF Stelle2 <= Length(Dateiname) THEN
- Gefunden := (Attribute AND Directory <> 0) AND
- (Name = Suchmaske)
- ELSE
- Gefunden := Matching(Name, Suchmaske);
- END;
- UNTIL (DiskError <> dskOk) OR Gefunden;
- END;
- FileMask := Suchmaske;
- FileInfo := DirBuf^[DirIndex];
- END;
- IF DiskError = dskOk THEN
- GetFirstEntry := @FileInfo
- ELSE BEGIN
- DirSector := 0;
- GetFirstEntry := NIL;
- END;
- END; { FileManager.GetFirstEntry }
-
- FUNCTION FileManager.GetNextEntry : PDirEntry;
- { Ermittelt nach vorhergehendem Aufruf von GetFirstEntry }
- { das nächste Vorkommen des betreffenden Dateinamens. }
- { Analogon zu Dos.FindNext. }
- BEGIN
- DiskError := dskOk;
- IF DirSector = 0 THEN
- DiskError := dskNoMoreFiles
- ELSE IF DirSector-RootDirStart < RootDirSectors THEN BEGIN
- REPEAT
- INC(DirIndex);
- IF DirIndex = DirEntriesPerSector THEN BEGIN
- INC(DirSector);
- IF DirSector-RootDirStart = RootDirSectors THEN
- DiskError := dskNoMoreFiles
- ELSE BEGIN
- Disk^.ReadSector(DirBuf^, DirSector, 1);
- DirIndex := 0;
- END;
- END;
- UNTIL (DiskError <> dskOk) OR
- Matching(DirBuf^[DirIndex].Name, FileMask);
- END ELSE BEGIN
- REPEAT
- INC(DirIndex);
- IF DirIndex = DirEntriesPerSector THEN BEGIN
- INC(DirOffset);
- IF DirOffset = SectorsPerCluster THEN BEGIN
- DirCluster := Disk^.GetFatEntry(DirCluster);
- IF DirCluster >= $FFF0 THEN
- DiskError := dskNoMoreFiles
- ELSE BEGIN
- DirSector := LONGINT(DirCluster-2)*
- SectorsPerCluster+ClusterStart;
- DirOffset := 0;
- END;
- END;
- IF DiskError = dskOk THEN BEGIN
- Disk^.ReadSector(DirBuf^,
- DirSector+DirOffset, 1);
- DirIndex := 0;
- END;
- END;
- UNTIL (DiskError <> 0) OR
- Matching(DirBuf^[DirIndex].Name, FileMask);
- END;
- IF DiskError = dskOk THEN BEGIN
- FileInfo := DirBuf^[DirIndex];
- GetNextEntry := @FileInfo;
- END ELSE BEGIN
- DirSector := 0;
- GetNextEntry := NIL;
- END;
- END; { FileManager.GetNextEntry }
-
- PROCEDURE FileManager.Load(MinAvail : LONGINT);
- { Liest die zuletzt mit GetFirstEntry/GetNextEntry }
- { gefundene Datei ein. Diese Datei kann auch ein }
- { Verzeichnis sein. Über den Parameter MinAvail wird }
- { angegeben, wieviel zusammenhängender Heap mindestens }
- { frei bleiben soll; beträgt dieser Wert 0, versucht }
- { Load, die Datei so vollständig wie möglich in den }
- { Hauptspeicher zu lesen. }
- VAR
- FirstPtr,
- LastPtr : PSecBuf;
- ClusterNr,
- Index : WORD;
- BEGIN
- Unload;
- IF MinAvail < 8 THEN
- MinAvail := 8;
- IF (DirSector = 0) AND(FileInfo.Name <> Root) THEN
- DiskError := dskFileNotFound
- ELSE BEGIN
- DiskError := dskOk;
- ClusterNr := FileInfo.FirstCluster;
- IF ClusterNr = 0 THEN BEGIN
- IF FileInfo.Name <> Root THEN BEGIN
- FileClusters := 0;
- FileSectors := 0;
- END ELSE BEGIN
- FileSectors := RootDirSectors;
- FileClusters := Succ(Pred(FileSectors) DIV
- SectorsPerCluster);
- IF MaxAvail-SizeOf(WORD)-SizeOf(SecBuf)-
- BytesPerSector < MinAvail THEN
- DiskError := dskNoMemory
- ELSE BEGIN
- GetMem(ClusTab[0], SizeOf(WORD));
- ClusTab[0]^[0] := 0;
- FirstSector := 0;
- NEW(FirstPtr);
- GetMem(FirstPtr^.BufPtr, BytesPerSector);
- ReadFileSector(FirstSector, FirstPtr^.BufPtr^);
- FirstPtr^.Check := GetCheckSum(FirstPtr^.BufPtr);
- LastSector := 1;
- LastPtr := FirstPtr;
- WHILE (DiskError = dskOk) AND
- (LastSector < RootDirSectors) AND
- (MaxAvail-SizeOf(SecBuf)-
- BytesPerSector >= MinAvail) DO BEGIN
- NEW(LastPtr^.Next);
- LastPtr^.Next^.Prev := LastPtr;
- LastPtr := LastPtr^.Next;
- GetMem(LastPtr^.BufPtr, BytesPerSector);
- ReadFileSector(LastSector, LastPtr^.BufPtr^);
- LastPtr^.Check := GetCheckSum(LastPtr^.BufPtr);
- INC(LastSector);
- END;
- LastPtr^.Next := FirstPtr;
- FirstPtr^.Prev := LastPtr;
- CurrPtr := FirstPtr;
- CurrSector := 0;
- BufferedSectors := LastSector;
- DEC(LastSector);
- END;
- END;
- END ELSE BEGIN
- FileClusters := 0;
- REPEAT
- INC(FileClusters);
- ClusterNr := Disk^.GetFatEntry(ClusterNr);
- UNTIL (DiskError <> dskOk) OR
- (ClusterNr = 0) OR(ClusterNr >= $FFF0);
- IF DiskError = dskOk THEN BEGIN
- FileSectors := LONGINT(FileClusters)*
- SectorsPerCluster;
- IF MaxAvail-LONGINT(FileClusters)*
- SizeOf(WORD)-SizeOf(SecBuf)-
- BytesPerSector < MinAvail THEN
- DiskError := dskNoMemory
- ELSE BEGIN
- IF FileClusters <= ClusListSize THEN
- GetMem(ClusTab[0], FileClusters*SizeOf(WORD))
- ELSE BEGIN
- NEW(ClusTab[0]);
- GetMem(ClusTab[1], FileClusters MOD
- ClusListSize*SizeOf(WORD));
- END;
- ClusterNr := FileInfo.FirstCluster;
- ClusTab[0]^[0] := ClusterNr;
- Index := 1;
- WHILE (DiskError = dskOk) AND
- (Index < FileClusters) DO BEGIN
- ClusterNr := Disk^.GetFatEntry(ClusterNr);
- ClusTab[Index DIV ClusListSize]^
- [Index MOD ClusListSize] := ClusterNr;
- INC(Index);
- END;
- FirstSector := 0;
- NEW(FirstPtr);
- GetMem(FirstPtr^.BufPtr, BytesPerSector);
- ReadFileSector(FirstSector, FirstPtr^.BufPtr^);
- FirstPtr^.Check := GetCheckSum(FirstPtr^.BufPtr);
- LastSector := 1;
- LastPtr := FirstPtr;
- WHILE (DiskError = dskOk) AND
- (LastSector < FileSectors) AND
- (MaxAvail-SizeOf(SecBuf)-
- BytesPerSector >= MinAvail) DO BEGIN
- NEW(LastPtr^.Next);
- LastPtr^.Next^.Prev := LastPtr;
- LastPtr := LastPtr^.Next;
- GetMem(LastPtr^.BufPtr, BytesPerSector);
- ReadFileSector(LastSector, LastPtr^.BufPtr^);
- LastPtr^.Check := GetCheckSum(LastPtr^.BufPtr);
- INC(LastSector);
- END;
- LastPtr^.Next := FirstPtr;
- FirstPtr^.Prev := LastPtr;
- CurrPtr := FirstPtr;
- CurrSector := 0;
- BufferedSectors := LastSector;
- DEC(LastSector);
- END;
- END;
- END;
- IF DiskError <> dskOk THEN Unload;
- END;
- END; { FileManager.Load }
-
- PROCEDURE FileManager.Unload;
- { Gibt sämtliche Dateipuffer frei und schreibt den }
- { Inhalt veränderter Sektoren auf den Datenträger. }
- VAR
- NextPtr : PSecBuf;
- Zaehler : LONGINT;
- BEGIN
- IF CurrPtr <> NIL THEN BEGIN
- WriteFileBuffer;
- FOR Zaehler := FirstSector TO LastSector DO BEGIN
- NextPtr := CurrPtr^.Next;
- FreeMem(CurrPtr^.BufPtr, BytesPerSector);
- Dispose(CurrPtr);
- CurrPtr := NextPtr;
- END;
- CurrPtr := NIL;
- END;
- IF ClusTab[0] <> NIL THEN BEGIN
- IF ClusTab[0]^[0] = 0 THEN
- FreeMem(ClusTab[0], SizeOf(WORD))
- ELSE IF FileClusters <= ClusListSize THEN
- FreeMem(ClusTab[0], FileClusters*SizeOf(WORD))
- ELSE BEGIN
- Dispose(ClusTab[0]);
- FreeMem(ClusTab[1], FileClusters MOD
- ClusListSize*SizeOf(WORD));
- END;
- ClusTab[0] := NIL;
- END;
- FileSectors := 0;
- BufferedSectors := 0;
- END; { FileManager.Unload }
-
- FUNCTION FileManager.GetCheckSum(BufPtr : PDiskSector) : LONGINT;
- { Berechnet eine Prüfsumme für den Inhalt eines Sektors. }
- VAR
- CheckSum : LONGINT;
- Index : WORD;
- BEGIN
- CheckSum := 0;
- FOR Index := 0 TO Pred(BytesPerSector) DO
- INC(CheckSum, Succ(WORD(BufPtr^[Index]))*
- (Succ(LONGINT(Index))*127-Index));
- GetCheckSum := CheckSum;
- END; { FileManager.GetCheckSum }
-
- FUNCTION FileManager.TestCheckSum(Check : LONGINT;
- BufPtr : PDiskSector) : BOOLEAN;
- { Überprüft, ob die angegebene Prüfsumme mit dem Inhalt }
- { des Sektors übereinstimmt. Falls ja, wird der Wert }
- { True zurückgegeben; ist das Funktionsergebnis False, }
- { wurde der Inhalt des Sektors zwischenzeitlich }
- { verändert. }
- BEGIN
- TestCheckSum := (Check = GetCheckSum(BufPtr));
- END; { FileManager.TestCheckSum }
-
- FUNCTION FileManager.GetFileSize : LONGINT;
- { Liefert die Dateigröße in Sektoren zurück. }
- BEGIN
- GetFileSize := FileSectors;
- END; { FileManager.GetFileSize }
-
- FUNCTION FileManager.GetBufSize : WORD;
- { Gibt an, wie viele Sektoren der Datei im Puffer }
- { enthalten sind. }
- BEGIN
- GetBufSize := BufferedSectors;
- END; { FileManager.GetBufSize }
-
- PROCEDURE FileManager.WriteFileBuffer;
- { Schreibt alle geänderten Sektoren der mit Load }
- { geladenen Datei auf den Datenträger. }
- VAR
- Zaehler : LONGINT;
- BEGIN
- DiskError := dskOk;
- IF CurrPtr <> NIL THEN BEGIN
- Zaehler := 0;
- REPEAT
- IF NOT TestCheckSum(CurrPtr^.Check, CurrPtr^.BufPtr) AND
- SaveFileSector(CurrSector) THEN BEGIN
- WriteFileSector(CurrSector, CurrPtr^.BufPtr^);
- IF DiskError = dskOk THEN
- CurrPtr^.Check := GetCheckSum(CurrPtr^.BufPtr);
- END;
- IF DiskError = dskOk THEN BEGIN
- IF CurrSector = LastSector THEN
- CurrSector := FirstSector
- ELSE
- INC(CurrSector);
- CurrPtr := CurrPtr^.Next;
- INC(Zaehler);
- END;
- UNTIL (DiskError <> dskOk) OR (Zaehler = BufferedSectors);
- END;
- END; { FileManager.WriteFileBuffer }
-
- PROCEDURE FileManager.ReadFileSector(LogSektor : LONGINT;
- VAR Buffer);
- { Liest einen Sektor einer Datei in den Puffer ein. }
- VAR
- SektorNr : LONGINT;
- BEGIN
- SektorNr := AbsSector(LogSektor);
- IF DiskError = dskOk THEN
- Disk^.ReadSector(Buffer, SektorNr, 1);
- END; { FileManager.ReadFileSector }
-
- PROCEDURE FileManager.WriteFileSector(LogSektor : LONGINT;
- VAR Buffer);
- { Schreibt einen Sektor aus dem Puffer auf den }
- { Datenträger. }
- VAR
- SektorNr : LONGINT;
- BEGIN
- SektorNr := AbsSector(LogSektor);
- IF DiskError = dskOk THEN
- Disk^.WriteSector(Buffer, SektorNr, 1);
- END; { FileManager.WriteFileSector }
-
- FUNCTION FileManager.GetFileSector(LogSektor : LONGINT) : PDiskSector;
- { Liefert einen Zeiger auf den angegebenen Sektor der }
- { mit Load geladenen Datei zurück; die Zählung beginnt }
- { bei Null. Falls sich dieser Sektor nicht im Puffer }
- { befindet, wird er eingelesen. }
-
- PROCEDURE SektorSuchen(LogSektor : LONGINT);
- BEGIN
- WHILE LogSektor < CurrSector DO BEGIN
- DEC(CurrSector);
- CurrPtr := CurrPtr^.Prev;
- END;
- WHILE LogSektor > CurrSector DO BEGIN
- INC(CurrSector);
- CurrPtr := CurrPtr^.Next;
- END;
- END; { SektorSuchen }
-
- VAR
- Offset,
- NewFirst,
- NewLast,
- NewCurr,
- LastToRead : LONGINT;
- BEGIN { FileManager.GetFileSector }
- IF (LogSektor < 0) OR(LogSektor >= FileSectors) THEN
- DiskError := dskAccessDenied
- ELSE BEGIN
- DiskError := dskOk;
- IF (LogSektor < FirstSector) OR (LogSektor > LastSector) THEN BEGIN
- WriteFileBuffer;
- IF DiskError = dskOk THEN BEGIN
- Offset := PRED(SUCC(BufferedSectors) DIV 2);
- IF Offset > LogSektor THEN
- NewFirst := 0
- ELSE BEGIN
- NewFirst := LogSektor-Offset;
- IF NewFirst > FileSectors-BufferedSectors THEN
- NewFirst := FileSectors-BufferedSectors;
- END;
- NewLast := NewFirst+PRED(BufferedSectors);
- IF (NewFirst > FirstSector) AND
- (NewFirst <= LastSector) THEN BEGIN
- SektorSuchen(LastSector);
- NewCurr := LastSector;
- LastToRead := NewLast;
- END ELSE IF (NewFirst < FirstSector) AND
- (NewLast >= FirstSector) THEN BEGIN
- SektorSuchen(NewLast);
- NewCurr := Pred(NewFirst);
- LastToRead := Pred(FirstSector);
- END ELSE BEGIN
- NewCurr := Pred(NewFirst);
- LastToRead := NewLast;
- END;
- REPEAT
- IF CurrSector = LastSector THEN
- CurrSector := FirstSector
- ELSE
- INC(CurrSector);
- INC(NewCurr);
- CurrPtr := CurrPtr^.Next;
- ReadFileSector(NewCurr, CurrPtr^.BufPtr^);
- CurrPtr^.Check := GetCheckSum(CurrPtr^.BufPtr);
- UNTIL (DiskError <> dskOk) OR
- (NewCurr = LastToRead);
- IF DiskError = dskOk THEN BEGIN
- CurrSector := NewCurr;
- FirstSector := NewFirst;
- LastSector := NewLast;
- END ELSE
- Unload;
- END;
- END;
- END;
- IF DiskError <> dskOk THEN
- GetFileSector := NIL
- ELSE BEGIN
- SektorSuchen(LogSektor);
- GetFileSector := CurrPtr^.BufPtr;
- END;
- END; { FileManager.GetFileSector }
-
- FUNCTION FileManager.SaveFileSector(LogSektor : LONGINT) : BOOLEAN;
- { Wird von WriteFileBuffer aufgerufen. Wenn diese }
- { Funktion den Wert True zurückliefert, wird der }
- { angegebene Sektor auf den Datenträger geschrieben, }
- { ansonsten unterbleibt die Speicherung. }
- BEGIN
- SaveFileSector := TRUE;
- END; { FileManager.SaveFileSector }
-
- FUNCTION FileManager.AbsSector(LogSektor : LONGINT) : LONGINT;
- { Berechnet für einen Sektor der mit Load geladenen }
- { Datei die tatsächliche Position auf dem Datenträger. }
- VAR
- ClusterNr,
- SektorOffset : WORD;
- BEGIN
- DiskError := dskOk;
- IF ClusTab[0] = NIL THEN
- DiskError := dskFileNotFound
- ELSE IF (LogSektor < 0) OR (LogSektor >= FileSectors) THEN
- DiskError := dskAccessDenied
- ELSE IF ClusTab[0]^[0] = 0 THEN
- AbsSector := RootDirStart+LogSektor
- ELSE BEGIN
- ClusterNr := LogSektor DIV SectorsPerCluster;
- SektorOffset := LogSektor MOD SectorsPerCluster;
- AbsSector := ClusterStart+
- (ClusTab[ClusterNr DIV ClusListSize]^
- [ClusterNr MOD ClusListSize]-2)*
- LONGINT(SectorsPerCluster)+
- SektorOffset;
- END;
- IF DiskError <> dskOk THEN
- AbsSector := 0;
- END; { FileManager.AbsSector }
-
- END.
- (* ------------------------------------------------------ *)
- (* Ende von FILEMAN.PAS *)
-