diff options
Diffstat (limited to 'v4.0/src/CMD/RECOVER/RECOVER.ASM')
| -rw-r--r-- | v4.0/src/CMD/RECOVER/RECOVER.ASM | 1615 |
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 @@ | |||
| 1 | page ,132 ; | ||
| 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 | \ No newline at end of file | ||