!
!       F I N D   B A D   C L U S T E R S
!
!       TESTS SDOS-INITTED DISK FOR BAD CLUSTERS
!       ALL BAD CLUSTERS FOUND ARE PLACED IN "BADCLUSTERS.SYS"
!       ONLY CLUSTERS NOT CURRENTLY ALLOCATED TO FILES ARE TESTED
!
!       V1.0a   1/27/81 IDB     Convert to Basic 14H
!               PRINT BAD SECTOR NUMBER IN HEX
!       V1.1a   11/30/83 (RCW) installed code to disable/enable write protect
!                              on DIRECTORY.SYS and DISKMAP.SYS.

        DIM     CCSETFILEPROT$/:E,8,0,:11/,WBPROTECT$/:41/,NOPROTECT$/0/

        DIM     NULL$/""/
        DIM     DISK/1/, DISKMAP/2/, DIRECTORY/3/
        DIM     BADLSN$/0,0,0/, BADLSN, BADLCN
        DIM     NAME$[16], ENTRY$[16]
        DIM     HCSIC/:12/
        DIM     TWOB$/0,0/
        DIM     ZEROS$[1024], FF$[1024]
        DIM     DISK$[100]
        DIM     DISKMAP$[2049]
        DIM     NBPS, NBPC
        DIM     STAT$[20]
        DIM     STATNBPS/1/, STATNSPT/3/, STATNTPC/5/, STATNCYL/7/
        DIM     BOOT$[64]
        DIM     BOOTNSPC/:12/, NSPC
        DIM     DUMMYLCN$/:FF,:FF/

        DIM     BADLCNCOUNT/0/, BADLCNS(100)

        DIM     GETSTAT$/:F,:E,1,5/
        DIM     UNLOCK$ /:E,4,1,:10/
        DIM     GETBADLSN$/:F,:E,1,:10/
        DIM     READB$/:B,:E,1/, WRITEB$/:D,8,1/
        DIM     READDISKMAP$/:B,:E,2/

        DIM     TOTAL
        DIM     SECTOR$[1024]

        DEF     LCNALLOCATED(X1)=SGN(DISKMAP$[1+(X1&:FFF8)/8]&(1**(X1&:7)))

DEF BADCLUSTERSHLCN = ENTRY$[1]*256+ENTRY$[2]
DEF BADCLUSTERSHCSIC = ENTRY$[HCSIC-15]
SUBROUTINE SETBADCLUSTERSHCSIC(X3)
        LET ENTRY$[HCSIC-15]=X3
        EXIT SUBROUTINE
END
DEF BADCLUSTERSNLCN = ENTRY$[4]*256+ENTRY$[5]
SUBROUTINE SETBADCLUSTERSNLCN(X2)
        LET ENTRY$[4]=X2**-8
        LET ENTRY$[5]=X2&:FF
        EXIT SUBROUTINE
END
        IF COL(0)>1 THEN
          INPUT   "" DISK$
          PRINT   "Find bad clusters V1.1a Copyright (C) 1983 Software Dynamics"
        ELSE
          PRINT   "Find bad clusters V1.1a Copyright (C) 1983 Software Dynamics"
          INPUT "Find bad clusters on which disk drive? " DISK$
        FI
        PRINT
        PRINT   "This program takes a long time to thoroughly test "; DISK$
        PRINT   "Please be patient."
        PRINT

        OPEN    #DISK, DISK$
        OPEN    #DISKMAP, DISK$ CAT "DISKMAP.SYS"
        OPEN    #DIRECTORY, DISK$ CAT "DIRECTORY.SYS"

!       NOW, FIND BADCLUSTERS.SYS

        ENTRY=-1
        REPEAT
700             ENTRY=ENTRY+1
!               RESTORE #DIRECTORY, ENTRY*32
                READ    #DIRECTORY, NAME$, ENTRY$
                IF EOF(DIRECTORY)
                THEN
                        PRINT "No BADCLUSTERS.SYS! Bye!"
                        EXIT
                FI
        UNLESS ENTRY$[HCSIC-15]>0 AND NAME$="BADCLUSTERS.SYS " END

!       READ DISKMAP SO WE CAN TEST UNALLOCATED CLUSTERS
        RESTORE #DISKMAP, 0
        READ    #DISKMAP, DISKMAP$
        IF      NOT(EOF(DISKMAP)) THEN
                Print "Size of DISKMAP.SYS is >2048 bytes! I quit."
                EXIT
        FI


        CALL    SYSCALL(GETSTAT$,NULL$,STAT$)

        NBPS    =STAT$[STATNBPS]*256+STAT$[STATNBPS+1]

        RESTORE #DISK, 0
        READ    #DISK, BOOT$

        NBPC    =NBPS*BOOT$[BOOTNSPC]
        NSPC    =BOOT$[BOOTNSPC]

        NLCN    =INT(((STAT$[STATNSPT]*256+STAT$[STATNSPT+1])* ...
&               (STAT$[STATNTPC]*256+STAT$[STATNTPC+1])* ...
&               (STAT$[STATNCYL]*256+STAT$[STATNCYL+1]))/ ...
&               NSPC)

        FOR     I=1 TO NBPS
                ZEROS$[I]=:A5
                FF$[I]  =:FF
        NEXT    I
        LEN(ZEROS$)=NBPS
        LEN(FF$)=NBPS
        LEN(SECTOR$)=NBPS

        CALL    SYSCALL(UNLOCK$)



        PRINT   "Disk Parameters: NBPS=";NBPS;" NLCN=";NLCN;" NSPC=";NSPC
!
!       M A I N   L O O P S
!       HERE WE SCAN ACROSS THE DISK, WRITING INTO ALL UNALLOCATED CLUSTERS.
!       THEN WE SCAN ACROSS THE DISK, READING EVERY CLUSTER.
!


        ON ERROR GOTO 100

!       WRITE INTO ALL UNALLOCATED CLUSTERS
        PRINT "Disk Write Phase."
        LCN=0
        REPEAT
                IF LCNALLOCATED(LCN) THEN 13
                REM FILL AN UNALLOCATED CLUSTER
                FOR J=0 TO NSPC-1
11                      POSITION #DISK@LCN*NBPC+J*NBPS
                        CALL SYSCALL(WRITEB$,ZEROS$)
                NEXT J
13              LCN=LCN+1
12      UNLESS LCN>=NLCN END

!       NOW SCAN ACROSS DISK, READING ALL CLUSTERS
        PRINT "Disk Read Phase."
        LCN=0
        REPEAT
                REM READ THE SECTORS IN THE CLUSTER
                IF LCNALLOCATED(LCN)
                THEN
                        FOR J=0 TO NSPC-1
21                              POSITION #DISK,LCN*NBPC+J*NBPS
                                CALL SYSCALL(READB$,NULL$,SECTOR$[1,NBPS])
                        NEXT J
                ELSE
                        FOR J=0 TO NSPC-1
22                              POSITION #DISK,LCN*NBPC+J*NBPS
                                CALL SYSCALL(READB$,NULL$,SECTOR$[1,NBPS])
                                IF SECTOR$[1,NBPS]<>ZEROS$
                                THEN
                                        PRINT "*** WRONG DATA RETREIVED ***"
                                        ERROR 1045
                                FI
                        NEXT J
                FI
                LCN=LCN+1
23      UNLESS LCN>=NLCN END
!
!       A REALLY THOROUGH TEST WOULD NOW REPEAT THE ABOVE WRITE/READ PROCESS,
!       WITH "ZEROS$" INTITZED TO $5A, BUT THAT IS NOT THE PURPOSE HERE.
!
1000    ! DISK SCANS COMPLETED, NOW UPDATE BADCLUSTERS.SYS
        IF      BADLCNCOUNT=0
        THEN    PRINT   "No bad lcns found!" \ EXIT
        Print   BADLCNCOUNT; " Bad Clusters were found."

        ON ERROR GOTO 0

!       FIX UP DISK MAP
        RESTORE #DISKMAP, 0

        SYSCALL #DISKMAP,CCSETFILEPROT$,NOPROTECT$
        WRITE   #DISKMAP, DISKMAP$
        SYSCALL #DISKMAP,CCSETFILEPROT$,WBPROTECT$

1010    ! ATTACK THAT HEADER!
        ! FIND DUPLICATES ALREADY LISTED IN BADCLUSTERS
        RESTORE #DISK, NBPC*BADCLUSTERSHLCN
        REM SCAN THRU LCNS IN ALL INITZED HEADER CLUSTER SECTORS
        FOR I=1 TO BADCLUSTERSHCSIC*NBPS/2
                REM READ AN LCN BYTE PAIR
                READ #DISK,TWOB$
                REM SEE IF LCN FOUND IN BADCLUSTERS IS IN BADLCNS LIST
                FOR J=1 TO BADLCNCOUNT
                        IF BADLCNS(J)=TWOB$[1]**8+TWOB$[2]
                        THEN
                                REM IT IS, TAKE IT OUT OF BADLCNS LIST
                                BADLCNS(J)=BADLCNS(BADLCNCOUNT)
                                BADLCNCOUNT=BADLCNCOUNT-1
                                REM IF NONE REMAIN, JUST QUIT
                                REM ELSE EXAMINE NEXT LCN FROM BADCLUSTERS
                                IF BADLCNCOUNT=0 THEN EXIT ELSE CYCLE I
                        FI
                NEXT J
        NEXT I
1020    REM BADLCNS NOW CONTAINS LIST OF UNDUPLICATED BADLCNS
        REM NOW HUNT FOR PLACES IN BADCLUSTERS.SYS TO PUT BADLCNS
        FOR BADCLUSTERSHEADERSCAN=0 TO NSPC*NBPS STEP 2
1023            IF BADCLUSTERSHEADERSCAN/2/NBPS>BADCLUSTERSHCSIC
                THEN
                        REM WE MUST EXTEND BADCLUSTERS HCSIC
                        IF BADCLUSTERSHCSIC=NSPC
                        THEN
                                PRINT "BADCLUSTERS.SYS is full! Some bad clusters lost."
                                EXIT BADCLUSTERSHEADERSCAN
                        FI
                        REM OK TO EXTEND
                        POSITION #DISK,NBPC*BADCLUSTERSHLCN+BADCLUSTERSHCSIC*NBPS
                        FOR I=0 TO NBPS/2
                                WRITE #DISK,DUMMYLCN$
                        NEXT I
                        LET BADCLUSTERSHCSIC=BADCLUSTERSHCSIC+1
                FI
1026            POSITION #DISK,NBPC*BADCLUSTERSHLCN+BADCLUSTERSHEADERSCAN
                READ #DISK,TWOB$
                IF TWOB$[1]*256+TWOB$[2]=:FFFF
                THEN
                        REM THIS IS THE PLACE!
                        POSITION #DISK,NBPC*BADCLUSTERSHLCN+BADCLUSTERSHEADERSCAN
                        LET TWOB$[1]=BADLCNS[BADLCNCOUNT]**-8
                        LET TWOB$[2]=BADLCNS[BADLCNCOUNT]&:FF
                        WRITE #DISK,TWOB$
                        LET BADCLUSTERSNLCN=BADCLUSTERSNLCN+1
                        LET BADLCNCOUNT=BADLCNCOUNT-1
                        IF BADLCNCOUNT=0 THEN EXIT BADCLUSTERSHEADERSCAN
                FI
        NEXT BADCLUSTERSHEADERSCAN
        RESTORE #DIRECTORY, ENTRY*32+16
        SYSCALL #DIRECTORY,CCSETFILEPROT$,NOPROTECT$
        WRITE   #DIRECTORY, ENTRY$
        SYSCALL #DIRECTORY,CCSETFILEPROT$,WBPROTECT$

        PRINT "SDOSDISKVALIDATE should now be performed on "; DISK$
        EXIT

100     ! MAGIC ERROR RECOVERY CODE!!
        IF      ERR=1047 THEN
          BADLCN = LCN
          GOTO 103
        FI
        IF      ERR<1045 OR ERR>1046 THEN ERROR
        IF      ELN<>11 AND ELN<>21 AND ELN<>22 THEN ERROR

101        CALL    SYSCALL(GETBADLSN$,NULL$,BADLSN$)

102        BADLSN  =BADLSN$[1]*65536+BADLSN$[2]*256+BADLSN$[3]
        BADLCN  =INT(BADLSN/NSPC)

!        PRINT "BADLSN= ";BADLSN
!        PRINT "NSPC= ";NSPC

        REM MARK THE BAD CLUSTER AS ALLOCATED

!       PRINT "BADLCN= ";BADLCN

103        DISKMAP$[1+INT(BADLCN/8)]=DISKMAP$[1+INT(BADLCN/8)]!1**(BADLCN&:7)

        REM REMEMBER THE BADLCN
        FOR I=1 TO BADLCNCOUNT
104                IF BADLCNS(I)=BADLCN THEN 150
        NEXT I
        REM THIS IS A NEW BADLCN
        IF BADLCNCOUNT>=LEN(BADLCNS)
        THEN
                PRINT "Bad LCN lost because too many found to save."
        ELSE
                BADLCNCOUNT=BADLCNCOUNT+1
105                BADLCNS(BADLCNCOUNT)=BADLCN
        FI
110     PRINT   "Sector ";HEX$(INT(BADLSN/256));HEX$(BADLSN-INT(BADLSN/256)*256)[4,2];
        PRINT   " is Bad (=LCN ";HEX$(BADLCN);")"


150     IF      BADLSN>LCN*NSPC+J
        THEN
                ! ERROR CAUSED BY WRITE OCCURRED DURING READ PASS, RE-DO THE READ
                GOTO ELN
        FI
        REM ADVANCE PAST THIS BAD CLUSTER, AND REPEAT
        LCN     =BADLCN+1
155        IF ELN=11 THEN 12 ELSE 23

        END

