]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/RECOVER/RECOVER.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / CMD / RECOVER / RECOVER.ASM
1 page ,132 ;\ f
2 TITLE 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 ;*****************************************************************************
24 data 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
33 data ends ;AN000;bgb
34
35
36 ;******************************************************************************
37 ; Public entries
38 ;******************************************************************************
39 code segment public para 'code' ;An000;bgb
40 pathlabl recover
41 public GetFat, getSmall, getfat1, getret, SetFat, setsmall, f_exists ;AN000;bgb
42 public nofspec, kill_bl, endl, next_char
43 Public Main_Routine
44
45 IF KANJI
46 public islead
47 PUBLIC notlead
48 PUBLIC dbcsmore
49 PUBLIC TESTKANJ
50 ENDIF
51
52
53 ;PUBLIC stop
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
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
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
107 return ;an005;bgb
108 EndProc 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 ;******************************************************************************
132 Procedure 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:
144 getSmall: 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:
157 getfat1: and bh,0fh ;even fat-num ; b &= 0xFFF; AC000;bgb
158 pop ax ; }
159 ; $ENDIF ;AN000;bgb
160 $$EN1:
161 getret: mov cx,secsiz ; c = SecSize;
162 return
163 EndProc 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 ;*****************************************************************************
179 Procedure 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:
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?
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:
205 setfat2: and ax,0f000h ; no, even ;keep unchanged part
206 ; $ENDIF
207 $$EN8:
208 setfat1: 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:
213 setret: return ; return;
214 EndProc 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 ;*****************************************************************************
226 Procedure 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
232 EndProc GetKeystroke
233
234
235 ;*****************************************************************************
236 ;PROMPT
237 ;*****************************************************************************
238 Procedure 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
261 NOSET:
262
263 return
264 EndProc 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 ;******************************************************************************
282 Procedure 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
291 EndProc 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 ;******************************************************************************
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
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:
329 ret ;an027;bgb
330 EndProc 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 ;****************************************************************************
353 Procedure WrtFat,NEAR
354 call load ; load (); ;an005;bgb
355 ; $DO ;an005;bgb
356 $$DO14:
357 wrtit: call Write_Disk ; Write_Disk (); ;an005;bgb
358 ; $LEAVE C ;an015;bgb
359 JC $$EN14
360 wrtok: 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
366 EndProc 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 ;*****************************************************************************
378 Procedure fEOF,NEAR
379 CMP BX,MaxClus
380 JBE EOFok
381 CMP BL,0F7h ; bad sector indicator
382 JZ EOFok
383 STC
384 return
385 EOFok: CLC
386 return
387 EndProc 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 ;*****************************************************************************
404 procedure 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;
421 EndProc SFFromFCB
422
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)
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
478 endproc 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 ;*****************************************************************************
489 Procedure 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
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
503 JZ NOTKANJ11
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 '/'
509 DEC DX
510 DEC DX ; Point to char before '/'
511 JMP DELLOOP
512
513 ;completed filename
514 gotdele: 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
543 same_dirjk:
544 ret ;AN000;bgb
545 ENDIF
546 check_kanji endp ; ;AN000;bgb
547 ;
548
549 ;****************************************************************************
550 ;****************************************************************************
551 break
552 IF KANJI
553 TESTKANJ: 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
560 dbcsmore: ;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
570 NOTLEAD:
571 PUSH AX
572 XOR AX,AX ; Set zero
573 POP AX
574 pop si
575 pop ds
576 RET
577 ISLEAD:
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
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
601 call get_fcb
602
603 ;An018;bgb
604
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
610 $$DO20:
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
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?
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
628
629
630
631 ;copy filename from cmd line to fname buffer
632 next_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
645 name_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
653 copy_fname endp ; ;an020;bgb
654
655
656
657
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
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
740 get_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 ;*****************************************************************************
777 Main_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
800 same_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
852 sja:
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
859 sjb:
860 mov [the_root],01h ; file is in the root
861 not_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
886 same_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
898 sj1:
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 ;
915 no_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 ;-----------------------------------------------------------------------;
928 same_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
936 noname: ;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.
946 drvok:
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:
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
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
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;
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
994 aSSUME DS:DG ;an026;bgb
995 call rest_dir
996 ;an026;bgb
997 mov cs:ExitStatus,0 ; good return ;AC000;
998 jmp [exitpgm] ;an026;bgb
999 rabort:
1000 ret ;Return to RECINIT for exit ;AC000;
1001 ; mov ah,exit
1002 ; int 21h
1003
1004
1005 ;*************************************************************************
1006 ; DO until either
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
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
1025 recfil0:
1026 JMP SHORT $$EN55
1027 $$IF55:
1028 f_exists: call process_file ;file was opend ok
1029 rexit1: 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
1045 endproc file_spec ;AN000;bgb
1046
1047 ;*************************************************************************
1048 ; DO until either
1049 ;*************************************************************************
1050 Procedure process_file,Near ; ;AN000;
1051 recfile0:
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
1075 STOP_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
1120 endproc process_file ;AN000;bgb
1121
1122 ;*************************************************************************
1123 ;***************************************************************************
1124 break
1125 ;----- Restore INT 24 vector and old current directory -----------------;
1126 Procedure 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:
1140 no_fudge:
1141 mov dl,old_drive ; restore old current drive ;an008;bgb
1142 mov ah,set_default_drive
1143 int 21h
1144 ret
1145 endproc 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
1160 endproc int_24
1161 ;*************************************************************************
1162 int_24_back:
1163 cmp al,2 ; abort?
1164 jnz ireti
1165 push cs
1166 pop ds
1167 assume ds:dg,es:dg,ss:dg
1168 call rest_dir
1169 ret ;Ret for common exit ;AC000;
1170 ireti:
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 ;*****************************************************************************
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
1200 ret ; ;AN000;
1201 endproc 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 ;***************************************************************************
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;
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
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
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;
1270 endproc 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
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
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
1372 endproc fill_fat ;AN000;bgb ;an005;bgb
1373 ;
1374
1375 ;
1376
1377 ;*****************************************************************************
1378 ;*****************************************************************************
1379 Procedure 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
1390 endproc 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 ;*************************************************************************
1399 Procedure chk_fat,Near ; ;AN000;bgb
1400 push es
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
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:
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
1416 $$DO88:
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
1420 JE $$EN88
1421 step4: 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:
1432 endlop2: 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
1437 endproc chk_fat ;AN000;bgb
1438
1439
1440 ;*****************************************************************************
1441 ;*****************************************************************************
1442 even
1443 Procedure 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
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
1456 JNA $$IF96
1457 direrr: 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:
1463 nodirerr: 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
1472 endlop1:
1473 JMP SHORT $$DO94
1474 $$EN94:
1475 ret ;AN000;bgb
1476 endproc 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 ;*****************************************************************************
1485 Procedure 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:
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
1494 call fEOF ;
1495 ; $LEAVE C ; goto step1a AN000;bgb
1496 JC $$EN101
1497 step6: 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
1511 endproc read_fats ; ;AN000;bgb
1512
1513 ;*****************************************************************************
1514 ;*****************************************************************************
1515 even
1516 Procedure fill_dir,Near ;AN000;bgb
1517 lea si,dirent+7 ; s = &dirent[7]; ;AC000;bgb
1518 ; $DO ;AN000;bgb
1519 $$DO106:
1520 nam0: 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:
1529 nam1: 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
1567 endproc 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 ;*****************************************************************************
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;
1578 mov ax,fatptr ;
1579 MOV exit_sw,bp ; false ; default to continue looping until true
1580 call main_loop1
1581 step7: 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:
1596 rexit2: 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
1606 endproc drive_spec ; ;AN000;bgb
1607 ;
1608 pathlabl recover
1609
1610 include msgdcl.inc
1611
1612 code ends
1613 end ;recover ;AC000;bgb
1614
1615 \1a