REM    SDOSDISKVALIDATE, PASS 2
REM    FINDS A DIRECTORY.SYS OR PUTS ONE THERE

REM    7/21/80    MODIFIED FOR BASICV1.4G
REM    1/30/81    MODIFIED FOR BASIC14H
REM               INSTALLED THOROUGH DIRECTORY.SYS ENTRY REPAIR
REM    12/23/82   MODIFIED FOR SDOS 1.1G

REM    11/29/83   Version updated from 1.1g to 1.1h to match
REM               all modules, no changes made otherwise. (RCW)

    PROGRAM ORIGIN :3600

    DATA ORIGIN :2E00

    COMMON Q$[34],DEVICE$[20],FNAME$[16],FNAME2$[16],OP$[12],DIR$[32]
    COMMON DIR2$[32],DEVDIR$[30]
    COMMON BYTE$[1],TWOB$[2],MINUS1$[2]
    COMMON NBPS,NLSN,NLCN,NSPC,HEADERBYTE,HCN,HCN2,HCSIC,HCSIC2
    COMMON MODF,MOD2F,DISMOUNT$[4],UNPROT$[4]
    COMMON NSPT,NTPC,NCYL,NOTBADS,NLCNS,NLCNS2,STAT$[23]
    COMMON SETMAP$[8],BUFFER$[20],BUFAD$[2]
    COMMON UNPROT2$[3]
    COMMON MAXFSIZE,GETPOS$[14],HCN$[2],HCSIC$[1],LCNS$[2],FSIZE$[4]
    COMMON PROT$[1],EMPTY$[6],PROT,FSIZE,CKSUM,BYTES,BAD,KILL,POS
    COMMON AZ$[27]
    COMMON PER09$[11]
    COMMON OPTIONS

    REM COMMON BETWEEN SDOSVALIDATE 1 AND SDOSVALIDATE 2
    COMMON BADLSN$[3],DIRLSN
    COMMON UPDATEBOOT/0/,FFFFFF$[3]
    COMMON FFFF$[2],ERTYPE

    REM LOCAL VARIABLES
    DIM BOOT$(512),BOOTDIRLSN/28/
        ! NOTE: MAXLEN(BOOT$) MUST BE >= NSPC
    DIM HEXDIGITS$/"0123456789ABCDEF"/
    DIM DIRECTORYDOTSYS$/"DIRECTORY.SYS   "/
    DIM DUMPBUFFERS$/:E,4,1,1/

    DEF MSB(X1)=INT(X1/256)
    DEF LSB(X2)=INT(X2-256*MSB(X2))

DEF INVALIDANSWER(ANSWER$)
    REM IS THAT A GOOD RESPONSE????
    IF ANSWER$=""
    THEN RETURN FALSE
    ELSE
        LET ANSWER$=UPPERCASE$(ANSWER$)[1,1] \  REM DON'T CARE ABOUT "ES" OR "O" OR ....
        RETURN ANSWER$<>"N" AND ANSWER$<>"Y"
    FI
END

DEF MAPALGORITHM=BOOT$[23]**8+BOOT$[24]

SUBROUTINE SETMAPALGORITHM(NEWMAPALGORITHM)
    LET BOOT$[23]=MSB(NEWMAPALGORITHM)
    LET BOOT$[24]=LSB(NEWMAPALGORITHM)
    RETURN SUBROUTINE
END
!^L
100 PRINT    "(200) SDOSDISKVALIDATE pass 2 V1.1h"
    REM OPEN THE DISK SELECTED, DISABLE WRITE PROTECT AND SET THE MAP
    OPEN #1,DEVICE$
    SYSCALL #1,DISMOUNT$
    SYSCALL #1,UNPROT$
    LET LEN(BOOT$)=NBPS
    READ #1@0,BOOT$[1,NBPS] \ ! GET MAP ALGORITHM
    SYSCALL #1,SETMAP$,BOOT$[23,2]

    IF OPTIONS<>0 THEN READDIRENTRY
SHOWBOOTPARAMETERS:
    PRINT "(201) NLSN=";NLSN;"NLCN=";NLCN;"BOOT:NSPC=";NSPC;
    PRINT "BOOT:MAPALGORITHM=";HEX$(MAPALGORITHM)
!^L
READDIRENTRY: REM READ PURPORTED DIRECTORY.SYS DIRECTORY ENTRY
    IF ERROR WHEN
        READ #1@DIRLSN*NBPS,FNAME$,HCN$,HCSIC$,LCNS$,FSIZE$,PROT$,EMPTY$
        HCN=HCN$[1]*256+HCN$[2]
        HCSIC=HCSIC$[1]
        NLCNS=LCNS$[1]**8+LCNS$[2]
        LET FILESIZE=(FSIZE$[1]**8+FSIZE$[2])*65536+FSIZE$[3]**8+FSIZE$[4]
        UPDATEDIRECTORYSYSENTRY=FALSE
    THEN
        IF ERR=1045
        THEN
            PRINT "(212) Disk Read Error occurred trying to read DIRECTORY.SYS directory entry."
            REPEAT
                INPUT "      Retry the Read (default=YES)? " Q$
            WHEN INVALIDANSWER(Q$) END
            IF Q$<>"Y" THEN READDIRENTRY
            REPEAT
                INPUT "(213) Write on sector, and then attempt reconstruction? " Q$
            WHEN INVALIDANSWER(Q$) END
            IF Q$="Y"
            THEN
                LET LEN(BOOT$)=NBPS
                LET BOOT$[1,NBPS]=DIRECTORYDOTSYS$
                WRITE #1@DIRLSN*NBPS,BOOT$
                SYSCALL #1,DUMPBUFFERS$\! FORCE SDOS TO DO THE WRITE
                READ #1@0,BOOT$[1,NBPS] \ ! RESTORE BOOT$ TO ORIGINAL STATE
                GOTO READDIRENTRY
            ELSE TRYCHANGEBOOTDIRLSN
        ELSE ERROR
    FI
!^L
    IF FNAME$=DIRECTORYDOTSYS$ THEN DIRECTORYSYSENTRYFOUND
70  PRINT "(202) Can't locate DIRECTORY.SYS directory entry."
    CALL PRINTANYCOULDBECAUSE
    PRINT "      The text 'DIRECTORY.SYS   ' in the directory entry is damaged."
    PRINT "      (This is the text found there: '";
    FOR I=1 TO LEN(FNAME$)
        IF FNAME$(I)&:7F>=:20 THEN PRINT FNAME$(I,1); ELSE PRINT "."; FI
    NEXT I
    PRINT "')"
    CALL PRINTDIRLSNORMAPISWRONG
    REPEAT
        PRINT "(209) Write the characters 'DIRECTORY.SYS   ' in the directory entry? ";
        INPUT "" Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="Y"
    THEN
        WRITE #1@DIRLSN*NBPS,DIRECTORYDOTSYS$
        GOTO READDIRENTRY
    FI
!^L
TRYCHANGEBOOTDIRLSN: REM FIND OUT IF USER WANTS TO CHANGE BOOT:DIRLSN
    REPEAT
        INPUT "(216) Change BOOT:DIRLSN? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$<>"Y" THEN TRYCHANGEMAPALGORITHM
    LET TEMP=INT(NLCN/2)*NSPC
    PRINT "      (Value used by SDOSDISKINIT with NSPC=";NSPC;" is near ";...
&         HEX$(MSB(TEMP));HEX$(LSB(TEMP))[4,2];")"
CHANGEBOOTDIRLSN:  REM USER DOESN'T LIKE BOOT:DIRLSN
    REPEAT
        PRINT "(217) Do you know what BOOT:DIRLSN should be? ";
        INPUT "" Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="N"
    THEN
        REM OPERATOR DOESN'T KNOW WHAT BOOT:DIRLSN SHOULD BE
        PRINT "      The following values for BOOT:DIRLSN might work:"
        FOR TEMP=0 TO NCYL*NTPC*NSPT-1
            READ #1@TEMP*NBPS,FNAME$,HCN$,HCSIC$,LCNS$
            IF FNAME$=DIRECTORYDOTSYS$
            THEN
                PRINT HEX$(MSB(TEMP));HEX$(LSB(TEMP))[4,2];
                GOSUB PRINTPOSSIBLEDIRECTORYENTRY
            FI
        NEXT TEMP
    FI
ENTERDIRLSN:
    INPUT "      Enter new value for BOOT:DIRLSN (default=No change): " Q$
    IF LEN(Q$)>0
    THEN
        LET Q$=UPPERCASE$(Q$)
        LET DIRLSN=0
        FOR I=1+(Q$[1]=ASC(":")) TO LEN(Q$)
            LET HEXDIGIT=FIND(HEXDIGITS$,Q$[I,1])
            IF HEXDIGIT=0 THEN DIRLSN=0\EXIT I
            ELSE DIRLSN=DIRLSN*16+HEXDIGIT-1
        NEXT I
    FI
    IF DIRLSN<2^24 THEN
        BOOT$[BOOTDIRLSN]=MSB(MSB(DIRLSN))
        BOOT$[BOOTDIRLSN+1]=LSB(MSB(DIRLSN))
        BOOT$[BOOTDIRLSN+2]=LSB(DIRLSN)
    ELSE ENTERDIRLSN FI
    GOTO UPDATEBOOTCHECKSUM
!^L
TRYCHANGEMAPALGORITHM: REM ASK USER IF HE WANTS TO FOOL WITH MAP
    REPEAT
          INPUT "(203) Change BOOT:MAPALGORITHM? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$<>"Y"
    THEN PRINT "(211) No Directory, SDOSDISKVALIDATE terminated."\ERROR 104
111 REPEAT
        INPUT "(206) Do you know the correct value for BOOT:MAPALGORITHM? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="Y" THEN 112
    PRINT "      Try one of the following values:"
    FOUNDAMAP=FALSE
    FOR PASS=1 TO 2
        FOR SPIRAL=0 TO NSPT-1
            FOR LATENCY=0 TO NSPT-1
                BOOT$[23]=SPIRAL\BOOT$[24]=LATENCY
                SYSCALL #1, SETMAP$,BOOT$[23,2]
                READ #1@DIRLSN*NBPS,FNAME$,HCN$,HCSIC$,LCNS$
                IF FNAME$=DIRECTORYDOTSYS$
                THEN
                    IF PASS=1
                    THEN
                        LET LCN=HCN$[1]**8+HCN$[2]
                        IF 0<LCN AND LCN<NLCN
                        THEN
                            READ #1@LCN*NSPC*NBPS,TWOB$
                            IF HCN$=TWOB$
                            THEN
                                FOUNDAMAP=TRUE
                                PRINT HEX$(SPIRAL**8+LATENCY);
                                GOSUB PRINTPOSSIBLEDIRECTORYENTRY
                            FI
                        FI
                    ELSE
                        PRINT HEX$(SPIRAL**8+LATENCY);
                        GOSUB PRINTPOSSIBLEDIRECTORYENTRY
                    FI
                FI
            NEXT LATENCY
        NEXT SPIRAL
        IF FOUNDAMAP THEN EXIT PASS
    NEXT PASS
112 INPUT "(204) Enter new value for BOOT:MAPALGORITHM: " MAPALGORITHM
    REM SELECT NEW MAP
    SYSCALL #1,SETMAP$,BOOT$[23,2]
UPDATEBOOTCHECKSUM:
    OPTIONS=2 \ ! YOU CHANGED THE MAP, YOU GET TO VERIFY EVERYTHING
    UPDATEBOOT=1
    GOTO SHOWBOOTPARAMETERS

PRINTPOSSIBLEDIRECTORYENTRY: ! Print possible DIRECTORY.SYS info
    Print " (DIR:HLCN=";Hex$(HCN$[1]**8+HCN$[2]);...
&         " DIR:HCSIC=";HCSIC$(1);...
&         "DIR:NCLUSTERS=";LCNS$[1]**8+LCNS$[2];")"
    Return
!^L
DIRECTORYSYSENTRYFOUND: REM FOUND THE FILENAME "DIRECTORY.SYS " WHERE IT WAS EXPECTED
    PRINT "(221) DIRECTORY.SYS directory entry apparantly located."
    IF HCSIC=0 OR NLCNS=0 THEN DIRECTORYSYSENTRYISGHOST
    IF NLCNS>INT(NLSN/NSPC) THEN DIRECTORYSYSNLCNSTOOBIG
    IF HCN=0 OR HCN>=NLCN THEN DIRECTORYSYSENTRYBADHCN
    RESTORE #1,HCN*NBPS*NSPC
    READ #1,TWOB$
    LCN=TWOB$[1]*256+TWOB$[2]
    IF HCN<>LCN THEN DIRECTORYSYSHEADERDOESNTSELFPOINT
    IF HCSIC>NSPC THEN DIRECTORYSYSHCSICISBAD
    REM SCAN PURPORTED DIRECTORY.SYS HEADER CLUSTER, COUNT LCNS
    REM CHECK THAT BOOT:DIRLSN IS MENTIONED BY SOME LCN
    DIRLSNINCLUDED=FALSE
    SPARSEDIRECTORY=FALSE
    ACTUALNLCNS=1
    FOR I=1 TO HCSIC*NBPS/2-1
        READ #1,TWOB$
        LET LCN=TWOB$[1]**8+TWOB$[2]
        IF LCN<>:FFFF
        THEN
            REM VALID LCN, COUNT IT
            ACTUALNLCNS=ACTUALNLCNS+1
            IF LCN=INT(DIRLSN/NSPC) THEN DIRLSNINCLUDED=TRUE FI
         ELSE IF ACTUALNLCNS<NLCNS THEN SPARSEDIRECTORY=TRUE
    NEXT I
    IF DIRLSNINCLUDED=FALSE THEN DIRECTORYSYSDOESNTCONTAINDIRLSN
    IF ACTUALNLCNS<>NLCNS THEN DIRECTORYSYSNLCNSWRONG
    IF SPARSEDIRECTORY THEN DIRECTORYISSPARSE
    IF FILESIZE>(HCSIC*NBPS/2-1)*NSPC*NBPS THEN DIRECTORYSYSTOOBIG
    IF FILESIZE/(NSPC*NBPS)<>INT(FILESIZE/(NSPC*NBPS))
    THEN DIRECTORYSIZENOTMULTIPLEOFCLUSTERSIZE
    IF FILESIZE<NSPC*NBPS THEN DIRECTORYISTOOSMALL
    REM IF WE GET HERE, THEN SDOS SHOULD HAVE NO TROUBLE OPENING DIRECTORY.SYS
    REM ANYTHING ELSE WRONG WITH DIRECTORY.SYS CAN BE FIXED BY ...PAS4
    PRINT "(222) DIRECTORY.SYS directory entry is now valid."
!^L
17  IF UPDATEBOOT
    THEN
        REPEAT
            INPUT "(218) Update Boot Sector? " Q$
        WHEN INVALIDANSWER(Q$) END
        IF Q$="Y"
        THEN
            BOOT$[18]=NSPC
            BOOT$[28]=MSB(MSB(DIRLSN))
            BOOT$[29]=LSB(MSB(DIRLSN))
            BOOT$[30]=LSB(DIRLSN)
            GOSUB COMPUTECHECKSUM
            BOOT$[32]=CKSUM
            WRITE #1@0,BOOT$[1,NBPS]
        FI
    FI
    IF UPDATEDIRECTORYSYSENTRY=TRUE
    THEN
        PRINT "(214) Updating DIRECTORY.SYS directory entry"
        HCN$(1)=MSB(HCN)\HCN$(2)=LSB(HCN)
        HCSIC$(1)=HCSIC
        LCNS$(1)=MSB(NLCNS)\LCNS$(2)=LSB(NLCNS)
        FSIZE$[1]=MSB(MSB(MSB(FILESIZE)))
        FSIZE$[2]=LSB(MSB(MSB(FILESIZE)))
        FSIZE$[3]=LSB(MSB(FILESIZE))
        FSIZE$[4]=LSB(FILESIZE)
        LET LEN(PROT$)=1
        LET LEN(EMPTY$)=6
        WRITE #1@DIRLSN*NBPS+16,HCN$,HCSIC$,LCNS$,FSIZE$,PROT$,EMPTY$
        OPTIONS=2
    FI
    PRINT "(219) Chaining to SDOSDISKVAL.PAS3"
    CHAIN "SDOSDISKVAL.PAS3"
!^L
UPDATEDIRECTORYENTRY: UPDATEDIRECTORYSYSENTRY=TRUE
    GOTO DIRECTORYSYSENTRYFOUND

SUBROUTINE PRINTANYCOULDBECAUSE
    PRINT "      Any of the following MIGHT be the cause:"
    RETURN SUBROUTINE
END

SUBROUTINE PRINTDIRLSNORMAPISWRONG
    PRINT "      BOOT:DIRLSN (";HEX$(MSB(DIRLSN));HEX$(LSB(DIRLSN))[4,2];...
&         ") might be wrong."
    PRINT "      BOOT:MAPALGORITHM (";HEX$(MAPALGORITHM);") might be wrong."
    RETURN SUBROUTINE
END

SUBROUTINE PRINTNSPCWRONG
    PRINT "      BOOT:NSPC (";NSPC;") might be incorrect."
    RETURN SUBROUTINE
END

SUBROUTINE PRINTNLCNSWRONG(LCNSWRONGMSG$,HCSICARG)
    REM DISPLAYS MESSAGE, COMPUTES ACTUAL NUMBER OF LCNS IN HEADER
    ACTUALNLCNS=0
    IF HCN>=NLCN THEN PRINT LCNSWRONGMSG$;" unknown number)."
    ELSE
        POSITION #1@HCN*NSPC*NBPS
        FOR HEADERDISPLACEMENT=0 TO HCSICARG*NBPS/2-1
            READ #1,TWOB$
            LET LCN=TWOB$[1]**8+TWOB$[2]
            IF LCN<>:FFFF
            THEN
                REM VALID LCN, COUNT IT
                ACTUALNLCNS=ACTUALNLCNS+1
            FI
        NEXT HEADERDISPLACEMENT
        PRINT LCNSWRONGMSG$;ACTUALNLCNS;")."
    FI
    RETURN SUBROUTINE
END

SUBROUTINE PRINTNLCNSWRONGHCSICOK
    PRINTNLCNSWRONG(...
&      "      DIR:NCLUSTERS is damaged and needs reconstruction (Header has",HCSIC)
    RETURN SUBROUTINE
END

SUBROUTINE PRINTHCSICISDAMAGED
    PRINT "      DIR:HCSIC value (";HCSIC;") is damaged."
    RETURN SUBROUTINE
END

SUBROUTINE PRINTHCNISDAMAGED
    PRINT "      DIR:HLCN is damaged (";HEX$(HCN);")."
    RETURN SUBROUTINE
END

SUBROUTINE PRINTFILESIZEISDAMAGED
    PRINT "      DIR:FILESIZE (";FILESIZE;"bytes) is damaged."
    RETURN SUBROUTINE
END
!^L
DEF USERFIXEDNLCNS
    REPEAT
        INPUT "(237) Change DIR:NCLUSTERS owned by DIRECTORY.SYS? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$<>"Y" THEN RETURN FALSE
    INPUT "(238) Enter new value for DIR:NCLUSTERS: " NLCNS
    RETURN TRUE
END

DEF USERFIXEDNSPC
    REPEAT
        INPUT "(205) Change BOOT:NSPC? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$<>"Y" THEN RETURN FALSE
    INPUT "(215) Enter new value for BOOT:NSPC: " NSPC
    LET NLCN=INT(NLSN/NSPC)
    UPDATEBOOT=TRUE
    RETURN TRUE
END

DEF USERFIXEDHCN
    REPEAT
        INPUT "(208) Change DIR:HCN of DIRECTORY.SYS directory entry? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="Y" THEN
        PRINT "      Enter new value for DIR:HCN (default=";...
&             HEX$(INT(NLCN/2)-1);"): ";
        INPUT "" Q$
        IF Q$=""
        THEN HCN=INT(NLCN/2)-1
        ELSE HCN=VAL(Q$)
        RETURN TRUE
    ELSE RETURN FALSE
END
!^L
DEF USERFIXEDHCSIC
    REPEAT
        INPUT "(223) Change DIR:HCSIC (Reasonable value is 1)? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$<>"Y" THEN RETURN FALSE
    INPUT "      Enter new value for DIR:HCSIC: " HCSIC
    RETURN TRUE
END

DEF USERFIXEDFILESIZE
    REPEAT
        PRINT "(232) Change DIR:FILESIZE (a reasonable value is";...
&             NBPS*NSPC*(NLCNS-1);")? ";
        INPUT "" Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$<>"Y" THEN RETURN FALSE
    INPUT "(233) Enter new DIR:FILESIZE for DIRECTORY.SYS: " FILESIZE
    RETURN TRUE
END
!^L
DIRECTORYSYSENTRYISGHOST: REM HCSIC=0 OR NLCNS=0
    PRINT "(239) DIRECTORY.SYS directory entry has DIR:HCSIC=0 or DIR:NCLUSTERS=0."
    PRINTANYCOULDBECAUSE
    IF HCSIC=0
    THEN
        PRINT "      DIR:HCSIC was accidentally zeroed (is normally 1)."
        TEMP=1
    ELSE TEMP=HCSIC
    IF NLCNS=0
    THEN PRINTNLCNSWRONG("      DIR:NCLUSTERS was accidentally zeroed (Header has",TEMP)
    PRINTDIRLSNORMAPISWRONG
    IF HCSIC=0
    THEN
        REPEAT INPUT "(240) Set DIR:HCSIC to 1? " Q$ WHEN INVALIDANSWER(Q$) END
        IF Q$="Y" THEN HCSIC=1\GOTO UPDATEDIRECTORYENTRY
    FI
!   The following two lines apply only if DIR:NCLUSTERS>0 --> file exists
!   IF NLCNS>0 OR USERFIXEDNLCNS THEN UPDATEDIRECTORYENTRY
!   ELSE TRYCHANGEBOOTDIRLSN
    GOTO TRYCHANGEBOOTDIRLSN

DIRECTORYSYSNLCNSTOOBIG: REM HCSIC>0 AND NLCNS>0
    REM NLCNS>INT(NLSN/NSPC)
    IF HCN=0 OR HCN>=NLCN THEN DIRECTORYSYSENTRYBADHCN
    PRINT "(225) DIR:NCLUSTERS of DIRECTORY.SYS directory entry has too many clusters."
    PRINTANYCOULDBECAUSE
    PRINTNLCNSWRONGHCSICOK
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDNLCNS THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN
!^L
DIRECTORYSYSENTRYBADHCN: REM HCN=0 OR HCN>=NLCN
    REM HCSIC>0 AND NLCNS>0
    PRINT "(220) DIR:HLCN contains an illegal cluster number (";
    PRINT HEX$(HCN);")."
    PRINTANYCOULDBECAUSE
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    REM WHY CAN'T WE SEARCH FOR HEADER CONTAINING BOOT:DIRLSN?
    IF USERFIXEDHCN THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN

DIRECTORYSYSHEADERDOESNTSELFPOINT: REM DIRECTORY.SYS HEADER IS WRONG
    REM HCSIC>0 AND NLCNS>0
    REM 0<HCN<NLCN
    PRINT "(207) DIRECTORY.SYS Header Cluster doesn't contain own LCN as 1st LCN."
    PRINTANYCOULDBECAUSE
    PRINTNSPCWRONG
    PRINTHCNISDAMAGED
    PRINT "      The 1st LCN of the Header Cluster (";HEX$(LCN);...
&         " might be damaged."
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDNSPC THEN READDIRENTRY
    IF USERFIXEDHCN THEN UPDATEDIRECTORYENTRY
    REPEAT
       INPUT "(210) Set 1st LCN of DIRECTORY.SYS Header Cluster to DIR:HLCN? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="Y" THEN
         REM USER BELEIVES HEADER WAS AT PROPER PLACE
         REM MAKE HEADER POINT BACK TO ITSELF
         TWOB$[1]=MSB(HCN)
         TWOB$[2]=LSB(HCN)
         WRITE #1@HCN*NBPS*NSPC,TWOB$
         GOTO DIRECTORYSYSENTRYFOUND
    ELSE TRYCHANGEBOOTDIRLSN

DIRECTORYSYSHCSICISBAD: REM HCSIC>NSPC
    REM HCSIC>0 AND NLCNS>0
    REM 0<HCN<NLCN
    REM PURPORTED DIRECTORY HEADER DOES POINT TO SELF
    REM 0<HCN<NLCN
    PRINT "(245) DIR:HCSIC of DIRECTORY.SYS directory entry is larger than BOOT:NSPC."
    PRINTANYCOULDBECAUSE
    PRINTHCSICISDAMAGED
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDHCSIC THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN
!^L
DIRECTORYSYSDOESNTCONTAINDIRLSN: REM HCN POINTS TO HEADER CLUSTER
    REM HEADER CLUSTER SELF POINTS CORRECTLY
    PRINT "(241) Header Cluster for DIRECTORY.SYS doesn't include BOOT:DIRLSN."
    PRINTANYCOULDBECAUSE
    PRINT "      LCN for BOOT:DIRLSN in Header Cluster is damaged."
    PRINTHCNISDAMAGED
    PRINTHCSICISDAMAGED
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    REPEAT
        LET LCN=INT(DIRLSN/NSPC)
        PRINT "(242) Add cluster ";HEX$(LCN);
        INPUT " (containing BOOT:DIRLSN) to DIRECTORY.SYS Header? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="Y"
    THEN
        REM SIGH... FIND A FREE CLUSTER SLOT AND STEP ON IT
        POSITION #1@HCN*NSPC*NBPS
        FOR HEADERDISPLACEMENT=0 TO HCSIC*NBPS-2 STEP 2
            READ #1,TWOB$
            LET TEMP=TWOB$[1]**8+TWOB$[2]
            IF TEMP=:FFFF
            THEN
                REM FOUND A PLACE!
                LET TWOB$[1]=MSB(LCN)\TWOB$[2]=LSB(LCN)
                WRITE #1@HCN*NSPC*NBPS+HEADERDISPLACEMENT,TWOB$
                LET NLCNS=NLCNS+1
                GOTO DIRECTORYSYSENTRYFOUND
            FI
        NEXT HEADERDISPLACEMENT
        REM DAMN! WE HAVE TO EXTEND THE DIRECTORY.SYS HEADER
        PRINT "(243) Must increase DIR:HCSIC to add new cluster."
    FI
    IF USERFIXEDHCN THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDHCSIC THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN
!^L
DIRECTORYSYSNLCNSWRONG: REM ACTUAL CLUSTER COUNT DOESN'T MATCH DIRECTORY ENTRY
    PRINT "(244) DIR:NCLUSTERS (";NLCNS;") for DIRECTORY.SYS <> number LCNs in Header."
    PRINTANYCOULDBECAUSE
    PRINTNLCNSWRONGHCSICOK
    PRINTHCNISDAMAGED
    PRINTHCSICISDAMAGED
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDNLCNS THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDHCN THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDHCSIC THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN

DIRECTORYSYSTOOBIG: REM FILESIZE IS TOO LARGE FOR CLUSTER SIZE
    PRINT "(230) DIR:FILESIZE for DIRECTORY.SYS is too large for current cluster size."
    PRINTANYCOULDBECAUSE
    PRINTFILESIZEISDAMAGED
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDFILESIZE THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN

DIRECTORYSIZENOTMULTIPLEOFCLUSTERSIZE: REM NEED I SAY MORE?
    PRINT "(231) DIR:FILESIZE of DIRECTORY.SYS is not a multiple of cluster size (";NSPC*NBPS;")."
    PRINTANYCOULDBECAUSE
    PRINTFILESIZEISDAMAGED
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDFILESIZE THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN
!^L
DIRECTORYISSPARSE: REM HEADER HAS GAPS
    PRINT "(234) DIRECTORY.SYS is a Sparse file."
    PRINTANYCOULDBECAUSE
    PRINT "      Header Cluster is damaged (Pass 4 can fix this problem)."
    PRINTHCSICISDAMAGED
    PRINTNSPCWRONG
    PRINTDIRLSNORMAPISWRONG
    REPEAT
        INPUT "(235) Allocate Cluster at point of sparseness? " Q$
    WHEN INVALIDANSWER(Q$) END
    IF Q$="Y"
    THEN
        POSITION #1@HCN*NSPC*NBPS
        FOR HEADERDISPLACEMENT=0 TO HCSIC*NBPS/2-1 STEP 2
            LET TEMP=LCN+1
            READ #1,TWOB$\LCN=TWOB$[1]**8+TWOB$[2]
            IF LCN=:FFFF
            THEN
                PRINT "      An appropriate contiguous cluster number is ";HEX$(TEMP);"."
                INPUT "(236) Enter cluster number to allocate: " LCN
                LET TWOB$[1]=MSB(LCN)\TWOB$[2]=LSB(LCN)
                WRITE #1@HCN*NSPC*NBPS+HEADERDISPLACEMENT,TWOB$
                GOTO DIRECTORYSYSENTRYFOUND
            FI
        NEXT HEADERDISPLACEMENT
    FI
    IF USERFIXEDHCSIC THEN UPDATEDIRECTORYENTRY
    IF USERFIXEDNSPC THEN READDIRENTRY ELSE TRYCHANGEBOOTDIRLSN
!^L
DIRECTORYISTOOSMALL: REM NLCNS DOESN'T ALLOW ANY DIRECTORY DATA!
    PRINT "(224) DIR:NCLUSTERS (1) for DIRECTORY.SYS directory entry is too small."
    PRINTANYCOULDBECAUSE
    PRINTNLCNSWRONGHCSICOK
    PRINTDIRLSNORMAPISWRONG
    IF USERFIXEDNLCNS THEN UPDATEDIRECTORYENTRY ELSE TRYCHANGEBOOTDIRLSN

COMPUTECHECKSUM: REM COMPUTE CHECKSUM OVER BOOT SECTOR
    CKSUM=0
    FOR I=17 TO 31 DO CKSUM=CKSUM+BOOT$[I]
    CKSUM=:FF XOR (CKSUM&:FF)
    RETURN

    END
