From 80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6 Mon Sep 17 00:00:00 2001 From: Rich Turner Date: Fri, 12 Aug 1983 17:53:34 -0700 Subject: MS-DOS v2.0 Release --- v2.0/source/RECOVER.ASM | 876 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 876 insertions(+) create mode 100644 v2.0/source/RECOVER.ASM (limited to 'v2.0/source/RECOVER.ASM') diff --git a/v2.0/source/RECOVER.ASM b/v2.0/source/RECOVER.ASM new file mode 100644 index 0000000..05d27f9 --- /dev/null +++ b/v2.0/source/RECOVER.ASM @@ -0,0 +1,876 @@ +TITLE RECOVER MS-DOS File/Disk Recovery Utility +;---------------------------------------------------------- +; +; Recover - Program to rebuild an ms.dos directory +; +; Copyright 1982 by Microsoft Corporation +; Written by Chris Peters, April 1982 +; +;----------------------------------------------------------- +; +;REV 1.5 added header message ARR +; + +FALSE EQU 0 +TRUE EQU NOT FALSE + + +IBMVER EQU true +KANJI EQU FALSE + +bdos equ 21h +boot equ 20h +aread equ 25h +awrite equ 26h + + INCLUDE DOSSYM.ASM + +; +cr equ 0dh +lf equ 0ah +; +fcb equ 5ch + +code segment public +code ends + +const segment public byte +const ends + +data segment public byte +data ends + + +dg group code,const,data + +code segment public + assume cs:dg,ds:dg,es:dg,ss:dg + + PUBLIC PCRLF,PRINT,INT_23,convert + EXTRN dskwrt:NEAR,dskrd:NEAR,DSKERR:NEAR,report:NEAR + + org 100h + +recover:jmp rec_start + +HEADER DB "Vers 1.50" + +;-----------------------------------------------------------------------; +hardch dd ? + +the_root db 0 ;root directory flag + +fudge db 0 ;directory changed flag +user_drive db 0 +drive db 0 + + +dirchar db "/",0 + + +userdir db "/",0 + db (dirstrlen) dup(0) + +fname_buffer db 128 dup(0) +;-----------------------------------------------------------------------; + +pcrlf: mov dx,offset dg: crlf +print: mov ah,STD_CON_STRING_OUTPUT + int bdos +pret: ret +; +convert: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 + + mov cx,1810h + xchg dx,ax + call digit + xchg ax,bx + call outword + mov ax,bp + call outword + pop dx + call print +ret2: 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 + xor cl,cl +blankzer: + dec ch + and cl,ch + or dl,30h + sub dl,cl + cmp dl,30h + jl ret2 + mov ah,STD_CON_OUTPUT + int bdos + ret +; +convwrd:adc al,al + daa + xchg al,ah + adc al,al + daa + xchg al,ah + ret +; +; bx = fat[ax] +; +getfat: mov bx,offset dg: fattbl + push ax + mov si,ax + sar ax,1 + pushf + add si,ax + mov bx,word ptr [bx][si] + popf + jnc getfat1 + mov cl,4 + shr bx,cl +getfat1:and bh,00001111b + pop ax + mov cx,secsiz + ret +; +; fat[ax] = dx +; +setfat: mov bx,offset dg: fattbl + push ax + push dx + mov si,ax + sar ax,1 + pushf + add si,ax + mov ax,word ptr [bx][si] + popf + jnc setfat2 + and ax,000fh + mov cl,4 + shl dx,cl +setfat1:or ax,dx + mov word ptr [bx][si],ax + pop dx + pop ax + ret + +setfat2:and ax,0f000h + jmp setfat1 + +load: mov dx,firfat + mov al,byte ptr fatnum + mov byte ptr fatcnt,al + mov al,byte ptr drive + mov cx,fatsiz + mov bx,offset dg: fattbl +ret66: ret + +readft: call load +readit: call dskrd + cmp [fndfat],0 ;save location of readable fat sector + jnz fdfat + mov [fndfat],dx +fdfat: cmp word ptr [bx+1],-1 + jz ret66 + + add dx,cx ;try to read the other fats + dec byte ptr fatcnt + jnz readit + + mov dx,[fndfat] ;see if any readable at all + or dx,dx + jz readft ;if not disk is blown, keep trying + call dskrd + ret + +wrtfat: call load +wrtit: push ax + push bx + push cx + push dx + call dskwrt + pop dx + pop cx + pop bx + pop ax + +wrtok: add dx,cx + dec byte ptr fatcnt + jnz wrtit + ret + +printerr: + call print + jmp rabort + + +rec_start: + +;Code to print header +; PUSH AX +; MOV DX,OFFSET DG:HEADER +; CALL print +; POP AX + +DOSVER_HIGH EQU 0200H ;2.00 in hex + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + XCHG AH,AL ;Turn it around to AH.AL + CMP AX,DOSVER_HIGH + JAE OKDOS +GOTBADDOS: + MOV DX,OFFSET DG:BADVER + CALL PRINT + INT 20H + +OKDOS: POP AX + + cmp al,0ffH + JZ BADDRVSPECJ + mov si,80h + lodsb + or al,al + jz noparm +look: lodsb + cmp al," " + jz look + cmp al,9 + jz look + cmp al,13 + jnz gotparm +noparm: + jmp noname + +BADDRVSPECJ: JMP BADDRVSPEC + +gotparm: + mov ah,DISK_RESET + int bdos ;empty buffer queue + + mov ah,get_default_drive ;save current drive + int 21h + mov [user_drive],al + + mov bx,fcb ;determine input command + mov al,[bx] + dec al + cmp al,-1 + jnz drvok1 + mov al,[user_drive] +drvok1: + mov [drive],al + add [drvlet],al + add [drvlet1],al + mov dx,offset dg: askmsg + call print + mov ah,STD_CON_INPUT_FLUSH + mov al,1 ;wait for a key + int bdos + + cmp al,17h + jnz drvok2 + mov dx,offset dg: egomes + jmp printerr +egomes: db "Chris Peters helped with the new dos!",cr,lf + db "Microsoft rules ok$" + +drvok2: + IF IBMVER + MOV AL,DRIVE ;This is for ibm's single drive sys + PUSH DS + MOV BX,50H + MOV DS,BX + MOV DS:(BYTE PTR 4),AL ;Indicate drive changed + POP DS + ENDIF + +;----- Process Pathnames -----------------------------------------------; + mov ax,(char_oper shl 8) ;get switch character + int 21h + cmp dl,"/" + jnz slashok ;if not / , then not PC + mov [dirchar],"\" ;in PC, dir separator = \ + mov [userdir],"\" + +slashok: + mov si,81h ;point to cammand line + mov di,offset dg: fname_buffer + xor cx,cx ;zero pathname length + +kill_bl: + lodsb ;get rid of blanks + cmp al,9 + je kill_bl + cmp al,' ' + je kill_bl + cmp al,13 ;A carriage return? + jne next_char + jmp noname ;yes, file name missing + +next_char: + stosb ;put patname in buffer + inc cx + lodsb + cmp al,' ' + je name_copied + cmp al,9 + je name_copied + cmp al,13 ; a CR ? + jne next_char + +name_copied: + mov byte ptr [di],0 ;nul terminate the pathname + dec di ;adjust to the end of the pathname + +;----- Scan for directory ----------------------------------------------; + + IF KANJI + mov dx,offset dg: [fname_buffer] + PUSH DX + PUSH DI + MOV BX,DI + MOV DI,DX +DELLOOP: + CMP DI,BX + JZ GOTDELE + MOV AL,[DI] + INC DI + CALL TESTKANJ + JZ NOTKANJ11 + INC DI + JMP DELLOOP + +NOTKANJ11: + cmp al,[dirchar] + JNZ DELLOOP + MOV DX,DI ;Point to char after '/' + DEC DX + DEC DX ;Point to char before '/' + JMP DELLOOP + +GOTDELE: + MOV DI,DX + POP AX ;Initial DI + POP DX + SUB AX,DI ;Distance moved + SUB CX,AX ;Set correct CX + CMP DX,DI + JB sja ;Found a pathsep + JA sjb ;Started with a pathsep, root + MOV AX,[DI] + CALL TESTKANJ + JNZ same_dirj + XCHG AH,AL + cmp al,[dirchar] + jz sja ;One character directory +same_dirj: + ELSE + mov al,[dirchar] ;get directory separator character + std ;scan backwards + repnz scasb ;(cx has the pathname length) + cld ;reset direction, just in case + jz sja + ENDIF + + jmp same_dir ;no dir separator char. found, the + ; file is in the current directory + ; of the corresponding drive. Ergo, + ; the FCB contains the data already. + +sja: + jcxz sjb ;no more chars left, it refers to root + cmp byte ptr [di],':' ;is the prvious character a disk def? + jne not_root +sjb: + mov [the_root],01h ;file is in the root +not_root: + inc di ;point to dir separator char. + mov al,0 + stosb ;nul terminate directory name + pop ax + push di ;save pointer to file name + mov [fudge],01h ;remember that the current directory + ; has been changed. + +;----- Save current directory for exit ---------------------------------; + mov dl,byte ptr ds:[fcb] ;get specified drive if any + or dl,dl ;default disk? + jz same_drive + dec dl ;adjust to real drive (a=0,b=1,...) + mov ah,set_default_drive ;change disks + int 21h + cmp al,-1 ;error? + jne same_drive +BADDRVSPEC: + mov dx,offset dg: baddrv + jmp printerr + +same_drive: + mov ah,get_default_dpb + int 21h + +assume ds:nothing + + cmp al,-1 ;bad drive? (should always be ok) + jne drvisok + mov dx,offset dg: baddrv + jmp printerr + +drvisok: + cmp [bx.dpb_current_dir],0 + je curr_is_root + mov si,bx + add si,dpb_dir_text + mov di,offset dg: userdir + 1 + +dir_save_loop: + lodsb + stosb + or al,al + jnz dir_save_loop + +curr_is_root: + push cs + pop ds + +assume ds:dg + + +;----- Change directories ----------------------------------------------; + cmp [the_root],01h + mov dx,offset dg: [dirchar] ;assume the root + je sj1 + mov dx,offset dg: [fname_buffer] +sj1: + mov ah,chdir ;change directory + int 21h + mov dx,offset dg: baddrv + jnc no_errors + jmp printerr +no_errors: + +;----- Set Up int 24 intercept -----------------------------------------; + + 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 23h + mov dx,offset dg: int_23 + int 21h + mov ax,(set_interrupt_vector shl 8) or 24h + mov dx,offset dg: int_24 + int 21h + push cs + pop es + +;----- Parse filename to FCB -------------------------------------------; + pop si + mov di,fcb + mov ax,(parse_file_descriptor shl 8) or 1 + int 21h + push ax +;-----------------------------------------------------------------------; +same_dir: + pop ax + + mov bx,fcb + cmp byte ptr [bx+1],' ' ;must specify file name + jnz drvok + cmp byte ptr [bx],0 ;or drive specifier + jnz drvok +noname: mov dx,offset dg: drverr + call print + jmp int_23 + +drvok: push ds + mov dl,drive + inc dl + mov ah,GET_DPB + int bdos + mov ax,word ptr [bx+2] ;get physical sector size + mov cl,byte ptr [bx+4] ;get sectors/cluster - 1 + xor ch,ch + inc cx + mov cs:secall,cx ;save sectors per cluster + mul cx ;ax = bytes per cluster + mov bp,word ptr [bx+11] ;get record of first sector + mov dx,word ptr [bx+16] ;get record of first directory entry + mov si,word ptr [bx+6] ;get record of first fat + mov cl,byte ptr [bx+15] ;get size of fat + mov di,word ptr [bx+13] ;get number of clusters + mov ch,byte ptr [bx+8] ;get number of fats on drive + mov bx,word ptr [bx+9] ;get max number of dir entries + pop ds + + mov maxent,bx + mov firfat,si + mov firrec,bp + mov firdir,dx + mov byte ptr fatsiz,cl + mov lastfat,di ;number of fat entries + mov byte ptr fatnum,ch ;save number of fats on disk + + mov secsiz,ax + + mov di,table ;di points into constructed directory + mov ax,0e5e5h ;deleted file magic number + shl bx,1 ;16 words in a dir entry + shl bx,1 + shl bx,1 + shl bx,1 + mov cx,bx + rep stosw + + call readft + mov bx,fcb + cmp byte ptr [bx+1],' ' + jz recdsk + jmp recfil + +recdsk: mov di,table + mov fatptr,2 + mov ax,fatptr +step1: call getfat + cmp bx,0fffh + jz step1a + jmp step6 +step1a: mov filsiz,0 + mov word ptr filsiz+2,0 + mov dx,lastfat + mov target,ax +step2: mov ax,2 + add filsiz,cx + adc word ptr filsiz+2,0 +step3: call getfat + cmp bx,target + jne step4 + mov target,ax + jmp step2 +step4: inc ax + cmp ax,dx + jle step3 +; +; at this point target = head of list, filsiz = file size +; + inc filcnt ;increment file count + mov ax,maxent + cmp filcnt,ax ;compare with max number of entries + ja direrr + + mov si,(offset dg: dirent)+7 +nam0: inc byte ptr [si] ;increment file name + cmp byte ptr [si],'9' + jle nam1 + mov byte ptr [si],'0' + dec si + jmp nam0 + +nam1: mov ah,GET_DATE + int bdos ;set the date + sub cx,1980 + add dh,dh + add dh,dh + add dh,dh + add dh,dh + add dh,dh + rcl cl,1 + or dh,dl + mov byte ptr dirent+24,dh + mov byte ptr dirent+25,cl + mov ah,GET_TIME + int bdos ;set the time + shr dh,1 + add cl,cl + add cl,cl + add cl,cl + rcl ch,1 + add cl,cl + rcl ch,1 + add cl,cl + rcl ch,1 + or dh,cl + mov byte ptr dirent+22,dh + mov byte ptr dirent+23,ch + + mov ax,filsiz ;set file size + mov word ptr dirent+28,ax + mov ax,word ptr filsiz+2 + mov word ptr dirent+30,ax + mov ax,target ;set first cluster location + mov word ptr dirent+26,ax + + mov si,offset dg: dirent ;copy in new dir entry + mov cx,32 + rep movsb + +step6: inc fatptr ;keep looking for eof's + mov ax,fatptr + cmp ax,lastfat + jg step7 + jmp step1 + +direrr: dec filcnt + mov dx,offset dg: dirmsg + call print + +step7: + mov al,drive + mov dx,firdir ;write out constructed directory + mov cx,firrec + sub cx,dx + mov bx,table + call dskwrt + call pcrlf + mov dx,offset dg: recmsg_pre + call print + mov bx,offset dg: recmsg_post + mov si,filcnt + xor di,di ;output number of files created + call convert + jmp rexit +recfil: mov dx,fcb + mov ah,FCB_OPEN + int bdos + inc al + jnz recfil0 + mov dx,offset dg: opnerr + call print + jmp rexit + +recfil0:mov lastfat,1 ;indicate location of list head + mov di,fcb + mov ax,[di+16] ;get file size + mov filsiz,ax + mov siztmp,ax + mov ax,[di+18] + mov filsiz+2,ax + mov siztmp+2,ax + mov ax,[di+25] ;get list head + or ax,ax + mov fatptr,ax + jnz recfil1 +recvec: jmp recfil6 + +recfil1:cmp fatptr,0fffh + jz recvec ;terminate loop at e-o-f + + mov cx,secall + mov ax,fatptr + dec ax + dec ax + mul cx + add ax,firrec + mov dx,ax + mov bx,table + mov al,drive + int aread + pop di ;restore stack pointer + mov di,fcb ;restore pointer to fcb + jnc recfil4 ;if no error continue reading + + mov ax,fatptr + call getfat + cmp lastfat,1 + jnz recfil2 + + cmp bx,0fffh + jnz noteof + xor bx,bx +noteof: mov word ptr [di+25],bx + jmp recfil3 + +recfil2:mov dx,bx ;jump around bad sector + mov ax,lastfat + call setfat + +recfil3:mov ax,fatptr ;mark sector bad + mov dx,0ff7h + call setfat + mov ax,secsiz ;prepare to dec filsiz by secsiz + cmp siztmp+2,0 + jnz recfilx + cmp siztmp,ax + ja recfilx + mov ax,siztmp + +recfilx:sub word ptr [di+16],ax + sbb word ptr [di+18],0 + sub siztmp,ax + sbb siztmp,0 + + and byte ptr [di+24],10111111b ;mark file dirty + + mov ax,lastfat ;point to next sector to check + jmp recfil5 + +recfil4: + mov ax,secsiz ;set bytes remaining to be read + sub siztmp,ax + sbb siztmp+2,0 + jnc recok + xor ax,ax ;if < 0, then set to zero + mov siztmp,ax + mov siztmp+2,ax + +recok: mov ax,fatptr ;get next sector to test + mov lastfat,ax +recfil5:call getfat + mov fatptr,bx + jmp recfil1 + +recfil6: ;all done + mov dx,fcb + mov ah,FCB_CLOSE + int bdos ;close the file + call pcrlf + call report + +; +rexit: mov ah,DISK_RESET + int bdos + call wrtfat ;save the fat +int_23: call rest_dir +rabort: int boot ;home, james... + +;----- Restore INT 24 vector and old current directory -----------------; +rest_dir: + cmp [fudge],0 + je no_fudge + + mov ax,(set_interrupt_vector shl 8) or 24h + lds dx,[hardch] + int 21h + push cs + pop ds + + mov dx,offset dg: userdir ;restore directory + mov ah,chdir + int 21h + mov dl,[user_drive] ;restore old current drive + mov ah,set_default_drive + int 21h + +no_fudge: + ret + +;----- INT 24 Processing -----------------------------------------------; + +int_24_retaddr dw 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 + push cs + pop ds + +assume ds:dg + + call rest_dir + int 20h +ireti: + iret + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + RET + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + RET + ENDIF + +code ends + +const segment public byte + + EXTRN BADVER:BYTE,askmsg:BYTE,drvlet:BYTE,dirmsg:BYTE + EXTRN recmsg_pre:BYTE,DRVLET1:BYTE,recmsg_post:BYTE + EXTRN crlf:BYTE,drverr:BYTE,baddrv:BYTE,opnerr:BYTE + +const ends + +data segment byte + + PUBLIC filsiz + +dirent db 'FILE0000REC' + db 21 dup (00) + +fndfat dw 0000 ;sector of first good fat +filcnt dw 0000 +fatcnt db 00 +fatnum db 00 +fatsiz dw 0000 +firfat dw 0000 +fatptr dw 0000 +secall dw 0000 ;sectors per cluster +target dw 0000 +maxent dw 0000 +firrec dw 0000 +firdir dw 0000 +secsiz dw 0000 +siztmp dw 0000 + dw 0000 +filsiz dw 0000 + dw 0000 +lastfat dw 0000 +; +table dw offset dg:fattbl + 6 * 1024 +fattbl db 0 + +data ends + + end recover + \ No newline at end of file -- cgit v1.2.3