/*static char *SCCSID = "@(#)map.c	6.1 90/11/18";*/
/*static char *SCCSID = "@(#)map.c 13.3 90/01/30";*/
/***	MAP.C - Routines to manipulate bit maps
 *
 *	RECOVER
 *	Gregory A. Jones
 *	Copyright 1988 Microsoft Corporation
 *
 *	Modification history:
 *	G.A. Jones	07/11/88     Adapted from Pinball CHKDSK.
 *	P.A. Williams	06/26/89     Added include of os2.h
 */

#include "ldefs.h"
#include "ltypes.h"
#include "globals.h"
#include "pr_rec.h"

/***	rec_read_bit_maps - read in the first bit map
 *
 *	This function is called by the main routine to read the
 *	bit map into memory from disk.	It first allocates a huge
 *	array, and then reads the bitmap sectors into that array.
 *	To avoid excess memory usage, only the first bit map is
 *	actually read, and that copy is used to update both copies
 *	of the bit map on disk.
 *
 *	This function also checks each block in the new bad block
 *	list to see if it was re-used by the file system before
 *	the disk was locked.  Any such blocks are edited out of
 *	the list.  If all bad blocks are edited out of the list,
 *	a TRUE value is returned, indicating to the main routine
 *	that it shouldn't bother saving the now-empty bad block list.
 *
 *	rec_read_bit_maps (void)
 *
 *	ENTRY		No parameters
 *
 *	EXIT		Returns TRUE if all bad blocks were re-used
 *			"bitmap" points to memory image of bit map
 *
 *	CALLS		halloc
 *			read_scratch
 *
 *	WARNINGS	Will terminate program if insufficient memory
 *
 *	EFFECTS         Allocates memory
 *			Reads disk
 */
USHORT rec_read_bit_maps (void)
{
  ULONG sect, *p;
  USHORT i, nbitmaps, rc=FALSE;

  nbitmaps = (USHORT)((number_of_sectors - 1L) / (8L * SPB * SECSIZE) + 1);
  if (((bitmap=halloc ((long)nbitmaps, SPB * SECSIZE)) == NULL) ||
      ((p=malloc (SPB * SECSIZE)) == NULL))
    rec_exit_error (INSF_MEM_ERROR);

  read_scratch ((ULONG)SEC_SUPERB, &sb, 1);

  read_scratch (sb.rspBitMapIndBlk.lsnMain, p, SPB);
  for (i=0; i<nbitmaps; i++)
    read_scratch (p [i], bitmap + ((ULONG)i * SPB * SECSIZE), SPB);
  free (p);

  for (i=0; i < (USHORT)num_bad_sectors; ) {
    sect = bad_list [i];
    if (!(bitmap [sect >> 3] & (1 << (sect & 7)))) {    /* sector already used */
      num_bad_sectors--;			/* we're ignoring one of them */
      memmove (&bad_list [i], &bad_list [i+1],	/* edit it out of the list */
	       (size_t)((num_bad_sectors - i) * sizeof (ULONG)));
    }
    else
      i++;
  }
  return (num_bad_sectors == 0L);
}

/***	rec_update_bit_maps - save bit maps to disk
 *
 *	This function is called after all of the bad sectors found
 *	in a file have been added to the bad block lists and marked
 *	as "in use" in the bit map.  The bit map is saved to the disk,
 *	using the same memory image for both copies to ensure consistency.
 *	The bit map is then deallocated using hfree.
 *
 *	rec_update_bit_maps (void)
 *
 *	ENTRY		"bitmap" points to memory image to save
 *
 *	EXIT		No return value
 *
 *	CALLS		free
 *			hfree
 *			malloc
 *			read_scratch
 *			write_scratch
 *
 *	WARNINGS	None
 *
 *	EFFECTS         Deallocates memory
 */
void rec_update_bit_maps (void)
{
  PULONG p;
  USHORT i, nbitmaps;

/*
 * Go through the list of bad sectors, marking each sector "in use" in
 * the bitmap so the filesystem won't use those sectors again.
 */

  for (p=bad_list; p < bad_list+num_bad_sectors; p++)
    clr_bit (*p);

/*
 * Now go get the bitmap indirect list and write out all the bitmaps.
 */

  nbitmaps = (USHORT)((number_of_sectors - 1L) / (8L * SPB * SECSIZE) + 1);
  if ((p=malloc (SPB * SECSIZE)) == NULL)
    rec_exit_error (INSF_MEM_ERROR);

  read_scratch ((ULONG)SEC_SUPERB, &sb, 1);

  read_scratch (sb.rspBitMapIndBlk.lsnMain, p, SPB);
  for (i=0; i<nbitmaps; i++)
    write_scratch (p [i], bitmap + ((ULONG)i * SPB * SECSIZE), SPB);

#ifdef TWO_MAPS
  read_scratch (sb.rspBitMapIndBlk.lsnSpare, p, SPB);
  for (i=0; i<nbitmaps; i++)
    write_scratch (p [i], bitmap + ((ULONG)i * SPB * SECSIZE), SPB);
#endif

  free (p);
  hfree (bitmap);
}
