Idáig csak előkészületeket tettünk a saját
file-kezelés megírására. Most, hogy – remélhetőleg – meg van minden
kedves T&T rovat Olvasónak a megfelelő
elméleti alapja elkezdjük a saját file-kezelés megírását. A legkönnyebb
kezelhetőség - átláthatóság, és persze
a profi megoldás végett objektumból építjük fel az egész file-kezelést.
Az eddig megismert file kezelő rutinok
neve hasonlóan a fő objektum metódusai
lesznek. Persze ha új operációs rendszerünk alapját akarná képezni a most
közlendő file-kezelés el kell szomorítanom
benneteket, hisz az OP rendszerek file-kezelését assembly-ben illik megírni.
Másrészről nem is valósítunk meg minden DOS
file-kezelő rutint lévén, hogy jó részük elavult (FCB-s utasítások),
a file-írás rutinjait annak bonyolultságuk és összetettségük miatt
csak nagyobb Olvasói érdeklődésre
közölném (PC-XUSER@freemail.c3.hu,
Subject: "T&T rovat file-írás"). Továbbá rovatunknak célja a logika,
a szerkezeti felépítés közlése a túlzott részletekbe merülés nélkül, hisz
nem mindenkit érdekel egyaránt az ilyen szintű
rendszerprogramozás.
Mivel már tudjuk, hogy milyen elemei vannak a DOS file-kezelésének megpróbálhatjuk
azt utánozni, újraírni saját magunknak, okulva a DOS hibáiból.
A korszerű objektum orientált irányzatot
követve vázoljuk a megvalósítás lépéseit:
-
Kell egy objektum mely megvalósítja magát
a file-kezelést úgy, hogy annak metódus nevei és paraméterezése 100%-an
megegyezzen a DOS-éval. Tehát adott egy DOS file-kezelő rutin, s annak
mintájára írjuk meg a saját objektum alapú rutinunkat:
-
DOS megvalósítás:
Read From File or Device - Olvasás file-ból vagy device-ról
AH = 3Fh
BX = a file handle (előzőleg megnyitott
file, melyhez érvényes handle tartozik)
CX = a beolvasandó byte-ok száma
DS:DX - buffer a beolvasáshoz
INT 21h
Visszatérési érték:
Ha CF = 0 akkor sikeres volt a
művelet, és:
AX = a beolvasott byte száma (Ha = 0 akkor
EOF volt a rutin meghívásakor.)
-
Saját Objektumos megvalósítás:
/ TR4sFileDOS = Object(TObject) /
function ReadFromFile(Handle: Word; var ByteToRead:
Word; var Buf; BufSize: Word): Boolean; virtual;
Láthatjuk, hogy a két megvalósítás (az eredeti DOS és a saját) között
a különbség csak annyi, hogy az egyiket (a DOS-ét) assembly-ből
a másikat meg simán programból hívhatjuk meg. Egyiknél sem kell azzal törődnünk,
hogy hogyan és mit csinál bent magában a megszakításban,
ill. az objektumban. Ha a paraméterezésnél – is – megtartjuk a 100%-os
kompatibilitást akkor azok akiknek már voltak assembly-n keresztül működő
DOS file-kezelő rutinjai egyszerűen
a assembly betétek objektum hívásra történő
kicserélésével átírhatják programjukat a saját file-kezelés használatára.
Nézzük sorba mit, hogyan csinál az objektum metódusa a megszakítás mintájára.
-
A rendszer-programozói körökben elfogatott rutin neveket fogjuk alkalmazni
objektumunk metódusának nevére. Pl. a 3Fh-s (INT 21h) alrutinnak a feladata
a handle-ös file beolvasás. Erre az angol terminológia szerint a Read
From File or Device elnevezést alkalmazzák. Mi is hasonlóan járunk
el azzal a kivétellel, hogy a device-ra írástól eltekintünk, hisz csak
saját file-kezelést írunk s nem egy OP rendszer file-kezelését.
Így lesz a neve fő objektum file-ból
(handle-lel) olvasó rutinjának a neve ReadFromFile.
Paraméterezés:
-
BX-ben a file-t azonosító handle-t adtuk meg, ugyanígy járunk el az objektum
esetében is, az-az:
Az első (Handle: Word
típusú) paraméter lesz a handle szám.
-
CX-ben adtuk meg a beolvasandó byte-ok számát, és a sikeres lefutás után
AX-ben kaptuk vissza a tényleges beolvasottat.
A objektumban a var ByteToRead: Word változó adja át
a rutinnak a file-ból beolvasandó byte-okszámát, míg ugyanez a változó
adja is vissza a ténylegesen beolvasottat. (Ezt láthatjuk a var
deklarációból.)
-
A DS:DX címen kell az assembly hívás esetén megadnunk a buffer címét ahova
akarjuk beolvasni a file-ból az adatokat.
Hasonlóan az objektumos megvalósításnál, itt is kell egy buffer csak
egyszerűbb a használata. Elég a buffer
nevét a paraméter-listában megadni a var Buf;
helyen. Itt viszont az elővigyázatosság jegyében meg kell adnunk a buffer
hosszát byte-okban a BufSize: Word változóban. Hisz
a var típus nélküli paraméter-átadásnál mivel nem adunk meg
típust, nem tudjuk, hogy elfér –e a buffer-ban a beolvasandó adat. Így
kell egy plusz paraméter a buffer hossza. (Ezt legkönnyebben a SizeOf(Buffer)
Pascal paranccsal adhatjuk meg, közvetlenül paraméterként.) (Igaz assembly-ben
sincs közvetlen buffer-méret ellenőrzés,
de mi azért itt megtesszük.)
-
Ha a lefutás sikeres akkor assembly-ben a CF (carry flag) üres (=0).
A saját megvalósításban pedig a függvény Boolean visszatérési
értéke True.
Nos ilyen megfontolás alapján kell felépíteni a fő
objektumunkat.
Nem kívánom részletezni minden metódus paraméterezésének logikáját,
hiszen kézenfekvő, így csak közlöm:
PR4sFileDOS = ^TR4sFileDOS;
TR4sFileDOS = Object(TObject)
public {Original DOS functions}
{R} constructor Init(ADriveObj: PAbstractDrive);
destructor Done; virtual;
{R} procedure SelectDefaultDrive(DriveImageFile: String);
virtual;
{210E}
{R} function OpenFileByFCB(var FCB: TFCB):
Boolean; virtual; {UnOp}
{210F}
{R} function CloseFileByFCB(var FCB:
TFCB): Boolean; virtual; { Op}
{2110}
function FindFirstByFCB(FCB:
TFCB): Boolean; virtual; {UnOp}
{2111}
function FindNextByFCB(FCB:
TFCB): Boolean; virtual; {UnOp}
{2112}
function DeleteFileByFCB(FCB:
TFCB): Boolean; virtual;{UnOp}
{2113}
{R} function SeqReadByFCB(var FCB: TFCB): Boolean;virtual;{Op,Return
data in DTA 2114}
function SeqWriteByFCB(FCB:
TFCB): Boolean; virtual; {Op,Expect data in DTA 2115}
function CreateFileByFCB(FCB:
TFCB): Boolean; virtual;{UnOp,overw. if exist 2116}
function RenameFileByFCB(RFCB:
TRFCB): Boolean; virtual;
{2117}
{R} function GetCurrentDrive: String; virtual;
{2119}
{R} procedure SetDTA(Address: Pointer); virtual;
{Disk Transfer Area 211A}
procedure GetAllocationInformationForDefDrive(var
SecClus: Byte; {211B}
var ByteSec: Word; var TotClus: Word; var MediaID:
Byte); virtual;
function GetDPBForDefDrive:
PDriveParameterBlock; virtual;
{211F}
function ReadRandomRecByFCB(FCB:
TFCB): Boolean; virtual; {Op,Return data in DTA 2121}
function WriteRandomRecByFCB(FCB:
TFCB): Boolean; virtual; {Op,Except data in DTA 2122}
function GetFileSizeByFCB(var
FCB: TFCB): Boolean; virtual; {UnOp 2123}
procedure SetRandomRecNumbForFCB(var
FCB: TFCB); virtual; {Op
2124}
function RandomBlockReadByFCB(var
NumbRecToRead: Word; var FCB: TFCB): Boolean; virtual;
{Op,Return data in DTA 2127}
function RandomBlockWriteByFCB(var
NumbRecToRead: Word; var FCB: TFCB): Boolean; virtual;{Op,Except
data in DTA 2128}
function PraseFileNameToFCB(var
FCB: TFCB; Str: String; var UnPrasedPos: Byte): Boolean;
virtual; {UnOp 2129}
{R} function GetDTA: Pointer; virtual;
{212F}
function GetFreeDiskSpace(Drive:
String; var SecClus, FreeClus, ByteClus, TotalClus: Word): Boolean;
virtual; {2136}
function MkDIR(Name: TASCIIZ):
Boolean; virtual; {2139}
function RmDIR(Name: TASCIIZ):
Boolean; virtual; {213A}
{R} function ChDIR(Name: TASCIIZ): Boolean;
virtual; {213B}
function CreatFile(Name:
TASCIIZ; Attributes: Word; var Handle: Word): Boolean; virtual;
{213C}
{R} function OpenFile(Name: TASCIIZ; AccessMode:
Byte; var Handle: Word): Boolean; virtual; {213D}
{R} function CloseFile(Handle: Word): Boolean;
virtual; {213E}
{R?}function ReadFromFile(Handle: Word; var
ByteToRead: Word; var Buf; BufSize: Word): Boolean; virtual;
{213F}
{N} function WriteToFile(Handle: Word; var
ByteToWrite: Word; var Buf): Boolean; virtual; {2140}
function DeleteFile(Name:
String): Boolean; virtual; {2141}
{R} function SeekFile(Handle: Word; SeekType:
Byte; var Pos: Longint): Boolean; virtual; {2142}
{R} function GetFilePos(Handle: Word): Longint;
{2142xx} {if Return = $FFFFFFFF then It means Error !}
{*} function GetFileAttributes(Name: String;
var Attributes: Word): Boolean; virtual; {214300}
function SetFileAttributes(Name:
String; Attributes: Word): Boolean; virtual;
{214301}
function DuplicateFileHandle(Handle:
Word; var NewHandle: Word): Boolean; virtual; {2145}
function GetCurrentDIR(Drive:
Byte; var ASCIIZPath: TASCIIZ): Boolean; virtual; {2147}
{R} function FindFirstFile(Name: TASCIIZ; Attribute:
Byte): Boolean; virtual; {Return FF DataBlock in DTA 214E}
{R} function FindNextFile: Boolean; virtual;
{EXCEPT previous FF DataBlock in DTA 214F}
function RenameFile(OldName,
NewName: TASCIIZ): Boolean; virtual; {2156}
{R} function GetFilesTimeAndDate(Handle: Word;
var Time, Date: Word): Boolean; virtual; {215700}
function SetFilesTimeAndDate(Handle:
Word; Time, Date: Word): Boolean; virtual;
{215701}
function CreateTempFile(var
Name: TASCIIZ {\ !}; Attribute: Word; var Handle: Word): Boolean;
virtual; {215A}
function CreateNewFile(var
Name: TASCIIZ; Attribute: Word; var Handle: Word): Boolean; virtual;
{215B}
function NameExpand(Name:
TASCIIZ; var OutNameBuffer: TNameBuffer): Boolean; virtual;
{Canonicalize filename or path 2160}
function FlushFileDatas(Handle:
Word): Boolean; virtual; {2168}
{*} function GetDiskSerialNumber(Disk: String;
var DiskInfo: TDiskInfo_Serial): Boolean; virtual; {216900}
function SetDiskSerialNumber(Disk:
String; DiskInfo: TDiskInfo_Serial): Boolean; virtual;
{216901}
function ComitFile(Handle:
Word): Boolean; virtual; {216A}
{} function ExtendedOpenOrCreateFile(Name:
String; OpenMode, Flags: Byte; Attribute: Word;
Action: Byte; var Handle: Word): Boolean; virtual; {216C00}
public {DOS Extensions}
function GetFileSize(Handle:
Word): Longint;
{...
private {internal procs}
...}
end;
-
Láthatjuk, hogy a TObject-ből származtattuk
TR4sFileDOS objektumunkat.
-
Az eredeti DOS megszakítási rutinok megfelelnek az objektum első
publikus részének metódusainak.
-
Az {R} jelenti, hogy ezen metódusokkal fogunk bővebben
foglalkozni.
-
A metódus nevek logikusan az általuk végrehajtandó tevékenységre utalnak.
-
Az adott metódusok paraméterei megegyeznek az eredetileg átadandó DOS paraméterekkel.
A visszaadott értékek a var-ral deklarált metódus-paraméterként,
ill. a függvények visszatérési értékeként kapható meg.
-
Számos metódust virtuálisan deklaráltunk, hogy a származtatott objektumokból
zökkenő mentesen átírhassuk őket.
-
A metódus nevek után látható kapcsos-zárójelben egy szám: {213F}. Ez jelenti,
hogy az INT 21h-s megszakítás 3Fh-s rutinjának megvalósítása az adott metódus.
Nos idáig eljutottunk:
De ne felejtsük el, hogy NEM egy teljes OP rendszer file-kezelését írjuk
meg, így meg kell adni ennek az objektumnak, hogy milyen Drive-ra legyen
értelmezve az-az, hogy saját file-kezelésünket min használjuk.
Most felvetődhet a kérdés:
-
Miért lehet több féle képen használni ?
-
Hát IGEN !
-
Használhatjuk először egy IMAGE file-ra
ami annyit tesz, hogy készítünk egy másolatot, pl. egy floppy lemezről
szektorról – szektorra (sáv a 0. fejjel, majd 1-ő
fejjel, majd sáv+1 a 0. fejjel, stb.). Ez egy olyan Image file, amit
a lemezmásoló programok is készítenek. Ez a DOS számára egy kezelhetetlen
1.44 MB-os adattömeg, nem más mint a floppy-nak a byte-ok szerinti másolata.
Ezt a másolatot már nem meghajtóként, hanem kutya közönséges adatként –
file-ként fogja a DOS kezelni.
Mi a saját file-kezelésünkkel viszont kezelhetjük már egy való meghajtóként
ezt az image-file-t.
-
A második még egyenlőre nem ajánlatos
használati mód a fizikai meghajtó kezelése saját rutinjainkkal.
Értem ezt arra, hogy a floppy-t ne DOS-sal, hanem saját file-kezelésünkkel
olvassuk. Ezt egyenlőre a jelenlegi
rutinokkal nem ajánlom, mert még nem gyorsabb mint a DOS (sőt
néha lassabb).
Hogyan valósítható meg ez egy objektummal, hogy különböző
médiákat kezeljünk ?
Gondolkozzunk logikusan, és objektumok szintjén !
Minden médiát, legyen az fizikai vagy egyéb: szektor szinten kezelünk
! Kell egy ős – absztrakt – objektum,
mely tartalmazza az alapvető szektor
szintű utasításokat. Ezen absztrakt
ős objektum típust adjuk meg a file-kezelő
TR4sFileDOS objektumnak, ugyanis a fő
objektumnak nem kell törődnie azzal,
hogy hogyan pl. olvasson be egy szektort, hanem csak meghívja a TxDrive
objektum ReadSectors… metódusát. (Tehát a TR4sFileDOS objektumnak csak
az a lényeg, hogy kapjon egy beolvasott szektort, a tényleges beolvasást
a drive objektum végzi.) Mivel szabványosítottunk egy ős
– absztrakt objektumot, az ebből származtatott
utód-objektumok metódusainak ugyanaz lesz a neve, csak másképp fog működni.
Lássuk a szabványosítást, azaz az őst:
PAbstractDrive = ^TAbstractDrive;
TAbstractDrive = Object(TObject)
public
LastStatus: Byte;
CF
: Boolean; {Carray Flag}
Drive : Byte;
constructor Init(ADrive: Byte);
destructor Done; virtual;
function ResetDisk(ADrive:
Byte): Byte; virtual; {Ret: Status} {1300}
function GetStatusOfLastOperation(ADrive:
Byte): Byte; virtual; {Ret: Status} {1301}
function ReadSectorsIntoMemory(var
Buf; ADrive, Head: Byte; Track: Word; Sector,
SecCount: Byte; var Status, ReadedSecCount: Byte): Boolean; virtual;
{1302}
function WriteSectors(var
Buf; ADrive, Head: Byte; Track: Word; Sector,
SecToWrite: Byte; var Status, SecWrited: Byte): Boolean; virtual;
{1303}
function VerifySectors(var
Buf; ADrive, Head: Byte; Track: Word; Sector,
SecToVerify: Byte; var Status, SecVerified: Byte): Boolean; virtual;
{1304}
function ReadLogicalSectorIntoMemory(var
Buf; ADrive: Byte; StartSec: Longint; SecCount: Byte;
var Status, ReadedSecCount: Byte): Boolean; virtual; {1301}
procedure GetDriveDatas(var
AFATStart, AFATSize, ARootStart, ARootSize, ADataStart: Word; var
AMaxEntryPerSec: Byte;
var ABootInf: TBootSecInforms);
function GetDriveNumber:
Byte;
private
{...}
end;
Nos íme az interface, ami a szektor szintű
rutinokat tartalmazza. Azért ezt az absztrakt őst
adjuk meg a TR4sFileDOS Init-jében mert az ebből
származtatott összes őst elfogadja
akkor majd ide paraméterének.
Tehát ha ebből az absztrakt ősből
származtatunk egy objektumot mi fizikailag kezeli a lemezt:
TPhisicalDrive = Object(TAbstractDrive)
Akkor azt közvetlenül megadhatjuk a TR4sFileDOS Init-jének, hisz kompatíbilis
az absztrakt őssel, s szektor metódusok
itt már működnek. (TEHÁT az absztrakt
őst NEM lehet az Init-be megadni hisz
ez még nem egy működő
objektum csak a közös ős mely a metódusneveket
tartalmazza. Ha ezt tennénk Runtime error 211 elszállnánk, jelezve, hogy
nem használható absztrakt objektumot használunk.)
Tehát ugyanígy használhatnánk a TAbstractDrive-ból származtatott TImageDrive-ot
is.
TImageDrive = Object(TAbstractDrive)
Persze a lényeg az utód objektumok implementációjában, a virtuális metódusok
kifejtésében van. Az egyik objektum pl. a TPhisicalDrive fizikai lemezkezeléssel
olvas be / ír ki szektorokat az INT 13h-mal, míg a TImageDrive pedig az
image-file-ból DOS file-kezeléssel olvas be egy szektornyi byte-ot. Ennek
áttanulányozására ajánlom az R4s_FDOS.INT file-t. (Azért nem kívánom
T...Drive objektumokat részletesen kifejteni, mert ez nem kapcsolódik közvetlenül
a file-kezeléshez, és a fizikai /INT 13h/ lemezkelést meg már kiveséztük.
A cél csak a felépítés elmagyarázása volt.) (Azt azért megjegyezném,
hogy mindig a logikai szektorokat fog a TR4sFileDOS olvasni / írni ( ReadLogicalSectorIntoMemory()
) és nem pedig fizikailag fej/sáv/szektor...)
Tehát ezen deklarált objektumokat adjuk át a TR4sFileDOS Init-jének.
Persze a T...Drive objektumoknak is van Init-je ahol meg kell adni pl.
a TPhisicalDrive-nak a fizikai lemezszámot, ill. a TImageDrive-nak az a
file-nevet melyben az image-file van. Íme:
/TPhisicalDrive/
constructor Init(ADrive: Byte);
A fizikai lemez – szektor kezelést megvalósító
TPhisicalDrive Init-jében csak a fizikai drive számot kell megadni, ahol
00h A:, 01h, B ... 80h az első HDD, 81h a második HDD ... A másik:
/TImageDrive/
constructor Init(ADrive: String);
Ha image-ből történik a file-kezelés,
(az-az már egy floppy lemezt előzőleg lementettünk
szektorról-szektorra HDD-re egy file-ba) akkor a TImageDrive
objektumot használjuk. Így egy virtuális meghajtót kapunk az image-file-ból
a TR4sFileDOS objektum segítségével. A TR4sFileDOS-nak az Init-jébe csak
megadjuk a TImageDrive-ot. Annak Init-jébe pedig a file-nevét ami a floppy-lemez
image-ét tartalmazza.
Lássuk konkrét példát a TR4sFileDOS inicializálására:
Fizikai lemezkezelés:
var FDOS: PR4sFileDOS;
New(FDOS, Init( New( PPhisicalDrive, Init( a_drive_száma_pl_0 )
) ) );
Image file-kezelés:
var FDOS: PR4sFileDOS;
New(FDOS, Init( New( PImageDrive, Init( az_imagefile_neve_pl_"proba.img"
) ) ) );
Nos, hogy ilyen szépen eljutottunk idáig lássuk hogyan kell image-file-t
készíteni. (Inkább leírom most, nehogy Nektek kelljen megerőltetni
magatokat. J )
Image-file készítése
Egyáltalán nem egy ördöngős dolog,
pár dolgot kell figyelembe vennünk:
-
A lemezt nyílván INT 13h-mal fogom beolvasni.
-
Logikus, hogy nem szektorról szektorra olvasom be, mert maga a hardware
úgy is egy sávot olvas be egyszerre. Ezért, hogy minél gyorsabb legyen
egyszerre egy sávot olvasunk be.
-
A mérési eredmények – s a józan ész – azt diktálja, hogy a beolvasás így
történjen:
x. sáv a 0. Oldalról, x. sáv az 1-ő
oldalról, majd a x+1. sáv a 0.-ról, és az x+1. az 1-ről,
stb.
Tehát egyik sáv az egyik fejről,
majd ugyanazon sáv a másik fejről,
majd a következő sáv a 0-dikról ...
Lássuk a megvalósítást:
BEGIN
Drive:= 0; {A fizikai lemez száma 0 = A}
Assign(F, ParamStr(2)); {És ParamStr(2)-ben van a
file neve amibe mentjük az image-t}
ReWrite(F, 1);
GetDriveInfo(Drive, DrvInf); {A lemezinformációk lekérdezése}
for Cylinder:=0 to DrvInf.CylinderNumber
do {Egymás után olvassa a lemez sávjait}
for Head:=0 to DrvInf.HeadNumber
do {Külnböző oldalról
olvassa az azonos sávot}
begin
ReadDiskSector(B, Drive, Head, Cylinder,
1, DrvInf.SectorPerCylinder, i, j);
BlockWrite(F, B, Word(DrvInf.BytePerSector)*j,
int);
GotoXY(1, 1);
Writeln('Drive: ', Drive, ' Head:
', Head, ' Track: ', Cylinder,
' Readed Sector: ', j, ' ');
end;
Close(F);
END.
-
GetDriveInfo()-val a lemezre jellemző
információkat kérdezhetjük le. Ez egy általam készített információs rekord,
melyet részint a Disk Parameter Block-ból, és egyéb apróságokból épít fel.
-
A for Cylinder .. ciklusban a 0. sávtól – a Lemezen található legnagyobb
sávig megy a ciklus. (pl. 0-79)
-
A for Head .. ciklusban 0. fej és a Maximum fejek számáig megy a ciklus.
(Floppy: 0-1)
-
A ReadDiskSector() rutint már tárgyaltuk:
B – a buffer amibe olvasunk
Drive – a lemez fizikai száma melyről
olvasunk (0 – A, 1 – B, 80h első HDD,
81h 2. HDD}
Head – a meghajtó melyik fejéről
akarunk olvasni ?
Cylinder – hányadik sávtól történjen az olvasás
Sector – ez a következő paraméter:
hányadik szektortól olvassunk ? (1-x vannak számozva)
SectorNumber – egyszerre mennyi szektort olvassunk be ? (Amennyi egy
sávban van, ez a leggyorsabb.)
Status (i) – az olvasás eredménye
ReadedSectorCount (j) – a beolvasott szektorok száma.
-
BlockWrite()-tal lementjük az image-file-ba. Annyi szektort kell leírni
a buffer-ből, amennyit beolvastunk
(j) * egy_szektor_byte_méretével (ált. 512).
-
A többi utasítás Write() GotoXY() csak sallang.
Használjátok egészséggel a SAVEDISK.pas forráskódot.
Ezzel egész jó image-file-t lehet készíteni.
Térjünk vissza a TR4sFileDOS objektumunkhoz pár sorra. Az Init ill.
Done utasításokat vegyük végig:
constructor TR4sFileDOS.Init(ADriveObj: PAbstractDrive);
var Mem, Disk: Longint;
begin
New(FAT);
DriveObj:=ADriveObj;
DriveNum:=ADriveObj^.GetDriveNumber;
SelectDefaultDrive(TheDrive);
if Error <> 0 then begin Error:=R4sFDOS_DriveNotReady;
Fail; end;
Is12bitFAT:=HasDrive12bitFAT;
SetDTA(Ptr(PrefixSeg, $80));
end;
-
Az ADriveObj: az adott médiát kezelő
objektum ez a fent leírtak szerint kerül létrehozásra.
-
Mivel az itt közölt TR4sFileDOS eléggé floppy lemez orientált így: létrehozunk
egy 64KB-os tömböt a FAT számára, hogy ne mindig a lemezről
kelljen olvasni. (Ez már bizonyos szintű
gyorsítás.)
-
A TR4sFileDOS DriveObj: PAbstractDrive mezőjének
a paraméterben megadottat adjuk értékéül.
-
A DriveNum ha fizikai lemezkezelést valósítunk meg (TPhisicalDrive van
az Init-ben) akkor a fizikai lemez száma.
-
Nézzük, mit valósít meg a SelectDefaultDisk():
procedure TR4sFileDOS.SelectDefaultDrive(DriveImageFile: String);
var
TempW: Word;
TempB: Boolean;
begin
ClearAllLocalVariable;
DriveObj^.GetDriveDatas(FATStart, FATSize, RootStart, RootSize,
DataStart, MaxEntryPerSec, BootInf);
CurDIR.Sector:=RootStart;
CurDIR.Path:=':\';
if IOResult <> 0 then Error:=R4sFDOS_DriveNotReady
else if Not ReadFAT then Error:=R4sFDOS_FATToBig;
end;
-
Tulajdon képen ez a TR4sFileDOS objektumnak egy belső
használatú rutinja. (Ennek ellenére publikusnak deklaráltam. Már nem is
emlékszem miért ...)
-
A ClearAllLocalVariable; nyilván kitörli a TR4sFileDOS objektum
minden nem használatos lokális változóját.
-
A GetDriveDatas() a TAbstractDrive-tól elkéri a drive-ra jellemző
adatokat, úgy mint a FAT hossza szektorban, vagy annak kezdete logikai
szektor-számban, stb. A TAbstractDrive ezt még saját Init()-jében tölti
fel az aktuális adatokkal. (Lásd: TPhisicalDrive, TImageDrive.) Így beadjuk
a FATStrat, stb. nevű változókat, s
azokat a GetDriveDatas() feltölti.
-
A Drive aktuális könyvtára a főkönyvtár
lesz. Az ehhez tartozó szektor, pedig a root-entry (ha nem tod' mi ez,
lásd az előző
előtti számot) első szektora.
-
Ha valami hiba lenne akkor kilépünk ...
-
És végül a ReadFAT-tel beolvassuk a FAT-ot a fent deklarált FAT dinamikus-tömbbe.
Térjünk vissza a TR4sFileDOS.Init()-hez:
-
HasDrive12bitFAT-tal megállapítjuk, hogy 12-bit-es –e a FAT, s ennek
eredményét lokális változóban tároljuk le.
-
S végül beállítjuk a DTA (Disk Transfer Address) címét. Alap programban
a PSP, $80-dik indexű helyén van a
címe.
Ha már az Init()-et végig nyálaztuk, akkor lássuk a destructor Done;-t
is:
destructor TR4sFileDOS.Done;
begin
ClearAllLocalVariable;
Dispose(FAT);
DriveObj^.Done;
Inherited Done;
end;
-
Kitöröljük a lokális változókat,
-
Felszabadítjuk a FAT számára lefoglalt helyet,
-
Meghívjuk a TAbstractDrive.Done-t aminek hatására az is felszabadítja magát,
-
S végül a TObject-től örökölt Done-t.
-
Így nem hagytunk a memóriában semmi olyan lefoglalt területet, amit fel
kellene szabadítani.
Nos mára ennyi, a TR4sFileDOS alapfelépítését, a hozzá csatolódó objektumokat
– típusokat elmondtam. Legfontosabbnak a dolgok LOGIKÁjanak, felépítésének
elmagyarázását tartottam, hisz eme rovatot nem a teljesen kezdők
olvassák és akit érdekel annak csak egy gondolatmenet kell, és már maga
is meg tudná írni. Ha valakinek összekuszálódtak volna soraim akkor kérem
írjon, segítek.
Következő számunkban a tényleges
file olvasásról, meg hasonló nyalánkságokról lesz szó.
Egy kérdés: Akit érdekel a Win95 – WinNT hosszú file-nevek rendszere
az írjon egy levelet a PC-XUSER@freemail.c3.hu
–ra, s ha elegen vagytok írhatok róla. (Nem olyan ördöngős.
A FAT32 DOS 6.22 alatti olvasása, meg stb-ről
lenne szó.)
A cikkhez csatolt R4sFDOS.INT segítséget
nyújt a fentiek megértéséhez !
Bérczi László