home *** CD-ROM | disk | FTP | other *** search
-
- {* -------------------------------------------------------------------------
- * M S - D O S S E C T O R R E A D / W R I T E P R O C E D U R E S
- * ------------------------------------------------------------------------- *}
-
- {*
- * The procedures ReadSector and WriteSector, which read respectively write
- * one sector of the MS-DOS disk, constitute the heart of TraMDF. These
- * procedures, together with procedure FlushCache, are the only procedures
- * which perform MS-DOS disk I/O.
- *
- * Within the procedures ReadSector and WriteSector, two functions are to
- * be performed.
- *
- * The first function to aid in mapping the sector ordinal onto the
- * physical address of the sector: the cylinder ordinal, the head ordinal,
- * the track number and the sector number. For instance, sector ordinal 0
- * must be mapped onto cylinder 0, head 0, track 0, sector 1. This mapping
- * is performed partly in these procedures and partly in BIOS. These
- * procedures must map the sector ordinal onto a logical track number and a
- * logical record number, which in turn are mapped onto the aforementioned
- * physical address by the BIOS. The latter mapping is VERY SYSTEM DEPENDENT!
- *
- * In case of the ASTER CT-80, the mapping performed by BIOS is:
- * - The cylinder ordinal is the logical track number divided by two.
- * - The head ordinal is the remainder of this division.
- * - The track number is equal to the cylinder ordinal.
- * - The sector number is XLT[logical record number divided by PSS].
- * One logical CP/M track is thus one physical track. As a result, the
- * mapping of the sector ordinal in procedures ReadSector and WriteSector
- * is simple.
- *
- * Through the mapping function, any sector is addressed by a single number
- * outside the procedures ReadSector and WriteSector. The sector ordinal is
- * in the range 0 (=boot-sector) through SectorsPerDisk-1.
- *
- * The second function is the actual disk transfer through multiple calls to
- * the BIOS. Note that there is NO call to perform sector translation. On
- * many (most?) CP/M hosts this function is a do-nothing, it is meant for
- * software skewing which is not used on MS-DOS disks and, last and least,
- * it requires two parameters to be passed to the BIOS, while the Bios
- * procedure (function) can pass only one.
- *}
-
- procedure ReadSector( Sector, Buffer: Integer ) ;
- {*
- * Read one MS-DOS sector from disk into the specified buffer.
- *}
- var
- CpmTrack : Integer ; { Ordinal of logical track }
- CpmRecord: Integer ; { Ordinal of record }
- BiosError: Boolean ; { Completion status of procedure }
- I : Integer ; { Loop control variable }
- begin
- CpmTrack := (Sector div SectorsPerTrack) ;
- CpmRecord:= (Sector mod SectorsPerTrack) * RecordsPerSector ;
-
- BiosError:= False ;
- Bios( SelectDrive, MsdosDrive ) ;
- Bios( SelectTrack, CpmTrack ) ;
- for I:= 1 to RecordsPerSector do
- begin
- Bios( SelectRecord, CpmRecord ) ;
- Bios( SelectBuffer, Buffer ) ;
- BiosError:= BiosError or
- (Bios( ReadRecord )<>0) ;
- CpmRecord:= Succ( CpmRecord ) ;
- Buffer:= Buffer + BytesPerRecord ;
- end ; { of for }
- Bios( SelectDrive, CpmCurrentDrive ) ;
-
- if BiosError then
- FlagError( 'ReaS: Disk read error' ) ;
- end ; { of ReadSector }
-
- procedure WriteSector( Sector, Buffer: Integer ) ;
- {*
- * Write one MS-DOS sector from the specified buffer onto disk.
- *}
- var
- CpmTrack : Integer ; { Ordinal of logical track }
- CpmRecord: Integer ; { Ordinal of record }
- BiosError: Boolean ; { Completion status of procedure }
- I : Integer ; { Loop control variable }
- begin
- CpmTrack := (Sector div SectorsPerTrack) ;
- CpmRecord:= (Sector mod SectorsPerTrack) * RecordsPerSector ;
-
- Bios( SelectDrive, MsdosDrive ) ;
- Bios( SelectTrack, CpmTrack ) ;
- for I:= 1 to RecordsPerSector do
- begin
- Bios( SelectRecord, CpmRecord ) ;
- Bios( SelectBuffer, Buffer ) ;
- if I=1 then
- BiosError:= (Bios( WriteRecord, 2 )<>0) { Inhibit pre-read }
- else
- BiosError:= BiosError or
- (Bios( WriteRecord, 0 )<>0) ;
- CpmRecord:= Succ( CpmRecord ) ;
- Buffer:= Buffer + BytesPerRecord ;
- end ; { of for }
- Bios( SelectDrive, CpmCurrentDrive ) ;
-
- if BiosError then
- FlagError( 'WriS: Disk write error' ) ;
- end ; { of WriteSector }
-
- procedure FlushCache ;
- {*
- * The BIOS cache (buffer) is not written until the cache is needed for
- * another sector. Force the cache to be flushed by reading the first (boot)
- * sector: this sector is never written by this program.
- *
- * BIOS supports a special write type for (CP/M) directory sectors, which
- * causes the cache to be flushed immediatly. However, this BIOS function
- * also includes a verify read, causing a serious degradation of the transfer
- * speed if used often, for instance in WriteSector.
- *}
- var
- Success: Boolean ; { Read operation completed normally }
- begin
- Bios( SelectDrive , MsdosDrive ) ;
- Bios( SelectTrack , 0 ) ;
- Bios( SelectRecord, 0 ) ;
- Bios( SelectBuffer, Addr(ClusterBuffer) ) ;
- Success:= Bios( ReadRecord ) = 0 ;
- Bios( SelectDrive, CpmCurrentDrive ) ;
-
- if not Success then
- FlagError( 'FluC: Can''t read the boot sector' ) ;
- end ; { of FlushCache }
-
-
-
- procedure ReadFat( FatOrdinal: Integer ) ;
- {*
- * Read the MS-DOS File Allocation Table into table FatBuffer. The
- * supplied FatOrdinal should be in the range 1 through FatsPerDisk.
- *}
- var
- Sector: Integer ; { Ordinal of sector }
- Buffer: Integer ; { Address of FAT buffer }
- I : Integer ; { Loop control variable }
- begin
- Sector:= FirstFatSector + FatOrdinal*SectorsPerFat ;
- Buffer:= Addr( FatBuffer ) ;
- for I:= 1 to SectorsPerFat do
- begin
- ReadSector( Sector, Buffer ) ;
- if ErrorDetected then
- begin
- BuildErrorTrace( 'ReaF_' ) ;
- Exit ;
- end ; { of if }
- Sector:= Succ( Sector ) ;
- Buffer:= Buffer + BytesPerSector ;
- end ; { of for }
- end ; { of ReadFat }
-
- procedure WriteFat( FatOrdinal: Integer ) ;
- {*
- * Write the File Allocation Table from table FatBuffer to disk. The
- * supplied FatOrdinal should be in the range 1 through FatsPerDisk.
- *}
- var
- Sector: Integer ; { Ordinal of sector }
- Buffer: Integer ; { Address of FAT buffer }
- I : Integer ; { Loop control variable }
- begin
- Sector:= FirstFatSector + FatOrdinal*SectorsPerFat ;
- Buffer:= Addr( FatBuffer ) ;
- for I:= 1 to SectorsPerFat do
- begin
- WriteSector( Sector, Buffer ) ;
- if ErrorDetected then
- begin
- BuildErrorTrace( 'WriF_' ) ;
- Exit ;
- end ; { of if }
- Sector:= Succ( Sector ) ;
- Buffer:= Buffer + BytesPerSector ;
- end ; { of for }
- end ; { of WriteFat }
-
- procedure ReadCluster( Cluster: Integer ) ;
- {*
- * Read one MS-DOS cluster from disk into the cluster buffer. The
- * supplied cluster number should be in the range 2 through ClustersPerDisk.
- *}
- var
- Sector: Integer ; { Ordinal of sector }
- Buffer: Integer ; { Start address of buffer area }
- I : Integer ; { Loop control variable }
- begin
- Sector:= FirstDataSector + (Cluster-2)*SectorsPerCluster ;
- Buffer:= Addr( ClusterBuffer ) ;
- for I:= 1 to SectorsPerCluster do
- begin
- ReadSector( Sector, Buffer ) ;
- if ErrorDetected then
- begin
- BuildErrorTrace( 'ReaC_' ) ;
- Exit ;
- end ; { of if }
- Sector:= Succ( Sector ) ;
- Buffer:= Buffer + BytesPerSector ;
- end ; { of for }
- end ; { of ReadCluster }
-
- procedure WriteCluster( Cluster: Integer ) ;
- {*
- * Write one MS-DOS cluster from the cluster buffer onto disk. The
- * supplied cluster number should be in the range 2 through ClustersPerDisk.
- *}
- var
- Sector: Integer ; { Ordinal of sector }
- Buffer: Integer ; { Start address of buffer area }
- I : Integer ; { Loop control variable }
- begin
- Sector:= FirstDataSector + (Cluster-2)*SectorsPerCluster ;
- Buffer:= Addr( ClusterBuffer ) ;
- for I:= 1 to SectorsPerCluster do
- begin
- WriteSector( Sector, Buffer ) ;
- if ErrorDetected then
- begin
- BuildErrorTrace( 'WriC_' ) ;
- Exit ;
- end ; { of if }
- Sector:= Succ( Sector ) ;
- Buffer:= Buffer + BytesPerSector ;
- end ; { of for }
- end ; { of WriteCluster }
-
- function GetFatEntry( Index: Integer ) : Integer ;
- {*
- * Return the pointer in the File Allocation Table at a given
- * index (ordinal). The supplied index should be in the range 0 through
- * ClustersPerDisk.
- *}
- var
- Result: Integer ; { Raw result }
- I : Integer ; { Index in FAT array }
- begin
- I := (Index * 3) shr 1 ;
- Result:= FatBuffer[I] + (FatBuffer[I+1] shl 8) ;
- if Odd(Index) then
- Result:= Result shr 4 ;
- GetFatEntry:= Result and $0FFF ;
- end ; { of GetFatEntry }
-
- function GetFreeFatEntry( ClOrd: Integer ) : Integer ;
- {*
- * Return the ordinal of the next free entry in the FAT. The search starts
- * at the entry following the specified FAT ordinal. If there is no free
- * entry in the FAT, an error condition is raised and an out-of-range value
- * is returned.
- *
- * Note: if the disk is full, in the last invokation of GetFatEntry the
- * parameter ClOrd will be out of range. However, the (rubbish?) value
- * returned by GetFatEntry won't have any effects.
- *}
- begin
- repeat
- ClOrd:= Succ( ClOrd ) ;
- until (ClOrd>ClustersPerDisk) or (GetFatEntry(ClOrd)=0) ;
- if ClOrd<=ClustersPerDisk then
- GetFreeFatEntry:= ClOrd
- else
- begin
- FlagError( 'GetFFE: Disk full' ) ;
- GetFreeFatEntry:= $0FFF ;
- end ; {of if }
- end ; { of GetFreeFatEntry }
-
- procedure PutFatEntry( Index, Value: Integer ) ;
- {*
- * Put the given value into the FAT entry with ordinal Index. The supplied
- * index should be in the range 2 through ClustersPerDisk. The supplied
- * value should be in the same range or it should be $FFF.
- *}
- var
- Result: Integer ; { Intermediate result }
- I : Integer ; { Index in FAT array }
- begin
- I := (Index * 3) shr 1 ;
- Result:= FatBuffer[I] + (FatBuffer[I+1] shl 8) ;
- if Odd(Index) then
- Result:= (Result and $000F) + (Value shl 4)
- else
- Result:= (Result and $F000) + (Value and $0FFF) ;
- FatBuffer[I ]:= Lo( Result ) ;
- FatBuffer[I+1]:= Hi( Result ) ;
- end ; { of PutFatEntry }
-