summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/RECOVER/RECOVER.ASM
diff options
context:
space:
mode:
authorGravatar Mark Zbikowski2024-04-25 21:24:10 +0100
committerGravatar Microsoft Open Source2024-04-25 22:32:27 +0000
commit2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch)
tree80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/CMD/RECOVER/RECOVER.ASM
parentMerge pull request #430 from jpbaltazar/typoptbr (diff)
downloadms-dos-main.tar.gz
ms-dos-main.tar.xz
ms-dos-main.zip
MZ is back!HEADmain
Diffstat (limited to 'v4.0/src/CMD/RECOVER/RECOVER.ASM')
-rw-r--r--v4.0/src/CMD/RECOVER/RECOVER.ASM1615
1 files changed, 1615 insertions, 0 deletions
diff --git a/v4.0/src/CMD/RECOVER/RECOVER.ASM b/v4.0/src/CMD/RECOVER/RECOVER.ASM
new file mode 100644
index 0000000..d83a2f5
--- /dev/null
+++ b/v4.0/src/CMD/RECOVER/RECOVER.ASM
@@ -0,0 +1,1615 @@
1page ,132 ;
2TITLE RECOVER.SAL - MS-DOS File/Disk Recovery Utility
3;----------------------------------------------------------
4;
5; Recover - Program to rebuild an ms.dos directory
6;
7; Copyright 1988 by Microsoft Corporation
8;
9;-----------------------------------------------------------
10.xlist
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
18 include pathmac.inc
19 msg_utilname<recover>
20; ;AN000;bgb
21;*****************************************************************************
22; Extrn Declarations
23;*****************************************************************************
24data segment public para 'DATA' ;An000;bgb
25 extrn Askmsg:Byte
26 extrn Baddrv:Byte
27 extrn FatErrRead:Byte
28 extrn FATErrWrite:Byte
29 extrn Dirmsg:Byte
30 extrn RecMsg:Byte
31 extrn OpnErr:Byte
32 extrn no_mem_arg:word ;an013;bgb
33data ends ;AN000;bgb
34
35
36;******************************************************************************
37; Public entries
38;******************************************************************************
39code segment public para 'code' ;An000;bgb
40 pathlabl recover
41public GetFat, getSmall, getfat1, getret, SetFat, setsmall, f_exists ;AN000;bgb
42public nofspec, kill_bl, endl, next_char
43Public Main_Routine
44
45IF KANJI
46 public islead
47 PUBLIC notlead
48 PUBLIC dbcsmore
49 PUBLIC TESTKANJ
50ENDIF
51
52
53;PUBLIC stop
54public setfat2, setfat1, setRet, GetKeystroke, Prompt, Load, ReadFt, WrtFat ;AN000;bgb
55public wrtit, wrtok, fEOF, EOFok, printerr, SFFromFCB, Main_Routine ;AN000;bgb
56public slashok, kill_bl, next_char, name_copied, sja, sjb, not_root ;AN000;bgb
57public same_drive, sj1, no_errors, same_dir, noname, drvok, See_If_File ;AN000;bgb
58public step2, step3, step4, direrr, fill_dir, file_spec ;AN000;bgb
59public RecFil, recfil0, rexit1, int_23, rabort, rest_dir, no_fudge ;AN000;bgb
60public int_24, int_24_back, ireti, Read_File, Bad_File_Read, read_fats ;AN000;bgb
61public fill_fat, rexit2, sfsize, stop_read, calc_fat_addr ;an027;bgb
62 EXTRN Write_Disk:NEAR,Read_Disk:NEAR,report:NEAR ; AC000;SM
63 Extrn Main_Init:Near
64 Extrn Change_Blanks:Near ;an012;bgb
65 Extrn Build_String:Near
66 extrn seg_adj:near
67 extrn exitpgm:near ;an026;bgb
68.list
69
70;***************************************************************************** ;an005;bgb
71; calc_fat_addr - calculate the seg/off of the fat cell from the cell number ;an005;bgb
72; ;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
78; ;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
94Procedure 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
107 return ;an005;bgb
108EndProc calc_fat_addr ;an005;bgb
109
110
111
112 break <GetFat - return the contents of a fat entry>
113;*****************************************************************************
114; GetFat - return the contents of a fat cell
115;
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
120;
121; pseudocode:
122; ----------
123; if large-fat, then
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
126; else
127; fat-table offset = fat-num + (fat-num/2)
128;
129; LARGE FAT SUPPORT - if this is a 16-bit fat, use the new calc algorithm
130; *****************
131;******************************************************************************
132Procedure GetFat,NEAR
133 set_data_segment
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
137 JNAE $$IF1
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
142 JMP SHORT $$EN1
143$$IF1:
144getSmall: push ax ;save fat-num ; i = clus + clus/2;
145 mov si,ax ;save fat-num ;
146 sar ax,1 ;div by 2 ;
147 pushf ;save low bit ;
148 add si,ax ;clus + clus/2 ;
149 mov bx,word ptr [bx][si] ; b = b[i];
150 popf ;get low bit ;
151; $IF C ;AN000;bgb
152 JNC $$IF3
153 mov cl,4 ; b >>= 4;
154 shr bx,cl ;
155; $ENDIF ;AN000;bgb
156$$IF3:
157getfat1: and bh,0fh ;even fat-num ; b &= 0xFFF; AC000;bgb
158 pop ax ; }
159; $ENDIF ;AN000;bgb
160$$EN1:
161getret: mov cx,secsiz ; c = SecSize;
162 return
163EndProc GetFat
164
165;
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.
170;
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
175;
176; LARGE FAT SUPPORT - if this is a 16-bit fat, use the new calc algorithm
177; *****************
178;*****************************************************************************
179Procedure SetFat,NEAR
180 set_data_segment
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
184 JNAE $$IF6
185 call calc_fat_addr ; calc the fat cell addr ;an005;bgb
186 mov word ptr es:[bx],dx ; get the contents ;an005;bgb
187; $ELSE
188 JMP SHORT $$EN6
189$$IF6:
190setsmall: 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?
198 JNC $$IF8
199 and ax,000fh ;yes ;keep unchanged part
200 mov cl,4 ; d <<= 4;
201 shl dx,cl
202; $ELSE
203 JMP SHORT $$EN8
204$$IF8:
205setfat2: and ax,0f000h ; no, even ;keep unchanged part
206; $ENDIF
207$$EN8:
208setfat1: or ax,dx ; move new value into ax
209 mov word ptr [bx][si],ax ; b[i] = a;
210 RestoreReg <dx,ax>
211; $ENDIF
212$$EN6:
213setret: return ; return;
214EndProc SetFat
215
216;
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
221;
222; Inputs: None.
223; Outputs: None.
224; Registers Revised: AX
225;*****************************************************************************
226Procedure GetKeystroke,NEAR
227 MOV AX,(Std_CON_Input_Flush SHL 8) + Std_CON_Input_No_Echo
228 INT 21H
229 MOV AX,(Std_CON_Input_Flush SHL 8) + 0
230 INT 21H
231 return
232EndProc GetKeystroke
233
234
235;*****************************************************************************
236;PROMPT
237;*****************************************************************************
238Procedure Prompt,NEAR
239 Cmp Prompted,0
240 retnz
241 MOV Prompted,1
242 push ds
243 push cs
244; move drive letter in message
245 lea dx,askmsg ; AC000;SM ;AC000;bgb
246; display msg
247 call DISPLAY_interface ;AC000;bgb
248 pop ax ; ;AN000;bgb
249 pop ds
250; wait for user
251 call GetKeystroke
252
253 MOV AL,cs:DRIVE ; This is for ibm's single drive sys;AN000;bgb
254 CMP AL,1
255 JA NOSET ; Values other than 0,1 are not appropriate.
256 PUSH DS
257 MOV BX,50H
258 MOV DS,BX
259 MOV DS:(BYTE PTR 4),AL ; Indicate drive changed
260 POP DS
261NOSET:
262
263 return
264EndProc Prompt
265
266
267;
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
271;
272; called by: readft, writeft
273;
274; Inputs: none.
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;******************************************************************************
282Procedure Load,NEAR
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
290 return
291EndProc Load
292
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.
297;
298; Inputs: none.
299; Outputs: Fats are read until one succeeds.
300; Carry set indicates no Fat could be read.
301; Registers Revised: all
302; LOGIC
303; *****
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
307;
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;******************************************************************************
312Procedure 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
324 JNC $$IF12
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
328$$IF12:
329ret ;an027;bgb
330EndProc ReadFt
331
332
333;
334 Break <WrtFat - write out the fat>
335;*****************************************************************************
336; WrtFat - using the results of a ReadFt, attempt to write out the fat
337; until successful.
338;
339; Inputs: none.
340; Outputs: A write of the fat is attempted in each fat position until
341; one succeeds.
342; Registers Revised: all
343; LOGIC
344; *****
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
348;
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;****************************************************************************
353Procedure WrtFat,NEAR
354 call load ; load (); ;an005;bgb
355; $DO ;an005;bgb
356$$DO14:
357wrtit: call Write_Disk ; Write_Disk (); ;an005;bgb
358; $LEAVE C ;an015;bgb
359 JC $$EN14
360wrtok: add dx,cx ; fatStart += fatsize; ;an005;bgb
361 dec byte ptr fatcnt ; } while (--fatcnt); ;an005;bgb
362; $ENDDO Z ;an005;bgb
363 JNZ $$DO14
364$$EN14:
365 return
366EndProc WrtFat
367
368
369;
370 Break <fEOF - check to see if the argument is EOF>
371;*****************************************************************************
372; fEOF - test BX to see if it indicates EOF
373;
374; Inputs: BX - contains cluster
375; Outputs: Carry is set if BX indicates EOF
376; Registers Revised: none
377;*****************************************************************************
378Procedure fEOF,NEAR
379 CMP BX,MaxClus
380 JBE EOFok
381 CMP BL,0F7h ; bad sector indicator
382 JZ EOFok
383 STC
384 return
385EOFok: CLC
386 return
387EndProc fEOF
388
389
390;*****************************************************************************
391;*****************************************************************************
392
393
394;
395 Break <sfFromFCB - take an FCB and convert it to a sf pointer>
396;*****************************************************************************
397; SFFromFCB - index into System File tables for SFN.
398;
399; Input: ES:DI has FCB pointer
400; Output: ES:DI points to Sys-File-table entry
401; Registers Revised: ES:DI, BX only
402;
403;*****************************************************************************
404procedure SFFromFCB,NEAR
405 MOV BL,ES:[DI].FCB_SFN ;fcb+18 = system file table 00
406 XOR BH,BH ; 00
407 SaveReg <AX,BX>
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
412 ; es:di = 0b37:0000
413 LEA DI,[DI].sfTable ; di=6 AC000;bgb
414 RestoreReg <BX>
415 SaveReg <DX>
416 MOV AX,SIZE SF_Entry ;42
417 MUL BX ;0
418 ADD DI,AX ;6
419 RestoreReg <DX,AX>
420 return ; return p;
421EndProc SFFromFCB
422
423;*****************************************************************************
424;*****************************************************************************
425Procedure 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)
431 int 21h ; call dos
432; note: ds is now changed !!!!
433 cmp al,0FFH ; -1 = bad return code
434; $IF NZ ;AN000;bgb
435 JZ $$IF17
436; get sector size
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
450;first dir entry
451 mov dx,[bx].dpb_dir_sector ; get record of first directory entry
452 mov es:firdir,dx ;5 ; ;AC000;bgb
453; first fat record
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
456; records in fat
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
459; number of cluster
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
466; max dir entries
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
470; $ELSE ;AN000;bgb
471 JMP SHORT $$EN17
472$$IF17:
473 pop ds ; restore ds register to group ;AC000;bgb
474 jmp noname ; bad return = display error msg
475; $ENDIF ;AN000;bgb
476$$EN17:
477 ret ; ;AN000;bgb
478endproc get_dpb_info ; ;AN000;bgb
479;
480
481;
482;*****************************************************************************
483; assemble this part if doing japanese version
484;
485;INPUTS: es:di - points to last char in filename
486; ds:dx - point to beginning of filename
487;
488;*****************************************************************************
489Procedure check_kanji,Near ;AN000;bgb
490 IF KANJI
491 lea dx,[fname_buffer] ;point to filename ;AC000;bgb
492 PUSH DX ;save regs
493 PUSH DI ;save regs
494 MOV BX,DI ;bx and di now point to last char in filename
495 MOV DI,DX ;di now points to filename
496
497;do for entrire filename
498delloop: 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
503 JZ NOTKANJ11
504 INC DI ;bump to past 2nd of dbcs pair
505 JMP DELLOOP ;check next char in file name
506notkanj11: cmp al,[dirchar] ;is it '\' ?
507 JNZ DELLOOP ;no, check next char
508 MOV DX,DI ; Point to char after '/'
509 DEC DX
510 DEC DX ; Point to char before '/'
511 JMP DELLOOP
512
513;completed filename
514gotdele: MOV DI,DX ;point to?
515 POP AX ; Initial DI
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
523; jmp sja ;an024;bgb
524;;;;;;;;;;;;;;; JB sja ; Found a pathsep ;an024;bgb
525; $endif ;an024;bgb
526; $if a ;an024;bgb
527; pop ax ;an024;bgb;an024;bgb
528; pop cx ;an024;bgb;an024;bgb;an024;bgb
529; jmp sjb ;an024;bgb
530;;;;;;;;;;;;;;; JA sjb ; Started with a pathsep, root ;an024;bgb
531; $endif ;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
537; $if z ;an024;bgb
538; pop ax ;an024;bgb;an024;bgb;an024;bgb
539; pop cx ;an024;bgb;an024;bgb;an024;bgb
540; jmp sja ;an024;bgb
541;;;;;;;;;;;;;;;;jz sja ; One character directory ;an024;bgb
542; $endif ;an024;bgb
543same_dirjk:
544 ret ;AN000;bgb
545 ENDIF
546check_kanji endp ; ;AN000;bgb
547;
548
549;****************************************************************************
550;****************************************************************************
551 break
552 IF KANJI
553TESTKANJ: push ds ;get dbcs vector ;an012;bgb
554 push si
555 push ax
556 mov ax,6300h ;get dbcs vector ;an024;bgb;an012;bgb
557 int 21h ;an012;bgb
558 pop ax ;an024;bgb
559 sub si,2 ;prep for loop ;an012;bgb
560dbcsmore: ;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
569
570NOTLEAD:
571 PUSH AX
572 XOR AX,AX ; Set zero
573 POP AX
574 pop si
575 pop ds
576 RET
577ISLEAD:
578 mov es:dbcs_sw,1 ;an024;bgb
579 PUSH AX
580 XOR AX,AX ; Set zero
581 INC AX ; Reset zero
582 POP AX
583 pop si
584 pop ds
585 RET
586 ENDIF
587
588
589
590
591
592
593;*****************************************************************************;an020;bgb
594; copy the filename from the fcb to the data segment ;an020;bgb
595;*****************************************************************************;an020;bgb
596Procedure copy_fname,Near ;AN000;bgb ;an020;bgb
597;get fcb1 from the psp
598slashok: mov cx,PSP_Segment ;Get addrbility of psp ;AN000;bgb
599 mov ds,cx ; " " " " " " ;AN000;bgb
600 assume ds:dg,es:dg ; " " " " " " ;AN000;bgb
601 call get_fcb
602
603 ;An018;bgb
604
605; remove leading blanks and tabs from filename
606nofspec: 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
610$$DO20:
611kill_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
614 JE $$LL21
615 cmp al,' ' ; leading blanks? (hex 20) ;AN000;bgb
616; $LEAVE NE
617 JNE $$EN20
618$$LL21:
619; $ENDDO ; ;AN000;bgb
620 JMP SHORT $$DO20
621$$EN20:
622;
623
624;was any parameter entered at all?
625endl: 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
628
629
630
631;copy filename from cmd line to fname buffer
632next_char:
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?
637 je name_copied ; yes
638 cmp al,9 ;terminated by tab?
639 je name_copied ; yes
640 cmp al,13 ; terminated by CR?
641 jne next_char ; yes
642
643
644;reset ds to data segment
645name_copied: ; got file name
646 push es
647 pop ds ;ds now points to data seg
648 assume ds:dg
649
650 mov byte ptr [di],0 ; nul terminate the pathname
651 dec di ; adjust to the end of the pathname
652 ret ;an020;bgb
653copy_fname endp ; ;an020;bgb
654
655
656
657
658;*****************************************************************************;an020;bgb
659; get a copy of the fcb ;an020;bgb
660;*****************************************************************************;an020;bgb
661Procedure 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
682$$DO23:
683 cmp byte ptr ds:[si],'\' ;look for back slash ;AN014;bgb
684; $IF E ;find it? ;an024;bgb;AN014;bgb
685 JNE $$IF24
686 mov al,[si-1] ;get possible leading byte ;an024;bgb
687 IF KANJI
688 call testkanj ;is it a leading byte of DBCS? ;an024;bgb
689 ENDIF
690; $IF Z ;no- then it is subdir delimiter ;an024;bgb
691 JNZ $$IF25
692 mov exit_sw,true ;so exit the search loop ;an024;bgb
693; $ELSE ;yes it is DBCS leading byte ;an024;bgb
694 JMP SHORT $$EN25
695$$IF25:
696 dec si ;so skip the leading byte ;an024;bgb
697; $ENDIF ;check for kanji ;an024;bgb
698$$EN25:
699; $ENDIF ;an024;bgb
700$$IF24:
701 cmp exit_sw,true ;an024;bgb
702; $LEAVE E ;an024;bgb
703 JE $$EN23
704 cmp byte ptr ds:[si],0 ;look for 00 (not a filespec) ;AN018;bgb
705; $IF E ;an020;bgb
706 JNE $$IF30
707 ret ;an020;bgb
708;;;;;;;;;;;;;;;;je nofspec ;filespec not found ;ac020;bgb
709; $ENDIF ;an020;bgb
710$$IF30:
711 dec si ;no , next char ;AN014;bgb
712; $ENDDO ;AN014;bgb
713 JMP SHORT $$DO23
714$$EN23:
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
719$$DO33:
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
723 JE $$EN33
724 cmp al,'.' ;is it extension indicator? ;AN014;bgb
725; $IF E ;yes ;AN014;bgb
726 JNE $$IF35
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
730 JMP SHORT $$EN35
731$$IF35:
732 stosb ;move char into fcb ;AN014;bgb
733; $ENDIF ;AN014;bgb
734$$EN35:
735; $ENDDO ;AN014;bgb
736 JMP SHORT $$DO33
737$$EN33:
738; $ENDIF ;AN014;bgb
739 ret ;an020;bgb
740get_fcb endp ; ;an020;bgb
741 ;an020;bgb
742 ;an020;bgb
743;
744 Break <Main code of recover - Version check and exit if incorrect>
745;*****************************************************************************
746;Routine name: Main_routine
747;*****************************************************************************
748;
749;description: Main routine for recovering a file from a bad sector
750;
751;Called from: recover_ifs in RECINIT.SAL
752;
753;
754;Called Procedures: prompt
755; readft
756; read_file
757; getfat (sic)
758; feof
759; sffromFCB
760; bad-file-read
761; report
762; wrtfat
763; stdprintf
764; RECPROC.SAL
765;
766;Input: ????
767;
768;Output: FAT is changed if a bad sector is found.
769; The file is complete except for the data in the bad sector.
770;
771;Change History: header created 7-19-87 BGB
772;
773;Psuedocode
774;----------
775;
776;*****************************************************************************
777Main_Routine:
778
779;get system switch character
780 xor bp,bp
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 / ?
786; $IF nz
787 JZ $$IF39
788 jmp slashok ; if not / , then not PC
789; $ENDIF
790$$IF39:
791 mov [dirchar],"\" ; in PC, dir separator = \
792 mov [userdir],"\"
793
794 call copy_fname
795
796;check for dbcs double byte chars
797 push di ;an019;bgb
798 push cx ;an019;bgb
799 call check_kanji
800same_dirj:
801 pop cx ;an019;bgb
802 pop di ;an019;bgb
803 mov lastchar,di
804
805
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
813; $DO ;an024;bgb
814$$DO41:
815 dec cx ;an024;bgb
816 and cx,cx ;compare cx to zero ;an024;bgb
817; $LEAVE E ;an024;bgb
818 JE $$EN41
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
822 JNE $$IF43
823 mov al,[di-1] ;get possible leading byte ;an024;bgb
824 IF KANJI
825 call testkanj ;see if it is leading byte ;an024;bgb
826 ENDIF
827; $IF Z ;not a leading byte? then its a '\' ;an024;bgb
828 JNZ $$IF44
829 mov lastbs,di ;an024;bgb
830 mov di,lastchar ;an024;bgb
831 jmp sja ;zero = not a leading byte ;an024;bgb
832; $ENDIF ;an024;bgb
833$$IF44:
834; $ENDIF ;an024;bgb
835$$IF43:
836 dec di ;an024;bgb
837; $ENDDO ;an024;bgb
838 JMP SHORT $$DO41
839$$EN41:
840;save current disk ;an008;bgb
841 mov ah,19h ;an008;bgb
842 int 21h ;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.
848
849
850;handle filespec here
851;at least one '\' found in filename
852sja:
853 jcxz sjb ; no more chars left, it refers to root
854 push di ;an024;bgb
855 mov di,lastbs ;an024;bgb
856 cmp byte ptr [di-1],':' ; is the prvious character a disk def?;an024;bgb
857 pop di ;an024;bgb
858 jne not_root
859sjb:
860 mov [the_root],01h ; file is in the root
861not_root:
862 inc di ; point to dir separator char.
863 mov ax,bp ;set to zero
864 stosb ; nul terminate directory name
865; pop ax
866; push di ; save pointer to file name
867 mov [fudge],01h ; remember that the current directory
868 ; has been changed.
869;save current disk ;an008;bgb
870 mov ah,19h ;an008;bgb
871 int 21h ;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
879 int 21h
880; cmp al,-1 ; error?
881; jne same_drive
882;BADDRVSPEC:
883; lea dx,baddrv ; AC000;SM ;AC000;bgb
884; jmp printerr
885
886same_drive:
887 call prompt
888 mov ah,Current_Dir ; userdir = current directory string
889 mov dx,bp ;set to zero
890 lea si,userdir+1 ;AC000;bgb
891 int 21h
892
893;----- Change directories ----------------------------------------------;
894 cmp [the_root],01h
895 lea dx,[dirchar] ; assume the root ;AC000;bgb
896 je sj1
897 lea dx,[fname_buffer] ;AC000;bgb
898sj1:
899 push di ;an024;bgb
900 mov di,lastbs ;an024;bgb
901 mov byte ptr [di],0 ;an024;bgb
902 mov ah,chdir ; change directory
903 int 21h
904 mov byte ptr [di],'\' ;an024;bgb
905 pop 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
910 jnc no_errors
911 call printerr
912 jmp rabort
913
914;
915no_errors:
916
917 Break <Set up exception handlers>
918
919;----- Parse filename to FCB -------------------------------------------;
920; pop si ;an024;bgb
921 mov si,lastbs ;an024;bgb
922 inc si ;an024;bgb
923 lea di,fcb_copy ;AC000;bgb
924 mov ax,(parse_file_descriptor shl 8) or 1
925 int 21h
926;;;;;;;;push ax
927;-----------------------------------------------------------------------;
928same_dir:
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
931 jnz drvok
932 cmp byte ptr [bx],0 ;or drive specifier
933 jnz drvok
934 cmp dbcs_sw,1 ; or dbcs ;an024;bgb
935 jz drvok ;an024;bgb
936noname: ;AC000;bgb
937 push es
938 pop ds
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
943 jmp int_23
944;****************************************************************************
945; we're finished with parsing here, do the main function of recover.
946drvok:
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
951 JNC $$IF48
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
956$$IF48:
957
958 call readft ; readft (); ;AN000;bgb
959; $IF C ; could the fat be read from disk? ;AN000;bgb
960 JNC $$IF50
961 lea dx,FATErrRead ; ;AC000;bgb
962 call printerr
963 jmp rabort
964; $ENDIF ;fat could be read from disk ;AN000;bgb
965$$IF50:
966See_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
970 JNE $$IF52
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
973 JNE $$IF52
974 call drive_spec ;only drive specified ;AN000;bgb
975; $ELSE ; file name specified ;AN000;bgb
976 JMP SHORT $$EN52
977$$IF52:
978 call file_spec ;file can be 'f' or 'a:,0,file' or 'a:file' or 'file.ext' ;an020;bgb
979; $ENDIF ;AN000;bgb
980$$EN52:
981
982
983int_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;
987
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;
991
992 PUSH CS ;reset ds ;an026;bgb
993 POP DS ;an026;bgb
994aSSUME DS:DG ;an026;bgb
995 call rest_dir
996 ;an026;bgb
997 mov cs:ExitStatus,0 ; good return ;AC000;
998 jmp [exitpgm] ;an026;bgb
999rabort:
1000 ret ;Return to RECINIT for exit ;AC000;
1001 ; mov ah,exit
1002 ; int 21h
1003
1004
1005;*************************************************************************
1006; DO until either
1007;*************************************************************************
1008procedure file_spec,near ;AN000;bgb
1009; try to open the file
1010recfil: 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
1015 JNE $$IF55
1016; display error msg
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
1025recfil0:
1026 JMP SHORT $$EN55
1027$$IF55:
1028f_exists: call process_file ;file was opend ok
1029rexit1: mov ah,DISK_RESET
1030 int 21h
1031 call wrtfat ; save the fat
1032; $IF C ;Couldn't write it ;AN000;
1033 JNC $$IF57
1034 lea dx,FATErrWrite ;Just tell user he is in deep! ;AC000;bgb
1035 call display_interface ; ;AN000;bgb
1036; $ELSE
1037 JMP SHORT $$EN57
1038$$IF57:
1039 call report ; report (); ;ac015;bgb
1040; $ENDIF ;AN000;bgb; ;AN000;
1041$$EN57:
1042; $ENDIF ;AN000;bgb
1043$$EN55:
1044 ret ;AN000;bgb
1045endproc file_spec ;AN000;bgb
1046
1047;*************************************************************************
1048; DO until either
1049;*************************************************************************
1050Procedure process_file,Near ; ;AN000;
1051recfile0:
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;
1055 mov filsiz,ax
1056 mov siztmp,ax
1057 mov ax,[di].FCB_FilSiz+2 ;00
1058 mov filsiz+2,ax
1059 mov siztmp+2,ax
1060 SaveReg <ES,DI> ; fatptr =
1061 call sfFromFCB ; sfFromFCB(d)->firclus;
1062 mov ax,ES:[DI].sf_firclus ; es:di +0b = 84
1063 RestoreReg <DI,ES>
1064 mov fatptr,ax
1065 or ax,ax ; if (fatptr == 0)
1066; $IF NZ ;AN000;bgb
1067 JZ $$IF61
1068; read each fat in the file
1069; $DO ;Loop until entire file read in ;AN000;bgb
1070$$DO62:
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
1074 JC $$EN62
1075STOP_read: call Read_File ;Go read in the cluster
1076; $IF C ;CY indicates an error ;AN000;bgb
1077 JNC $$IF64
1078 call Bad_File_Read ;Go play in the FAT
1079; $ELSE ;Read cluster in okay ;AN000;bgb
1080 JMP SHORT $$EN64
1081$$IF64:
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
1086 JNC $$IF66
1087 xor ax,ax ;Set our running count to 0
1088 mov siztmp,ax
1089 mov siztmp+2,ax
1090; $ENDIF ;AN000; ;AN000;bgb
1091$$IF66:
1092 mov ax,fatptr ;The previous cluster is now
1093 mov lastfat,ax ; the current cluster
1094; $ENDIF ;AX has current cluster ;AN000;bgb
1095$$EN64:
1096 call getfat ;Get the next cluster
1097 mov fatptr,bx ;Save it
1098; $ENDDO ;Keep chasing the chain ;AN000;bgb
1099 JMP SHORT $$DO62
1100$$EN62:
1101; $ENDIF ;All done with data ;AN000;bgb
1102$$IF61:
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
1117 mov ah,FCB_CLOSE
1118 int 21h ;
1119 return ;AN000;bgb
1120endproc process_file ;AN000;bgb
1121
1122;*************************************************************************
1123;***************************************************************************
1124 break
1125;----- Restore INT 24 vector and old current directory -----------------;
1126Procedure Rest_dir,Near ; ;AN000;
1127 cmp cs:[fudge],0
1128; $IF NE
1129 JE $$IF71
1130 mov ax,(set_interrupt_vector shl 8) or 24h
1131 lds dx,cs:[hardch]
1132 int 21h
1133 push cs
1134 pop ds
1135 lea dx,userdir ; restore directory ;AC000;bgb
1136 mov ah,chdir
1137 int 21h
1138; $ENDIF
1139$$IF71:
1140no_fudge:
1141 mov dl,old_drive ; restore old current drive ;an008;bgb
1142 mov ah,set_default_drive
1143 int 21h
1144 ret
1145endproc rest_dir
1146
1147;;----- INT 24 Processing -----------------------------------------------;
1148;*************************************************************************
1149 int_24_retaddr dw int_24_back
1150
1151 int_24 proc far
1152 assume ds:nothing,es:nothing,ss:nothing
1153 pushf ; ** MAKE CHANGES **
1154 push cs
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
1159 ret
1160endproc int_24
1161;*************************************************************************
1162int_24_back:
1163 cmp al,2 ; abort?
1164 jnz ireti
1165 push cs
1166 pop ds
1167assume ds:dg,es:dg,ss:dg
1168 call rest_dir
1169 ret ;Ret for common exit ;AC000;
1170ireti:
1171 iret
1172
1173 break < read in a cluster of the file>
1174;****************************************************************************
1175; READ_FILE
1176;Read in cluster of file.
1177;
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 ???
1182;
1183; Output: CY set if error on read on ret
1184; DI = pointer to FCB
1185;*****************************************************************************
1186Procedure 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
1200 ret ; ;AN000;
1201endproc Read_File ; ;AN000;
1202
1203
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.
1210;
1211; Input: FatPtr = Cluster that failed to read
1212; LastFat = Previous cluster, equals 1 if first cluster
1213;
1214; Output: AX = previous cluster
1215; File size = file size - cluster size ( = 0 if cluster size > file)
1216;***************************************************************************
1217Procedure 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;
1222 JNE $$IF73
1223 call fEOF ;Is the next the last cluster?
1224; $IF C ;Yes ;AC000;
1225 JNC $$IF74
1226 xor bx,bx ;Need to zero out first cluster
1227; $ENDIF ; because the first one is bad! ;AN000;
1228$$IF74:
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;
1235 JMP SHORT $$EN73
1236$$IF73:
1237 mov dx,bx ;DX = next cluster
1238 mov ax,lastfat ;AX = Previous cluster
1239 call setfat ;prev fat points to next fat
1240 ; offending cluster
1241; $ENDIF ; Ta-Da! ;AN000;
1242$$EN73:
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;
1249 JE $$IF78
1250 cmp siztmp,ax ;Shorter than cluster size?
1251; $IF BE ;Yes ;AC000;
1252 JNBE $$IF78
1253 mov ax,siztmp ;File size = smaller of the two
1254; $ENDIF ;AN000;
1255$$IF78:
1256 SaveReg <ES,DI> ;Save regs
1257 call sfFromFCB ;Get sf pointer
1258sfsize: 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
1261 sbb siztmp,bp ;
1262 and ES:[di].sf_flags,NOT devid_file_clean ; mark file dirty
1263 RestoreReg <DI,ES> ; sfFromFCB(d)->flags &= ~CLEAN;
1264 lea di,fcb_copy
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
1269 ret ; ;AN000;
1270endproc Bad_File_Read ; ;AN000;
1271
1272
1273;***************************************************************************** ;an005;bgb
1274; description: fill the fat table in memory with the 'E5' character ;an005;bgb
1275; ;an005;bgb
1276; called from: main-routine ;an005;bgb
1277; ;an005;bgb
1278;Change History: Created 8/7/87 bgb ;an005;bgb
1279; ;an005;bgb
1280;Input: bytes-per-sector ;an005;bgb
1281; fatsiz ;an005;bgb
1282; maxent ;an005;bgb
1283; ;an005;bgb
1284;Output: ram-based fat table ;an005;bgb
1285; ;an005;bgb
1286; LOGIC ;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
1297 even
1298Procedure 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
1310 mov bx,es
1311 add ax,bx ;seg of dir area ;an005;bgb
1312 mov es,ax
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
1327 push ax ;an013;bgb
1328 push ds ;save ds reg ;an013;bgb
1329 mov bx,es
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
1336 pop ds ;an013;bgb
1337 assume ds:dg
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
1340 JNAE $$IF80
1341 pop ax ;an013;bgb
1342;fill each para ;an005;bgb
1343 push ds
1344 pop es
1345 lea bx,fattbl ; es:di = point to beg of fat table ;an005;bgb
1346 call seg_adj
1347 mov di,bx
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
1351$$DO81:
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
1357 JZ $$EN81
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
1361; $ENDDO ;an005;bgb
1362 JMP SHORT $$DO81
1363$$EN81:
1364; $ELSE ;not enough memory ;an013;bgb
1365 JMP SHORT $$EN80
1366$$IF80:
1367 pop ax ;an013;bgb
1368 stc ;set carry flag indicating badddd!!! ;an013;bgb
1369; $ENDIF ;an013;bgb
1370$$EN80:
1371 return ;AN000;bgb ;an005;bgb
1372endproc fill_fat ;AN000;bgb ;an005;bgb
1373;
1374
1375;
1376
1377;*****************************************************************************
1378;*****************************************************************************
1379Procedure printerr,Near ;AN000;bgb
1380 push cs
1381 pop ds
1382 PUSH DX ; Save message pointer
1383 mov dl,[user_drive] ; restore old current drive
1384 mov ah,set_default_drive
1385 int 21h
1386 POP DX
1387 call display_interface ; AC000;bgb
1388 mov al,0ffh ; erc = 0xFF;
1389 ret ;AN000;bgb
1390endproc printerr ;AN000;bgb ;AN000;
1391
1392
1393;*************************************************************************
1394; CHK_FAT:
1395;
1396; inputs: AX - last fat number for a file
1397; CX - bytes per cluster
1398;*************************************************************************
1399Procedure chk_fat,Near ; ;AN000;bgb
1400 push es
1401step1a: 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
1407 JMP SHORT $$SD86
1408$$DO86:
1409 mov target,ax ; do this 2+ times around
1410; $STRTDO ; START here 1st time ;AN000;bgb
1411$$SD86:
1412step2: 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
1416$$DO88:
1417Step3: 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
1420 JE $$EN88
1421step4: inc ax ; no - inc target
1422 cmp ax,dx ; target > max-clusters?
1423; $IF NBE ; yes ;AN000;bgb
1424 JBE $$IF90
1425 mov exit_sw2,true ; request exit both loops
1426; $ENDIF ; ;AN000;bgb
1427$$IF90:
1428 cmp exit_sw2,true ; exit requested?
1429; $ENDDO E ; $ENDDO if exit requested ;AN000;bgb
1430 JNE $$DO88
1431$$EN88:
1432endlop2: cmp exit_sw2,true ; outer loop test- exit requested?
1433; $ENDDO E ; ENDDO if exit requested ;AN000;bgb
1434 JNE $$DO86
1435 pop es ; else- go do mov target,ax
1436 ret ;AN000;bgb
1437endproc chk_fat ;AN000;bgb
1438
1439
1440;*****************************************************************************
1441;*****************************************************************************
1442 even
1443Procedure main_loop1,Near ;AN000;bgb
1444; $DO ;AN000;bgb
1445$$DO94:
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
1449 JE $$EN94
1450 call chk_fat ; ended read_fats on carry from feof
1451; at this point target = head of list, filsiz = file size
1452step4a: 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
1456 JNA $$IF96
1457direrr: dec filcnt
1458 lea dx,dirmsg ; ;AC000;bgb
1459 call display_interface ; ;an006;bgb
1460 mov exit_sw,true
1461; $ENDIF ;AN000;bgb
1462$$IF96:
1463nodirerr: cmp exit_sw,true
1464; $LEAVE E ;AN000;bgb
1465 JE $$EN94
1466 call fill_dir
1467 mov ax,fatptr
1468 cmp ax,MaxClus
1469; $LEAVE A ;AN000;bgb
1470 JA $$EN94
1471;ndlop1: $ENDDO ;AN000;bgb
1472endlop1:
1473 JMP SHORT $$DO94
1474$$EN94:
1475 ret ;AN000;bgb
1476endproc main_loop1 ; ;AN000;bgb
1477
1478
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;*****************************************************************************
1485Procedure read_fats,Near ;AN000;bgb
1486 push es
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
1489; $DO ;AN000;bgb
1490$$DO101:
1491step1: 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
1494 call fEOF ;
1495; $LEAVE C ; goto step1a AN000;bgb
1496 JC $$EN101
1497step6: inc fatptr ; if (++fatptr <= MaxClus)
1498 mov ax,fatptr
1499 cmp ax,MaxClus
1500; $IF A ;AN000;bgb
1501 JNA $$IF103
1502 mov exit_sw,true
1503; $ENDIF ;AN000;bgb
1504$$IF103:
1505 cmp exit_sw,true ; time to end? ;AN000;bgb
1506; $ENDDO E ; goto step7 ;AN000;bgb
1507 JNE $$DO101
1508$$EN101:
1509 pop es
1510 ret ;AN000;bgb
1511endproc read_fats ; ;AN000;bgb
1512
1513;*****************************************************************************
1514;*****************************************************************************
1515 even
1516Procedure fill_dir,Near ;AN000;bgb
1517 lea si,dirent+7 ; s = &dirent[7]; ;AC000;bgb
1518; $DO ;AN000;bgb
1519$$DO106:
1520nam0: inc byte ptr [si] ; while (++*s > '9')
1521 cmp byte ptr [si],'9'
1522; $LEAVE LE ;AN000;bgb
1523 JLE $$EN106
1524 mov byte ptr [si],'0' ; *s-- = '0';
1525 dec si
1526; $ENDDO ;AN000;bgb
1527 JMP SHORT $$DO106
1528$$EN106:
1529nam1: mov ah,GET_DATE ; dirent.dir_date = GetDate ();
1530 int 21h
1531 sub cx,1980 ; cx = 87
1532 add dh,dh ; dh = 1-12
1533 add dh,dh
1534 add dh,dh
1535 add dh,dh
1536 add dh,dh ; dh = dh * 32 (32-384)
1537 rcl cl,1
1538 or dh,dl
1539 mov byte ptr dirent+24,dh
1540 mov byte ptr dirent+25,cl
1541 mov ah,GET_TIME ; dirent.dir_time = GetTime ();
1542 int 21h
1543 shr dh,1 ;seconds/2
1544 add cl,cl ;minutes
1545 add cl,cl
1546 add cl,cl ;mins * 8
1547 rcl ch,1
1548 add cl,cl
1549 rcl ch,1
1550 add cl,cl
1551 rcl ch,1
1552 or dh,cl
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)
1566 ret ;AN000;bgb
1567endproc fill_dir ; ;AN000;bgb
1568;
1569;*****************************************************************************
1570; DRIVE_SPEC - this procedure is executed if the user only specifies a drive
1571; letter to recover.
1572;*****************************************************************************
1573Procedure drive_spec,Near ;AN000;bgb
1574recdsk: 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;
1578 mov ax,fatptr ;
1579 MOV exit_sw,bp ; false ; default to continue looping until true
1580 call main_loop1
1581step7: mov al,drive ;AN000;bgb
1582 mov dx,firdir ; write out constructed directory
1583 mov cx,firrec
1584 sub cx,dx
1585 xor bx,bx ;addr of dir area ;an005;bgb
1586 mov es,table ;seg of dir area ;an005;bgb
1587 call Write_Disk
1588; $IF NC ;good write? ;an015;bgb
1589 JC $$IF109
1590 lea dx,recmsg ; ;AC000;bgb
1591 mov si,filcnt
1592 mov rec_num,si
1593 call display_interface ; AC000;bgb
1594; $ENDIF ;an015;bgb
1595$$IF109:
1596rexit2: mov ah,DISK_RESET
1597 int 21h
1598 call wrtfat ; save the fat
1599; $IF C ;Couldn't write it ;AN000;bgb ;AN000;bgb
1600 JNC $$IF111
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
1604$$IF111:
1605 ret ;AN000;bgb
1606endproc drive_spec ; ;AN000;bgb
1607;
1608 pathlabl recover
1609
1610include msgdcl.inc
1611
1612code ends
1613 end ;recover ;AC000;bgb
1614
1615 \ No newline at end of file