MS-DOS/v2.0/source/CHKPROC.ASM

1408 lines
40 KiB
NASM
Raw Normal View History

1983-08-13 01:53:34 +01:00
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