home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
utils
/
dskutl
/
swp-ms10.ark
/
TRAMDF.IF5
< prev
next >
Wrap
Text File
|
1989-09-27
|
13KB
|
318 lines
{* ------------------------------------------------------------------------- *}
{* M S - D O S F I L E M A N A G E R U T I L I T I E S
{* ------------------------------------------------------------------------- *}
procedure DisplayMsdosDiskParameters ;
{*
* Display the physical parameters of the last, which is possibly also
* the current MS-DOS disk read.
*}
begin
DisplayTitle( 'MS-DOS disk parameters' ) ;
Write ( ^M^J'Disk parameters of the ' ) ;
if MsdosDriveName='?' then
Write( 'last' )
else
Write( 'current' ) ;
WriteLn( ' MS-DOS disk.'^M^J ) ;
WriteLn( 'System Identification = ', SystemIdent ) ;
WriteLn( 'Media descriptor = $', Hex(FormatIdent,2) ) ;
WriteLn ;
WriteLn( '# bytes per sector = ', BytesPerSector:4 ) ;
WriteLn( '# sectors per track = ', SectorsPerTrack:4 ) ;
WriteLn( '# heads = ', SidesPerDisk:4 ) ;
WriteLn( '# sectors per disk = ', SectorsPerDisk:4 ) ;
WriteLn( '# cylinders per disk = ', CylindersPerDisk:4 ) ;
WriteLn ;
WriteLn( '# sectors per FAT = ', SectorsPerFat:4 ) ;
WriteLn( '# sectors per cluster = ', SectorsPerCluster:4 ) ;
WriteLn( '# FATs = ', FatsPerDisk:4 ) ;
WriteLn( '# reserved sectors = ', FirstFatSector:4 ) ;
WriteLn ;
Continue ;
end ; { of DisplayMsdosDiskParameters }
function GetMsdosFreeSpace: Integer ;
{*
* Return the amount of free space, in Kbyte, on the MS-DOS disk.
*}
const
BytesPerKilo= 1024 ; { One KByte }
var
FreeClusters: Integer ; { Counter of free clusters }
I : Integer ; { Loop control variable }
begin
FreeClusters:= 0 ;
for I:= 2 to ClustersPerDisk do
if GetFatEntry(I)=0 then
FreeClusters:= Succ( FreeClusters ) ;
{*
* Compute the free disk space in KiloBytes. Note that the parenthesis
* in the next expression are needed to prevent integer overflow!
*}
GetMsdosFreeSpace:= FreeClusters*(SectorsPerCluster*BytesPerSector div
BytesPerKilo) ;
end ; { of GetMsdosFreeSpace }
procedure UnInstallMsdosDrive ;
{*
* Remove the MS-DOS DPB from the BIOS internal tables and restore the
* original CP/M DPB.
*}
begin
if MsdosDriveName<>'?' then
begin
MsdosDpb^ := SavedDpb ; { Restore XLT and DPB }
MsdosDpb := Nil ; { Remove pointer }
MsdosDriveName := '?' ; { Signal absence of MS-DOS drive }
MsdosDriveAddress:= 254 ; { Remove allocation of physical drive }
end ; { of if }
end ; { of UnInstallMsdosDrive }
procedure InstallMsdosDrive ;
{*
* Install the MS-DOS drive in BIOS. The disk parameters are read from the
* bootsector on the disk. Then the fields within the CP/M DPB are modified
* accordingly. Thus upon successfull completion of this routine, BIOS is
* set up to read and write the MS-DOS disk.
*
* This routine will fail if one of the following conditions occur:
* - The bootsector cannot be read from the disk. A possible cause is that
* there is no disk inserted in the disk drive.
* - The parameters of the disk and the drive are not compatible: either the
* number of cylinders or the number of heads of the disk drive is less
* than required to read the floppy disk.
*
* In case of an error is detected, the global error flag is set and this
* procedure will leave the DPB in an undetermined state!
*
* CAUTION : This procedure is very system dependent! It sets the various
* fields in the extension of the DPB.
*}
type
MsdosBoots = record { Layout of the MS-DOS boot sector }
BJumpCode : array[0..2] of byte ;
BSystemIdent : array[0..7] of char ;
BBytesPerSector : Integer ;
BSectorsPerCluster: Byte ;
BReservedSectors : Integer ;
BFatsPerDisk : Byte ;
BEntriesInRoot : Integer ;
BSectorsPerDisk : Integer ;
BFormatIdent : Byte ;
BSectorsPerFat : Integer ;
BsectorsPerTrack : Integer ;
BSidesPerDisk : Integer ;
BSpecResvSectors : Integer ;
end ; { of MsdosBoot record }
var
BootSector: MsdosBoots absolute ClusterBuffer ;
procedure ReadBootSector ;
{*
* Read the bootsector of an MS-DOS disk. In this sector the actual
* characteristics of the disk can be found. FlushCache reads the
* bootsector in order to force the BIOS cache to be flushed:
* therefore only procedure FlushCache is invoked!
*}
begin
FlushCache ;
end ; { of ReadBootSector }
begin
{*
* Copy the MS-DOS DPB into the BIOS tables and fill it with the currently
* known information.
*}
MsdosDpb^ := SkeletDpb ; { Install skeleton of MS-DOS DPB }
MsdosDpb^.PDA:= MsdosDriveAddress ; { Set the physical drive address }
if MsdosDriveAddress=3 then { Build the drive select mask : }
MsdosDpb^.DDS:= $B0 { MFM & Drive_3 }
else
MsdosDpb^.DDS:= $A0 + ($01 shl MsdosDriveAddress) ; { MFM & Drive_n }
{*
* Read the disk parameters of the MS-DOS floppy disk: they are saved in the
* first sector, the boot sector, of the disk.
*}
ReadBootSector ;
if ErrorDetected then Exit ;
SystemIdent := BootSector.BSystemIdent ;
FormatIdent := Bootsector.BFormatIdent ;
BytesPerSector := BootSector.BBytesPerSector ;
SectorsPerFat := BootSector.BSectorsPerFat ;
SectorsPerCluster:= BootSector.BSectorsPerCluster ;
SectorsPerTrack := BootSector.BSectorsPerTrack ;
SectorsPerDisk := BootSector.BSectorsPerDisk ;
FatsPerDisk := BootSector.BFatsPerDisk ;
SidesPerDisk := BootSector.BSidesPerDisk ;
FcbsPerSector := BytesPerSector div BytesPerFcb ;
FirstFatSector := BootSector.BReservedSectors ;
RootDirectoryStart:= FirstFatSector + SectorsPerFat*FatsPerDisk ;
RootDirectorySize := BootSector.BEntriesInRoot div FcbsPerSector ;
FirstDataSector := RootDirectoryStart + RootDirectorySize ;
RecordsPerSector := BytesPerSector div BytesPerRecord ;
RecordsPerCluster:= RecordsPerSector * SectorsPerCluster ;
CylindersPerDisk := SectorsPerDisk div (SectorsPerTrack*SidesPerDisk) ;
{*
* Compute the index of the last cluster on the disk. This is almost the
* number of clusters on the disk: the FAT contains two dummy entries in the
* beginning, thus the 1st cluster is given index 2.
*}
ClustersPerDisk := (SectorsPerDisk - FirstDataSector) div
SectorsPerCluster + 1 ;
DirectoryStartCls:= 0 ; { Go to root directory }
DirectoryStartSct:= RootDirectoryStart ;
DirectorySize := RootDirectorySize ;
DirectoryNesting := 0 ;
{*
* Check whether the format of the disk and the drive are compatible, that is
* the number of heads and cylinders of the drive must be big enough.
*}
if ( DriveAttribute[MsdosDriveName].Heads < SidesPerDisk ) or
( DriveAttribute[MsdosDriveName].Cylinders<CylindersPerDisk ) then
FlagError( 'InsMD: Incompatible drive selected : ' + MsdosDriveName )
else
{*
* Check whether the cluster buffer and the FAT buffer are big enough.
*}
if (SectorsPerCluster*BytesPerSector>Succ(ClusterSize)) or
(SectorsPerFat *BytesPerSector>Succ(FatSize )) then
FlagError( 'InsMD: Cluster/FAT buffer too small' )
else
{*
* Fill in the other fields of the DPB; Besides all the extension fields in
* the DPB also the fields SPT and BLM need to be set properly. One CP/M
* block is associated with one physical sector
*}
begin
with MsdosDpb^ do
begin
SPT:= SectorsPerTrack*RecordsPerSector ;
BLM:= Pred( RecordsPerSector ) ;
PSS:= RecordsPerSector ;
PCD:= CylindersPerDisk ;
PST:= SectorsPerTrack ;
if SidesPerDisk=1 then
FNO:= $00 ; { Select single sided format }
if CylindersPerDisk<DriveAttribute[MsdosDriveName].Cylinders then
FNO:= FNO + $10 ; { Select double step }
end ; { of with }
end ; { of else/else }
end ; { of InstallMsdosDrive }
procedure SetMsdosDrive ;
{*
* Select another (?) drive as the MS-DOS disk drive. It
* must meet the following criteria:
* - it is a floppy disk drive,
* - it is not the CP/M default and
* - the physical addresses of that drive and the default drive differ.
*}
var
NewDriveName : Char ; { Name of drive for MS-DOS disk }
NewMsdosDrive: Integer ; { Ordinal of selected drive }
Success : Boolean ; { Assignment was successfull }
begin
Write( 'Enter MS-DOS drive : ' ) ;
Read ( Kbd, NewDriveName ) ; NewDriveName:= UpCase( NewDriveName ) ;
Write( NewDriveName ) ;
Success:= False ;
if NewDriveName in (FloppyDrives-[ExtractDisk(CpmDriveName)]) then
with DriveAttribute[NewDriveName] do
begin
NewMsdosDrive:= Ord(NewDriveName) - Ord('A') ;
if DevAddress <> CpmDriveAddress then
begin
Success:= True ;
UnInstallMsdosDrive ; { Remove previous selection }
MsdosDpb := DpbAddress ; { Save address of XLT and DPB }
MsdosDrive := NewMsdosDrive ; { Save drive number }
MsdosDriveAddress:= DevAddress ; { Claim physical drive }
MsdosDriveName := NewDriveName ; { Save drive name }
SavedDpb := MsdosDpb^ ; { Save original XLT and DPB }
InstallMsdosDrive ; { Modify BIOS, determine disk pars }
{*
* Complete the MS-DOS disk installation by reading the FAT. If reading of
* the first FAT fails, use the second FAT (if present).
*}
if not ErrorDetected then
begin
ReadFat( 0 ) ; { Try the primary FAT }
if ErrorDetected and (FatsPerDisk>1) then
begin
ClearError ;
ReadFat( 1 ) ; { Read the back-up FAT }
end ; { of if }
end ; {of if }
{*
* One final check on the internal consistency can be performed now: the
* media descriptor byte in the boot sector and in the FAT should be
* identical.
*}
if not ErrorDetected then
if FormatIdent<>FatBuffer[0] then
FlagError( 'SetMD: Media descriptors don''t match' ) ;
if ErrorDetected then
UnInstallMsdosDrive ; { Undo install in case of an error }
end ; { of if }
end ; { of with/if }
if not Success then
FlagError( 'SetMD: Illegal specification: '+NewDriveName ) ;
end ; { of SetMsdosDrive }
procedure ReadMsdosDirectory ;
{*
* Build the filelist from the current MS-DOS directory.
*}
var
EntryType : EntryTypes ; { Type of MS-DOS directory entry }
begin
PresetFileList ; { Clear the file list }
DirectorySearchPos:= BeforeFirstEntry ;
repeat
{*
* Read the next directory entry and return its type. If an error is
* detected, the returned EntryType will be EndOfDirectory. This will
* cause an immediate termination of this procedure.
*}
GetNextDirEntry( EntryType ) ;
if ErrorDetected then
begin
BuildErrorTrace( 'ReaMD_' ) ;
Exit ;
end ; { of if }
{*
* If a name is encountered, build a file entry from it. The file entry
* is inserted in the filelist, which is ordered on the name field.
*}
if EntryType in [VolumeNameEntry,SubDirectoryNameEntry,FileNameEntry] then
with MsdosFcb^ do
begin
New( FileEntry ) ;
FileEntry^.Next:= Nil ;
FileEntry^.Prev:= Nil ;
FileEntry^.Name:= FileName ;
FileEntry^.Attr:= Attribute ;
FileEntry^.Mark:= False ;
FileEntry^.Size:= (GetMsdosFileSize + 7) div 8 ;
EnterFileInList ;
end ; { of with/if }
until EntryType in [UnusedEntry,EndOfDirectory] ;
FileEntry:= HeadFileList ; { Preset 'current' file }
FileIndex:= 1 ;
end ; { of ReadMsdosDirectory }