From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/CMD/CHKDSK/CHKFAT.ASM | 1064 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1064 insertions(+) create mode 100644 v4.0/src/CMD/CHKDSK/CHKFAT.ASM (limited to 'v4.0/src/CMD/CHKDSK/CHKFAT.ASM') diff --git a/v4.0/src/CMD/CHKDSK/CHKFAT.ASM b/v4.0/src/CMD/CHKDSK/CHKFAT.ASM new file mode 100644 index 0000000..badd48c --- /dev/null +++ b/v4.0/src/CMD/CHKDSK/CHKFAT.ASM @@ -0,0 +1,1064 @@ +TITLE CHKFAT - procedures that acces the fat and/or fatmap +page ,132 ; + + .xlist + include chkseg.inc ;an005;bgb + INCLUDE CHKCHNG.inc + INCLUDE DOSSYM.inc + INCLUDE CHKEQU.inc + INCLUDE CHKMACRO.inc + include pathmac.inc + + +CONST SEGMENT PUBLIC PARA 'DATA' + EXTRN CREATMES:byte,FIXMES_ARG:word + EXTRN FREEMES:byte + EXTRN BADW_ARG:word,FATAL_END:word + EXTRN badrw_num:word,BADRW_STR:WORD,HAVFIX:byte + EXTRN FREEBYMES1:byte,FREEBYMES2:byte + EXTRN FREE_ARG1:WORD,FREE_ARG2:WORD,FREE_ARG3:WORD,ORPHCNT:dword + EXTRN DIRTYFAT:byte,CROSSCNT:dword,DOFIX:byte,SECONDPASS:byte + EXTRN BADSIZ:word,ORPHSIZ:word,LCLUS:word,ORPHFCB:byte + EXTRN HECODE:byte,USERDIR:byte,FRAGMENT:byte + EXTRN ORPHEXT:byte,ALLDRV:byte,FIXMFLG:byte,DIRCHAR:byte + EXTRN BIGFAT:byte,EOFVAL:word,BADVAL:word + extrn fTrunc:BYTE, rarg1:word ;an018;bgb + extrn temp_dd:dword ;an049;bgb +CONST ENDS + +DATA SEGMENT PUBLIC PARA 'DATA' + extrn fatcnt:byte ;an005;bgb + EXTRN THISDPB:dword,NUL_ARG:byte + EXTRN NAMBUF:byte,SRFCBPT:word,FATMAP:word + EXTRN MCLUS:word,CSIZE:byte,SSIZE:word + EXTRN DSIZE:word,ARG1:word,ARG_BUF:byte,ERRCNT:byte + EXTRN USERDEV:byte,HARDCH:dword,CONTCH:dword + EXTRN ExitStatus:Byte,Read_Write_Relative:Byte + extrn bytes_per_sector:word, fattbl:word ;an005;bgb + extrn sec_count:word, secs_per_64k:word, paras_per_64k:word ;an005;bgb + extrn fattbl_seg:word, fatsiz:word, paras_per_fat:word ;an005;bgb + extrn end_of_fatmap:word ;an030;bgb + extrn root_entries:word ;ac048;bgb;an047;bgb +DATA ENDS + +CODE SEGMENT PUBLIC PARA 'CODE' +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + EXTRN PRINTF_CRLF:NEAR,FCB_TO_ASCZ:NEAR, recover:near + EXTRN EPRINT:NEAR, makorphnam:near + EXTRN DOINT26:NEAR,PROMPTYN:NEAR,CHECKFILES:NEAR,DIRPROC:NEAR + EXTRN DOCRLF:NEAR, getfilsiz:near, fatal:near, write_disk:near + EXTRN GETENT:NEAR,CHECKNOFMES:NEAR, systime:near + EXTRN multiply_32_bits:near ;an049;bgb + +public calc_fatmap_seg, MARKMAP, CHKMAP, CHKMAPLP, ORPHAN, CONTLP, RET18 +public PromptRecover, NOCHAINREC, CHKMAPLP2, NEXTCLUS +public DISPFRB, FINDCHAIN, CHKMAPLP3, CHAINLP, INSERTEOF, FAT12_4, CHKCHHEAD +public ADDCHAIN, CHGOON, NEXTCLUS2, +public CHAINREC, MAKFILLP, GOTENT, OPAGAIN, GOTORPHNAM, ENTMADE, NEXTENT +public NXTORP, RET100, nextorph +public AMDONE, REWRITE, WRTLOOP +public WRTOK, NOWRITE, DONE, CROSSCHK, calc_fat_addr, pack, unpack + .list +PHONEY_STACK DW 5 DUP(0) ;ac048;bgb + + pathlabl chkfat +;***************************************************************************** ;an005;bgb +; CALC-FAT-ADDR - calculate the seg/off of the fat cell from the cell number ;an005;bgb +; ;an005;bgb +; Inputs: es - fat table segment +; si - cluster number +; +; Outputs: es - fat table segment + cluster seg +; di - cluster offset +; ;an005;bgb +; LARGE FAT SUPPORT ;an005;bgb +;******************* ;an005;bgb +; the offset into the fat table is cluster number times 2 (2 bytes per fat entry) ;an005;bgb +; This will result not only in the segment boundary being passed, but also in ;an005;bgb +; a single-word math overflow. So, we calculate the the address as follows: ;an005;bgb +; 0. start with cluster number (1-65535) ;an005;bgb +; 1. divide by 8 to get the number of paragraphs per fat-cell (0-8191) ;an005;bgb +; remainder = (0-7) ;an005;bgb +; 2. multiply the remainder by 2 to get offset in bytes (0-15) ;an005;bgb +; You now have a paragraph-offset number that you can use to calc the addr into ;an005;bgb +; the fat table. To get the physical addr you must add it to the offset of the ;an005;bgb +; table in memory. ;an005;bgb +; 3. add the paras to the segment register ;an005;bgb +; 4. add the offset to the offset register ;an005;bgb +;****************************************************************************** ;an005;bgb +Procedure calc_fat_addr,near ;an005;bgb + savereg ; ;an005;bgb + mov ax,si ;get cluster number from si + mov bx,0008h ; div by para (* 2 bytes per clus) ;an005;bgb + xor dx,dx ; zero dx for word divide ;an005;bgb + div bx ; do it ;an022;bgb;bgb + mov bx,es ; get fat table segment ;an005;bgb + add bx,ax ; add number of paras to the cluster ;an005;bgb + mov es,bx ; move it back ;an005;bgb + shl dx,1 ; remainder times 2 ;an005;bgb + mov di,dx ; offset = 00 + remainder ;an005;bgb + restorereg ;an005;bgb + return ;an005;bgb +EndProc calc_fat_addr ;an005;bgb + +;========================================================================= +; UNPACK : This routine calculates the position in the FAT +; where the cluster number resides and obtains +; its contents. +; +; Inputs : SI - Cluster number +; Outputs : DI - Cluster contents +; zero flag is set if fat cell = zero +; +; LOGIC +; - get addr of fat table +; - if 16-bit fat, +; then get the address of the cell (calc_fat_addr) +; mov it into di +; set the zero flag +; else multiply the cluster-number by 1.5 to get the byte-offset +; move the contents of the cluster into di +; if the cluster-number is odd, +; then shift it right by 1 nibble +; set the zero flag +; else (its already shifted right) +; set the zero flag +;========================================================================= +UNPACK proc near ;ac005; dms;unpack FAT + push es ;an005;bgb + mov es,fattbl_seg ;point to FAT in memory ;an005;bgb + mov DI,SI ;put cluster number in DI + cmp [BIGFAT],0 ;big fat? +; $IF nz ;yes + JZ $$IF1 + call calc_fat_addr ;calc addr of cluster ;an005;bgb + mov di,word ptr es:[di] ;es:bx points to fat cluster ;an005;bgb + or DI,DI ; Set zero +; $ELSE ;small fat + JMP SHORT $$EN1 +$$IF1: + SHR DI,1 + ADD DI,SI ; Mult by 1.5 + mov DI,word ptr es:[di] + TEST SI,1 ;is the cluster number odd? +; $IF nz ;last bit is non-zero; means it is odd + JZ $$IF3 + SHR DI,1 ;shift by 1 nibble + SHR DI,1 + SHR DI,1 + SHR DI,1 + and di,0fffh ;ac005; dms; +; $ELSE ;ac005; dms;even cluster bound. + JMP SHORT $$EN3 +$$IF3: + AND DI,0FFFH +; $ENDIF +$$EN3: +; $ENDIF +$$EN1: + pop es + return +UNPACK endp ;ac005; dms; + +;========================================================================= +; PACK : This routine puts data into the FAT. +; +; Inputs : SI - Cluster number to be packed +; dx - Data to be packed +; +; Outputs : Altered FAT +; LOGIC +; - set the fat-changed-flags +; - get the seg of the fat-table +; - if 16-bit fat, +; then get the address of the cell (calc_fat_addr) +; mov the new value into it +; else multiply the cluster-number by 1.5 to get the byte-offset +; move the contents of the cluster into di +; if the cluster-number is odd, +; then shift it right by 1 nibble +; set the zero flag +; else (its already shifted right) +; set the zero flag +;========================================================================= +PACK proc near ;ac005; dms; + savereg ;ac048;bgb + mov [DIRTYFAT],1 ;Set FAT dirty byte + mov [HAVFIX],1 ;Indicate a fix + mov es,fattbl_seg ; ;an005;bgb + mov DI,SI + cmp [BIGFAT],0 +; $IF nz ;ac005; dms;big fat? + JZ $$IF7 + call calc_fat_addr ;calc addr of cluster ;an005;bgb + mov es:[di],dx ;move dx into cluster ;an005;bgb +; $ELSE + JMP SHORT $$EN7 +$$IF7: + shr di,1 ;offset = clus-num * 1.5 + add di,si ;offset = clus-num * 1.5 + push di ;save cluster offset + mov DI,es:[di] ;get previous value, 4 nibbles + test si,1 ;is the cluster number odd? +; $IF nz ;last bit is non-zero; means it is odd + JZ $$IF9 + SHL dx,1 ;shift by 1 nibble + SHL dx,1 + SHL dx,1 + SHL dx,1 + AND DI,0FH ;zero out 1st 3 nibbles '000f' +; $ELSE ;even cluster number + JMP SHORT $$EN9 +$$IF9: + AND DI,0F000H ;zero out last 3 nibbles 'f000' +; $ENDIF +$$EN9: + or DI,dx ;put new value in with old + pop si ;get cluster offset + mov es:[SI],DI +; $ENDIF +$$EN7: + restorereg ;ac048;bgb + ret +PACK endp ;ac005; dms; + +;========================================================================= ;an005;bgb +; CROSSCHK : this proc gets the value of the fatmap entry that is pointed ;an005;bgb +; to by an orphan ;an005;bgb +; ;an005;bgb +; Inputs : si - cluster number of the orphan ;an005;bgb +; ;an005;bgb +; Outputs : ah - contents of the fatmap pointed to by di ;an005;bgb +; LOGIC ;an005;bgb +; ***** ;an005;bgb +;========================================================================= ;an005;bgb +procedure CROSSCHK ;an005;bgb + push es + mov es,fatmap ;an005;bgb + xor di,di ;an005;bgb + ADD DI,SI + mov ah,es:[di] ;an005;bgb + TEST AH,10H + pop es + ret +EndProc CROSSCHK ;an005;bgb + +;***************************************************************************** ;an005;bgb +; INIT_FATMAP ;an005;bgb +; description: initialize the fatmap area to all zeros ;an005;bgb +; ;an005;bgb +; called from: main-routine ;an005;bgb +; ;an005;bgb +;Change History: Created 8/31/87 bgb ;an005;bgb +; ;an005;bgb +;Input: segment addr of the fatmap ;an005;bgb +; number of clusters in the fat (1-65535) ;an005;bgb +; ;an005;bgb +;Output: fatmap ;an005;bgb +; ;an005;bgb +; LOGIC ;an005;bgb +;---------- ;an005;bgb +;***************************************************************************** ;an005;bgb +Procedure init_fatmap,Near ;AN000;bgb ;an005;bgb + savereg + mov es,fatmap ;get seg of the fatmap ;an005;bgb + xor di,di ;get off of the fatmap ;an005;bgb + mov cx,[MCLUS] ;do once for each cluster + xor AL,AL ;zero means free + REP STOSB ;Initialize fatmap to all free + mov byte ptr es:[di],al ; ;an010;bgb + restorereg + return +endproc init_fatmap ; ;AN000; +; +;***************************************************************************** ;an005;bgb +; CALC_FATMAP_SEG ;an005;bgb +; description: calculate the segment of the fatmap for addressing purposes ;an005;bgb +; ;an005;bgb +; called from: main-routine ;an005;bgb +; ;an005;bgb +;Change History: Created 8/31/87 bgb ;an005;bgb +; ;an005;bgb +;Input: bytes-per-sector ;an005;bgb +; fatsiz ;an005;bgb +; ;an005;bgb +;Output: ram-based fat table ;an005;bgb +; paras-per-fat - number of paragraphs of mem in the fat +; fattbl-seg - segment number of fat table +; fatmap - segment number of the fat map table +; ;an005;bgb +; LOGIC ;an005;bgb +;---------- ;an005;bgb +; - calc length fat-table (in paras) ;an005;bgb +; = bytes-per-sector / 16 * sectors-per-fat ;an005;bgb +; - calc segment of fat table in memory ;an005;bgb +; = es + 64k ;an005;bgb +; - calc segment of fatmap area in memory ;an005;bgb +; = es + 64k + length of fat-table ;an005;bgb +;***************************************************************************** ;an005;bgb +Procedure calc_fatmap_seg,Near ;AN000;bgb ;an005;bgb +; calc fat table length ;an005;bgb + push es + mov ax,bytes_per_sector ; bytes per sector ;an005;bgb + xor dx,dx ;an005;bgb + mov bx,16 ;an005;bgb + div bx ; paras per sector ;an022;bgb;bgb + mov cx,fatsiz ;2 ; get sectors per fat ;an005;bgb + xor dx,dx ;an005;bgb + mul cx ; paras per fat ;an005;bgb + mov paras_per_fat,ax ;an005;bgb +; calc fat table segment ;an005;bgb + mov bx,es ;get seg of fat-table ;an005;bgb + add bx,01000h ;add 64k for end of pgm seg ;an005;bgb + mov fattbl_seg,bx ;starting segment of fattbl ;an005;bgb +; calc fatmap segment :an005;bgb + add ax,bx ;seg of fatmap= seg of fattbl + size of fattbl ;an005;bgb + mov fatmap,ax ;this is the seg of the fatmap ;an005;bgb +; find segment number of end of fatmap ;an030;bgb +;ptm p5000 mov bx,paras_per_fat ;each fat cell is 2 bytes ;an030;bgb +;ptm p5000 shr bx,1 ;each fatmap cell is 1 byte = ;an030;bgb + mov bx, [MCLUS] ;P5000 INIT_FATMAP use [MCLUS] + shr bx, 1 ;P5000 convert it to para. + shr bx, 1 ;P5000 + shr bx, 1 ;P5000 + shr bx, 1 ;P5000 + add ax,bx ;add in fatmap seg = ;an030;bgb + inc ax ;P5000 + mov end_of_fatmap,ax ;last seg value ;an030;bgb + pop es + ret ; ;AN000; +endproc calc_fatmap_seg ; ;AN000; +; + ;ac048;bgb +;***************************************************************************** ;ac048;bgb +; FIX_ENTRY - fill in the dir entry with the lost cluster information, give it ;ac048;bgb +; unique filename, and write it back to disk. ;ac048;bgb +; ;ac048;bgb +; WARNING!! NOTE!! --> ;ac048;bgb +; ;ac048;bgb +; called by - CHAINREC ;ac048;bgb +; ;ac048;bgb +; inputs: AX - drive number ;ac048;bgb +; BX - ram offset of beginning of sector ;ac048;bgb +; CX - ;ac048;bgb +; DX - sector number low ;ac048;bgb +; SP - ;ac048;bgb +; BP - ;ac048;bgb +; SI - cluster number of first cluster in this lost chain ;ac048;bgb +; DI - points to entry in ram ;ac048;bgb +; ;ac048;bgb +; output: AX - ;ac048;bgb +; BX - ;ac048;bgb +; CX - ;ac048;bgb +; DX - ;ac048;bgb +; SP - ;ac048;bgb +; BP - ;ac048;bgb +; SI - ;ac048;bgb +; DI- ;ac048;bgb +; ;ac048;bgb +; Regs abused - di,si,cx ;ac048;bgb +; ;ac048;bgb +;logic: 1. save the starting cluster number ;ac048;bgb +; ;ac048;bgb +; 2. if the recovered file name already exists, then use the next one. ;ac048;bgb +; do this until the name is unique. ;ac048;bgb +; ;ac048;bgb +; 3. move all the pertinant info into the dir entry. ;ac048;bgb +; ;ac048;bgb +; 4. write the dir entry out to disk. ;ac048;bgb +;***************************************************************************** ;ac048;bgb +procedure fix_entry,near ;ac048;bgb + mov ds:[DI+26],SI ;move 1st clus num into dir entry ;ac048;bgb ;an005;bgb + savereg ;Save INT 26 data ;ac048;bgb +;make sure this name is unique ;ac048;bgb + DOS_Call Disk_Reset ;func 0d - flush buffers ;AC000;ac048;bgb; + mov dx,OFFSET DG:ORPHFCB ;point to filename file0000.chk ;ac048;bgb + mov AH,FCB_OPEN ;open the file just put into the dir ;ac048;bgb +OPAGAIN: ;ac048;bgb +; $do ;ac048;bgb +$$DO13: + INT 21H ;ac048;bgb + or AL,AL ;did the open fail? ;ac048;bgb +; $leave nz ;ac048;bgb + JNZ $$EN13 + call MAKORPHNAM ;Try next name ;ac048;bgb +; $enddo ;ac048;bgb + JMP SHORT $$DO13 +$$EN13: +GOTORPHNAM: ;di still points to entry ;ac048;bgb + mov SI,OFFSET DG:ORPHFCB + 1 ;ORPHFCB Now has good name ;ac048;bgb + mov cx,11 ;move filename, ext ;ac048;bgb + REP MOVSB ;ac048;bgb + call MAKORPHNAM ;Make next name ;ac048;bgb + xor ax,ax ;fill dir entry with zeros ;ac048;bgb + mov cx,11 ;ac048;bgb + REP STOSB ;ac048;bgb +; Add in time for orphan file - BAS July 17/85 ;ac048;bgb + push dx ;save starting sector number ;ac048;bgb;an045;bgb + call SYSTIME ;ac048;bgb + STOSW ; Time ;ac048;bgb + mov ax,dx ;ac048;bgb + STOSW ; Date ;ac048;bgb + pop dx ;restore starting sector number ;ac048;bgb ;an045;bgb + mov SI,ds:[DI] ;get starting cluster number ;ac048;bgb ;an005;bgb + inc DI ;skip firstclus in entry ;ac048;bgb + inc DI ;ac048;bgb + PUSH DI ;save it from getfilsiz ;ac048;bgb + call GETFILSIZ ;calc file size from number of clus ;ac048;bgb + POP DI ;restore di ;ac048;bgb + STOSW ;ax=file size low ;ac048;bgb + mov ax,dx ;dx=filesize high ;ac048;bgb + STOSW ; ;ac048;bgb + restorereg ;offset, sector num, drive num ;ac048;bgb + mov cx,1 ;number of sectors = 1 ;ac048;bgb + call DOINT26 ;write it out to disk ;ac048;bgb + ret ;ac048;bgb +endproc fix_entry ;ac048;bgb + ;ac048;bgb +;***************************************************************************** ;ac048;bgb;an047;bgb +; NEXTORPH - find the cluster number of the next orphan. This assumes that ;ac048;bgb;an047;bgb +; there is at least one lost cluster available. ;ac048;bgb;an047;bgb +; ;ac048;bgb;an047;bgb +; WARNING!! NOTE!! --> ;ac048;bgb;an047;bgb +; ;ac048;bgb;an047;bgb +; called by - PROCEDURE NAME ;ac048;bgb;an047;bgb +; ;ac048;bgb;an047;bgb +; inputs: AX - ;ac048;bgb;an047;bgb +; BX - ;ac048;bgb;an047;bgb +; CX - ;ac048;bgb;an047;bgb +; DX - ;a;ac048;bgbn047;bgb +; SP - ;;ac048;bgban047;bgb +; BP - ;a;ac048;bgbn047;bgb +; SI - cluster number of the previous orphan ;a;ac048;bgbn047;bgb +; DI - ;a;ac048;bgbn047;bgb +; DS - ;a;ac048;bgbn047;bgb +; ES - points to one byte map of the fat ;a;ac048;bgbn047;bgb +; ;a;ac048;bgbn047;bgb +; output: AX - ;;ac048;bgban047;bgb +; BX - ;a;ac048;bgbn047;bgb +; CX - ;;ac048;bgban047;bgb +; DX - ;a;ac048;bgbn047;bgb +; SP - ;a;ac048;bgbn047;bgb +; BP - ;a;ac048;bgbn047;bgb +; SI - cluster number of one past the orphan ;ac048;bgb;an047;bgb +; DI - cluster number of the orphan ;a;ac048;bgbn047;bgb +; DS - ;a;ac048;bgbn047;bgb +; ES - ;a;ac048;bgbn047;bgb +; ;a;ac048;bgbn047;bgb +; Regs abused - none ;ac048;bgb;an047;bgb +; ;;ac048;bgban047;bgb +;logic: 1. save ax & es, and point to fat map ;ac048;bgb;an047;bgb +; ;a;ac048;bgbn047;bgb +; 2. do until the head of a chain is found: ;ac048;bgb ;an047;bgb +; ;;ac048;bgban047;bgb +; 3. get the next cell ;ac048;bgb ;an047;bgb +; ;;ac048;bgban047;bgb +; 4. bump pointers into fat map ;ac048;bgb ;an047;bgb +; ;;ac048;bgban047;bgb +; 5. restore ax & es ;;ac048;bgban047;bgb +;*****************************************************************************;a;ac048;bgbn047;bgb +procedure NEXTORPH,near ;a;ac048;bgbn047;bgb + savereg ;save regs abused ;ac048;bgb + mov es,[FATMAP] ;point to fat map ;ac048;bgb +; $do ;ac048;bgb +$$DO16: +loopno: mov al,byte ptr es:[si] ;get the indicated fatmap entry ;ac048;bgb ;an005;bgb + inc si ;point to the next one ;ac048;bgb ;an005;bgb + inc di ;point to the next one ;ac048;bgb ;an005;bgb + cmp AL,89H ;stop when you find an 89 ;ac048;bgb +; $leave z ;this means head(80), found(1), and orphan(8) ;ac048;bgb + JZ $$EN16 +; $enddo ;ac048;bgb + JMP SHORT $$DO16 +$$EN16: + restorereg ;restore regs ;ac048;bgb +return ;ac048;bgb +endproc nextorph ;ac048;bgb + ;ac048;bgb + ;ac048;bgb + +;**************************************************************************** +; MARKMAP - make a mark in the fat map for every cluster encountered +; +; called by - markfat, +; +; inputs - AL - the mark +; DI - cluster number +; +; outputs - CY if crosslink found +; - AH - previous mark +; - crosscnt (count of number of crosslinks found) +; - fatmap marked +; +; LOGIC +;****** +; - point to fatmap with es +; - if that cell has been found before, +; then mark it crossed x'10' +; else mark it found al +;**************************************************************************** +markmap: savereg ;Save registers ;AN000; + xor si,si ;Get addr of map ;an005;bgb + mov es,[FATMAP] ;Get addr of map ;an005;bgb + mov ah,es:[di] ;Get entry at that spot ;an005;bgb + or ah,ah ;Is it zero? ; ; +; $IF NZ ;already found - mark crossed;If not, we got crosslink ;AC000; + JZ $$IF19 + add word ptr crosscnt,1 ;Count the crosslink ; ; + adc word ptr crosscnt+2,0 ;Count the crosslink ; ; + or byte ptr es:[di],10H ;Resets zero in map ;An005;bgb + stc ;Indicate crosslink on ret ; ; +; $ELSE ;not found - mark found ;No crosslink ; ; + JMP SHORT $$EN19 +$$IF19: + mov es:[di],al ;Set mark in map ;Ac005;bgb + clc ;Indicate things okay ; ; +; $ENDIF ; ;AN000; +$$EN19: + restorereg ; ;AN005;bgb + ret ; ; ; + + +;**************************************************************************** +; CHKMAP - Compare FAT and FATMAP looking for badsectors and orphans +; +; called by - +; +; inputs - fatmap +; - dsize - number of clusters on the disk +; +; outputs - badsiz - +; - +; - +; LOGIC +;****** +; - get addr of fatmap +; - get offset of 1st cluster in fatmap +; - do for all the clusters on the disk: +; - if the cluster has been found +; then get the next cluster in its chain +; if the cell was never pointed to by anyone (0) +; then get the contents of that cell from the fat +; (the contents of the fat cell should be zero, too) +; if the fat-cell is not zero +; then (it should only be a bad sector) +; if it is a bad sector, inc the bad-sector-counter +; otherwise, we have found an orphan sector +; end-of-loop +; - if there are any orphans, +; then recover them +;**************************************************************************** +CHKMAP: + push es ;an014;bgb + mov es,fatmap ;get segment of the fatmap ;an005;bgb + xor si,si ;get the offset of the fatmap ;an005;bgb + mov si,2 ;go past the first two (invalid) entries;an005;bgb +;do for all the clusters on the disk + mov cx,[DSIZE] ;loop for the number of clusters on the disk +CHKMAPLP: + mov al,es:[si] ;move a byte from the fatmap to al ;an005;bgb + or al,al ;is the cluster found already? +; $IF Z ;fatmap cell is zero + JNZ $$IF22 + call unpack ;get the contents of it +; $IF NZ ;is there something in the cell? + JZ $$IF23 + cmp di,[badval] ;is the fat cell pointing to a bad sector? fff7 +; $IF Z ; yes + JNZ $$IF24 + inc [badsiz] ;inc the bad sector counter + mov byte ptr es:[si],4 ;Flag the map ;an005;bgb +; $ELSE ; no, not a bad sector + JMP SHORT $$EN24 +$$IF24: +orphan: inc [orphsiz] ; then its an orphan + mov byte ptr es:[si],8 ;Flag it ;an005;bgb +; $ENDIF +$$EN24: +; $ENDIF +$$IF23: +; $ENDIF +$$IF22: +CONTLP: + inc si ;point si to next cluster + loop chkmaplp + cmp [orphsiz],0 ;an005;bgb +; $IF A ;if there are any orphans, go recover them ;an005;bgb + JNA $$IF29 + call recover +; $ENDIF +$$IF29: + pop es ;an014;bgb +RET18: ret + +;***************************************************************************** +; PROMPTRECOVER - do the actual recovering of files +; +; inputs: es - points to fatmap +; ax - +; bx - +; cx - +; dx - +; +; outputs: +; LOGIC +; - ask the user if he wants to convert the orphans to files +; - +; - +;*************************************************************************** +PromptRecover: + mov dx,OFFSET DG:FREEMES + call PROMPTYN ;Ask user +; $IF Z + JNZ $$IF31 + jmp CHAINREC +; $ENDIF +$$IF31: +NOCHAINREC: + mov es,[fatmap] ;Free all orphans ;an005;bgb + mov si,2 ;an005;bgb + mov cx,[dsize] + xor dx,dx ;dx is the new value (free) +CHKMAPLP2: + mov al,es:[si] ;get next byte from fatmap into al + TEST AL,8 ; is it an orphan? +; $IF NZ ;yes + JZ $$IF33 + call PACK ;si=cluster number dx=new value +; $ENDIF +$$IF33: +NEXTCLUS: + inc si + loop CHKMAPLP2 + xor ax,ax + XCHG ax,[ORPHSIZ] ;number of orphans = zero + mov cx,OFFSET DG:FREEBYMES1 ;print msg + cmp [DOFIX],0 +; $IF Z + JNZ $$IF35 + mov cx,OFFSET DG:FREEBYMES2 + mov [LCLUS],ax ;move number of lost clust would be ;an049;bgb +; $ENDIF +$$IF35: +DISPFRB: ;ax=lost clusters (1-fff6) + push bx ;save it ;an049;bgb + push cx ;save it ;an049;bgb + mov cl,[csize] ;get sectors per cluster (1-32) ;an049;bgb + xor ch,ch ;zero out high byte ;an049;bgb + xor dx,dx ;zero out hi word for word mult ;an049;bgb + mul cx ;cx*ax=dx:ax lost sectors (1-1ffec0);an049;bgb + mov bx,dx ;move high word for call ;an049;bgb + mov cx,ssize ;word to mult with ;an049;bgb + call multiply_32_bits ;bx:ax is result ;an049;bgb + mov word ptr rarg1,ax ;low word into low word ;an049;bgb + mov word ptr rarg1+2,bx ;hi word into hi word ;an049;bgb + mov [free_arg1],ax + mov [free_arg2],bx ;an049;bgb + mov [free_arg3],cx + pop cx + pop bx + mov dx,cx ;Point to right message;an049;bgb + call printf_crlf + ret + + + + +;***************************************************************************** +; FINDCHAIN - +; +; called by - recover +; +; inputs: +; +; outputs: +; LOGIC - search thru entire fatmap +; - +; - +;*************************************************************************** +lostdeb equ 0 ;set private build version on ;an047;bgb +lost_str db '00000' ;max size of cluster number +FINDCHAIN: +;Do chain recovery on orphans + mov es,[FATMAP] ; point to fatmap + mov SI,2 ; point to fatmap + mov dx,si ; point to fatmap + mov cx,[DSIZE] ;get total number of clusters on disk +CHKMAPLP3: + mov al,es:[si] ;get next fatmap entry + inc si ;point to next fatmap entry + ;has to be an orphan(08) + TEST AL,8 ;Orphan? + jz NEXTCLUS2 ;Nope + ;make sure its not a regular file entry + TEST AL,1 ;Seen before ? + jnz NEXTCLUS2 ;Yup +;recover this chain + savereg ;Save search environment + dec SI + or byte ptr es:[si],81H ;Mark as seen and head + + + IF LOSTDEB ;is this private build version? + call lostdisp ;display lost cluster numbers + ENDIF + + add word ptr orphcnt,1 ;Found a chain + adc word ptr orphcnt+2,0 ;Found a chain + mov SI,dx ;point to the next fatmap entry +CHAINLP: + call UNPACK ;si = fat cell + XCHG SI,DI ;si=contents, di=cell number + cmp SI,[EOFVAL] ;is this the end of the file? + JAE CHGOON ;yes, then we are done + PUSH DI ;no, not eof +;dont do this next part if any of two conditions: +; 1. invalid cluster number +; 2. points to itself + cmp SI,2 ;well, is it a valid cluster number? + JB INSERTEOF ;Bad cluster number + cmp SI,[dsize] + JA INSERTEOF ;Bad cluster number + cmp SI,DI ;how bout if it points to itself? + jz INSERTEOF ;Tight loop +; find out what it points TO + call CROSSCHK + TEST AH,8 ;Points to a non-orphan? + jnz CHKCHHEAD ;Nope + ;orphan points to nothing +INSERTEOF: +; you come here if: +; 1. invalid cluster number +; 2. points to itself +; 3. points to nothing + POP SI ;the previous cluster number + mov dx,0FFFH ;get eof value (12-bit) + cmp [BIGFAT],0 + jz FAT12_4 + mov dx,0FFFFH ;get eof value (16-bit) +FAT12_4: + call PACK ;stick it in! + jmp SHORT CHGOON ;and we are done +; orphan point to a head entry +CHKCHHEAD: + TEST AH,80H ;Previosly marked head? + jz ADDCHAIN ;Nope + AND BYTE PTR es:[DI],NOT 80H ;Turn off head bit + sub word ptr orphcnt,1 ;Wasn't really a head + sbb word ptr orphcnt+2,0 ;Wasn't really a head + POP DI ;Clean stack + jmp SHORT CHGOON +ADDCHAIN: + TEST AH,1 ;Previosly seen? + jnz INSERTEOF ;Yup, don't make a cross link + or BYTE PTR es:[DI],1 ;Mark as seen + POP DI ;Clean stack + jmp CHAINLP ;Follow chain +CHGOON: + POP dx ;Restore search + POP cx + POP SI +NEXTCLUS2: + inc dx + loop CHKMAPLP3 + ret + + + +;***************************************************************************** ;ac048;bgb +; CHAINREC - the user has requested us to recover the lost clusters ;ac048;bgb +; ;ac048;bgb +; inputs: ;ac048;bgb +; note: although called from PROMPTRECOVER, this routine returns control to ;ac048;bgb +; recover via the ret instruction. ;ac048;bgb +;***************************************************************************** ;ac048;bgb + ;ac048;bgb +;***************************************************************************** ;ac048;bgb +; CHAINREC - The user has requested us to recover the lost clusters ;ac048;bgb +; ;ac048;bgb +; WARNING!! NOTE!! --> the count of the number of lost cluster chains remains, +; for this proc, a single word. More than 64k chains +; will cause this proc to fail. +; ;ac048;bgb +; called by - PROCEDURE NAME ;ac048;bgb +; ;ac048;bgb +; inputs: AX - N/A ;ac048;bgb +; bx - ;ac048;bgb +; cx - N/A ;ac048;bgb +; dx - N/A ;ac048;bgb +; SP - ;ac048;bgb +; BP - N/A ;ac048;bgb +; SI - N/A ;ac048;bgb +; DI - N/A ;ac048;bgb +; data: root_entries ;ac048;bgb +; orphcnt ;ac048;bgb +; ;ac048;bgb +; output: AX - ;ac048;bgb +; bx - ;ac048;bgb +; cx - ;ac048;bgb +; dx - ;ac048;bgb +; SP - ;ac048;bgb +; BP - ;ac048;bgb +; SI - ;ac048;bgb +; DI- ;ac048;bgb +; ;ac048;bgb +; Regs abused - ;ac048;bgb +; ;ac048;bgb +;logic: 1. ;ac048;bgb +;***************************************************************************** ;ac048;bgb + CHAINREC: ;ac048;bgb + push es ;save es if it is used for anything ;ac048;bgb + push ds ;make es point to data ;ac048;bgb + pop es ;ac048;bgb +;find the cluster number of the orphan ;ac048;bgb + mov SI,2 ;start at first cluster ;an005;bgb ;ac048;bgb + mov DI,1 ;point to previous cluster? ;ac048;bgb + call NEXTORPH ;di points to orphan ;ac048;bgb +;init for loop ;ac048;bgb + savereg ;save orphan, orphan+1 ;ac048;bgb + mov SI,DI ;si point to orphan ;ac048;bgb + xor ax,ax ;set count of dir entries processed to zero;ac048;bgb + mov dx,word ptr orphcnt ;get low word of lost clusters ;ac048;bgb;an049;bgb + mov word ptr temp_dd,dx ;get low word of lost clusters ;an049;bgb + mov dx,word ptr orphcnt+2 ;get hi word of lost clusters ;an049;bgb + mov word ptr temp_dd+2,dx ;get hi word of lost clusters ;an049;bgb + mov BP,OFFSET DG:PHONEY_STACK ;Set BP to point to "root" ;ac048;bgb +;do for all dir entries: ;ac048;bgb +MAKFILLP: ;ac048;bgb +; $DO ;do for all root entries ;ac048;bgb +$$DO37: + savereg ;cnt of entries processed, num orphans ;ac048;bgb;an049;bgb + call GETENT ;DI points to entry ;ac048;bgb + cmp BYTE PTR ds:[DI],0E5H ;is this dir entry erased? ;an;ac048;bgb005;bgb +; $if z,or ;ac048;bgb + JZ $$LL38 + cmp BYTE PTR ds:[DI],0 ;is this dir entry empty? ;an;ac048;bgb005;bgb +; $if z ;ac048;bgb + JNZ $$IF38 +$$LL38: +GOTENT: mov [HAVFIX],1 ;Making a fix ;ac048;bgb + cmp [DOFIX],0 ;/f parameter specified? ;ac048;bgb +; $if NZ ;yes- do the fix ;ac048;bgb + JZ $$IF39 + call fix_entry ;ac048;bgb +; $endif ;ac048;bgb +$$IF39: +ENTMADE: restorereg ;ac048;bgb;an049;bgb + sub word ptr temp_dd,1 ;finished with one orphan ;ac048;bgb;an049;bgb + sbb word ptr temp_dd+2,0 ;finished with one orphan ;ac048;bgb;an049;bgb + cmp word ptr temp_dd,0 ;is that the last one? ;ac048;bgb;an049;bgb +; $IF Z,AND ;no, check the hi word ;an049;bgb + JNZ $$IF41 + cmp word ptr temp_dd+2,0;is that the last one? ;ac048;bgb;an049;bgb +; $IF Z ;neither are zero ;an049;bgb + JNZ $$IF41 + jmp RET100 ; yes,we are done ;ac048;bgb;an049;bgb +; $endif ;an049;bgb +$$IF41: + call NEXTORPH ;get the cluster of the next one ;ac048;bgb + savereg ;ac048;bgb + mov SI,DI ;ac048;bgb +; $else ;dir entry was not erased or zero ;ac048;bgb + JMP SHORT $$EN38 +$$IF38: +NEXTENT: restorereg ;ac048;bgb;an049;bgb +; $endif ;ac048;bgb +$$EN38: +NXTORP: inc ax ;ac048;bgb + cmp ax,root_entries ;do for 0 to (root_entries - 1) ;ac048;bgb +; $leave z ;ac048;bgb + JZ $$EN37 +; $ENDDO ;ac048;bgb + JMP SHORT $$DO37 +$$EN37: + restorereg ;Clean Stack from si,di ;ac048;bgb + sub word ptr orphcnt,dx ;Couldn't make them all ;ac048;bgb + sbb word ptr orphcnt+2,0 ;Couldn't make them all ;ac048;bgb + mov dx,OFFSET DG:CREATMES ;ac048;bgb + mov byte ptr [arg_buf],0 ;ac048;bgb + call EPRINT ;ac048;bgb +RET100: pop es ;restore es ;ac048;bgb + ret ;ac048;bgb + ;ac048;bgb + ;ac048;bgb + ;ac048;bgb + +;***************************************************************************** +;***************************************************************************** +SUBTTL AMDONE - Finish up routine +PAGE +Public AmDone +AMDONE: +ASSUME DS:NOTHING + cmp [DIRTYFAT],0 + jz NOWRITE ;FAT not dirty + cmp [DOFIX],0 + jz NOWRITE ;Not supposed to fix +REWRITE: + LDS bx,[THISDPB] +ASSUME DS:NOTHING + mov cx,[bx.dpb_FAT_size] ;Sectors for one fat (DCR) ;AC000; + mov DI,cx + mov CL,[bx.dpb_FAT_count] ;Number of FATs + mov dx,[bx.dpb_first_FAT] ;First sector of FAT + PUSH CS + POP DS +ASSUME DS:DG + mov [ERRCNT],0 +; set up to write to the disk + xor bx,bx ;offset of the fat-table ;an005;bgb + mov es,fattbl_seg ;segment of the fat-table ;an005;bgb + mov AL,[ALLDRV] + dec AL + mov AH,1 + PUSH cx +WRTLOOP: + XCHG cx,DI + PUSH dx + PUSH cx + PUSH DI + PUSH ax + + call Write_Disk ;Do relative sector write ;AC000; + + JNC WRTOK + inc [ERRCNT] + ;mov [badrw_str],offset dg:writing + POP ax ; Get fat # in AH + PUSH ax ; Back on stack + xchg al,ah ; Fat # to AL + xor ah,ah ; Make it a word + mov [badrw_num],ax + mov dx,offset dg:badw_arg + call PRINTf_crlf +WRTOK: + POP ax + POP cx + POP DI + POP dx + inc AH + ADD dx,DI + loop WRTLOOP ;Next FAT + POP cx ;Number of FATs + cmp CL,[ERRCNT] ;Error on all? +; $if e + JNE $$IF47 + jmp fatal +; $endif +$$IF47: +; make sure that the data fields are always adressable, because +;we can come here after a ctl - break has happened. so point to them w/ cs: +NOWRITE: + DOS_Call Disk_Reset ; ;AC000; + mov dx,OFFSET DG:USERDIR ;Recover users directory + DOS_Call ChDir ; ;AC000; + cmp BYTE PTR cs:[FRAGMENT],1 ;Check for any fragmented files? ;an029;bgb + jnz DONE ;No -- we're finished + call CHECKFILES ;Yes -- report any fragments +Public Done +DONE: +ASSUME DS:NOTHING + mov DL,cs:[USERDEV] ;Recover users drive ;an029;bgb + DOS_Call Set_Default_Drive ; ;AC000; + ret + + + + + + + + + + IF LOSTDEB ;is this private build version? +Procedure lostdisp,near ;an005;bgb + savereg ; ;an005;bgb + mov ax,dx ;save orig value + + mov cl,12 ;shift 3 nibbles + shr dx,cl ;remove al but last nibble + and dx,000fh + cmp dx,0ah +; $IF B + JNB $$IF49 + add dx,30h ;make it char +; $ELSE + JMP SHORT $$EN49 +$$IF49: + add dx,37h +; $ENDIF +$$EN49: + push ax + mov ah,2 + int 21h + pop ax + + mov dx,ax ;get orig value + mov cl,8 + shr dx,cl + and dx,000fh + cmp dx,0ah +; $IF B + JNB $$IF52 + add dx,30h ;make it char +; $ELSE + JMP SHORT $$EN52 +$$IF52: + add dx,37h +; $ENDIF +$$EN52: + push ax + mov ah,2 + int 21h + pop ax + + mov dx,ax ;get orig value + mov cl,4 + shr dx,cl + and dx,000fh + cmp dx,0ah +; $IF B + JNB $$IF55 + add dx,30h ;make it char +; $ELSE + JMP SHORT $$EN55 +$$IF55: + add dx,37h +; $ENDIF +$$EN55: + push ax + mov ah,2 + int 21h + pop ax + + mov dx,ax ;get orig value + and dx,000fh + cmp dx,0ah +; $IF B + JNB $$IF58 + add dx,30h ;make it char +; $ELSE + JMP SHORT $$EN58 +$$IF58: + add dx,37h +; $ENDIF +$$EN58: + mov ah,2 + int 21h + + mov dl,' ' ;space after last number + mov ah,2 + int 21h + + restorereg ;an005;bgb + return ;an005;bgb +EndProc lostdisp ;an005;bgb +ENDIF + + + pathlabl chkfat + + +CODE ENDS + END + \ No newline at end of file -- cgit v1.2.3