2 TITLE RECOVER
.SAL - MS-DOS
File/Disk Recovery Utility
3 ;----------------------------------------------------------
5 ; Recover - Program to rebuild an ms.dos directory
7 ; Copyright 1988 by Microsoft Corporation
9 ;-----------------------------------------------------------
11 include recchng
.inc ;an000;bgb
12 include recseg
.inc ;AN000;bgb
13 INCLUDE DOSSYM
.INC ;AN000;bgb
14 INCLUDE RECEQU
.INC ;AN000;bgb
15 INCLUDE RECdata
.INC ;AN000;bgb
16 INCLUDE recmacro
.inc ;AN000;bgb
17 INCLUDE sysmsg
.INC ;AN000;bgb
21 ;*****************************************************************************
23 ;*****************************************************************************
24 data segment public para
'DATA' ;An000;bgb
28 extrn FATErrWrite
:Byte
32 extrn no_mem_arg
:word ;an013;bgb
36 ;******************************************************************************
38 ;******************************************************************************
39 code segment public para
'code' ;An000;bgb
41 public GetFat
, getSmall
, getfat1
, getret
, SetFat
, setsmall
, f_exists
;AN000;bgb
42 public nofspec
, kill_bl
, endl
, next_char
54 public setfat2
, setfat1
, setRet
, GetKeystroke
, Prompt
, Load, ReadFt
, WrtFat
;AN000;bgb
55 public wrtit
, wrtok
, fEOF
, EOFok
, printerr
, SFFromFCB
, Main_Routine
;AN000;bgb
56 public slashok
, kill_bl
, next_char
, name_copied
, sja
, sjb
, not_root
;AN000;bgb
57 public same_drive
, sj1
, no_errors
, same_dir
, noname
, drvok
, See_If_File
;AN000;bgb
58 public step2
, step3
, step4
, direrr
, fill_dir
, file_spec
;AN000;bgb
59 public RecFil
, recfil0
, rexit1
, int_23
, rabort
, rest_dir
, no_fudge
;AN000;bgb
60 public int_24
, int_24_back
, ireti
, Read_File
, Bad_File_Read
, read_fats
;AN000;bgb
61 public fill_fat
, rexit2
, sfsize
, stop_read
, calc_fat_addr
;an027;bgb
62 EXTRN Write_Disk
:NEAR,Read_Disk
:NEAR,report
:NEAR ; AC000;SM
64 Extrn Change_Blanks
:Near ;an012;bgb
65 Extrn Build_String
:Near
67 extrn exitpgm
:near ;an026;bgb
70 ;***************************************************************************** ;an005;bgb
71 ; calc_fat_addr - calculate the seg/off of the fat cell from the cell number ;an005;bgb
73 ; Inputs: AX the fat cell number ;an005;bgb
74 ; BX the fat table offset
75 ; ES the fat table segment (same as program seg) ;an005;bgb
76 ; Outputs: BX contains the offset of the fat cell ;an005;bgb
77 ; ES contains the segment of the fat cell ;an005;bgb
79 ; LARGE FAT SUPPORT ;an005;bgb
80 ;******************* ;an005;bgb
81 ; the offset into the fat table is cluster number times 2 (2 bytes per fat entry) ;an005;bgb
82 ; This will result not only in the segment boundary being passed, but also in ;an005;bgb
83 ; a single-word math overflow. So, we calculate the the address as follows: ;an005;bgb
84 ; 0. start with cluster number (1-65535) ;an005;bgb
85 ; 1. divide by 8 to get the number of paragraphs per fat-cell (0-8191) ;an005;bgb
86 ; remainder = (0-7) ;an005;bgb
87 ; 2. multiply the remainder by 2 to get offset in bytes (0-15) ;an005;bgb
88 ; You now have a paragraph-offset number that you can use to calc the addr into ;an005;bgb
89 ; the fat table. To get the physical addr you must add it to the offset of the ;an005;bgb
90 ; table in memory. ;an005;bgb
91 ; 3. add the paras to the segment register ;an005;bgb
92 ; 4. add the offset to the offset register ;an005;bgb
93 ;****************************************************************************** ;an005;bgb
94 Procedure calc_fat_addr
,near ;an005;bgb
95 savereg
<ax,dx> ; ax already has cluster number ;an005;bgb
96 lea bx,fattbl
;point to fat table in memory ;an005;bgb
97 call seg_adj
;es:bx = es:00
98 mov bx,0008h ; set up div by para (* 2 bytes per clus) ;an005;bgb
99 xor dx,dx ; zero dx for word divide ;an005;bgb
100 div bx ; do it ;an005;bgb
101 mov bx,es ; get fat table segment ;an005;bgb
102 add bx,ax ; add number of paras to the cluster ;an005;bgb
103 mov es,bx ; move it back ;an005;bgb
104 shl dx,1 ; remainder times 2 ;an005;bgb
105 mov bx,dx ; offset = 00 + remainder ;an005;bgb
106 restorereg
<dx,ax> ;an005;bgb
108 EndProc calc_fat_addr
;an005;bgb
112 break <GetFat
- return the contents of a fat
entry>
113 ;*****************************************************************************
114 ; GetFat - return the contents of a fat cell
116 ; Inputs: AX the fat cell number
117 ; Outputs: BX contains the contents of the fat cell AX
118 ; CX contains the number of bytes per sector
119 ; Registers Revised: SI
124 ; double fat-number 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
125 ; fat-table offset = fat-num * 2 2 4 6 8 10 12 14 16 18 20
127 ; fat-table offset = fat-num + (fat-num/2)
129 ; LARGE FAT SUPPORT - if this is a 16-bit fat, use the new calc algorithm
131 ;******************************************************************************
132 Procedure GetFat
,NEAR
134 lea bx,fattbl
;point to fat table in memory ;AC000;bgb
135 cmp MaxClus
,4086 ; if (MaxClus >= 4086) {
136 ; $IF AE ;changed to above because max clusters ;an005;bgb
138 ;can now be 'FFFF'hex ;an005;bgb
139 call calc_fat_addr
; ;set up div by para ;an005;bgb
140 mov bx,word ptr es:[bx] ; get contents of fat ;an005;bgb
141 ; $ELSE ;small fat ;AN000;bgb
144 getSmall: push ax ;save fat-num ; i = clus + clus/2;
145 mov si,ax ;save fat-num ;
147 pushf ;save low bit ;
148 add si,ax ;clus + clus/2 ;
149 mov bx,word ptr [bx][si] ; b = b[i];
157 getfat1: and bh,0fh ;even fat-num ; b &= 0xFFF; AC000;bgb
161 getret: mov cx,secsiz
; c = SecSize;
166 break <SetFat
- change the contents of a fat element
>
167 ;*****************************************************************************
168 ; SetFat - given a fat index and a value, change the contents of the fat
169 ; cell to be the new value.
171 ; Inputs: AX contains the fat cell to change
172 ; DX contains the new value to put into the fat cell
173 ; Outputs: FAT [AX] = DX
174 ; Registers Revised: CX, SI
176 ; LARGE FAT SUPPORT - if this is a 16-bit fat, use the new calc algorithm
178 ;*****************************************************************************
179 Procedure SetFat
,NEAR
181 lea bx,fattbl
; b = &Table; ;AC000;bgb
182 cmp MaxClus
,4086 ;12 bit fat? if (MaxClus >= 4086) {
183 ; $IF AE ;changed to above because max clusters now 'ffff'hex ;an005;bgb
185 call calc_fat_addr
; calc the fat cell addr ;an005;bgb
186 mov word ptr es:[bx],dx ; get the contents ;an005;bgb
190 setsmall: SaveReg
<ax,dx> ;yes, 12 bit fat
191 mov si,ax ; fat cell number i = clus + clus / 2;
192 sar ax,1 ; fat cell num /2
193 pushf ; save result if ax was odd
194 add si,ax ; offset = 1 1/2 bytes * fat cell num
195 mov ax,word ptr [bx][si] ; get contents of fat cell
196 popf ; get results from div ; if ((clus&1) != 0) {
197 ; $IF C ; was fat cell num odd?
199 and ax,000fh ;yes ;keep unchanged part
205 setfat2: and ax,0f000h ; no, even ;keep unchanged part
208 setfat1: or ax,dx ; move new value into ax
209 mov word ptr [bx][si],ax ; b[i] = a;
213 setret: return
; return;
217 Break <GetKeystroke
- await a single keystroke
and flush all remaining
>
218 ;*****************************************************************************
219 ; GetKeystroke - let the user hit a key and flush the input buffer. Kanji/
220 ; Taiwanese force this
224 ; Registers Revised: AX
225 ;*****************************************************************************
226 Procedure GetKeystroke
,NEAR
227 MOV AX,(Std_CON_Input_Flush
SHL 8) + Std_CON_Input_No_Echo
229 MOV AX,(Std_CON_Input_Flush
SHL 8) + 0
235 ;*****************************************************************************
237 ;*****************************************************************************
238 Procedure Prompt
,NEAR
244 ; move drive letter in message
245 lea dx,askmsg
; AC000;SM ;AC000;bgb
247 call DISPLAY_interface
;AC000;bgb
253 MOV AL,cs:DRIVE
; This is for ibm's single drive sys;AN000;bgb
255 JA NOSET
; Values other than 0,1 are not appropriate.
259 MOV DS:(BYTE PTR 4),AL ; Indicate drive changed
268 Break <Load - set up registers for abs sector read
/write
>
269 ;******************************************************************************
270 ; Load - load up all registers for absolute sector read/write of FAT
272 ; called by: readft, writeft
275 ; Outputs: AL - drive number (a=0)
276 ; ES:BX - point to FAT table ;an005;bgb
277 ; CX - number of sectors in FAT
278 ; DX - sector number of the first FAT sector
279 ; FatCnt - is set to the number of fats
280 ; Registers Revised: ax, dx, cx, bx
281 ;******************************************************************************
283 set_data_segment
;an005;bgb
284 mov dx,firfat
;sector number of first fat 1-65535
285 mov al,fatnum
;number of fats 2 ;AC000;bgb
286 mov fatcnt
,al ;FatCnt = FatNum; 1-65535 ;AC000;bgb
287 mov al,drive
;drive number a=0 b=1 ;AN000;bgb
288 mov cx,fatsiz
;sectors in the fat 1-65535
289 lea bx,fattbl
; es:bx --> fat table ;an005;bgb
293 Break <ReadFT
- read
in the entire fat
>
294 ;******************************************************************************
295 ; ReadFt - attempt to read in the fat. If there are errors, step to
296 ; successive fats until no more.
299 ; Outputs: Fats are read until one succeeds.
300 ; Carry set indicates no Fat could be read.
301 ; Registers Revised: all
304 ; DO for each of the fats on the disk:
305 ; read - all the sectors in the fat
306 ; increase the starting sector by the number of sectors in each fat
308 ; LARGE FAT SUPPORT - the big change here is in read disk. since the fat must ;an005;bgb
309 ; be within the first 32M, then the starting sector number of 65535 is ok, ;an005;bgb
310 ; as is a larger number of sectors to read/write. ;an005;bgb
311 ;******************************************************************************
312 Procedure ReadFt
,NEAR
313 set_data_segment
;an027;bgb;an005;bgb
314 mov dx,firfat
;sector number of first fat 1-65535 ;an027;bgb
315 mov al,fatnum
;number of fats 2 ;an027;bgb ;AC000;bgb
316 mov fatcnt
,al ;FatCnt = FatNum; 1-65535 ;an027;bgb ;AC000;bgb
317 mov al,drive
;drive number a=0 b=1 ;an027;bgb;AN000;bgb
318 mov cx,fatsiz
;sectors in the fat 1-65535 ;an027;bgb
319 lea bx,fattbl
; es:bx --> fat table ;an027;bgb;an005;bgb
320 clc ;clear carry flag ;an027;bgb
321 mov Read_Write_Relative
.Start_Sector_High
,bp ;set hi word to zero ;AN000;
322 call Read_Disk
; read in fat #1 ;AC000;
323 ; $IF C ; was it a bad read? ;an027;bgb
325 add dx,cx ;point to 2nd fat
326 call Read_Disk
; read in 2nd fat ;AC000;
327 ; $ENDIF ;carry flag set if both fats bad ;AC000;bgb
334 Break <WrtFat
- write
out the fat
>
335 ;*****************************************************************************
336 ; WrtFat - using the results of a ReadFt, attempt to write out the fat
340 ; Outputs: A write of the fat is attempted in each fat position until
342 ; Registers Revised: all
345 ; DO for each fat on the disk
346 ; write the fat to disk
347 ; increase the starting sector number by the number of sectors per fat
349 ; LARGE FAT SUPPORT - the big change here is in read disk. since the fat must ;an005;bgb
350 ; be within the first 32M, then the starting sector number of 65535 is ok, ;an005;bgb
351 ; as is a larger number of sectors to read/write. ;an005;bgb
352 ;****************************************************************************
353 Procedure WrtFat
,NEAR
354 call load ; load (); ;an005;bgb
357 wrtit: call Write_Disk
; Write_Disk (); ;an005;bgb
358 ; $LEAVE C ;an015;bgb
360 wrtok: add dx,cx ; fatStart += fatsize; ;an005;bgb
361 dec byte ptr fatcnt
; } while (--fatcnt); ;an005;bgb
362 ; $ENDDO Z ;an005;bgb
370 Break <fEOF
- check to see
if the argument is EOF
>
371 ;*****************************************************************************
372 ; fEOF - test BX to see if it indicates EOF
374 ; Inputs: BX - contains cluster
375 ; Outputs: Carry is set if BX indicates EOF
376 ; Registers Revised: none
377 ;*****************************************************************************
381 CMP BL,0F7h ; bad sector indicator
390 ;*****************************************************************************
391 ;*****************************************************************************
395 Break <sfFromFCB
- take an FCB
and convert it to a sf pointer
>
396 ;*****************************************************************************
397 ; SFFromFCB - index into System File tables for SFN.
399 ; Input: ES:DI has FCB pointer
400 ; Output: ES:DI points to Sys-File-table entry
401 ; Registers Revised: ES:DI, BX only
403 ;*****************************************************************************
404 procedure SFFromFCB
,NEAR
405 MOV BL,ES:[DI].FCB_SFN
;fcb+18 = system file table 00
408 MOV AH,Get_IN_Vars
;52h
409 INT 21h
; p = DOSBASE();
410 ; bx = 0026, ax=5200 es=0257
411 LES DI,DWORD PTR ES:[BX].SYSI_FCB
;load es:di w/ ptr to sf table
413 LEA DI,[DI].sfTable
; di=6 AC000;bgb
416 MOV AX,SIZE SF_Entry
;42
423 ;*****************************************************************************
424 ;*****************************************************************************
425 Procedure get_dpb_info
,Near ;AN000;bgb
426 ; get dpb for drive indicated
427 push ds ;save ds seg reg
428 mov dl,drive
; get drive number a=0 b=1 c=2 ;AN000;bgb
429 inc dl ; a=1, b=2, c=3
430 mov ah,GET_DPB
; hidden system call (032h)
432 ; note: ds is now changed !!!!
433 cmp al,0FFH ; -1 = bad return code
437 mov ax,word ptr [bx].dpb_sector_size
; get physical sector size
438 mov es:bytes_per_sector
,ax ; save bytes per sector 200 ;AN000;bgb
439 ; get sectors per cluster
440 xor ch,ch ; zero out high byte ;ac000;bgb
441 mov cl,byte ptr [bx].dpb_cluster_mask
; get sectors/cluster - 1
442 inc cx ;1+1=2 ; get sectors / cluster
443 mov es:secall
,cx ;2 ; save sectors per cluster ;AC000;bgb
444 ; get bytes per cluster
445 mul cx ; ax = bytes per cluster
446 mov eS:secsiz
,ax ;400 ; save bytes per cluster ;AC000;bgb
447 ; first sector record
448 mov ax,[bx].dpb_first_sector
; get record of first sector
449 mov es:firrec
,ax ;c ; ;AC000;bgb
451 mov dx,[bx].dpb_dir_sector
; get record of first directory entry
452 mov es:firdir
,dx ;5 ; ;AC000;bgb
454 mov si,[bx].dpb_first_fat
; get record of first fat
455 mov es:firfat
,si ;1 ; sector number of first fat ;AC000;bgb
457 mov cX,[bx].dpb_fat_size
; get size of fat (num of rcds) ;AC000;BGB
458 mov es:fatsiz
,cX ;2 ;SIZE OF FAT FROM DPB ;AC000;BGB
460 mov di,[bx].dpb_max_cluster
; get number of clusters
461 mov es:lastfat
,di ;163 ; number of fat entries ;AC000;bgb
462 mov es:MaxClus
,di ;163 ; number of fat entries ;AC000;bgb
463 ; number of fats (1 or 2)
464 mov ch,[bx].dpb_fat_count
; get number of fats on drive
465 mov byte ptr es:fatnum
,ch ;2 ; save number of fats on disk ;AC000;bgb
467 mov bx,[bx].dpb_root_entries
; get max number of dir entries
468 mov ES:maxent
,bx ;70 ; ;AC000;bgb
469 pop ds ; restore ds register to group ;AC000;bgb
473 pop ds ; restore ds register to group ;AC000;bgb
474 jmp noname
; bad return = display error msg
478 endproc get_dpb_info
; ;AN000;bgb
482 ;*****************************************************************************
483 ; assemble this part if doing japanese version
485 ;INPUTS: es:di - points to last char in filename
486 ; ds:dx - point to beginning of filename
488 ;*****************************************************************************
489 Procedure check_kanji
,Near ;AN000;bgb
491 lea dx,[fname_buffer
] ;point to filename ;AC000;bgb
494 MOV BX,DI ;bx and di now point to last char in filename
495 MOV DI,DX ;di now points to filename
497 ;do for entrire filename
498 delloop: CMP DI,BX ;are we at the beginning of the filename?
499 JAE GOTDELE
;yes, and we are finished
500 MOV AL,[DI] ;get next char in filename
501 INC DI ;point one past it
502 CALL TESTKANJ
;see if it is dbcs
504 INC DI ;bump to past 2nd of dbcs pair
505 JMP DELLOOP
;check next char in file name
506 notkanj11: cmp al,[dirchar
] ;is it '\' ?
507 JNZ DELLOOP
;no, check next char
508 MOV DX,DI ; Point to char after '/'
510 DEC DX ; Point to char before '/'
514 gotdele: MOV DI,DX ;point to?
516 POP DX ;re-point to beginning of filename
517 SUB AX,DI ; Distance moved
518 SUB CX,AX ; Set correct CX
519 ; CMP DX,DI ;an024;bgb
520 ;stop: $if b ;an024;bgb
521 ; pop ax ;an024;bgb;an024;bgb
522 ; pop cx ;an024;bgb;an024;bgb;an024;bgb
524 ;;;;;;;;;;;;;;; JB sja ; Found a pathsep ;an024;bgb
527 ; pop ax ;an024;bgb;an024;bgb
528 ; pop cx ;an024;bgb;an024;bgb;an024;bgb
530 ;;;;;;;;;;;;;;; JA sjb ; Started with a pathsep, root ;an024;bgb
532 MOV AX,[DI] ;an024;bgb
533 CALL TESTKANJ
;an024;bgb
534 JNZ same_dirjk
;an024;bgb
535 XCHG AH,AL ;an024;bgb
536 ; cmp al,[dirchar] ;an024;bgb
538 ; pop ax ;an024;bgb;an024;bgb;an024;bgb
539 ; pop cx ;an024;bgb;an024;bgb;an024;bgb
541 ;;;;;;;;;;;;;;;;jz sja ; One character directory ;an024;bgb
546 check_kanji endp
; ;AN000;bgb
549 ;****************************************************************************
550 ;****************************************************************************
553 TESTKANJ: push ds ;get dbcs vector ;an012;bgb
556 mov ax,6300h
;get dbcs vector ;an024;bgb;an012;bgb
559 sub si,2 ;prep for loop ;an012;bgb
561 add si,2 ;point to next dbcs vector ;an012;bgb
562 cmp word ptr ds:[SI],bp ;do until 00 found in dbcs vector table ;an012;bgb
563 je notlead
;00 found, quit ;an012;bgb
564 CMP AL,byte ptr ds:[si] ;look at lead byte of dbcs char ;an012;bgb
565 jb dbcsmore
;al < lead byte means not dbcs ;an012;bgb
566 CMP al,byte ptr ds:[si+1] ;look at 2nd byte of dbcs ;an012;bgb
567 JBE ISLEAD
;if it is between the 2 chars, it is dbcs ;an012;bgb
568 jmp dbcsmore
;go get the next dbcs vector ;an012;bgb
578 mov es:dbcs_sw
,1 ;an024;bgb
593 ;*****************************************************************************;an020;bgb
594 ; copy the filename from the fcb to the data segment ;an020;bgb
595 ;*****************************************************************************;an020;bgb
596 Procedure copy_fname
,Near ;AN000;bgb ;an020;bgb
597 ;get fcb1 from the psp
598 slashok: mov cx,PSP_Segment
;Get addrbility of psp ;AN000;bgb
599 mov ds,cx ; " " " " " " ;AN000;bgb
600 assume
ds:dg
,es:dg
; " " " " " " ;AN000;bgb
605 ; remove leading blanks and tabs from filename
606 nofspec: mov si,81h
; point to command line ;AC000;bgb
607 lea di,fname_buffer
; point to filename ;ac000;bgb
608 xor cx,cx ; zero pathname length
609 ; $DO ;get source chars until neither tabs or blanks found
611 kill_bl: lodsb ; get next char ;AN000;bgb
612 cmp al,tab
; leading tabs? (hex 9) ;AN000;bgb
613 ; $LEAVE NE,AND ; yes - done ;AN000;bgb
615 cmp al,' ' ; leading blanks? (hex 20) ;AN000;bgb
619 ; $ENDDO ; ;AN000;bgb
624 ;was any parameter entered at all?
625 endl: cmp al,13 ; no name found if the 1st char is CR
626 jne next_char
; file name or drive entered
627 jmp noname
; no parameter entered
631 ;copy filename from cmd line to fname buffer
633 stosb ; move byte in al to fname_buffer
634 inc cx ;inc fname counter
635 lodsb ; get next byte
636 cmp al,' ' ; terminated by blank?
638 cmp al,9 ;terminated by tab?
640 cmp al,13 ; terminated by CR?
644 ;reset ds to data segment
645 name_copied: ; got file name
647 pop ds ;ds now points to data seg
650 mov byte ptr [di],0 ; nul terminate the pathname
651 dec di ; adjust to the end of the pathname
653 copy_fname endp
; ;an020;bgb
658 ;*****************************************************************************;an020;bgb
659 ; get a copy of the fcb ;an020;bgb
660 ;*****************************************************************************;an020;bgb
661 Procedure get_fcb
,Near ;AN000;bgb ;an020;bgb
662 mov si,fcb
; ds:si point to fcb in the psp ;AN000;bgb
663 lea di,fcb_copy
; es:di point to the copy in the data seg;AC000;bgb
664 mov cx,32 ; move 32 bytes ;AN000;bgb
665 rep movsb ; from ds:si (fcb) to es:di (fcb-copy) ;AN000;bgb
666 ;check if it is not there (in psp) ;an024;bgb;an020;bgb
667 ; mov si,fcb ;point to fcb1 ;an024;bgb;AN014;bgb
668 ; cmp byte ptr ds:[si+1],' ' ;it will be blank if a filespec used ;an024;bgb;AN014;bgb
669 ; $IF E,AND ;an024;bgb;Ac015;bgb
670 ; cmp byte ptr ds:[84h],0dh ;this will be CR if drive letter used ;an024;bgb;AN015;bgb
671 ; $IF NE ;if no drive letter and fcb blank, then filespec! ;an024;bgb;AN015;bgb
672 ;now get the filename from the command line ;an024;bgb;an020;bgb
673 ; step 1 - point to end of cmd line ;an024;bgb
674 mov si,081h ;point to beginning of command line ;AN014;bgb
675 mov cl,byte ptr ds:[80h
] ;get length of cmd line ;AN014;bgb
676 xor ch,ch ;zero out hi byte for word arith ;AN014;bgb
677 add si,cx ;begin plus length of cmd line = end ;AN014;bgb
678 dec si ;point to last char, not CR ;an020;bgb
679 ;step 2 - find the first backslash ;an020;bgb
680 mov exit_sw
,bp ;false ;an024;bgb
681 ; $DO ;do until back slash found ;AN014;bgb
683 cmp byte ptr ds:[si],'\' ;look for back slash ;AN014;bgb
684 ; $IF E ;find it? ;an024;bgb;AN014;bgb
686 mov al,[si-1] ;get possible leading byte ;an024;bgb
688 call testkanj ;is it a leading byte of DBCS? ;an024;bgb
690 ; $IF Z ;no- then it is subdir delimiter ;an024;bgb
692 mov exit_sw,true ;so exit the search loop ;an024;bgb
693 ; $ELSE ;yes it is DBCS leading byte ;an024;bgb
696 dec si ;so skip the leading byte ;an024;bgb
697 ; $ENDIF ;check for kanji ;an024;bgb
701 cmp exit_sw,true ;an024;bgb
702 ; $LEAVE E ;an024;bgb
704 cmp byte ptr ds:[si],0 ;look for 00 (not a filespec) ;AN018;bgb
708 ;;;;;;;;;;;;;;;;je nofspec ;filespec not found ;ac020;bgb
711 dec si ;no , next char ;AN014;bgb
715 ;found backslash, move it into fcb
716 inc si ;point to 1st char of filename ;AN014;bgb
717 lea di,fcb_copy+1 ; move addr of fcb_copy into di ;an024;bgb;AN014;bgb
718 ; $DO ;do until eol - CR found ;AN014;bgb
720 lodsb ;get one byte of filename from cmd line ;AN014;bgb
721 cmp al,0dh ;end of line? ;AN014;bgb
722 ; $LEAVE E ;if so, we are done ;AN014;bgb
724 cmp al,'.' ;is it extension indicator? ;AN014;bgb
725 ; $IF E ;yes ;AN014;bgb
727 lea di,fcb_copy ;point to extension in fcb ;AN014;bgb
728 add di,9 ;point to extension in fcb ;AN014;bgb
729 ; $ELSE ;dont move the period ;AN014;bgb
732 stosb ;move char into fcb ;AN014;bgb
740 get_fcb endp ; ;an020;bgb
744 Break <Main code of recover - Version check and exit if incorrect>
745 ;*****************************************************************************
746 ;Routine name: Main_routine
747 ;*****************************************************************************
749 ;description: Main routine for recovering a file from a bad sector
751 ;Called from: recover_ifs in RECINIT.SAL
754 ;Called Procedures: prompt
768 ;Output: FAT is changed if a bad sector is found.
769 ; The file is complete except for the data in the bad sector.
771 ;Change History: header created 7-19-87 BGB
776 ;*****************************************************************************
779 ;get system switch character
781 set_data_segment ; set es,ds to data ;AN000;bgb
782 ;;;;;;; call change_blanks ; get dbcs blanks ;an012;bgb
783 mov ax,(char_oper shl 8) ; get switch character
784 int 21h ; put into dl
785 cmp dl,"/" ; is it / ?
788 jmp slashok ; if not / , then not PC
791 mov [dirchar],"\" ; in PC, dir separator = \
796 ;check for dbcs double byte chars
806 ;see if there are any '\' in filename parameter
- means filespec
;an024;bgb
807 ;do until a \ is found or end-of-string ;an024;bgb
808 ; if a \ is found ;an024;bgb
809 ; then test for dbcs leading byte ;an024;bgb
810 ; if it is not dbcs leading byte ;an024;bgb
811 ; then exit loop ;an024;bgb
812 ; else continue loop ;an024;bgb
816 and cx,cx ;compare cx to zero ;an024;bgb
817 ; $LEAVE E ;an024;bgb
819 mov al,[dirchar
] ;05ch ; get directory separator character ;an024;bgb
820 cmp al,byte ptr [di] ; (cx has the pathname length) ;an024;bgb
821 ; $IF E ; reset direction, just in case ;an024;bgb
823 mov al,[di-1] ;get possible leading byte ;an024;bgb
825 call testkanj
;see if it is leading byte ;an024;bgb
827 ; $IF Z ;not a leading byte? then its a '\' ;an024;bgb
829 mov lastbs
,di ;an024;bgb
830 mov di,lastchar
;an024;bgb
831 jmp sja
;zero = not a leading byte ;an024;bgb
840 ;save current disk ;an008;bgb
841 mov ah,19h
;an008;bgb
843 mov old_drive
,al ;an008;bgb
844 jmp same_dir
; no dir separator char. found, the
845 ; file is in the current directory
846 ; of the corresponding drive. Ergo,
847 ; the FCB contains the data already.
850 ;handle filespec here
851 ;at least one '\' found in filename
853 jcxz sjb
; no more chars left, it refers to root
855 mov di,lastbs
;an024;bgb
856 cmp byte ptr [di-1],':' ; is the prvious character a disk def?;an024;bgb
860 mov [the_root
],01h ; file is in the root
862 inc di ; point to dir separator char.
863 mov ax,bp ;set to zero
864 stosb ; nul terminate directory name
866 ; push di ; save pointer to file name
867 mov [fudge
],01h ; remember that the current directory
869 ;save current disk ;an008;bgb
870 mov ah,19h
;an008;bgb
872 mov old_drive
,al ;an008;bgb
873 ;----- Save current directory for exit ---------------------------------;
874 mov dl, drive
; get specified drive if any
875 ;;;;;;; or dl,dl ; default disk? ;an021;bgb
876 ;;;;;;; jz same_drive ;an021;bgb
877 ;;;;;;;;dec dl ; adjust to real drive (a=0,b=1,...) ;an021;bgb
878 mov ah,set_default_drive
; change disks
883 ; lea dx,baddrv ; AC000;SM ;AC000;bgb
888 mov ah,Current_Dir
; userdir = current directory string
889 mov dx,bp ;set to zero
890 lea si,userdir
+1 ;AC000;bgb
893 ;----- Change directories ----------------------------------------------;
895 lea dx,[dirchar
] ; assume the root ;AC000;bgb
897 lea dx,[fname_buffer
] ;AC000;bgb
900 mov di,lastbs
;an024;bgb
901 mov byte ptr [di],0 ;an024;bgb
902 mov ah,chdir
; change directory
904 mov byte ptr [di],'\' ;an024;bgb
906 mov al,Drive ;Get drive number ;AN000;bgb
907 add al,"A"-1 ;Make it drive letter ;AN000;
908 mov Drive_Letter_Msg,al ;Put in message ;AN000;
909 lea dx,baddrv ;AC000;bgb
917 Break <Set up exception handlers>
919 ;----- Parse filename to FCB -------------------------------------------;
921 mov si,lastbs ;an024;bgb
923 lea di,fcb_copy ;AC000;bgb
924 mov ax,(parse_file_descriptor shl 8) or 1
927 ;-----------------------------------------------------------------------;
929 lea bx,fcb_copy ;point to 1st byte of fcb (drive num) ;AC000;bgb
930 cmp byte ptr [bx+1],' ' ; must specify file name
932 cmp byte ptr [bx],0 ;or drive specifier
934 cmp dbcs_sw,1 ; or dbcs ;an024;bgb
939 lea dx,baddrv ;AC000;bgb
940 call display_interface ; AC000;bgb
941 pop ax ;reset stack ;an024;bgb
942 pop ax ;reset stack ;an024;bgb
944 ;****************************************************************************
945 ; we're finished with parsing here, do the main function of recover.
947 CALL Prompt ;wait for user keystroke to begin ;AN000;bgb
948 call get_dpb_info ;get device info ;AN000;bgb
949 call fill_fat ; fill fat table w/ null ;AN000;bgb
950 ; $IF C ;was there not enuff memory to run? ;an013;bgb
952 lea dx,no_mem_arg ; ;an013;bgb
953 call printerr ;an013;bgb
954 jmp rabort ;an013;bgb
955 ; $ENDIF ;fat could be read from disk ;an013;bgb
958 call readft ; readft (); ;AN000;bgb
959 ; $IF C ; could the fat be read from disk? ;AN000;bgb
961 lea dx,FATErrRead ; ;AC000;bgb
964 ; $ENDIF ;fat could be read from disk ;AN000;bgb
966 See_If_File: ; ;AN000;
967 lea bx,fname_buffer ; ;AC014;bgb
968 cmp byte ptr [bx+1],':' ;if fname = 'a
:' and..... ;ac020;bgb
969 ; $IF E,AND ; ;an020;bgb
971 cmp word ptr [bx+2],bp ;set to zero ;all zeros following that, then ;an020;bgb
972 ; $IF E ;then drive spec ;AN202;BGB
974 call drive_spec ;only drive specified ;AN000;bgb
975 ; $ELSE ; file name specified ;AN000;bgb
978 call file_spec ;file can be 'f
' or 'a
:,0,file' or 'a
:file' or 'file.ext
' ;an020;bgb
983 int_23: sti ;allow interrupts ;an026;bgb
984 lds dx,cs:dword ptr [int_24_old_off] ;point to old vector ;an026;bgb
985 mov al,24h ;which interrupt to set? ;an026;bgb;AC000;
986 DOS_Call Set_Interrupt_Vector ;set vector to old ;an026;bgb;AC000;
988 lds dx,cs:dword ptr [int_23_old_off] ;point to old vector ;an026;bgb
989 mov al,23h ;which interrupt to set? ;an026;bgb;AC000;
990 DOS_Call Set_Interrupt_Vector ;set vector to old ;an026;bgb;AC000;
992 PUSH CS ;reset ds ;an026;bgb
994 aSSUME DS:DG ;an026;bgb
997 mov cs:ExitStatus,0 ; good return ;AC000;
998 jmp [exitpgm] ;an026;bgb
1000 ret ;Return to RECINIT for exit ;AC000;
1005 ;*************************************************************************
1007 ;*************************************************************************
1008 procedure file_spec,near ;AN000;bgb
1009 ; try to open the file
1010 recfil: lea dx,fcb_copy ; if (FCBOpen (FCB) == -1) { ;AC000;bgb
1011 mov ah,FCB_OPEN ; function ofh = open
1012 int 21h ;returns -1 in al if bad open
1013 cmp al,0ffh ;was file opened ok? ;AN000;bgb
1014 ; $IF E ; no ;AN000;bgb
1017 lea si,FCB_Copy.fcb_name ;Point at filename in FCB ; ;AC000;bgb
1018 lea di,Fname_Buffer ;Point at buffer ; ;AC000;bgb
1019 mov cx,FCB_Filename_Length ;Length of filename ;AN000;
1020 call Change_Blanks ;Convert DBCS blanks to SBCS ;AN000;
1021 call Build_String ;Build ASCIIZ string ending ;AN000;
1022 lea dx,opnerr ; AC000;SM printf (Can't open); ;AC000;bgb
1023 call display_interface ; AC000;bgb
1024 ;ecfil0: $ELSE ; LastFat = 1; ;AN000;bgb
1028 f_exists: call process_file ;file was opend ok
1029 rexit1: mov ah,DISK_RESET
1031 call wrtfat ; save the fat
1032 ; $IF C ;Couldn't write it ;AN000;
1034 lea dx,FATErrWrite ;Just tell user he is in deep! ;AC000;bgb
1035 call display_interface ; ;AN000;bgb
1039 call report ; report (); ;ac015;bgb
1040 ; $ENDIF ;AN000;bgb; ;AN000;
1045 endproc file_spec ;AN000;bgb
1047 ;*************************************************************************
1049 ;*************************************************************************
1050 Procedure process_file,Near ; ;AN000;
1052 mov lastfat,1 ;set to 1 : means 1st fat read in
1053 lea di,fcb_copy ; d = &FCB ;AC000;bgb
1054 mov ax,[di].FCB_FilSiz ;55 siztmp = filsiz = d->filsiz;
1057 mov ax,[di].FCB_FilSiz+2 ;00
1060 SaveReg <ES,DI> ; fatptr =
1061 call sfFromFCB ; sfFromFCB(d)->firclus;
1062 mov ax,ES:[DI].sf_firclus ; es:di +0b = 84
1065 or ax,ax ; if (fatptr == 0)
1068 ; read each fat in the file
1069 ; $DO ;Loop until entire file read in ;AN000;bgb
1071 mov bx,fatptr ;Get current cluster
1072 call fEOF ;Got to the end of the file?
1073 ; $LEAVE C ;Yes if CY ;AN000;bgb
1075 STOP_read: call Read_File ;Go read in the cluster
1076 ; $IF C ;CY indicates an error ;AN000;bgb
1078 call Bad_File_Read ;Go play in the FAT
1079 ; $ELSE ;Read cluster in okay ;AN000;bgb
1082 mov ax,secsiz ;Get bytes/cluster
1083 sub siztmp,ax ;Is size left < 1 cluster?
1084 sbb siztmp+2,bp ;zero ;
1085 ; $IF C ;Yes ;AN000;bgb
1087 xor ax,ax ;Set our running count to 0
1090 ; $ENDIF ;AN000; ;AN000;bgb
1092 mov ax,fatptr ;The previous cluster is now
1093 mov lastfat,ax ; the current cluster
1094 ; $ENDIF ;AX has current cluster ;AN000;bgb
1096 call getfat ;Get the next cluster
1097 mov fatptr,bx ;Save it
1098 ; $ENDDO ;Keep chasing the chain ;AN000;bgb
1101 ; $ENDIF ;All done with data ;AN000;bgb
1103 ; recover extended attributes ;an032;bgb
1104 ; SaveReg <ES,DI> ;Save regs ;AN000; ;an032;bgb
1105 ; call sfFromFCB ;Get sf pointer ;AN000; ;an032;bgb
1106 ; mov ax,[di].sf_ExtCluster ;Look at extended attrib entry ;AN000; ;an032;bgb
1107 ; cmp word ptr [di].sf_ExtCluster,bp ;zero ;Is there extended attribs? ;;an032;bgbAN000;
1108 ; $IF NE ;Yes ;AN000; ;an032;bgb
1109 ; call Read_File ;Try to read it in ;AN000; ;an032;bgb
1110 ; $IF C ;CY means we couldn't ;AN000; ;an032;bgb
1111 ; mov word ptr [di].sf_ExtCluster,bp ;zero ;Off with its head!;an032;bgb;AN000;
1112 ; and ES:[di].sf_flags,NOT devid_file_clean ; mark file dirty ;AN000; ;an032;bgb
1113 ; $ENDIF ; ;AN000; ;an032;bgb
1114 ; $ENDIF ; ;AN000; ;an032;bgb
1115 ; RestoreReg <DI,ES> ; ;AN000; ;an032;bgb
1116 lea dx,fcb_copy ; close (FCB); ;AC000;bgb
1120 endproc process_file ;AN000;bgb
1122 ;*************************************************************************
1123 ;***************************************************************************
1125 ;----- Restore INT 24 vector and old current directory -----------------;
1126 Procedure Rest_dir,Near ; ;AN000;
1130 mov ax,(set_interrupt_vector shl 8) or 24h
1135 lea dx,userdir ; restore directory ;AC000;bgb
1141 mov dl,old_drive ; restore old current drive ;an008;bgb
1142 mov ah,set_default_drive
1147 ;;----- INT 24 Processing -----------------------------------------------;
1148 ;*************************************************************************
1149 int_24_retaddr dw int_24_back
1152 assume ds:nothing,es:nothing,ss:nothing
1153 pushf ; ** MAKE CHANGES **
1155 push [int_24_retaddr]
1156 push word ptr [hardch+2]
1157 push word ptr [hardch]
1158 assume ds:dg,es:dg,ss:dg ;AN000;bgb
1161 ;*************************************************************************
1167 assume ds:dg,es:dg,ss:dg
1169 ret ;Ret for common exit ;AC000;
1173 break < read in a cluster of the file>
1174 ;****************************************************************************
1176 ;Read in cluster of file.
1178 ; Input: Secall = sectors/cluster
1179 ; FatPtr = cluster to read
1180 ; Firrec = Start of data area - always in first 32mb of partition
1181 ; dx = offset of fcb_copy ???
1183 ; Output: CY set if error on read on ret
1184 ; DI = pointer to FCB
1185 ;*****************************************************************************
1186 Procedure Read_File,Near ; ;AN000;
1187 mov cx,secall ;2 ;if (aread((fatptr-2)*secall+firrec) == -1) {
1188 mov ax,fatptr ;84 ;cluster number to read
1189 sub ax,2 ;ax=82 ; -1 ;AN000;bgb
1190 mul cx ;ax=104 ; sectors/clus * (clus-2)
1191 add ax,firrec ;ax=110 ; plus beg of data area
1192 adc dx,bp ;0 ;Handle high word of sector ;AN000;
1193 mov Read_Write_Relative.Start_Sector_High,dx ;Start sector ;AN000;
1194 mov dx,ax ;110 ;clus-2
1195 mov es,table ;2b62 ;segment of area past fat table ;an005;bgb
1196 xor bx,bx ;es:bx --> dir/file area ;an005;bgb
1197 mov al,drive ;0 ;drive num ;AN000;bgb
1198 call Read_Disk ; ; ;AC000;
1199 lea di,fcb_copy ; ;AC000;bgb
1201 endproc Read_File ; ;AN000;
1204 break < found a bad cluster in the file >
1205 ;*************************************************************************
1206 ;Play around with the FAT cluster chain, by marking the cluster that failed
1207 ;to read as bad. Then point the preceding cluster at the one following it.
1208 ;Special case if there is only one cluster, than file gets set to zero
1209 ;length with no space allocated.
1211 ; Input: FatPtr = Cluster that failed to read
1212 ; LastFat = Previous cluster, equals 1 if first cluster
1214 ; Output: AX = previous cluster
1215 ; File size = file size - cluster size ( = 0 if cluster size > file)
1216 ;***************************************************************************
1217 Procedure Bad_File_Read,Near
1218 mov ax,fatptr ;Get current cluster
1219 call getfat ;Get the next cluster in BX
1220 cmp lastfat,1 ;Is this the first entry?
1221 ; $IF E ;Yes ;AC000;
1223 call fEOF ;Is the next the last cluster?
1224 ; $IF C ;Yes ;AC000;
1226 xor bx,bx ;Need to zero out first cluster
1227 ; $ENDIF ; because the first one is bad! ;AN000;
1229 SaveReg <ES,DI,BX> ;Save some info
1230 call sfFromFCB ;Get pointer to sf table
1231 RestoreReg <BX> ;Get back clus to point to
1232 mov ES:[DI].sf_firclus,BX ;Skip offending cluster
1233 RestoreReg <DI,ES> ;Get back regs
1234 ; $ELSE ;Not first entry in chain ;AC000;
1237 mov dx,bx ;DX = next cluster
1238 mov ax,lastfat ;AX = Previous cluster
1239 call setfat ;prev fat points to next fat
1241 ; $ENDIF ; Ta-Da! ;AN000;
1243 mov ax,fatptr ;Get the offending cluster
1244 mov dx,0fff7h ;Mark it bad
1245 call setfat ;Never use it again!
1246 mov ax,secsiz ;Get bytes/sector
1247 cmp siztmp+2,bp ;Is file < 32mb long?
1248 ; $IF NE,AND ; and ;AC000;
1250 cmp siztmp,ax ;Shorter than cluster size?
1251 ; $IF BE ;Yes ;AC000;
1253 mov ax,siztmp ;File size = smaller of the two
1256 SaveReg <ES,DI> ;Save regs
1257 call sfFromFCB ;Get sf pointer
1258 sfsize: sub word ptr ES:[di].sf_size,ax ;Adjust internal file sizes
1259 sbb word ptr ES:[di].sf_size+2,bp ; " " " "
1260 sub siztmp,ax ;Keep track of how much done
1262 and ES:[di].sf_flags,NOT devid_file_clean ; mark file dirty
1263 RestoreReg <DI,ES> ; sfFromFCB(d)->flags &= ~CLEAN;
1265 sub word ptr [di].fcb_filsiz,ax ;And change the FCB
1266 sbb word ptr [di].fcb_filsiz+2,bp ;
1267 and byte ptr [di].fcb_nsl_bits,NOT devid_file_clean ; mark file dirty ;AN000;
1268 mov ax,lastfat ;AX = previous cluster
1270 endproc Bad_File_Read ; ;AN000;
1273 ;***************************************************************************** ;an005;bgb
1274 ; description: fill the fat table in memory with the 'E5
' character ;an005;bgb
1276 ; called from: main-routine ;an005;bgb
1278 ;Change History: Created 8/7/87 bgb ;an005;bgb
1280 ;Input: bytes-per-sector ;an005;bgb
1284 ;Output: ram-based fat table ;an005;bgb
1287 ;---------- ;an005;bgb
1288 ; calc number of para in fat table ;an005;bgb
1289 ; = bytes-per-sector / 16 * sectors-per-fat ;an005;bgb
1290 ; calc segment of directory area in memory ;an005;bgb
1291 ; = fat-table offset + length of fat-table ;an005;bgb
1292 ; calc number of para in directory ;an005;bgb
1293 ; = entries-per-directory * bytes-per-entry / 16 ;an005;bgb
1294 ; do for each para ;an005;bgb
1295 ; move 16 bytes into memory ;an005;bgb
1296 ;***************************************************************************** ;an005;bgb
1298 Procedure fill_fat,Near ;AN000;bgb ;an005;bgb
1299 ; calc fat table length ;an005;bgb
1300 set_data_segment ;an005;bgb
1301 mov ax,bytes_per_sector ; bytes per sector ;an005;bgb
1302 xor dx,dx ;an005;bgb
1303 mov bx,16 ;an005;bgb
1304 div bx ; paras per sector ;an005;bgb
1305 mov cx,fatsiz ;2 ; get sectors per fat ;an005;bgb
1306 xor dx,dx ;an005;bgb
1307 mul cx ; paras per fat ;an005;bgb
1308 mov paras_per_fat,ax ;length of fat in paragraphs ;an005;bgb
1309 ; calc dir area addr ;an005;bgb
1311 add ax,bx ;seg of dir area ;an005;bgb
1313 lea bx,fattbl ;off ;an005;bgb
1314 call seg_adj ;seg:off = seg:0000 ;an005;bgb
1315 mov table,es ;segment of beginning of fat table ;an005;bgb
1316 ; calc dir area length ;an005;bgb
1317 mov ax,maxent ;ax= max dir entries ;an005;bgb
1318 mov bx,32 ; 32 bytes per dir entry ;an005;bgb
1319 xor dx,dx ;an005;bgb
1320 mul bx ; bytes per dir ;an005;bgb
1321 xor dx,dx ;zero out for divide ;an005;bgb
1322 mov bx,16 ;divide by bytes per para ;an005;bgb
1323 div bx ;paras per dir ;an005;bgb
1324 ; calc total length to fill ;an005;bgb
1325 add ax,paras_per_fat ;paras/fat + paras/dir = total paras ;an005;bgb
1326 ; see if we have enough memory ;an013;bgb
1328 push ds ;save ds reg ;an013;bgb
1330 add ax,bx ;add in starting seg of fat table ;an013;bgb
1331 inc ax ; one more to go past our area ;an013;bgb
1332 DOS_Call GetCurrentPSP ;Get PSP segment address ;an013;bgb
1333 mov ds,bx ;ds points to the psp ;an013;bgb
1334 Assume DS:Nothing ;point to psp ;an013;bgb
1335 MOV DX,DS:[2] ;get the last para of memory ;an013;bgb
1338 cmp dx,ax ;last-para must be greater or equal ;an013;bgb
1339 ; $IF AE ;it was, so complete filling the fat ;an013;bgb
1342 ;fill each para ;an005;bgb
1345 lea bx,fattbl ; es:di = point to beg of fat table ;an005;bgb
1348 mov bx,ax ;total number of paras to do ;an005;bgb
1349 mov ax,0e5e5h ;fill characters Fill (d, 16*dirent, 0xe5e5);;an005;bgb
1350 ; $DO ;do for each para ;an005;bgb
1352 mov cx,8 ; number of times to repeat ;an005;bgb
1353 xor di,di ;bump addr pointers by 16 bytes -
1354 rep stosw ; mov 2 bytes, 1 ea for 16 * num-of-entries ;an005;bgb
1355 dec bx ;loop counter ;an005;bgb
1356 ; $LEAVE Z ;until zero ;an005;bgb
1358 mov dx,es ;since we move more than 64k total, we
1359 inc dx ;have to bump es by 1 para, keeping
1360 mov es,dx ;di at zero
1364 ; $ELSE ;not enough memory ;an013;bgb
1368 stc ;set carry flag indicating badddd!!! ;an013;bgb
1371 return ;AN000;bgb ;an005;bgb
1372 endproc fill_fat ;AN000;bgb ;an005;bgb
1377 ;*****************************************************************************
1378 ;*****************************************************************************
1379 Procedure printerr,Near ;AN000;bgb
1382 PUSH DX ; Save message pointer
1383 mov dl,[user_drive] ; restore old current drive
1384 mov ah,set_default_drive
1387 call display_interface ; AC000;bgb
1388 mov al,0ffh ; erc = 0xFF;
1390 endproc printerr ;AN000;bgb ;AN000;
1393 ;*************************************************************************
1396 ; inputs: AX - last fat number for a file
1397 ; CX - bytes per cluster
1398 ;*************************************************************************
1399 Procedure chk_fat,Near ; ;AN000;bgb
1401 step1a: mov filsiz,bp ;start the file size at 0
1402 mov word ptr filsiz+2,bp ;start the file size at 0
1403 mov dx,MaxClus ; dx = MaxClus;
1404 mov target,ax ; target = last fat in this file
1405 mov exit_sw2,bp ;false ; set exit switch to no
1406 ; $DO COMPLEX ; DO until exit ;AN000;bgb
1409 mov target,ax ; do this 2+ times around
1410 ; $STRTDO ; START here 1st time ;AN000;bgb
1412 step2: add filsiz,cx ;add in cluster size
1413 adc word ptr filsiz+2,bp ;inc 2nd word if there was a carry
1414 mov ax,2 ;start at first cluster
1415 ; $DO ;DO until exit ;AN000;bgb
1417 Step3: call getfat ; bx= contents of fat cell
1418 cmp bx,target ; reached the end of file yet?
1419 ; $LEAVE E ; yes - return to outer loop;AN000;bgb
1421 step4: inc ax ; no - inc target
1422 cmp ax,dx ; target > max-clusters?
1423 ; $IF NBE ; yes ;AN000;bgb
1425 mov exit_sw2,true ; request exit both loops
1426 ; $ENDIF ; ;AN000;bgb
1428 cmp exit_sw2,true ; exit requested?
1429 ; $ENDDO E ; $ENDDO if exit requested ;AN000;bgb
1432 endlop2: cmp exit_sw2,true ; outer loop test- exit requested?
1433 ; $ENDDO E ; ENDDO if exit requested ;AN000;bgb
1435 pop es ; else- go do mov target,ax
1437 endproc chk_fat ;AN000;bgb
1440 ;*****************************************************************************
1441 ;*****************************************************************************
1443 Procedure main_loop1,Near ;AN000;bgb
1446 call read_fats ;inner loop AN000;bgb
1447 cmp exit_sw,true ; 1st way out of loop - fatptr>maxclus
1448 ; $LEAVE E ; goto step7 AN000;bgb
1450 call chk_fat ; ended read_fats on carry from feof
1451 ; at this point target = head of list, filsiz = file size
1452 step4a: inc filcnt ; filcnt++;
1453 mov ax,maxent ; if (filcnt > maxent)
1454 cmp filcnt,ax ; more files than possible dir entries?
1455 ; $IF A ; yes - this is an error ;AN000;bgb
1458 lea dx,dirmsg ; ;AC000;bgb
1459 call display_interface ; ;an006;bgb
1463 nodirerr: cmp exit_sw,true
1464 ; $LEAVE E ;AN000;bgb
1469 ; $LEAVE A ;AN000;bgb
1471 ;ndlop1: $ENDDO ;AN000;bgb
1476 endproc main_loop1 ; ;AN000;bgb
1479 ;*****************************************************************************
1480 ; purpose: this procedure looks at all the fats for a particular file, until
1481 ; the end of file marker is reached. then returns
1482 ; inputs: AX = fat cell number 2
1483 ; outputs: if any of the
1484 ;*****************************************************************************
1485 Procedure read_fats,Near ;AN000;bgb
1487 mov filsiz,bp ;start the file size at 0 ;an027;bgb
1488 mov word ptr filsiz+2,bp ;start the file size at 0 ;an027;bgb
1491 step1: call getfat ; if (fEOF (GetFat (a)) {
1492 add filsiz,cx ;add in cluster size ;an027;bgb
1493 adc word ptr filsiz+2,bp ;inc 2nd word if there was a carry ;an027;bgb
1495 ; $LEAVE C ; goto step1a AN000;bgb
1497 step6: inc fatptr ; if (++fatptr <= MaxClus)
1505 cmp exit_sw,true ; time to end? ;AN000;bgb
1506 ; $ENDDO E ; goto step7 ;AN000;bgb
1511 endproc read_fats ; ;AN000;bgb
1513 ;*****************************************************************************
1514 ;*****************************************************************************
1516 Procedure fill_dir,Near ;AN000;bgb
1517 lea si,dirent+7 ; s = &dirent[7]; ;AC000;bgb
1520 nam0: inc byte ptr [si] ; while (++*s > '9')
1521 cmp byte ptr [si],'9'
1522 ; $LEAVE LE ;AN000;bgb
1524 mov byte ptr [si],'0' ; *s-- = '0';
1529 nam1: mov ah,GET_DATE ; dirent.dir_date = GetDate ();
1531 sub cx,1980 ; cx = 87
1532 add dh,dh ; dh = 1-12
1536 add dh,dh ; dh = dh * 32 (32-384)
1539 mov byte ptr dirent+24,dh
1540 mov byte ptr dirent+25,cl
1541 mov ah,GET_TIME ; dirent.dir_time = GetTime ();
1553 mov byte ptr dirent+22,dh
1554 mov byte ptr dirent+23,ch
1555 mov ax,filsiz ; dirent.dir_fsize = filsiz;
1556 mov word ptr dirent+28,ax
1557 mov ax,word ptr filsiz+2
1558 mov word ptr dirent+30,ax
1559 mov ax,target ; dirent.dir_firclus = target;
1560 mov word ptr dirent+26,ax
1561 lea si,dirent ; di:si --> directory entry ;an005;bgb
1562 mov cx,32 ;move 32 bytes - 1 dir entry ;an005;bgb
1563 rep movsb ;move ds:si to es:di, then ;an005;bgb
1564 ;inc di and inc si ;an005;bgb
1565 inc fatptr ; if (++fatptr <= MaxClus)
1567 endproc fill_dir ; ;AN000;bgb
1569 ;*****************************************************************************
1570 ; DRIVE_SPEC - this procedure is executed if the user only specifies a drive
1571 ; letter to recover.
1572 ;*****************************************************************************
1573 Procedure drive_spec,Near ;AN000;bgb
1574 recdsk: xor di,di ;init addr of dir/file area ;an005;bgb
1575 mov es,table ;es:di --> area ;an005;bgb
1576 ;this addr is incremented by the rep movsb in fill_dir ;an005;bgb
1577 mov fatptr,2 ;INIT FATPTR ; a = fatPtr = 2;
1579 MOV exit_sw,bp ; false ; default to continue looping until true
1581 step7: mov al,drive ;AN000;bgb
1582 mov dx,firdir ; write out constructed directory
1585 xor bx,bx ;addr of dir area ;an005;bgb
1586 mov es,table ;seg of dir area ;an005;bgb
1588 ; $IF NC ;good write? ;an015;bgb
1590 lea dx,recmsg ; ;AC000;bgb
1593 call display_interface ; AC000;bgb
1596 rexit2: mov ah,DISK_RESET
1598 call wrtfat ; save the fat
1599 ; $IF C ;Couldn't write it ;AN000;bgb ;AN000;bgb
1601 lea dx,FATErrWrite ;Just tell user he is in deep! ; ;AC000;bgb
1602 call display_interface ; ;AN000;bgb
1603 ; $ENDIF ; ;AN000;bgb ;AN000;bgb
1606 endproc drive_spec ; ;AN000;bgb
1613 end ;recover ;AC000;bgb