]> wirehaze git hosting - MS-DOS.git/blob - v2.0/source/RECOVER.ASM

wirehaze git hosting

Merge pull request #1 from ggurbet/turkish-readme
[MS-DOS.git] / v2.0 / source / RECOVER.ASM
1 TITLE RECOVER MS-DOS File/Disk Recovery Utility
2 ;----------------------------------------------------------
3 ;
4 ; Recover - Program to rebuild an ms.dos directory
5 ;
6 ; Copyright 1982 by Microsoft Corporation
7 ; Written by Chris Peters, April 1982
8 ;
9 ;-----------------------------------------------------------
10 ;
11 ;REV 1.5 added header message ARR
12 ;
13
14 FALSE EQU 0
15 TRUE EQU NOT FALSE
16
17
18 IBMVER EQU true
19 KANJI EQU FALSE
20
21 bdos equ 21h
22 boot equ 20h
23 aread equ 25h
24 awrite equ 26h
25
26 INCLUDE DOSSYM.ASM
27
28 ;
29 cr equ 0dh
30 lf equ 0ah
31 ;
32 fcb equ 5ch
33
34 code segment public
35 code ends
36
37 const segment public byte
38 const ends
39
40 data segment public byte
41 data ends
42
43
44 dg group code,const,data
45
46 code segment public
47 assume cs:dg,ds:dg,es:dg,ss:dg
48
49 PUBLIC PCRLF,PRINT,INT_23,convert
50 EXTRN dskwrt:NEAR,dskrd:NEAR,DSKERR:NEAR,report:NEAR
51
52 org 100h
53
54 recover:jmp rec_start
55
56 HEADER DB "Vers 1.50"
57
58 ;-----------------------------------------------------------------------;
59 hardch dd ?
60
61 the_root db 0 ;root directory flag
62
63 fudge db 0 ;directory changed flag
64 user_drive db 0
65 drive db 0
66
67
68 dirchar db "/",0
69
70
71 userdir db "/",0
72 db (dirstrlen) dup(0)
73
74 fname_buffer db 128 dup(0)
75 ;-----------------------------------------------------------------------;
76
77 pcrlf: mov dx,offset dg: crlf
78 print: mov ah,STD_CON_STRING_OUTPUT
79 int bdos
80 pret: ret
81 ;
82 convert:push bx
83 xor ax,ax
84 mov bx,ax
85 mov bp,ax
86 mov cx,32
87 convlp: shl si,1
88 rcl di,1
89 xchg ax,bp
90 call convwrd
91 xchg ax,bp
92 xchg ax,bx
93 call convwrd
94 xchg ax,bx
95 adc al,0
96 loop convlp
97
98 mov cx,1810h
99 xchg dx,ax
100 call digit
101 xchg ax,bx
102 call outword
103 mov ax,bp
104 call outword
105 pop dx
106 call print
107 ret2: ret
108 ;
109 outword:push ax
110 mov dl,ah
111 call outbyte
112 pop dx
113 outbyte:mov dh,dl
114 shr dl,1
115 shr dl,1
116 shr dl,1
117 shr dl,1
118 call digit
119 mov dl,dh
120 digit: and dl,0fh
121 jz blankzer
122 xor cl,cl
123 blankzer:
124 dec ch
125 and cl,ch
126 or dl,30h
127 sub dl,cl
128 cmp dl,30h
129 jl ret2
130 mov ah,STD_CON_OUTPUT
131 int bdos
132 ret
133 ;
134 convwrd:adc al,al
135 daa
136 xchg al,ah
137 adc al,al
138 daa
139 xchg al,ah
140 ret
141 ;
142 ; bx = fat[ax]
143 ;
144 getfat: mov bx,offset dg: fattbl
145 push ax
146 mov si,ax
147 sar ax,1
148 pushf
149 add si,ax
150 mov bx,word ptr [bx][si]
151 popf
152 jnc getfat1
153 mov cl,4
154 shr bx,cl
155 getfat1:and bh,00001111b
156 pop ax
157 mov cx,secsiz
158 ret
159 ;
160 ; fat[ax] = dx
161 ;
162 setfat: mov bx,offset dg: fattbl
163 push ax
164 push dx
165 mov si,ax
166 sar ax,1
167 pushf
168 add si,ax
169 mov ax,word ptr [bx][si]
170 popf
171 jnc setfat2
172 and ax,000fh
173 mov cl,4
174 shl dx,cl
175 setfat1:or ax,dx
176 mov word ptr [bx][si],ax
177 pop dx
178 pop ax
179 ret
180
181 setfat2:and ax,0f000h
182 jmp setfat1
183
184 load: mov dx,firfat
185 mov al,byte ptr fatnum
186 mov byte ptr fatcnt,al
187 mov al,byte ptr drive
188 mov cx,fatsiz
189 mov bx,offset dg: fattbl
190 ret66: ret
191
192 readft: call load
193 readit: call dskrd
194 cmp [fndfat],0 ;save location of readable fat sector
195 jnz fdfat
196 mov [fndfat],dx
197 fdfat: cmp word ptr [bx+1],-1
198 jz ret66
199
200 add dx,cx ;try to read the other fats
201 dec byte ptr fatcnt
202 jnz readit
203
204 mov dx,[fndfat] ;see if any readable at all
205 or dx,dx
206 jz readft ;if not disk is blown, keep trying
207 call dskrd
208 ret
209
210 wrtfat: call load
211 wrtit: push ax
212 push bx
213 push cx
214 push dx
215 call dskwrt
216 pop dx
217 pop cx
218 pop bx
219 pop ax
220
221 wrtok: add dx,cx
222 dec byte ptr fatcnt
223 jnz wrtit
224 ret
225
226 printerr:
227 call print
228 jmp rabort
229
230
231 rec_start:
232
233 ;Code to print header
234 ; PUSH AX
235 ; MOV DX,OFFSET DG:HEADER
236 ; CALL print
237 ; POP AX
238
239 DOSVER_HIGH EQU 0200H ;2.00 in hex
240 PUSH AX ;Save DRIVE validity info
241 MOV AH,GET_VERSION
242 INT 21H
243 XCHG AH,AL ;Turn it around to AH.AL
244 CMP AX,DOSVER_HIGH
245 JAE OKDOS
246 GOTBADDOS:
247 MOV DX,OFFSET DG:BADVER
248 CALL PRINT
249 INT 20H
250
251 OKDOS: POP AX
252
253 cmp al,0ffH
254 JZ BADDRVSPECJ
255 mov si,80h
256 lodsb
257 or al,al
258 jz noparm
259 look: lodsb
260 cmp al," "
261 jz look
262 cmp al,9
263 jz look
264 cmp al,13
265 jnz gotparm
266 noparm:
267 jmp noname
268
269 BADDRVSPECJ: JMP BADDRVSPEC
270
271 gotparm:
272 mov ah,DISK_RESET
273 int bdos ;empty buffer queue
274
275 mov ah,get_default_drive ;save current drive
276 int 21h
277 mov [user_drive],al
278
279 mov bx,fcb ;determine input command
280 mov al,[bx]
281 dec al
282 cmp al,-1
283 jnz drvok1
284 mov al,[user_drive]
285 drvok1:
286 mov [drive],al
287 add [drvlet],al
288 add [drvlet1],al
289 mov dx,offset dg: askmsg
290 call print
291 mov ah,STD_CON_INPUT_FLUSH
292 mov al,1 ;wait for a key
293 int bdos
294
295 cmp al,17h
296 jnz drvok2
297 mov dx,offset dg: egomes
298 jmp printerr
299 egomes: db "Chris Peters helped with the new dos!",cr,lf
300 db "Microsoft rules ok$"
301
302 drvok2:
303 IF IBMVER
304 MOV AL,DRIVE ;This is for ibm's single drive sys
305 PUSH DS
306 MOV BX,50H
307 MOV DS,BX
308 MOV DS:(BYTE PTR 4),AL ;Indicate drive changed
309 POP DS
310 ENDIF
311
312 ;----- Process Pathnames -----------------------------------------------;
313 mov ax,(char_oper shl 8) ;get switch character
314 int 21h
315 cmp dl,"/"
316 jnz slashok ;if not / , then not PC
317 mov [dirchar],"\" ;in PC, dir separator = \
318 mov [userdir],"\"
319
320 slashok:
321 mov si,81h ;point to cammand line
322 mov di,offset dg: fname_buffer
323 xor cx,cx ;zero pathname length
324
325 kill_bl:
326 lodsb ;get rid of blanks
327 cmp al,9
328 je kill_bl
329 cmp al,' '
330 je kill_bl
331 cmp al,13 ;A carriage return?
332 jne next_char
333 jmp noname ;yes, file name missing
334
335 next_char:
336 stosb ;put patname in buffer
337 inc cx
338 lodsb
339 cmp al,' '
340 je name_copied
341 cmp al,9
342 je name_copied
343 cmp al,13 ; a CR ?
344 jne next_char
345
346 name_copied:
347 mov byte ptr [di],0 ;nul terminate the pathname
348 dec di ;adjust to the end of the pathname
349
350 ;----- Scan for directory ----------------------------------------------;
351
352 IF KANJI
353 mov dx,offset dg: [fname_buffer]
354 PUSH DX
355 PUSH DI
356 MOV BX,DI
357 MOV DI,DX
358 DELLOOP:
359 CMP DI,BX
360 JZ GOTDELE
361 MOV AL,[DI]
362 INC DI
363 CALL TESTKANJ
364 JZ NOTKANJ11
365 INC DI
366 JMP DELLOOP
367
368 NOTKANJ11:
369 cmp al,[dirchar]
370 JNZ DELLOOP
371 MOV DX,DI ;Point to char after '/'
372 DEC DX
373 DEC DX ;Point to char before '/'
374 JMP DELLOOP
375
376 GOTDELE:
377 MOV DI,DX
378 POP AX ;Initial DI
379 POP DX
380 SUB AX,DI ;Distance moved
381 SUB CX,AX ;Set correct CX
382 CMP DX,DI
383 JB sja ;Found a pathsep
384 JA sjb ;Started with a pathsep, root
385 MOV AX,[DI]
386 CALL TESTKANJ
387 JNZ same_dirj
388 XCHG AH,AL
389 cmp al,[dirchar]
390 jz sja ;One character directory
391 same_dirj:
392 ELSE
393 mov al,[dirchar] ;get directory separator character
394 std ;scan backwards
395 repnz scasb ;(cx has the pathname length)
396 cld ;reset direction, just in case
397 jz sja
398 ENDIF
399
400 jmp same_dir ;no dir separator char. found, the
401 ; file is in the current directory
402 ; of the corresponding drive. Ergo,
403 ; the FCB contains the data already.
404
405 sja:
406 jcxz sjb ;no more chars left, it refers to root
407 cmp byte ptr [di],':' ;is the prvious character a disk def?
408 jne not_root
409 sjb:
410 mov [the_root],01h ;file is in the root
411 not_root:
412 inc di ;point to dir separator char.
413 mov al,0
414 stosb ;nul terminate directory name
415 pop ax
416 push di ;save pointer to file name
417 mov [fudge],01h ;remember that the current directory
418 ; has been changed.
419
420 ;----- Save current directory for exit ---------------------------------;
421 mov dl,byte ptr ds:[fcb] ;get specified drive if any
422 or dl,dl ;default disk?
423 jz same_drive
424 dec dl ;adjust to real drive (a=0,b=1,...)
425 mov ah,set_default_drive ;change disks
426 int 21h
427 cmp al,-1 ;error?
428 jne same_drive
429 BADDRVSPEC:
430 mov dx,offset dg: baddrv
431 jmp printerr
432
433 same_drive:
434 mov ah,get_default_dpb
435 int 21h
436
437 assume ds:nothing
438
439 cmp al,-1 ;bad drive? (should always be ok)
440 jne drvisok
441 mov dx,offset dg: baddrv
442 jmp printerr
443
444 drvisok:
445 cmp [bx.dpb_current_dir],0
446 je curr_is_root
447 mov si,bx
448 add si,dpb_dir_text
449 mov di,offset dg: userdir + 1
450
451 dir_save_loop:
452 lodsb
453 stosb
454 or al,al
455 jnz dir_save_loop
456
457 curr_is_root:
458 push cs
459 pop ds
460
461 assume ds:dg
462
463
464 ;----- Change directories ----------------------------------------------;
465 cmp [the_root],01h
466 mov dx,offset dg: [dirchar] ;assume the root
467 je sj1
468 mov dx,offset dg: [fname_buffer]
469 sj1:
470 mov ah,chdir ;change directory
471 int 21h
472 mov dx,offset dg: baddrv
473 jnc no_errors
474 jmp printerr
475 no_errors:
476
477 ;----- Set Up int 24 intercept -----------------------------------------;
478
479 mov ax,(get_interrupt_vector shl 8) or 24h
480 int 21h
481 mov word ptr [hardch],bx
482 mov word ptr [hardch+2],es
483 mov ax,(set_interrupt_vector shl 8) or 23h
484 mov dx,offset dg: int_23
485 int 21h
486 mov ax,(set_interrupt_vector shl 8) or 24h
487 mov dx,offset dg: int_24
488 int 21h
489 push cs
490 pop es
491
492 ;----- Parse filename to FCB -------------------------------------------;
493 pop si
494 mov di,fcb
495 mov ax,(parse_file_descriptor shl 8) or 1
496 int 21h
497 push ax
498 ;-----------------------------------------------------------------------;
499 same_dir:
500 pop ax
501
502 mov bx,fcb
503 cmp byte ptr [bx+1],' ' ;must specify file name
504 jnz drvok
505 cmp byte ptr [bx],0 ;or drive specifier
506 jnz drvok
507 noname: mov dx,offset dg: drverr
508 call print
509 jmp int_23
510
511 drvok: push ds
512 mov dl,drive
513 inc dl
514 mov ah,GET_DPB
515 int bdos
516 mov ax,word ptr [bx+2] ;get physical sector size
517 mov cl,byte ptr [bx+4] ;get sectors/cluster - 1
518 xor ch,ch
519 inc cx
520 mov cs:secall,cx ;save sectors per cluster
521 mul cx ;ax = bytes per cluster
522 mov bp,word ptr [bx+11] ;get record of first sector
523 mov dx,word ptr [bx+16] ;get record of first directory entry
524 mov si,word ptr [bx+6] ;get record of first fat
525 mov cl,byte ptr [bx+15] ;get size of fat
526 mov di,word ptr [bx+13] ;get number of clusters
527 mov ch,byte ptr [bx+8] ;get number of fats on drive
528 mov bx,word ptr [bx+9] ;get max number of dir entries
529 pop ds
530
531 mov maxent,bx
532 mov firfat,si
533 mov firrec,bp
534 mov firdir,dx
535 mov byte ptr fatsiz,cl
536 mov lastfat,di ;number of fat entries
537 mov byte ptr fatnum,ch ;save number of fats on disk
538
539 mov secsiz,ax
540
541 mov di,table ;di points into constructed directory
542 mov ax,0e5e5h ;deleted file magic number
543 shl bx,1 ;16 words in a dir entry
544 shl bx,1
545 shl bx,1
546 shl bx,1
547 mov cx,bx
548 rep stosw
549
550 call readft
551 mov bx,fcb
552 cmp byte ptr [bx+1],' '
553 jz recdsk
554 jmp recfil
555
556 recdsk: mov di,table
557 mov fatptr,2
558 mov ax,fatptr
559 step1: call getfat
560 cmp bx,0fffh
561 jz step1a
562 jmp step6
563 step1a: mov filsiz,0
564 mov word ptr filsiz+2,0
565 mov dx,lastfat
566 mov target,ax
567 step2: mov ax,2
568 add filsiz,cx
569 adc word ptr filsiz+2,0
570 step3: call getfat
571 cmp bx,target
572 jne step4
573 mov target,ax
574 jmp step2
575 step4: inc ax
576 cmp ax,dx
577 jle step3
578 ;
579 ; at this point target = head of list, filsiz = file size
580 ;
581 inc filcnt ;increment file count
582 mov ax,maxent
583 cmp filcnt,ax ;compare with max number of entries
584 ja direrr
585
586 mov si,(offset dg: dirent)+7
587 nam0: inc byte ptr [si] ;increment file name
588 cmp byte ptr [si],'9'
589 jle nam1
590 mov byte ptr [si],'0'
591 dec si
592 jmp nam0
593
594 nam1: mov ah,GET_DATE
595 int bdos ;set the date
596 sub cx,1980
597 add dh,dh
598 add dh,dh
599 add dh,dh
600 add dh,dh
601 add dh,dh
602 rcl cl,1
603 or dh,dl
604 mov byte ptr dirent+24,dh
605 mov byte ptr dirent+25,cl
606 mov ah,GET_TIME
607 int bdos ;set the time
608 shr dh,1
609 add cl,cl
610 add cl,cl
611 add cl,cl
612 rcl ch,1
613 add cl,cl
614 rcl ch,1
615 add cl,cl
616 rcl ch,1
617 or dh,cl
618 mov byte ptr dirent+22,dh
619 mov byte ptr dirent+23,ch
620
621 mov ax,filsiz ;set file size
622 mov word ptr dirent+28,ax
623 mov ax,word ptr filsiz+2
624 mov word ptr dirent+30,ax
625 mov ax,target ;set first cluster location
626 mov word ptr dirent+26,ax
627
628 mov si,offset dg: dirent ;copy in new dir entry
629 mov cx,32
630 rep movsb
631
632 step6: inc fatptr ;keep looking for eof's
633 mov ax,fatptr
634 cmp ax,lastfat
635 jg step7
636 jmp step1
637
638 direrr: dec filcnt
639 mov dx,offset dg: dirmsg
640 call print
641
642 step7:
643 mov al,drive
644 mov dx,firdir ;write out constructed directory
645 mov cx,firrec
646 sub cx,dx
647 mov bx,table
648 call dskwrt
649 call pcrlf
650 mov dx,offset dg: recmsg_pre
651 call print
652 mov bx,offset dg: recmsg_post
653 mov si,filcnt
654 xor di,di ;output number of files created
655 call convert
656 jmp rexit
657 recfil: mov dx,fcb
658 mov ah,FCB_OPEN
659 int bdos
660 inc al
661 jnz recfil0
662 mov dx,offset dg: opnerr
663 call print
664 jmp rexit
665
666 recfil0:mov lastfat,1 ;indicate location of list head
667 mov di,fcb
668 mov ax,[di+16] ;get file size
669 mov filsiz,ax
670 mov siztmp,ax
671 mov ax,[di+18]
672 mov filsiz+2,ax
673 mov siztmp+2,ax
674 mov ax,[di+25] ;get list head
675 or ax,ax
676 mov fatptr,ax
677 jnz recfil1
678 recvec: jmp recfil6
679
680 recfil1:cmp fatptr,0fffh
681 jz recvec ;terminate loop at e-o-f
682
683 mov cx,secall
684 mov ax,fatptr
685 dec ax
686 dec ax
687 mul cx
688 add ax,firrec
689 mov dx,ax
690 mov bx,table
691 mov al,drive
692 int aread
693 pop di ;restore stack pointer
694 mov di,fcb ;restore pointer to fcb
695 jnc recfil4 ;if no error continue reading
696
697 mov ax,fatptr
698 call getfat
699 cmp lastfat,1
700 jnz recfil2
701
702 cmp bx,0fffh
703 jnz noteof
704 xor bx,bx
705 noteof: mov word ptr [di+25],bx
706 jmp recfil3
707
708 recfil2:mov dx,bx ;jump around bad sector
709 mov ax,lastfat
710 call setfat
711
712 recfil3:mov ax,fatptr ;mark sector bad
713 mov dx,0ff7h
714 call setfat
715 mov ax,secsiz ;prepare to dec filsiz by secsiz
716 cmp siztmp+2,0
717 jnz recfilx
718 cmp siztmp,ax
719 ja recfilx
720 mov ax,siztmp
721
722 recfilx:sub word ptr [di+16],ax
723 sbb word ptr [di+18],0
724 sub siztmp,ax
725 sbb siztmp,0
726
727 and byte ptr [di+24],10111111b ;mark file dirty
728
729 mov ax,lastfat ;point to next sector to check
730 jmp recfil5
731
732 recfil4:
733 mov ax,secsiz ;set bytes remaining to be read
734 sub siztmp,ax
735 sbb siztmp+2,0
736 jnc recok
737 xor ax,ax ;if < 0, then set to zero
738 mov siztmp,ax
739 mov siztmp+2,ax
740
741 recok: mov ax,fatptr ;get next sector to test
742 mov lastfat,ax
743 recfil5:call getfat
744 mov fatptr,bx
745 jmp recfil1
746
747 recfil6: ;all done
748 mov dx,fcb
749 mov ah,FCB_CLOSE
750 int bdos ;close the file
751 call pcrlf
752 call report
753
754 ;
755 rexit: mov ah,DISK_RESET
756 int bdos
757 call wrtfat ;save the fat
758 int_23: call rest_dir
759 rabort: int boot ;home, james...
760
761 ;----- Restore INT 24 vector and old current directory -----------------;
762 rest_dir:
763 cmp [fudge],0
764 je no_fudge
765
766 mov ax,(set_interrupt_vector shl 8) or 24h
767 lds dx,[hardch]
768 int 21h
769 push cs
770 pop ds
771
772 mov dx,offset dg: userdir ;restore directory
773 mov ah,chdir
774 int 21h
775 mov dl,[user_drive] ;restore old current drive
776 mov ah,set_default_drive
777 int 21h
778
779 no_fudge:
780 ret
781
782 ;----- INT 24 Processing -----------------------------------------------;
783
784 int_24_retaddr dw int_24_back
785
786 int_24 proc far
787 assume ds:nothing,es:nothing,ss:nothing
788
789 pushf
790 push cs
791 push [int_24_retaddr]
792 push word ptr [hardch+2]
793 push word ptr [hardch]
794 ret
795 int_24 endp
796
797 int_24_back:
798 cmp al,2 ;abort?
799 jnz ireti
800 push cs
801 pop ds
802
803 assume ds:dg
804
805 call rest_dir
806 int 20h
807 ireti:
808 iret
809
810 IF KANJI
811 TESTKANJ:
812 CMP AL,81H
813 JB NOTLEAD
814 CMP AL,9FH
815 JBE ISLEAD
816 CMP AL,0E0H
817 JB NOTLEAD
818 CMP AL,0FCH
819 JBE ISLEAD
820 NOTLEAD:
821 PUSH AX
822 XOR AX,AX ;Set zero
823 POP AX
824 RET
825
826 ISLEAD:
827 PUSH AX
828 XOR AX,AX ;Set zero
829 INC AX ;Reset zero
830 POP AX
831 RET
832 ENDIF
833
834 code ends
835
836 const segment public byte
837
838 EXTRN BADVER:BYTE,askmsg:BYTE,drvlet:BYTE,dirmsg:BYTE
839 EXTRN recmsg_pre:BYTE,DRVLET1:BYTE,recmsg_post:BYTE
840 EXTRN crlf:BYTE,drverr:BYTE,baddrv:BYTE,opnerr:BYTE
841
842 const ends
843
844 data segment byte
845
846 PUBLIC filsiz
847
848 dirent db 'FILE0000REC'
849 db 21 dup (00)
850
851 fndfat dw 0000 ;sector of first good fat
852 filcnt dw 0000
853 fatcnt db 00
854 fatnum db 00
855 fatsiz dw 0000
856 firfat dw 0000
857 fatptr dw 0000
858 secall dw 0000 ;sectors per cluster
859 target dw 0000
860 maxent dw 0000
861 firrec dw 0000
862 firdir dw 0000
863 secsiz dw 0000
864 siztmp dw 0000
865 dw 0000
866 filsiz dw 0000
867 dw 0000
868 lastfat dw 0000
869 ;
870 table dw offset dg:fattbl + 6 * 1024
871 fattbl db 0
872
873 data ends
874
875 end recover
876