TITLE   CHKFAT  - procedures that acces the fat and/or fatmap
;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1991
; *                      All Rights Reserved.
; */
page    ,132                                    ;

	.xlist
	include chkseg.inc                                                      ;an005;bgb
	INCLUDE CHKCHNG.inc
	INCLUDE DOSSYM.inc
	INCLUDE CHKEQU.inc
	INCLUDE CHKMACRO.inc
	include pathmac.inc
	include dpb.inc
	include syscall.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   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 <ax,bx,dx>              ;                                           ;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 <dx,bx,ax>                                                       ;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 <si,di,es>                                                      ;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 <es,di,si>                                                   ;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 <es,di,ax,cx>
    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 <cx,ax,di,es>
    return
endproc init_fatmap                         ;                               ;AN000;
;
;*****************************************************************************  
; CALC_FATMAP_SEG                                                               
; description: calculate the segment of the fatmap for addressing purposes      
;                                                                               
; called from: main-routine                                                     
;                                                                               
;Change History: Created    8/31/87            bgb                              
;                                                                               
;Input: bytes-per-sector                                                        
;       fatsiz                                                                  
;                                                                               
;OUTPUT:
;       CY  ->  not enough memory/some other mem alloc failure
;               ax = error code
;       NC  ->  Mem alloc succesful
;        ram-based fat table                                                    
;        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
;
;                                                                               
; LOGIC                                                                         
;----------                                                                     
;     - calc length fat-table (in paras)
;           = bytes-per-sector / 16 * sectors-per-fat                           
;       allocate mem for this size
;     - calculate length of fatmap area
;       allocate mem for this size
;
;*****************************************************************************  
Procedure calc_fatmap_seg,Near                 
; calc fat table length                                                         
	push    es
	mov     ax,bytes_per_sector     ; bytes per sector                      
	xor     dx,dx                                                           
	mov     bx,16                                                           
	div     bx                      ; paras per sector                  
	mov     cx,fatsiz               ;2         ; get sectors per fat        
	xor     dx,dx                                                           
	mul     cx                      ; paras per fat                         
	mov     paras_per_fat,ax                                                

; allocate mem for fat table
	mov     bx,ax
	mov     ax,4800h                ; allocate mem
	int     21h                     
	jc      cfs_100                  ; error on alloc ?

; alloc successful ; ax = seg of FAT TABLE

	mov     fattbl_seg,ax           ;starting segment of fattbl             

; calculate size of fat map
	mov     bx, [MCLUS]             ;P5000 INIT_FATMAP use [MCLUS]
	mov     cx, 4
	shr     bx, cl                   ;P5000 convert it to para.
	inc     bx                      ;P5000 ;size of fatmap
	mov     ax,4800h                ; allocate mem
	int     21h
	jc      cfs_100                  ; mem not avail ?

; alloc successful; ax = seg of fatmap

	mov     fatmap,ax
	clc
cfs_100: pop    es 
	ret                             ;                                     

endproc calc_fatmap_seg                     ;                               
;
										;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         
    savereg <ax,dx,bx>                  ;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            
	call    SYSTIME                                                         ;ac048;bgb
	STOSW                           ; Time                                  ;ac048;bgb
	mov     ax,dx                                                           ;ac048;bgb
	STOSW                           ; Date                                  ;ac048;bgb
	pop     dx                      ;restore starting sector number         
	mov     SI,ds:[DI]              ;get starting cluster number            ;ac048;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 <bx,dx,ax>   ;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
;*****************************************************************************  
; 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 <ax,es>                     ;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 <es,ax>                  ;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 <si,es>                         ;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 <es,si>                      ;                               ;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:

    cmp     DoFix,ON                        ; Are we fixing errors?
    jne     NoChainRec                      ; Don't prompt if not
    mov     dx,OFFSET DG:FREEMES
    call    PROMPTYN                        ;Ask user
    jnz     NoChainRec                      ; User doesn't want files
    jmp     CHAINREC

NOCHAINREC:
    mov     es,[fatmap]                     ;Free all orphans
    mov     si,2
    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?
    jz      NextClus         ; yes
    call    PACK             ;si=cluster number dx=new value

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
    jnz     DispFRB
    mov     cx,OFFSET DG:FREEBYMES2
    mov     [LCLUS],ax               ;move number of lost clust would be

DISPFRB:                             ;ax=lost clusters (1-fff6)
    push    bx                       ;save it
    push    cx                       ;save it
    mov     cl,[csize]               ;get sectors per cluster (1-32)
    xor     ch,ch                    ;zero out high byte
    xor     dx,dx                    ;zero out hi word for word mult
    mul     cx                       ;cx*ax=dx:ax  lost sectors (1-1ffec0)
    mov     bx,dx                    ;move high word for call
    mov     cx,ssize                 ;word to mult with
    call    multiply_32_bits         ;bx:ax is result
    mov     word ptr rarg1,ax        ;low word into low word
    mov     word ptr rarg1+2,bx      ;hi  word into hi  word
    mov     [free_arg1],ax
    mov     [free_arg2],bx
    mov     [free_arg3],cx
    pop     cx
    pop     bx
    mov     dx,cx                    ;Point to right message
    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 <si,cx,dx>                      ;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 <si,di>                 ;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 <ax>              ;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 <ax,di,si>                                            ;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     SHORT 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 <si,di>                                                     ;ac048;bgb
	    mov     SI,DI                                                       ;ac048;bgb
;       $else                           ;dir entry was not erased or zero       ;ac048;bgb
	JMP SHORT $$EN38
$$IF38:
NEXTENT:    restorereg <ax>                                                  ;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 <ax,ax>                      ;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     di,[bx.dpb_FAT_size]            ;Sectors for one fat (DCR)      ;AC000;
	xor     ch,ch				; M106 Clear high byte #1594
	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 <ax,bx,cx,dx,si,di>              ;                                           ;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 <di,si,dx,bx,cx,ax>                                                       ;an005;bgb
  return                                                                        ;an005;bgb
EndProc lostdisp                                                                ;an005;bgb
ENDIF


	pathlabl chkfat


CODE    ENDS
	END
