TITLE CHKPROC - Procedures called from chkdsk FALSE EQU 0 TRUE EQU NOT FALSE DRVCHAR EQU ":" INCLUDE DOSSYM.ASM SUBTTL Segments used in load order CODE SEGMENT PUBLIC CODE ENDS CONST SEGMENT PUBLIC BYTE EXTRN CLUSBAD:BYTE,BADATT:BYTE,BADSIZM:BYTE EXTRN DIRECMES:BYTE,CDDDMES:BYTE,NDOTMES:BYTE EXTRN BADTARG1:BYTE,BADTARG2:BYTE,FATALMES:BYTE EXTRN STACKMES:BYTE,BADDPBDIR:BYTE,CREATMES:BYTE EXTRN FREEBYMES_PRE:BYTE,FREEBYMESF_PRE:BYTE EXTRN FREEBYMES_POST:BYTE,FREEBYMESF_POST:BYTE EXTRN NULNZ:BYTE,NULDMES:BYTE,BADCLUS:BYTE EXTRN NORECDDOT:BYTE,NORECDOT:BYTE,DOTMES:BYTE EXTRN BADWRITE_PRE:BYTE,BADCHAIN:BYTE,CROSSMES_PRE:BYTE EXTRN BADWRITE_POST:BYTE,CROSSMES_POST:BYTE,INDENT:BYTE EXTRN PTRANDIR:BYTE,PTRANDIR2:BYTE,FREEMES:BYTE,FIXMES:BYTE EXTRN NOISY:BYTE,DOFIX:BYTE,DIRBUF:WORD,DOTENT:BYTE,FIXMFLG:BYTE EXTRN HAVFIX:BYTE,SECONDPASS:BYTE,LCLUS:WORD,DIRTYFAT:BYTE EXTRN NUL:BYTE,ALLFILE:BYTE,PARSTR:BYTE,ERRSUB:WORD,USERDIR:BYTE EXTRN HIDCNT:WORD,HIDSIZ:WORD,FILCNT:WORD,FILSIZ:WORD,DIRCHAR:BYTE EXTRN DIRCNT:WORD,DIRSIZ:WORD,FRAGMENT:BYTE,HECODE:BYTE EXTRN BADSIZ:WORD,ORPHSIZ:WORD,DDOTENT:BYTE,CROSSCNT:WORD EXTRN ORPHCNT:WORD,ORPHFCB:BYTE,ORPHEXT:BYTE,ALLDRV:BYTE,DIRCHAR:BYTE CONST ENDS DATA SEGMENT PUBLIC WORD EXTRN THISDPB:DWORD,HARDCH:DWORD,CONTCH:DWORD,USERDEV:BYTE EXTRN CSIZE:BYTE,SSIZE:WORD,DSIZE:WORD,MCLUS:WORD,NAMBUF:BYTE EXTRN DOTSNOGOOD:BYTE,ZEROTRUNC:BYTE,ISCROSS:BYTE,SRFCBPT:WORD EXTRN FATMAP:WORD,SECBUF:WORD,ERRCNT:BYTE,STACKLIM:WORD,FAT:WORD DATA ENDS DG GROUP CODE,CONST,DATA SUBTTL Initialized Data PAGE CODE SEGMENT PUBLIC ASSUME CS:DG,DS:DG,ES:DG,SS:DG PUBLIC INT_23,INT_24,FINDCHAIN,DONE,AMDONE,RDONE PUBLIC FATAL,DIRPROC,CHKMAP,CHKCROSS,UNPACK PUBLIC PRINTTHISEL2,CHECKERR,PRINTCURRDIRERR EXTRN EPRINT:NEAR,DOCRLF:NEAR,PRINT:NEAR EXTRN PROMPTYN:NEAR,DOINT26:NEAR,SUBERRP:NEAR EXTRN DOTCOMBMES:NEAR,DISP16BITS:NEAR EXTRN CHAINREPORT:NEAR,DISPCLUS:NEAR EXTRN PRTCHR:NEAR,WDSKERR:NEAR,CHECKFILES:NEAR EXTRN FCB_TO_ASCZ:NEAR,FIGREC:NEAR,RDSKERR:NEAR CHKPROC: SUBTTL DIRPROC -- Recursive directory processing ; YOU ARE ADVISED NOT TO COPY THE FOLLOWING METHOD!!! DOTDOTHARDWAY: LDS DI,[THISDPB] ASSUME DS:NOTHING MOV [DI.dpb_current_dir],-1 ;Invalidate path MOV SI,DI ADD SI,dpb_dir_text MOV CX,SI FINDEND: LODSB ;Scan to end of current path OR AL,AL JNZ FINDEND DEC SI ;Point at the NUL DELLOOP: ;Delete last element CMP SI,CX JZ SETROOT CMP BYTE PTR [SI],"/" JZ SETTERM CMP BYTE PTR [SI],"\" JZ SETTERM DEC SI JMP SHORT DELLOOP SETTERM: MOV BYTE PTR [SI],0 SETCURR: PUSH CS POP DS ASSUME DS:DG MOV DX,OFFSET DG:DOTMES MOV AH,CHDIR ;Chdir to altered path INT 21H RET SETROOT: ASSUME DS:NOTHING MOV [DI.dpb_current_dir],0 ;Set Path to Root JMP SHORT SETCURR ;The CHDIR will fail, but who cares ;Structures used by DIRPROC SRCHFCB STRUC DB 44 DUP (?) SRCHFCB ENDS SFCBSIZ EQU SIZE SRCHFCB THISENT EQU 17H ;Relative entry number of current entry DIRENT STRUC DB 7 DUP (?) ;Ext FCB junk DB ? ;Drive DIRNAM DB 11 DUP (?) DIRATT DB ? DB 10 DUP (?) DIRTIM DW ? DIRDAT DW ? DIRCLUS DW ? DIRESIZ DD ? DIRENT ENDS ENTSIZ EQU SIZE DIRENT ;Attribute bits RDONLY EQU 1 HIDDN EQU 2 SYSTM EQU 4 VOLIDA EQU 8 ISDIR EQU 10H ASSUME DS:DG NODOT: ;No . PUSH AX ;Return from SRCH CMP [NOISY],0 JNZ DOEXTMES1 CALL SUBERRP JMP SHORT MESD1 DOEXTMES1: MOV SI,OFFSET DG:DOTMES CALL PRINTCURRDIRERR MOV DX,OFFSET DG:NDOTMES CALL EPRINT MESD1: XOR AX,AX PUSH BX PUSH BP CALL GETENT POP BP PUSH BP CMP BYTE PTR [DI],0E5H ;Have place to put .? JNZ CANTREC ;Nope MOV SI,OFFSET DG:DOTENT MOV CX,11 REP MOVSB ;Name PUSH AX MOV AL,ISDIR STOSB ;Attribute ADD DI,10 XOR AX,AX STOSW ;Date = 0 STOSW ;Time = 0 MOV AX,[BP+6] STOSW ;Alloc # XOR AX,AX STOSW STOSW ;Size POP AX MOV [HAVFIX],1 ;Have a fix CMP [DOFIX],0 JZ DOTGOON ;No fix if not F MOV CX,1 CALL DOINT26 JMP SHORT DOTGOON CANTREC: INC [DOTSNOGOOD] CMP [NOISY],0 JZ DOTGOON MOV DX,OFFSET DG:NORECDOT CALL EPRINT DOTGOON: POP BP POP BX POP AX MOV SI,OFFSET DG:DIRBUF JMP CHKDOTDOT ;Go look for .. NODDOT: ;No .. PUSH AX ;Return from SRCH CMP [NOISY],0 JNZ DOEXTMES2 CALL SUBERRP JMP SHORT MESD2 DOEXTMES2: MOV SI,OFFSET DG:PARSTR CALL PRINTCURRDIRERR MOV DX,OFFSET DG:NDOTMES CALL EPRINT MESD2: MOV AX,1 PUSH BX PUSH BP CALL GETENT POP BP PUSH BP CMP BYTE PTR [DI],0E5H ;Place to put it? JNZ CANTREC2 ;Nope MOV SI,OFFSET DG:DDOTENT MOV CX,11 REP MOVSB ;Name PUSH AX MOV AL,ISDIR STOSB ;Attribute ADD DI,10 XOR AX,AX STOSW ;Date STOSW ;Time MOV AX,[BP+4] STOSW ;Alloc # XOR AX,AX STOSW STOSW ;Size POP AX MOV [HAVFIX],1 ;Got a fix CMP [DOFIX],0 JZ NFIX ;No fix if no F, carry clear MOV CX,1 CALL DOINT26 NFIX: POP BP POP BX POP AX MOV SI,OFFSET DG:DIRBUF JMP ROOTDIR ;Process files CANTREC2: POP BP POP BX POP AX CMP [NOISY],0 JZ DOTSBAD MOV DX,OFFSET DG:NORECDDOT CALL EPRINT JMP DOTSBAD NULLDIRERR: CMP [NOISY],0 JNZ DOEXTMES3 CALL SUBERRP JMP SHORT DOTSBAD DOEXTMES3: MOV SI,OFFSET DG:NUL CALL PRINTCURRDIRERR MOV DX,OFFSET DG:NULDMES CALL EPRINT DOTSBAD: ;Can't recover MOV DX,OFFSET DG:BADTARG2 CALL EPRINT CALL DOTDOTHARDWAY INC [DOTSNOGOOD] JMP DIRDONE ;Terminate tree walk at this level ROOTDIRJ: JMP ROOTDIR PAGE DIRPROC: ;Recursive tree walker ;dirproc(self,parent) MOV [DOTSNOGOOD],0 ;Init to dots OK MOV [ERRSUB],0 ;No subdir errors yet PUSH BP ;Save frame pointer MOV BP,SP SUB SP,SFCBSIZ ;Only local var CMP SP,[STACKLIM] JA STACKISOK MOV BX,OFFSET DG:STACKMES ;Out of stack JMP FATAL STACKISOK: CMP [NOISY],0 JZ NOPRINT CMP [SECONDPASS],0 JNZ NOPRINT ;Don't do it again on second pass MOV DX,OFFSET DG:DIRECMES ;Tell user where we are CALL PRINT MOV SI,OFFSET DG:NUL CALL PRINTCURRDIR CALL DOCRLF NOPRINT: MOV SI,OFFSET DG:ALLFILE MOV DI,SP PUSH DI MOV CX,SFCBSIZ REP MOVSB ;Initialize search FCB POP DX MOV BX,DX ;BX points to SRCH FCB MOV AH,DIR_SEARCH_FIRST INT 21H CMP WORD PTR [BP+6],0 ;Am I the root JZ ROOTDIRJ ;Yes, no . or .. OR AL,AL JZ NONULLDERR JMP NULLDIRERR ;Dir is empty! NONULLDERR: MOV SI,OFFSET DG:DIRBUF + DIRNAM MOV DI,OFFSET DG:DOTENT MOV CX,11 REP CMPSB JZ DOTOK ;Got a . as first entry JMP NODOT ;No . DOTOK: MOV SI,OFFSET DG:DIRBUF MOV AL,[SI.DIRATT] TEST AL,ISDIR JNZ DATTOK PUSH SI ;. not a dir? MOV SI,OFFSET DG:DOTMES MOV DX,OFFSET DG:BADATT CALL DOTCOMBMES POP SI OR [SI.DIRATT],ISDIR CALL FIXENT ;Fix it DATTOK: MOV AX,[SI.DIRCLUS] CMP AX,[BP+6] ;. link = MYSELF? JZ DLINKOK PUSH SI ;Link messed up MOV SI,OFFSET DG:DOTMES MOV DX,OFFSET DG:CLUSBAD CALL DOTCOMBMES POP SI MOV AX,[BP+6] MOV [SI.DIRCLUS],AX CALL FIXENT ;Fix it DLINKOK: MOV AX,WORD PTR [SI.DIRESIZ] OR AX,AX JNZ BADDSIZ MOV AX,WORD PTR [SI.DIRESIZ+2] OR AX,AX JZ DSIZOK BADDSIZ: ;Size should be zero PUSH SI MOV SI,OFFSET DG:DOTMES MOV DX,OFFSET DG:BADSIZM CALL DOTCOMBMES POP SI XOR AX,AX MOV WORD PTR [SI.DIRESIZ],AX MOV WORD PTR [SI.DIRESIZ+2],AX CALL FIXENT ;Fix it DSIZOK: ;Get next (should be ..) MOV DX,BX MOV AH,DIR_SEARCH_NEXT INT 21H CHKDOTDOT: ;Come here after . failure OR AL,AL JZ DOTDOTOK NODDOTJ: JMP NODDOT ;No .. DOTDOTOK: MOV SI,OFFSET DG:DIRBUF + DIRNAM MOV DI,OFFSET DG:DDOTENT MOV CX,11 REP CMPSB JNZ NODDOTJ ;No .. MOV SI,OFFSET DG:DIRBUF MOV AL,[SI.DIRATT] TEST AL,ISDIR JNZ DDATTOK ;.. must be a dir PUSH SI MOV SI,OFFSET DG:PARSTR MOV DX,OFFSET DG:BADATT CALL DOTCOMBMES POP SI OR [SI.DIRATT],ISDIR CALL FIXENT ;Fix it DDATTOK: PUSH SI MOV AX,[SI.DIRCLUS] CMP AX,[BP+4] ;.. link must be PARENT JZ DDLINKOK MOV SI,OFFSET DG:PARSTR MOV DX,OFFSET DG:CLUSBAD CALL DOTCOMBMES POP SI MOV AX,[BP+4] MOV [SI.DIRCLUS],AX CALL FIXENT ;Fix it DDLINKOK: MOV AX,WORD PTR [SI.DIRESIZ] OR AX,AX JNZ BADDDSIZ MOV AX,WORD PTR [SI.DIRESIZ+2] OR AX,AX JZ DDSIZOK BADDDSIZ: ;.. size should be 0 PUSH SI MOV SI,OFFSET DG:PARSTR MOV DX,OFFSET DG:BADSIZM CALL DOTCOMBMES POP SI XOR AX,AX MOV WORD PTR [SI.DIRESIZ],AX MOV WORD PTR [SI.DIRESIZ+2],AX CALL FIXENT ;Fix it DDSIZOK: MOV DX,BX ;Next entry MOV AH,DIR_SEARCH_NEXT INT 21H ROOTDIR: ;Come here after .. failure also OR AL,AL JZ MOREDIR ;More to go CMP WORD PTR [BP+6],0 ;Am I the root? JZ DIRDONE ;Yes, no chdir MOV DX,OFFSET DG:PARSTR MOV AH,CHDIR ;Chdir to parent (..) INT 21H JNC DIRDONE ;Worked CMP [NOISY],0 JZ DODDH MOV SI,OFFSET DG:NUL CALL PRINTCURRDIRERR MOV DX,OFFSET DG:CDDDMES CALL EPRINT DODDH: CALL DOTDOTHARDWAY ;Try again DIRDONE: MOV SP,BP ;Pop local vars POP BP ;Restore frame RET 4 ;Pop args MOREDIR: MOV SI,OFFSET DG:DIRBUF TEST [SI.DIRATT],ISDIR JNZ NEWDIR ;Is a new directory CMP [SECONDPASS],0 JZ FPROC1 ;First pass CALL CROSSLOOK ;Check for cross links JMP DDSIZOK ;Next FPROC1: CMP [NOISY],0 JZ NOPRINT2 MOV DX,OFFSET DG:INDENT ;Tell user where we are CALL PRINT PUSH BX MOV BX,SI CALL PRINTTHISEL CALL DOCRLF MOV SI,BX POP BX NOPRINT2: MOV AL,81H ;Head of file CALL MARKFAT TEST [SI.DIRATT],VOLIDA JNZ HIDENFILE ;VOL ID counts as hidden TEST [SI.DIRATT],HIDDN JZ NORMFILE HIDENFILE: INC [HIDCNT] ADD [HIDSIZ],CX JMP DDSIZOK ;Next NORMFILE: INC [FILCNT] ADD [FILSIZ],CX JMP DDSIZOK ;Next NEWDIR: CMP [SECONDPASS],0 JZ DPROC1 CALL CROSSLOOK ;Check for cross links JMP SHORT DPROC2 DPROC1: MOV AL,82H ;Head of dir CALL MARKFAT INC [DIRCNT] ADD [DIRSIZ],CX CMP [ZEROTRUNC],0 JZ DPROC2 ;Dir not truncated CONVDIR: AND [SI.DIRATT],NOT ISDIR ;Turn into file CALL FIXENT JMP DDSIZOK ;Next DPROC2: PUSH [ERRSUB] PUSH BX ;Save my srch FCB pointer PUSH [SI.DIRCLUS] ;MYSELF for next directory PUSH [BP+6] ;His PARENT is me ADD SI,DIRNAM MOV DI,OFFSET DG:NAMBUF PUSH DI CALL FCB_TO_ASCZ POP DX MOV AH,CHDIR ;CHDIR to new dir INT 21H JC CANTTARG ;Barfed CALL DIRPROC POP BX ;Get my SRCH FCB pointer back POP [ERRSUB] CMP [DOTSNOGOOD],0 JNZ ASKCONV JMP DDSIZOK ;Next CANTTARG: POP AX ;Clean stack POP AX POP AX POP AX PUSH DX ;Save pointer to bad DIR MOV DX,OFFSET DG:BADTARG1 CALL EPRINT POP SI ;Pointer to bad DIR CALL PRINTCURRDIRERR MOV DX,OFFSET DG:BADTARG2 CALL EPRINT DDSIZOKJ: JMP DDSIZOK ;Next ASKCONV: CMP [SECONDPASS],0 JNZ DDSIZOKJ ;Leave on second pass MOV DX,OFFSET DG:PTRANDIR CMP [NOISY],0 JNZ PRINTTRMES MOV DX,OFFSET DG:PTRANDIR2 PRINTTRMES: CALL PROMPTYN ;Ask user what to do JNZ DDSIZOKJ ;User say leave alone PUSH BP PUSH BX MOV AX,[BX+THISENT] ;Entry number CALL GETENT ;Get the entry MOV SI,DI MOV DI,OFFSET DG:DIRBUF PUSH DI ADD DI,DIRNAM MOV CX,32 REP MOVSB ;Transfer entry to DIRBUF POP SI PUSH SI MOV SI,[SI.DIRCLUS] ;First cluster CALL GETFILSIZ POP SI POP BX POP BP MOV WORD PTR [SI.DIRESIZ],AX ;Fix entry MOV WORD PTR [SI.DIRESIZ+2],DX JMP CONVDIR SUBTTL FAT Look routines PAGE CROSSLOOK: ;Same as MRKFAT only simpler for pass 2 MOV [SRFCBPT],BX MOV BX,SI MOV SI,[BX.DIRCLUS] CALL CROSSCHK JNZ CROSSLINKJ CHLP: PUSH BX CALL UNPACK POP BX XCHG SI,DI CMP SI,0FF8H JAE CHAINDONEJ CALL CROSSCHK JZ CHLP CROSSLINKJ: JMP SHORT CROSSLINK CROSSCHK: MOV DI,[FATMAP] ADD DI,SI MOV AH,[DI] TEST AH,10H RET NOCLUSTERSJ: JMP NOCLUSTERS MARKFAT: ; Map the file and perform checks ; SI points to dir entry ; AL is head mark with app type ; On return CX is number of clusters ; BX,SI preserved ; ZEROTRUNC is non zero if the file was trimmed to zero length ; ISCROSS is non zero if the file is cross linked MOV [ZEROTRUNC],0 ;Initialize MOV [ISCROSS],0 MOV [SRFCBPT],BX MOV BX,SI XOR CX,CX MOV SI,[BX.DIRCLUS] CMP SI,2 JB NOCLUSTERSJ ;Bad cluster # or nul file (SI = 0) CMP SI,[MCLUS] JA NOCLUSTERSJ ;Bad cluster # PUSH BX CALL UNPACK POP BX JZ NOCLUSTERSJ ;Bad cluster (it is marked free) CALL MARKMAP JNZ CROSSLINK AND AL,7FH ;Turn off head bit CHASELOOP: PUSH BX CALL UNPACK POP BX INC CX XCHG SI,DI CMP SI,0FF8H JAE CHAINDONE CMP SI,2 JB MRKBAD CMP SI,[MCLUS] JBE MRKOK MRKBAD: ;Bad cluster # in chain PUSH CX PUSH DI CALL PRINTTHISELERR MOV DX,OFFSET DG:BADCHAIN CALL EPRINT POP SI MOV DX,0FFFH ;Insert EOF PUSH BX CALL PACK POP BX POP CX CHAINDONEJ: JMP SHORT CHAINDONE MRKOK: CALL MARKMAP JZ CHASELOOP CROSSLINK: ;File is cross linked INC [ISCROSS] CMP [SECONDPASS],0 JZ CHAINDONE ;Crosslinks only on second pass PUSH SI ;Cluster number CALL PRINTTHISEL CALL DOCRLF MOV DX,OFFSET DG:CROSSMES_PRE CALL PRINT POP SI PUSH BX PUSH CX MOV BX,OFFSET DG:CROSSMES_POST XOR DI,DI CALL DISP16BITS POP CX POP BX CHAINDONE: TEST [BX.DIRATT],ISDIR JNZ NOSIZE ;Don't size dirs CMP [ISCROSS],0 JNZ NOSIZE ;Don't size cross linked files CMP [SECONDPASS],0 JNZ NOSIZE ;Don't size on pass 2 (CX garbage) MOV AL,[CSIZE] XOR AH,AH MUL [SSIZE] PUSH AX ;Size in bytes of one alloc unit MUL CX MOV DI,DX ;Save allocation size MOV SI,AX SUB AX,WORD PTR [BX.DIRESIZ] SBB DX,WORD PTR [BX.DIRESIZ+2] JC BADFSIZ ;Size to big OR DX,DX JNZ BADFSIZ ;Size to small POP DX CMP AX,DX JB NOSIZE ;Size within one Alloc unit PUSH DX ;Size to small BADFSIZ: POP DX PUSH CX ;Save size of file MOV WORD PTR [BX.DIRESIZ],SI MOV WORD PTR [BX.DIRESIZ+2],DI CALL FIXENT2 ;Fix it CALL PRINTTHISELERR MOV DX,OFFSET DG:BADCLUS CALL EPRINT POP CX ;Restore size of file NOSIZE: MOV SI,BX MOV BX,[SRFCBPT] RET NOCLUSTERS: ;File is zero length OR SI,SI JZ CHKSIZ ;Firclus is OK, Check size MOV DX,OFFSET DG:NULNZ ADJUST: PUSH DX CALL PRINTTHISELERR POP DX CALL EPRINT XOR SI,SI MOV [BX.DIRCLUS],SI ;Set it to 0 MOV WORD PTR [BX.DIRESIZ],SI ;Set size too MOV WORD PTR [BX.DIRESIZ+2],SI CALL FIXENT2 ;Fix it INC [ZEROTRUNC] ;Indicate truncation JMP CHAINDONE CHKSIZ: MOV DX,OFFSET DG:BADCLUS CMP WORD PTR [BX.DIRESIZ],0 JNZ ADJUST ;Size wrong CMP WORD PTR [BX.DIRESIZ+2],0 JNZ ADJUST ;Size wrong JMP CHAINDONE ;Size OK UNPACK: ;Cluster number in SI, Return contents in DI, BX destroyed ;ZERO SET IF CLUSTER IS FREE MOV BX,OFFSET DG:FAT MOV DI,SI SHR DI,1 ADD DI,SI MOV DI,WORD PTR [DI+BX] TEST SI,1 JZ HAVCLUS SHR DI,1 SHR DI,1 SHR DI,1 SHR DI,1 HAVCLUS: AND DI,0FFFH RET PACK: ; SI CLUSTER NUMBER TO BE PACKED ; DX DATA TO BE PLACED IN CLUSTER (SI) ; BX,DX DESTROYED MOV [DIRTYFAT],1 ;Set FAT dirty byte MOV [HAVFIX],1 ;Indicate a fix MOV BX,OFFSET DG:FAT PUSH SI MOV DI,SI SHR SI,1 ADD SI,BX ADD SI,DI SHR DI,1 MOV DI,[SI] JNC ALIGNED SHL DX,1 SHL DX,1 SHL DX,1 SHL DX,1 AND DI,0FH JMP SHORT PACKIN ALIGNED: AND DI,0F000H PACKIN: OR DI,DX MOV [SI],DI POP SI RET MARKMAP: ; Mark in AL ; Cluster in SI ; AL,SI,CX preserved ; ZERO RESET IF CROSSLINK, AH IS THE MARK THAT WAS THERE MOV DI,[FATMAP] ADD DI,SI MOV AH,[DI] OR AH,AH PUSH AX JZ SETMARK MOV AL,AH INC [CROSSCNT] ;Count the crosslink OR AL,10H ;Resets zero SETMARK: MOV [DI],AL POP AX RET CHKMAP: ;Compare FAT and FATMAP looking for badsectors orphans MOV SI,[FATMAP] INC SI INC SI MOV DX,2 MOV CX,[DSIZE] CHKMAPLP: LODSB OR AL,AL JNZ CONTLP ;Already seen this one XCHG SI,DX CALL UNPACK XCHG SI,DX JZ CONTLP ;Free cluster CMP DI,0FF7H ;Bad sector? JNZ ORPHAN ;No, found an orphan INC [BADSIZ] MOV BYTE PTR [SI-1],4 ;Flag it JMP CONTLP ORPHAN: INC [ORPHSIZ] MOV BYTE PTR [SI-1],8 ;Flag it CONTLP: INC DX ;Next cluster LOOP CHKMAPLP MOV SI,[ORPHSIZ] OR SI,SI JZ RET18 ;No orphans CALL RECOVER RET18: RET RECOVER: ;free orphans or do chain recovery CALL CHECKNOFMES CALL DOCRLF CALL CHAINREPORT MOV DX,OFFSET DG:FREEMES CALL PROMPTYN ;Ask user JNZ NOCHAINREC JMP CHAINREC NOCHAINREC: MOV SI,[FATMAP] ;Free all orphans INC SI INC SI MOV DX,2 MOV CX,[DSIZE] CHKMAPLP2: LODSB TEST AL,8 JZ NEXTCLUS XCHG SI,DX PUSH DX XOR DX,DX CALL PACK ;Mark as free POP DX XCHG SI,DX NEXTCLUS: INC DX LOOP CHKMAPLP2 XOR AX,AX XCHG AX,[ORPHSIZ] PUSH AX MOV DX,OFFSET DG:FREEBYMESF_PRE CMP [DOFIX],0 JNZ PRINTFMES MOV DX,OFFSET DG:FREEBYMES_PRE PRINTFMES: CALL PRINT POP AX MOV BX,OFFSET DG:FREEBYMESF_POST CMP [DOFIX],0 JNZ DISPFRB MOV BX,OFFSET DG:FREEBYMES_POST MOV [LCLUS],AX DISPFRB: CALL DISPCLUS ;Tell how much freed RET FINDCHAIN: ;Do chain recovery on orphans MOV SI,[FATMAP] INC SI INC SI MOV DX,2 MOV CX,[DSIZE] CHKMAPLP3: LODSB TEST AL,8 ;Orphan? JZ NEXTCLUS2 ;Nope TEST AL,1 ;Seen before ? JNZ NEXTCLUS2 ;Yup PUSH SI ;Save search environment PUSH CX PUSH DX DEC SI OR BYTE PTR [SI],81H ;Mark as seen and head INC [ORPHCNT] ;Found a chain MOV SI,DX CHAINLP: CALL UNPACK XCHG SI,DI CMP SI,0FF8H JAE CHGOON ;EOF PUSH DI CMP SI,2 JB INSERTEOF ;Bad cluster number CMP SI,[MCLUS] JA INSERTEOF ;Bad cluster number CMP SI,DI JZ INSERTEOF ;Tight loop CALL CROSSCHK TEST AH,8 ;Points to a non-orphan? JNZ CHKCHHEAD ;Nope INSERTEOF: POP SI ;Need to stick EOF here MOV DX,0FFFH CALL PACK JMP SHORT CHGOON CHKCHHEAD: TEST AH,80H ;Previosly marked head? JZ ADDCHAIN ;Nope AND BYTE PTR [DI],NOT 80H ;Turn off head bit DEC [ORPHCNT] ;Wasn't really a head POP DI ;Clean stack JMP SHORT CHGOON ADDCHAIN: TEST AH,1 ;Previosly seen? JNZ INSERTEOF ;Yup, don't make a cross link OR BYTE PTR [DI],1 ;Mark as seen POP DI ;Clean stack JMP CHAINLP ;Follow chain CHGOON: POP DX ;Restore search POP CX POP SI NEXTCLUS2: INC DX LOOP CHKMAPLP3 RET CHAINREC: LDS DI,[THISDPB] ASSUME DS:NOTHING MOV CX,[DI.dpb_root_entries] PUSH CS POP DS ASSUME DS:DG MOV SI,[FATMAP] INC SI INC SI MOV DI,1 CALL NEXTORPH PUSH SI PUSH DI MOV SI,DI XOR AX,AX MOV DX,[ORPHCNT] MAKFILLP: PUSH AX PUSH CX PUSH DX PUSH SI CALL GETENT POP SI CMP BYTE PTR [DI],0E5H JZ GOTENT CMP BYTE PTR [DI],0 JNZ NEXTENT GOTENT: MOV [HAVFIX],1 ;Making a fix CMP [DOFIX],0 JZ ENTMADE ;Not supposed to, carry clear MOV [DI+26],SI ;FIRCLUS Pointer PUSH AX ;Save INT 26 data PUSH DX PUSH BX MOV AH,DISK_RESET ;Force current state INT 21H MOV DX,OFFSET DG:ORPHFCB MOV AH,FCB_OPEN OPAGAIN: INT 21H OR AL,AL JNZ GOTORPHNAM CALL MAKORPHNAM ;Try next name JMP SHORT OPAGAIN GOTORPHNAM: MOV SI,OFFSET DG:ORPHFCB + 1 ;ORPHFCB Now has good name MOV CX,11 REP MOVSB CALL MAKORPHNAM ;Make next name XOR AX,AX MOV CX,15 REP STOSB MOV SI,[DI] INC DI ;Skip FIRCLUS INC DI PUSH DI CALL GETFILSIZ POP DI STOSW MOV AX,DX STOSW POP BX POP DX POP AX MOV CX,1 CALL DOINT26 ENTMADE: POP DX POP CX POP AX POP DI POP SI DEC DX OR DX,DX JZ RET100 CALL NEXTORPH PUSH SI PUSH DI MOV SI,DI JMP SHORT NXTORP NEXTENT: POP DX POP CX POP AX NXTORP: INC AX LOOP MAKFILLPJ POP AX ;Clean Stack POP AX SUB [ORPHCNT],DX ;Couldn't make them all MOV DX,OFFSET DG:CREATMES CALL EPRINT RET100: RET MAKFILLPJ: JMP MAKFILLP NEXTORPH: PUSH AX LODSB INC DI CMP AL,89H POP AX JZ RET100 JMP SHORT NEXTORPH MAKORPHNAM: PUSH SI MOV SI,OFFSET DG:ORPHEXT - 1 NAM0: INC BYTE PTR [SI] CMP BYTE PTR [SI],'9' JLE NAMMADE MOV BYTE PTR [SI],'0' DEC SI JMP NAM0 NAMMADE: POP SI RET GETFILSIZ: ;SI is start cluster, returns filesize as DX:AX XOR AX,AX NCLUS: CALL UNPACK XCHG SI,DI INC AX CMP SI,0FF8H JAE GOTEOF CMP SI,2 JAE NCLUS GOTEOF: MOV BL,[CSIZE] XOR BH,BH MUL BX MUL [SSIZE] RET CHKCROSS: ;Check for Crosslinks, do second pass if any to find pairs MOV SI,[CROSSCNT] OR SI,SI JZ RET8 ;None CALL DOCRLF INC [SECONDPASS] XOR AX,AX PUSH AX PUSH AX CALL DIRPROC ;Do it again RET8: RET SUBTTL AMDONE - Finish up routine PAGE AMDONE: ASSUME DS:NOTHING CMP [DIRTYFAT],0 JZ NOWRITE ;FAT not dirty CMP [DOFIX],0 JZ NOWRITE ;Not supposed to fix REWRITE: LDS BX,[THISDPB] ASSUME DS:NOTHING MOV CL,[BX.dpb_FAT_size] ;Sectors for one fat XOR CH,CH MOV DI,CX MOV CL,[BX.dpb_FAT_count] ;Number of FATs MOV DX,[BX.dpb_first_FAT] ;First sector of FAT PUSH CS POP DS ASSUME DS:DG MOV [ERRCNT],CH MOV BX,OFFSET DG:FAT MOV AL,[ALLDRV] DEC AL MOV AH,'1' PUSH CX WRTLOOP: XCHG CX,DI PUSH DX PUSH CX PUSH DI PUSH AX INT 26H ;Write out the FAT MOV [HECODE],AL POP AX ;Flags JNC WRTOK INC [ERRCNT] MOV DX,OFFSET DG:BADWRITE_PRE CALL PRINT POP AX PUSH AX MOV DL,AH CALL PRTCHR MOV DX,OFFSET DG:BADWRITE_POST CALL PRINT WRTOK: POP AX POP CX POP DI POP DX INC AH ADD DX,DI LOOP WRTLOOP ;Next FAT POP CX ;Number of FATs CMP CL,[ERRCNT] ;Error on all? JNZ NOWRITE ;no CALL WDSKERR JZ REWRITE NOWRITE: MOV AH,DISK_RESET ;Invalidate any buffers in system INT 21H MOV DX,OFFSET DG:USERDIR ;Recover users directory MOV AH,CHDIR INT 21H CMP BYTE PTR [FRAGMENT],1 ;Check for any fragmented files? JNZ DONE ;No -- we're finished CALL CHECKFILES ;Yes -- report any fragments DONE: ASSUME DS:NOTHING MOV DL,[USERDEV] ;Recover users drive MOV AH,SET_DEFAULT_DRIVE INT 21H RET SUBTTL Routines for manipulating dir entries PAGE FIXENT2: ;Same as FIXENT only [SRFCBPT] points to the search FCB, BX points to the entry PUSH SI PUSH BX PUSH CX MOV SI,BX MOV BX,[SRFCBPT] CALL FIXENT POP CX POP BX POP SI RET20: RET FIXENT: ;BX Points to search FCB ;SI Points to Entry to fix MOV [HAVFIX],1 ;Indicate a fix CMP [DOFIX],0 JZ RET20 ;But don't do it! PUSH BP PUSH BX PUSH SI PUSH SI ;Entry pointer MOV AX,[BX+THISENT] ;Entry number CALL GETENT POP SI ;Entry pointer ADD SI,DIRNAM ;Point to start of entry MOV CX,32 REP MOVSB INC CL CALL DOINT26 POP SI POP BX POP BP RET GETENT: ;AX is desired entry number (in current directory) ; ;DI points to entry in SECBUF ;AX DX BX set to do an INT 26 to write it back out (CX must be reset to 1) ;ALL registers destroyed (via int 25) LDS DI,[THISDPB] ASSUME DS:NOTHING MOV BX,[DI.dpb_current_dir] PUSH CS POP DS ASSUME DS:DG CMP BX,0FF8H JB CLUSISOK MOV BX,OFFSET DG:BADDPBDIR ;This should never happen JMP FATAL CLUSISOK: MOV CL,4 SHL AX,CL XOR DX,DX SHL AX,1 RCL DX,1 ;Account for overflow MOV CX,[SSIZE] AND CL,255-31 ;Must be a multiple of 32 DIV CX ;DX is position in sector, AX is dir sector # OR BX,BX JZ WANTROOT DIV [CSIZE] ;AL # clusters to skip, AH position in cluster MOV CL,AL XOR CH,CH JCXZ GOTCLUS MOV SI,BX SKIPLP: CALL UNPACK XCHG SI,DI LOOP SKIPLP MOV BX,SI GOTCLUS: PUSH DX ;Position in sector CALL FIGREC ;Convert to sector # DOROOTDIR: MOV BX,[SECBUF] MOV AL,[ALLDRV] DEC AL RDRETRY: PUSH AX PUSH DX PUSH BX MOV CX,1 INT 25H ;Read it MOV [HECODE],AL POP AX ;FLAGS POP BX POP DX POP AX JNC RDOK2 CALL RDSKERR JZ RDRETRY RDOK2: POP DI ;Offset into sector ADD DI,BX ;Add sector base offset RET WANTROOT: PUSH DX LDS DI,[THISDPB] ASSUME DS:NOTHING MOV DX,AX ADD DX,[DI.dpb_dir_sector] PUSH CS POP DS ASSUME DS:DG JMP DOROOTDIR CHECKNOFMES: MOV AL,1 XCHG AL,[FIXMFLG] OR AL,AL JNZ RET14 ;Don't print it more than once CMP [DOFIX],0 JNZ RET14 ;Don't print it if F switch specified PUSH DX MOV DX,OFFSET DG:FIXMES CALL PRINT POP DX RET CHECKERR: CALL CHECKNOFMES CMP [SECONDPASS],0 RET14: RET PRINTCURRDIRERR: CALL CHECKERR JNZ RET14 CALL PRINTCURRDIR JMP SHORT ERREX PRINTTHISELERR: CALL CHECKERR JNZ RET14 CALL PRINTTHISEL ERREX: CALL DOCRLF RET PRINTTHISEL: MOV SI,BX ADD SI,DIRNAM PRINTTHISEL2: MOV DI,OFFSET DG:NAMBUF PUSH DI CALL FCB_TO_ASCZ POP SI PRINTCURRDIR: PUSH SI MOV DL,[ALLDRV] ADD DL,'@' CALL PRTCHR MOV DL,DRVCHAR CALL PRTCHR LDS SI,[THISDPB] ASSUME DS:NOTHING CMP [SI.dpb_current_dir],0 JZ CURISROOT MOV DL,[DIRCHAR] CALL PRTCHR ADD SI,dpb_dir_text PCURRLP: LODSB OR AL,AL JZ CURISROOT MOV DL,AL CALL PRTCHR JMP PCURRLP CURISROOT: PUSH CS POP DS ASSUME DS:DG POP SI CMP BYTE PTR [SI],0 JZ LPDONE ;If tail string NUL, no '/' MOV DL,[DIRCHAR] CALL PRTCHR ERRLOOP: LODSB OR AL,AL JZ LPDONE MOV DL,AL CALL PRTCHR JMP ERRLOOP LPDONE: RET FATAL: ;Unrecoverable error MOV DX,OFFSET DG:FATALMES CALL PRINT MOV DX,BX CALL PRINT MOV DL,[USERDEV] ;At least leave on same drive MOV AH,SET_DEFAULT_DRIVE INT 21H INT 20H INT_24_RETADDR DW OFFSET DG:INT_24_BACK INT_24 PROC FAR ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING PUSHF PUSH CS PUSH [INT_24_RETADDR] PUSH WORD PTR [HARDCH+2] PUSH WORD PTR [HARDCH] RET INT_24 ENDP INT_24_BACK: CMP AL,2 ;Abort? JNZ IRETI CALL DONE ;Forget about directory, restore users drive INT 20H IRETI: IRET INT_23: LDS DX,[HARDCH] MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H INT 21H LDS DX,[CONTCH] MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H INT 21H PUSH CS POP DS ASSUME DS:DG MOV [FRAGMENT],0 RDONE: CALL NOWRITE ;Restore users drive and directory INT 20H CODE ENDS END CHKPROC