TITLE CHKDSK - MS-DOS Disk consistancy checker ; CHKDSK Version 2.30 ; Verifies and repairs MS-DOS disk directory. ; To build CHKDSK you need three modules: ; CHKDSK CHKPROC CHKMES ; They should be linked the that order as well. ; REVISION HISTORY ;REV 1.1 ; 05/21/82 Added rev number ;REV 1.5 ; Mod by NANCYP to report on extents ; Mod by AARONR to report volume ID ;REV 2.0 ; Total rewrite for directories ;REV 2.1 ; Added ^C and INT 24H handlers ;REV 2.2 ; INTERNATIONAL support ;REV 2.3 ; Split into two modules to allow assembly on a PC ; CHKDSK and CHKPROC FALSE EQU 0 TRUE EQU NOT FALSE DRVCHAR EQU ":" ;The following defines the ranges of DOS version numbers for which this CHKDSK ; is good DOSVER_LOW EQU 0136H ;1.54 in hex DOSVER_HIGH EQU 020BH ;2.11 in hex INCLUDE DOSSYM.ASM FCB EQU 5CH ;Drive parameter block from DOS header SUBTTL Segments used in load order CODE SEGMENT PUBLIC CODE ENDS CONST SEGMENT PUBLIC BYTE CONST ENDS DATA SEGMENT PUBLIC WORD DATA ENDS DG GROUP CODE,CONST,DATA SUBTTL Initialized Data PAGE CONST SEGMENT PUBLIC BYTE PUBLIC HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX PUBLIC HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS PUBLIC DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS PUBLIC DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV PUBLIC FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR EXTRN IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE EXTRN TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE EXTRN CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE EXTRN BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE EXTRN CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE EXTRN BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE DIRBUF LABEL BYTE ;Entry buffer for searches VOLID DB -1,0,0,0,0,0,8 ;Volume ID FCB VOLNAM DB 0,"???????????" DB 25 DUP(0) ALLFILE DB -1,0,0,0,0,0,1EH ;Extended FCB ALLDRV DB 0,"???????????" DB 25 DUP (?) ORPHFCB DB 0,"FILE0000" ORPHEXT DB "CHK" DB 25 DUP (?) ;Non-message data SWITCHAR DB "-" ROOTSTR LABEL BYTE DIRCHAR DB "/" NUL DB 0 PARSTR DB "..",0 DOTMES DB ".",0 DOTENT DB ". " DDOTENT DB ".. " HECODE DB ? FIXMFLG DB 0 ;Flag for printing fixmes ERRSUB DW 0 ;Flag for bad subdir error FRAGMENT DB 0 ;Flag for extent processing DIRTYFAT DB 0 ;Dirty flag for FAT DIRCNT DW 0 ;# directories DIRSIZ DW 0 ;# alloc units in directories FILCNT DW 0 ;# reg files FILSIZ DW 0 ;# alloc units in reg files HIDCNT DW 0 ;# hidden files HIDSIZ DW 0 ;# alloc units in hidden files BADSIZ DW 0 ;# alloc units in bad sectors ORPHCNT DW 0 ;# orphan files made ORPHSIZ DW 0 ;# alloc units in orphan files LCLUS DW 0 ;# alloc units in lost clusters DISPFLG DB 0 ;used by number routines CROSSCNT DW 0 ;# crosslinked files (first pass) SECONDPASS DB 0 ;Pass flag HAVFIX DB 0 ;non zero if any fixes DOFIX DB 0 ;flag for F switch NOISY DB 0 ;flag for V switch USERDIR DB "/",0 ;Users current dir for drive DB (DIRSTRLEN-1) DUP (?) CONBUF DB 15,0 ;Input buffer DB 15 DUP (?) CONST ENDS SUBTTL Un-initialized Data PAGE DATA SEGMENT PUBLIC WORD PUBLIC ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT PUBLIC SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP PUBLIC HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD HARDCH DD ? ;Pointer to real INT 24 handler CONTCH DD ? ;Pointer to real INT 23 handler THISDPB DD ? ;Pointer to drive DPB USERDEV DB ? ;Users current device CSIZE DB ? ;Sectors per cluster SSIZE DW ? ;bytes per sector DSIZE DW ? ;# alloc units on disk MCLUS DW ? ;DSIZE + 1 NAMBUF DB 14 DUP (?) ;Buffer DOTSNOGOOD DB ? ;. or .. error flag ZEROTRUNC DB ? ;Trimming flag ISCROSS DB ? ;Crosslink flag OLDCLUS DW ? SRFCBPT DW ? FATMAP DW OFFSET DG:FAT ;Offset of FATMAP table SECBUF DW ? ;Offset of sector buffer ERRCNT DB ? ;Used by FATread and write STACKLIM DW ? ;Stack growth limit INTERNATVARS internat_block <> DB (internat_block_max - ($ - INTERNATVARS)) DUP (?) FAT LABEL WORD DATA ENDS SUBTTL Start of CHKDSK CODE SEGMENT PUBLIC ASSUME CS:DG,DS:DG,ES:DG,SS:DG PUBLIC SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT PUBLIC PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES EXTRN RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR EXTRN PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR EXTRN INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR EXTRN FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR ORG 100H CHKDSK: JMP SHORT CHSTRT HEADER DB "Ver 2.30" CHSTRT: ;Code to print header. ; PUSH AX ; MOV DX,OFFSET DG:HEADER ; CALL PRINT ; POP AX PUSH AX ;Save DRIVE validity info MOV AH,GET_VERSION INT 21H XCHG AH,AL ;Turn it around to AH.AL CMP AX,DOSVER_LOW JB GOTBADDOS CMP AX,DOSVER_HIGH JBE OKDOS GOTBADDOS: MOV DX,OFFSET DG:BADVER JMP CERROR OKDOS: POP AX ;Get back drive info MOV BX,0FFF0H MOV DX,SP CMP DX,BX JAE STACKOK ;Lots of stack MOV DX,DS:[2] ;High break MOV CX,CS SUB DX,CX CMP DX,0FFFH JAE SETSTACK ;Lots to grab MOV CX,4 ;Suck up more stack (blast command) SHL DX,CL MOV BX,DX SETSTACK: CLI MOV SP,BX STI STACKOK: PUSH AX MOV AH,DISK_RESET ;Flush everything, and invalidate INT 21H POP AX CMP AL,0FFH ;Illegal drive specifier? JNZ FILECHK ;No -- check for filename DRVERR: MOV DX,OFFSET DG:BADDRV CERROR: PUSH CS ;Make sure DS is OK POP DS CALL PRINT ;Print error message INT 20H CERROR2: PUSH DX CALL DONE ;Reset users disk POP DX JMP SHORT CERROR FILECHK: MOV AX,(CHAR_OPER SHL 8) INT 21H MOV [SWITCHAR],DL CMP DL,"/" JNZ SLASHOK MOV [DIRCHAR],"\" MOV [USERDIR],"\" SLASHOK: CMP DS:(BYTE PTR FCB+1)," " ;Filename specified? JZ DRVCHK ;No -- get the correct drive MOV AL,[SWITCHAR] CMP DS:(BYTE PTR FCB+1),AL ;Filename specified? JZ DRVCHK ;No -- get the correct drive MOV BYTE PTR [FRAGMENT],1 ;Set flag to perform fragment ;check on specified files DRVCHK: CALL SETSWITCH ;Look for switches MOV AH,GET_DEFAULT_DRIVE ;Get current drive INT 21H MOV [USERDEV],AL ;Save for later MOV AH,AL INC AH ;A = 1 MOV BH,DS:(BYTE PTR FCB) ;See if drive specified OR BH,BH JZ SETDSK MOV AL,BH MOV AH,AL DEC AL ;A = 0 SETDSK: MOV [ALLDRV],AH ;Target drive MOV [VOLNAM],AH ;A = 1 MOV [ORPHFCB],AH ;A = 1 ADD [BADDRVM],AL ;A = 0 ADD [BADDRVM2],AL ;A = 0 MOV DL,AH ;A = 1 MOV AH,GET_DPB ;Get the DPB INT 21H ASSUME DS:NOTHING CMP AL,-1 JNZ DRVISOK ;Bad drive (should always be ok) MOV DX,OFFSET DG:BADDRV CERROR2J: JMP CERROR2 DRVISOK: DEC DL ;A = 0 MOV AH,SET_DEFAULT_DRIVE ;Set Target INT 21H CMP [BX.dpb_current_dir],0 JZ CURRISROOT ;Save users current dir for target MOV SI,BX ADD SI,dpb_dir_text MOV DI,OFFSET DG:USERDIR + 1 SETDIRLP: LODSB STOSB OR AL,AL JZ CURRISROOT JMP SHORT SETDIRLP CURRISROOT: MOV WORD PTR [THISDPB+2],DS PUSH CS POP DS ASSUME DS:DG MOV WORD PTR [THISDPB],BX MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 23H INT 21H MOV WORD PTR [CONTCH],BX MOV WORD PTR [CONTCH+2],ES MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H MOV DX,OFFSET DG:INT_23 INT 21H MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H INT 21H MOV WORD PTR [HARDCH],BX MOV WORD PTR [HARDCH+2],ES MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H MOV DX,OFFSET DG:INT_24 INT 21H PUSH CS POP ES MOV DX,OFFSET DG:ROOTSTR MOV AH,CHDIR ;Start at root INT 21H MOV DX,OFFSET DG:BADCD JC CERROR2J ;Couldn't get there MOV DX,OFFSET DG:FAT ;Scratch space MOV AH,SET_DMA INT 21H MOV DX,OFFSET DG:VOLID ;Look for VOL ID MOV AH,DIR_SEARCH_FIRST INT 21H CMP AL,-1 JZ NOTVOLID CALL PRINTID ;Have a VOL ID NOTVOLID: LDS BX,[THISDPB] ASSUME DS:NOTHING MOV AX,[BX.dpb_sector_size] MOV [SSIZE],AX ;Sector size in bytes MOV AL,[BX.dpb_cluster_mask] INC AL MOV [CSIZE],AL ;Sectros per cluster MOV AX,[BX.dpb_max_cluster] MOV [MCLUS],AX ;Bound for FAT searching DEC AX MOV [DSIZE],AX ;Total data clusters on disk MOV AL,[BX.dpb_FAT_size] ;Sectors for one fat XOR AH,AH MOV CX,AX MUL [SSIZE] ;Bytes for FAT ADD [FATMAP],AX ;Allocate FAT space MOV AX,[FATMAP] ADD AX,[MCLUS] ADD AX,2 ;Insurance MOV [SECBUF],AX ;Allocate FATMAP space ADD AX,[SSIZE] ADD AX,20 ;Insurance MOV [STACKLIM],AX ;Limit on recursion 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 BX,OFFSET DG:FAT MOV AL,[ALLDRV] DEC AL MOV AH,'1' RDLOOP: XCHG CX,DI PUSH DX PUSH CX PUSH DI PUSH AX INT 25H ;Read in the FAT MOV [HECODE],AL POP AX ;Flags JNC RDOK MOV DX,OFFSET DG:BADREAD_PRE ;Barfed CALL PRINT POP AX PUSH AX MOV DL,AH CALL PRTCHR MOV DX,OFFSET DG:BADREAD_POST CALL PRINT POP AX POP CX POP DI POP DX INC AH ADD DX,DI LOOP RDLOOP ;Try next FAT CALL RDSKERR JNZ NORETRY1 JMP NOTVOLID NORETRY1: MOV BX,OFFSET DG:BADRDMES JMP FATAL ;Couldn't read any FAT, BARF RDOK: POP AX ;Clean up POP AX POP AX POP AX MOV SI,OFFSET DG:FAT LODSB ;Check FAT ID byte CMP AL,0F8H JAE IDOK MOV DX,OFFSET DG:BADIDBYT ;FAT ID bad CALL PROMPTYN ;Ask user JZ IDOK JMP ALLDONE ;User said stop IDOK: MOV DI,[FATMAP] MOV CX,[MCLUS] INC CX XOR AL,AL REP STOSB ;Initialize FATMAP to all free MOV DX,OFFSET DG:DIRBUF ;FOR ALL SEARCHING MOV AH,SET_DMA INT 21H XOR AX,AX PUSH AX ;I am root PUSH AX ;Parent is root CALL DIRPROC CALL CHKMAP ;Look for badsectors, orphans CALL CHKCROSS ;Check for second pass CALL DOCRLF CALL REPORT ALLDONE: CALL AMDONE INT 20H ;Fini ASSUME DS:DG SUBTTL Check for extents in specified files PAGE CHECKFILES: ;Search the directory for the files specified on the command line ;and report the number of fragmented allocation units found in ;each one. CALL DOCRLF MOV AH,SET_DMA MOV DX,[FATMAP] ;Use the first free space available MOV BP,DX ADD BP,27 ;cluster in the directory entry INT 21H MOV AH,DIR_SEARCH_FIRST ;Look for the first file FRAGCHK: MOV DX,FCB INT 21H OR AL,AL ;Did we find it? JNZ MSGCHK ;No -- we're done XOR AX,AX ;Initialize the fragment counter MOV SI,[BP] ;Get the first cluster CALL UNPACK CMP DI,0FF8H ;End-of-file? JAE NXTCHK ;Yes -- go report the results INC SI CMP SI,DI JZ EACHCLUS INC AX EACHCLUS: MOV [OLDCLUS],DI ;Save the last cluster found MOV SI,DI ;Get the next cluster CALL UNPACK INC [OLDCLUS] ;Bump the old cluster CMP DI,[OLDCLUS] ;Are they the same? JNZ LASTCLUS ;No -- check for end-of-file JMP SHORT EACHCLUS ;Continue processing LASTCLUS: CMP DI,0FF8H ;End-of-file? JAE NXTCHK ;Yes -- go report the results INC AX ;No -- found a fragement JMP SHORT EACHCLUS ;Continue processing NXTCHK: OR AX,AX JZ GETNXT MOV [FRAGMENT],2 ;Signal that we output at least one file PUSH AX ;Save count of fragments MOV SI,[FATMAP] INC SI CALL PRINTTHISEL2 CALL DOCRLF MOV DX,OFFSET DG:CONTAINS ;Print message CALL PRINT POP SI ;Number of fragments found INC SI ;Number non-contig blocks XOR DI,DI MOV BX,OFFSET DG:EXTENTS PUSH BP CALL DISP16BITS POP BP GETNXT: MOV AH,DIR_SEARCH_NEXT ;Look for the next file JMP FRAGCHK MSGCHK: CMP AH,DIR_SEARCH_FIRST JNZ FILSPOK MOV SI,FCB + 1 ;File not found error CALL PRINTTHISEL2 CALL DOCRLF MOV DX,OFFSET DG:OPNERR CALL PRINT ;Bad file spec RET FILSPOK: CMP BYTE PTR [FRAGMENT],2 JZ CDONE MOV DX,OFFSET DG:NOEXTENTS CALL PRINT CDONE: RET FIGREC: ;Convert cluster number in BX to sector # AH of cluster in DX LDS DI,[THISDPB] ASSUME DS:NOTHING MOV CL,[DI.dpb_cluster_shift] MOV DX,BX DEC DX DEC DX SHL DX,CL OR DL,AH ADD DX,[DI.dpb_first_sector] PUSH CS POP DS ASSUME DS:DG RET SUBTTL PRINTID - Print Volume ID info PAGE PRINTID: ASSUME DS:DG MOV DX,OFFSET DG:INTERNATVARS MOV AX,INTERNATIONAL SHL 8 INT 21H MOV [DISPFLG],1 ;Don't sub spaces for leading zeros MOV SI,OFFSET DG:FAT + 8 MOV DI,OFFSET DG:VNAME MOV CX,11 REP MOVSB MOV DX,OFFSET DG:IDMES1 CALL PRINT ;Print ID message ADD SI,13 LODSW ;Get date PUSH SI MOV DX,AX MOV AX,[INTERNATVARS.Date_tim_format] OR AX,AX JZ USPDAT DEC AX JZ EUPDAT CALL P_YR CALL P_DSEP CALL P_MON CALL P_DSEP MOV CX,1000H ;Do not supress leading zeroes CALL P_DAY JMP P_TIME USPDAT: CALL P_MONTH_NAM MOV CX,1110H ;Supress at most 1 leading 0 CALL P_DAY PUSH DX MOV DL,',' CALL PRTCHR MOV DL,' ' CALL PRTCHR POP DX PYA: CALL P_YR JMP P_TIME EUPDAT: MOV CX,1110H ;Supress at most 1 leading 0 CALL P_DAY PUSH DX MOV DL,' ' CALL PRTCHR POP DX CALL P_MONTH_NAM JMP PYA P_DSEP: PUSH DX MOV DL,[INTERNATVARS.Date_sep] CALL PRTCHR POP DX RET P_MONTH_NAM: MOV AX,DX PUSH DX MOV CL,5 SHR AX,CL AND AX,0FH ;Month in AX DEC AX ;Make 0 indexed MOV CX,AX SHL AX,1 ADD AX,CX ;Mult by 3 chars/mo MOV SI,OFFSET DG:MONTAB ADD SI,AX LODSB MOV DL,AL CALL PRTCHR LODSB MOV DL,AL CALL PRTCHR LODSB MOV DL,AL CALL PRTCHR MOV DL,' ' CALL PRTCHR POP DX RET P_MON: MOV SI,DX PUSH DX MOV CL,5 SHR SI,CL AND SI,0FH ;Month in SI CALL CONVERT MOV DL,AL MOV CX,1000H ;Do not supress leading 0 CALL OUTBYTE ;Print month POP DX RET P_DAY: MOV SI,DX PUSH DX PUSH CX AND SI,01FH ;SI has day CALL CONVERT POP CX MOV DL,AL CALL OUTBYTE ;Print day POP DX RET P_YR: MOV SI,DX PUSH DX MOV CL,9 SHR SI,CL AND SI,07FH ;SI has raw year ADD SI,1980 ;Real year CALL CONVERT MOV CX,1000H ;Do not supress leading zeros CALL OUTWORD ;Print year POP DX RET P_TIME: MOV DL,' ' CALL PRTCHR POP SI ADD SI,-4 LODSW ;Get time MOV DI,AX MOV SI,DI MOV CL,11 SHR SI,CL AND SI,01FH ;SI has hour CMP [INTERNATVARS.Time_24],0 JNZ ISOK2 ;24 hour time? CMP SI,12 JB ISOK ;Is AM MOV [TCHAR],'p' JZ ISOK ;Is 12-1p SUB SI,12 ;Is PM ISOK: OR SI,SI JNZ ISOK2 MOV SI,12 ;0 is 12a ISOK2: CALL CONVERT MOV CX,1110H ;Supress at most 1 leading 0 MOV DL,AL CALL OUTBYTE ;Print hour MOV DL,BYTE PTR [INTERNATVARS.Time_sep] CALL PRTCHR MOV SI,DI MOV CL,5 SHR SI,CL AND SI,03FH ;SI has minute CALL CONVERT MOV CX,1000H ;Do not supress leading zeroes MOV DL,AL CALL OUTBYTE ;Print minute MOV DL,[TCHAR] CMP [INTERNATVARS.Time_24],0 JNZ NOAP ;24 hour time, no a or p CALL PRTCHR ;Print a or p NOAP: MOV DX,OFFSET DG:IDPOST CALL PRINT MOV [DISPFLG],0 RET CONVERT: MOV CX,16 XOR AX,AX CNVLOOP: SHL SI,1 CALL CONVWRD CLC LOOP CNVLOOP RET SUBTTL Misc Routines - Mostly I/O PAGE CONVWRD: ADC AL,AL DAA XCHG AL,AH ADC AL,AL DAA XCHG AL,AH RET1: RET UNSCALE: SHR CX,1 JC RET1 SHL SI,1 RCL DI,1 JMP SHORT UNSCALE DISP16BITS: MOV BYTE PTR DISPFLG,1 JMP SHORT DISP32BITS DISPCLUS: MUL [SSIZE] MOV CL,[CSIZE] XOR CH,CH MOV SI,AX MOV DI,DX CALL UNSCALE DISP32BITS: PUSH BP PUSH BX XOR AX,AX MOV BX,AX MOV BP,AX MOV CX,32 CONVLP: SHL SI,1 RCL DI,1 XCHG AX,BP CALL CONVWRD XCHG AX,BP XCHG AX,BX CALL CONVWRD XCHG AX,BX ADC AL,0 LOOP CONVLP ; Conversion complete MOV CX,1310H ;Print 3-digit number with 2 leading blanks CMP BYTE PTR DISPFLG,0 JNZ FOURDIG MOV CX,1810H ;Print 8-digit number with 2 leading blanks XCHG DX,AX CALL DIGIT XCHG AX,BX CALL OUTWORD FOURDIG: MOV AX,BP CALL OUTWORD MOV BYTE PTR DISPFLG,0 POP DX CALL PRINT POP BP RET OUTWORD: PUSH AX MOV DL,AH CALL OUTBYTE POP DX OUTBYTE: MOV DH,DL SHR DL,1 SHR DL,1 SHR DL,1 SHR DL,1 CALL DIGIT MOV DL,DH DIGIT: AND DL,0FH JZ BLANKZER MOV CL,0 BLANKZER: DEC CH AND CL,CH OR DL,30H SUB DL,CL CMP BYTE PTR DISPFLG,0 JZ PRTCHR CMP DL,30H JL RET2 PRTCHR: MOV AH,STD_CON_OUTPUT INT 21H RET2: RET PRINTCNT: LODSB MOV DL,AL INT 21H LOOP PRINTCNT RET EPRINT: CALL CHECKERR JNZ RET$1 JMP SHORT PRINT DOCRLF: MOV DX,OFFSET DG:CRLF PRINT: MOV AH,STD_CON_STRING_OUTPUT INT 21H RET$1: RET DOTCOMBMES: CMP [NOISY],0 JZ SUBERRP PUSH DX CALL PRINTCURRDIRERR MOV DX,OFFSET DG:CENTRY CALL EPRINT POP DX CALL EPRINT CALL DOCRLF RET SUBERRP: MOV AL,1 XCHG AL,[ERRSUB] CMP AL,0 JNZ RET32 MOV SI,OFFSET DG:NUL CALL PRINTCURRDIRERR MOV DX,OFFSET DG:BADSUBDIR CALL EPRINT RET32: RET FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI MOV CX,8 MAINNAME: LODSB CMP AL,' ' JZ SKIPSPC STOSB SKIPSPC: LOOP MAINNAME LODSB CMP AL,' ' JZ GOTNAME MOV AH,AL MOV AL,'.' STOSB XCHG AL,AH STOSB MOV CL,2 EXTNAME: LODSB CMP AL,' ' JZ GOTNAME STOSB LOOP EXTNAME GOTNAME: XOR AL,AL STOSB RET CODE ENDS END CHKDSK