1 TITLE CHKDSK
- MS-DOS Disk consistancy checker
4 ; Verifies and repairs MS-DOS disk directory.
7 ; To build CHKDSK you need three modules:
8 ; CHKDSK CHKPROC CHKMES
9 ; They should be linked the that order as well.
15 ; 05/21/82 Added rev number
18 ; Mod by NANCYP to report on extents
19 ; Mod by AARONR to report volume ID
22 ; Total rewrite for directories
25 ; Added ^C and INT 24H handlers
28 ; INTERNATIONAL support
31 ; Split into two modules to allow assembly on a PC
39 ;The following defines the ranges of DOS version numbers for which this CHKDSK
42 DOSVER_LOW EQU
0136H ;1.54 in hex
43 DOSVER_HIGH EQU
020BH ;2.11 in hex
50 ;Drive parameter block from DOS header
52 SUBTTL Segments
used in load order
57 CONST
SEGMENT PUBLIC BYTE
60 DATA SEGMENT PUBLIC WORD
63 DG GROUP
CODE,CONST
,DATA
65 SUBTTL Initialized
Data
67 CONST
SEGMENT PUBLIC BYTE
69 PUBLIC HECODE
,SWITCHAR
,NOISY
,DOFIX
,CONBUF
,ORPHCNT
,ORPHSIZ
,DOFIX
70 PUBLIC HIDCNT
,HIDSIZ
,DIRCNT
,DIRSIZ
,FILCNT
,FILSIZ
,BADSIZ
,LCLUS
71 PUBLIC DOTENT
,HAVFIX
,SECONDPASS
,NUL
,ALLFILE
,PARSTR
,ERRSUB
,LCLUS
72 PUBLIC DIRTYFAT
,BADSIZ
,DDOTENT
,CROSSCNT
,ORPHFCB
,ORPHEXT
,ALLDRV
73 PUBLIC FRAGMENT
,USERDIR
,DIRBUF
,USERDIR
,FIXMFLG
,DOTMES
,DIRCHAR
75 EXTRN IDMES1
:BYTE,IDPOST
:BYTE,VNAME
:BYTE,MONTAB
:BYTE
76 EXTRN TCHAR
:BYTE,BADREAD_PRE
:BYTE,BADREAD_POST
:BYTE
77 EXTRN CRLF
:BYTE,BADVER
:BYTE,BADSUBDIR
:BYTE,CENTRY
:BYTE
78 EXTRN BADDRV
:BYTE,BADCD
:BYTE,BADRDMES
:BYTE,OPNERR
:BYTE
79 EXTRN CONTAINS
:BYTE,EXTENTS
:BYTE,NOEXTENTS
:BYTE
80 EXTRN BADDRVM
:BYTE,BADDRVM2
:BYTE,BADIDBYT
:BYTE
83 DIRBUF
LABEL BYTE ;Entry buffer for searches
84 VOLID
DB -1,0,0,0,0,0,8 ;Volume ID FCB
85 VOLNAM
DB 0,"???????????"
88 ALLFILE
DB -1,0,0,0,0,0,1EH
;Extended FCB
89 ALLDRV
DB 0,"???????????"
92 ORPHFCB
DB 0,"FILE0000"
108 FIXMFLG
DB 0 ;Flag for printing fixmes
109 ERRSUB
DW 0 ;Flag for bad subdir error
110 FRAGMENT
DB 0 ;Flag for extent processing
111 DIRTYFAT
DB 0 ;Dirty flag for FAT
112 DIRCNT
DW 0 ;# directories
113 DIRSIZ
DW 0 ;# alloc units in directories
114 FILCNT
DW 0 ;# reg files
115 FILSIZ
DW 0 ;# alloc units in reg files
116 HIDCNT
DW 0 ;# hidden files
117 HIDSIZ
DW 0 ;# alloc units in hidden files
118 BADSIZ
DW 0 ;# alloc units in bad sectors
119 ORPHCNT
DW 0 ;# orphan files made
120 ORPHSIZ
DW 0 ;# alloc units in orphan files
121 LCLUS
DW 0 ;# alloc units in lost clusters
122 DISPFLG
DB 0 ;used by number routines
123 CROSSCNT
DW 0 ;# crosslinked files (first pass)
124 SECONDPASS
DB 0 ;Pass flag
125 HAVFIX
DB 0 ;non zero if any fixes
126 DOFIX
DB 0 ;flag for F switch
127 NOISY
DB 0 ;flag for V switch
128 USERDIR
DB "/",0 ;Users current dir for drive
129 DB (DIRSTRLEN
-1) DUP (?
)
130 CONBUF
DB 15,0 ;Input buffer
135 SUBTTL Un
-initialized
Data
137 DATA SEGMENT PUBLIC WORD
139 PUBLIC ZEROTRUNC
,NAMBUF
,MCLUS
,THISDPB
,STACKLIM
,ERRCNT
140 PUBLIC SRFCBPT
,ISCROSS
,CSIZE
,DSIZE
,SSIZE
,FAT
,FATMAP
141 PUBLIC HARDCH
,CONTCH
,USERDEV
,SECBUF
,DOTSNOGOOD
143 HARDCH
DD ?
;Pointer to real INT 24 handler
144 CONTCH
DD ?
;Pointer to real INT 23 handler
145 THISDPB
DD ?
;Pointer to drive DPB
146 USERDEV
DB ?
;Users current device
147 CSIZE
DB ?
;Sectors per cluster
148 SSIZE
DW ?
;bytes per sector
149 DSIZE
DW ?
;# alloc units on disk
150 MCLUS
DW ?
;DSIZE + 1
151 NAMBUF
DB 14 DUP (?
) ;Buffer
152 DOTSNOGOOD
DB ?
;. or .. error flag
153 ZEROTRUNC
DB ?
;Trimming flag
154 ISCROSS
DB ?
;Crosslink flag
157 FATMAP
DW OFFSET DG
:FAT
;Offset of FATMAP table
158 SECBUF
DW ?
;Offset of sector buffer
159 ERRCNT
DB ?
;Used by FATread and write
160 STACKLIM
DW ?
;Stack growth limit
162 INTERNATVARS internat_block
<>
163 DB (internat_block_max
- ($ - INTERNATVARS
)) DUP (?
)
169 SUBTTL Start of CHKDSK
172 ASSUME
CS:DG
,DS:DG
,ES:DG
,SS:DG
174 PUBLIC SUBERRP
,DOTCOMBMES
,FIGREC
,FCB_TO_ASCZ
,PRTCHR
,EPRINT
175 PUBLIC PRINT
,DOCRLF
,DISP16BITS
,DISP32BITS
,DISPCLUS
,CHECKFILES
177 EXTRN RDSKERR
:NEAR,SETSWITCH
:NEAR,PROMPTYN
:NEAR,REPORT
:NEAR
178 EXTRN PRINTCURRDIRERR
:NEAR,PRINTTHISEL2
:NEAR,CHECKERR
:NEAR
179 EXTRN INT_23
:NEAR,INT_24
:NEAR,FINDCHAIN
:NEAR,DONE
:NEAR,AMDONE
:NEAR
180 EXTRN FATAL
:NEAR,DIRPROC
:NEAR,CHKMAP
:NEAR,CHKCROSS
:NEAR,UNPACK
:NEAR
191 ;Code to print header.
193 ; MOV DX,OFFSET DG:HEADER
197 PUSH AX ;Save DRIVE validity info
200 XCHG AH,AL ;Turn it around to AH.AL
206 MOV DX,OFFSET DG
:BADVER
210 POP AX ;Get back drive info
214 JAE STACKOK
;Lots of stack
215 MOV DX,DS:[2] ;High break
219 JAE SETSTACK
;Lots to grab
220 MOV CX,4 ;Suck up more stack (blast command)
229 MOV AH,DISK_RESET
;Flush everything, and invalidate
232 CMP AL,0FFH ;Illegal drive specifier?
233 JNZ FILECHK
;No -- check for filename
236 MOV DX,OFFSET DG
:BADDRV
238 PUSH CS ;Make sure DS is OK
240 CALL PRINT
;Print error message
245 CALL DONE
;Reset users disk
250 MOV AX,(CHAR_OPER
SHL 8)
258 CMP DS:(BYTE PTR FCB
+1)," " ;Filename specified?
259 JZ DRVCHK
;No -- get the correct drive
261 CMP DS:(BYTE PTR FCB
+1),AL ;Filename specified?
262 JZ DRVCHK
;No -- get the correct drive
263 MOV BYTE PTR [FRAGMENT
],1 ;Set flag to perform fragment
264 ;check on specified files
266 CALL SETSWITCH
;Look for switches
267 MOV AH,GET_DEFAULT_DRIVE
;Get current drive
269 MOV [USERDEV
],AL ;Save for later
272 MOV BH,DS:(BYTE PTR FCB
) ;See if drive specified
279 MOV [ALLDRV
],AH ;Target drive
280 MOV [VOLNAM
],AH ;A = 1
281 MOV [ORPHFCB
],AH ;A = 1
282 ADD [BADDRVM
],AL ;A = 0
283 ADD [BADDRVM2
],AL ;A = 0
285 MOV AH,GET_DPB
;Get the DPB
289 JNZ DRVISOK
;Bad drive (should always be ok)
290 MOV DX,OFFSET DG
:BADDRV
291 CERROR2J: JMP CERROR2
295 MOV AH,SET_DEFAULT_DRIVE
;Set Target
297 CMP [BX.dpb_current_dir
],0
298 JZ CURRISROOT
;Save users current dir for target
301 MOV DI,OFFSET DG
:USERDIR
+ 1
309 MOV WORD PTR [THISDPB
+2],DS
313 MOV WORD PTR [THISDPB
],BX
314 MOV AX,(GET_INTERRUPT_VECTOR
SHL 8) OR 23H
316 MOV WORD PTR [CONTCH
],BX
317 MOV WORD PTR [CONTCH
+2],ES
318 MOV AX,(SET_INTERRUPT_VECTOR
SHL 8) OR 23H
319 MOV DX,OFFSET DG
:INT_23
321 MOV AX,(GET_INTERRUPT_VECTOR
SHL 8) OR 24H
323 MOV WORD PTR [HARDCH
],BX
324 MOV WORD PTR [HARDCH
+2],ES
325 MOV AX,(SET_INTERRUPT_VECTOR
SHL 8) OR 24H
326 MOV DX,OFFSET DG
:INT_24
330 MOV DX,OFFSET DG
:ROOTSTR
331 MOV AH,CHDIR
;Start at root
333 MOV DX,OFFSET DG
:BADCD
334 JC CERROR2J
;Couldn't get there
335 MOV DX,OFFSET DG
:FAT
;Scratch space
338 MOV DX,OFFSET DG
:VOLID
;Look for VOL ID
339 MOV AH,DIR_SEARCH_FIRST
343 CALL PRINTID
;Have a VOL ID
347 MOV AX,[BX.dpb_sector_size
]
348 MOV [SSIZE
],AX ;Sector size in bytes
349 MOV AL,[BX.dpb_cluster_mask
]
351 MOV [CSIZE
],AL ;Sectros per cluster
352 MOV AX,[BX.dpb_max_cluster
]
353 MOV [MCLUS
],AX ;Bound for FAT searching
355 MOV [DSIZE
],AX ;Total data clusters on disk
356 MOV AL,[BX.dpb_FAT_size
] ;Sectors for one fat
359 MUL [SSIZE
] ;Bytes for FAT
360 ADD [FATMAP
],AX ;Allocate FAT space
364 MOV [SECBUF
],AX ;Allocate FATMAP space
367 MOV [STACKLIM
],AX ;Limit on recursion
369 MOV CL,[BX.dpb_FAT_count
] ;Number of FATs
370 MOV DX,[BX.dpb_first_FAT
] ;First sector of FAT
384 INT 25H
;Read in the FAT
388 MOV DX,OFFSET DG
:BADREAD_PRE
;Barfed
394 MOV DX,OFFSET DG
:BADREAD_POST
402 LOOP RDLOOP
;Try next FAT
407 MOV BX,OFFSET DG
:BADRDMES
408 JMP FATAL
;Couldn't read any FAT, BARF
416 LODSB ;Check FAT ID byte
419 MOV DX,OFFSET DG
:BADIDBYT
;FAT ID bad
420 CALL PROMPTYN
;Ask user
422 JMP ALLDONE
;User said stop
428 REP STOSB ;Initialize FATMAP to all free
429 MOV DX,OFFSET DG
:DIRBUF
;FOR ALL SEARCHING
434 PUSH AX ;Parent is root
436 CALL CHKMAP
;Look for badsectors, orphans
437 CALL CHKCROSS
;Check for second pass
448 SUBTTL Check for extents
in specified files
451 ;Search the directory for the files specified on the command line
452 ;and report the number of fragmented allocation units found in
456 MOV DX,[FATMAP
] ;Use the first free space available
458 ADD BP,27 ;cluster in the directory entry
460 MOV AH,DIR_SEARCH_FIRST
;Look for the first file
464 OR AL,AL ;Did we find it?
465 JNZ MSGCHK
;No -- we're done
466 XOR AX,AX ;Initialize the fragment counter
467 MOV SI,[BP] ;Get the first cluster
469 CMP DI,0FF8H ;End-of-file?
470 JAE NXTCHK
;Yes -- go report the results
476 MOV [OLDCLUS
],DI ;Save the last cluster found
477 MOV SI,DI ;Get the next cluster
479 INC [OLDCLUS
] ;Bump the old cluster
480 CMP DI,[OLDCLUS
] ;Are they the same?
481 JNZ LASTCLUS
;No -- check for end-of-file
482 JMP SHORT EACHCLUS
;Continue processing
484 CMP DI,0FF8H ;End-of-file?
485 JAE NXTCHK
;Yes -- go report the results
486 INC AX ;No -- found a fragement
487 JMP SHORT EACHCLUS
;Continue processing
492 MOV [FRAGMENT
],2 ;Signal that we output at least one file
493 PUSH AX ;Save count of fragments
498 MOV DX,OFFSET DG
:CONTAINS
;Print message
500 POP SI ;Number of fragments found
501 INC SI ;Number non-contig blocks
503 MOV BX,OFFSET DG
:EXTENTS
508 MOV AH,DIR_SEARCH_NEXT
;Look for the next file
512 CMP AH,DIR_SEARCH_FIRST
514 MOV SI,FCB
+ 1 ;File not found error
517 MOV DX,OFFSET DG
:OPNERR
518 CALL PRINT
;Bad file spec
521 CMP BYTE PTR [FRAGMENT
],2
523 MOV DX,OFFSET DG
:NOEXTENTS
530 ;Convert cluster number in BX to sector # AH of cluster in DX
533 MOV CL,[DI.dpb_cluster_shift
]
539 ADD DX,[DI.dpb_first_sector
]
546 SUBTTL PRINTID
- Print Volume ID info
550 MOV DX,OFFSET DG
:INTERNATVARS
551 MOV AX,INTERNATIONAL
SHL 8
553 MOV [DISPFLG
],1 ;Don't sub spaces for leading zeros
554 MOV SI,OFFSET DG
:FAT
+ 8
555 MOV DI,OFFSET DG
:VNAME
558 MOV DX,OFFSET DG
:IDMES1
559 CALL PRINT
;Print ID message
564 MOV AX,[INTERNATVARS
.Date_tim_format
]
573 MOV CX,1000H
;Do not supress leading zeroes
579 MOV CX,1110H
;Supress at most 1 leading 0
592 MOV CX,1110H
;Supress at most 1 leading 0
603 MOV DL,[INTERNATVARS
.Date_sep
]
613 AND AX,0FH ;Month in AX
614 DEC AX ;Make 0 indexed
617 ADD AX,CX ;Mult by 3 chars/mo
618 MOV SI,OFFSET DG
:MONTAB
639 AND SI,0FH ;Month in SI
642 MOV CX,1000H
;Do not supress leading 0
643 CALL OUTBYTE
;Print month
651 AND SI,01FH ;SI has day
655 CALL OUTBYTE
;Print day
664 AND SI,07FH ;SI has raw year
665 ADD SI,1980 ;Real year
667 MOV CX,1000H
;Do not supress leading zeros
668 CALL OUTWORD
;Print year
682 AND SI,01FH ;SI has hour
683 CMP [INTERNATVARS
.Time_24
],0
684 JNZ ISOK2
;24 hour time?
696 MOV CX,1110H
;Supress at most 1 leading 0
698 CALL OUTBYTE
;Print hour
699 MOV DL,BYTE PTR [INTERNATVARS
.Time_sep
]
704 AND SI,03FH ;SI has minute
706 MOV CX,1000H
;Do not supress leading zeroes
708 CALL OUTBYTE
;Print minute
710 CMP [INTERNATVARS
.Time_24
],0
711 JNZ NOAP
;24 hour time, no a or p
712 CALL PRTCHR
;Print a or p
714 MOV DX,OFFSET DG
:IDPOST
729 SUBTTL Misc Routines
- Mostly I
/O
748 MOV BYTE PTR DISPFLG
,1
777 ; Conversion complete
778 MOV CX,1310H
;Print 3-digit number with 2 leading blanks
779 CMP BYTE PTR DISPFLG
,0
781 MOV CX,1810H
;Print 8-digit number with 2 leading blanks
789 MOV BYTE PTR DISPFLG
,0
817 CMP BYTE PTR DISPFLG
,0
822 MOV AH,STD_CON_OUTPUT
839 MOV DX,OFFSET DG
:CRLF
841 MOV AH,STD_CON_STRING_OUTPUT
850 MOV DX,OFFSET DG
:CENTRY
864 MOV DX,OFFSET DG
:BADSUBDIR
869 FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI