/*static char *SCCSID = "@(#)clrbit.c	6.4 92/01/31";*/
#define ASWAP0 ASWAP0

#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "superb.h"
#include "pb_ifs.h"
#include "pbmacros.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"

#include "pr_BITMP.h"
#include "pr_CACHE.h"
#include "pr_MISC.h"
#include "pr_DEBUG.h"


/*
 ***	ClrBit - Clear bits from a bit map
 *
 *	ClrBit is called to clear bits from the filesys bit map to
 *	show that the sectors are busy.  ClrBit should be called
 *	right after the bits are allocated before any blocks have been
 *	done, since CBBM assumes that they're set and doesn't check.
 *
 *    >>  Note that the bits must fit within one ballocation band.  <<
 *
 *	This will always be the case since we always call CBR or VBR
 *	before ClrBit and CBR and VBR will always stay within 1 band.
 *
 *	Also note that if we get a hard error we'll wipe the bits for
 *	the sectors in error.  When we have DEBUG enabled we may trap
 *	if we try to claim those bits.  This should be rare since the
 *	finding routine just caused the bitmap to be read successfully
 *	and it's probably still in the cache.  The production code
 *	won't check for the bits being already zero and won't fault.
 *
 *	ENTRY	lsnFirstToClr = number of first bit/sector to claim
 *		culBitsToClr = # of bits to clear
 *		fFile = Set if we are clearing bits (i.e. allocating
 *			disk space) for the current file (i.e the one
 *			whose flDMask is in the global FRAME).
 *	EXIT
 *		  FALSE if error
 *		Yields CPU
 *
 *	HISTORY
 *	    28-Oct-1988 by Leif Pederson [leifp] resynch to 10-25
 *	    29-Sep-1988 17:06:54 by Jon Parati [jonpa]	Added Banding
 *
 *	NOTE
 *	    ClrBit MUST subtract the bitcount to clear (culBitsToClr) from
 *	    pfrm->pvol->csecSpace BEFORE does anything that may block.
 */

BOOL
ClrBit (lsnFirstToClr, culBitsToClr, fFile, pfrm)
LSN lsnFirstToClr;	/* first bit to clear */
ULONG culBitsToClr;	/* Number of bits to clear */
BOOL fFile;
PFRAME pfrm;
{
    PBYTE pbWork;
    UINT  ui;
    PBUFNODE pbuf;
    PBANDTAB pbtb;

#ifdef DEBUG
    if (lsnFirstToClr >= pfrm->pvol->cSectsOnVol )
	INTERR( __FILE__": starting sector not on volume" );

    if (lsnFirstToClr + culBitsToClr > pfrm->pvol->cSectsOnVol )
	INTERR( __FILE__": ending sector not on volume" );

    if( (lsnFirstToClr % BANDSIZE) + culBitsToClr > BANDSIZE ) {
	INTERR( __FILE__": Trying to clear across band boundary" );
    }

#endif

                                                          //#101488 start
    lsnFirstToClr &= SECMASK; /* zero out volume bits */

    if ( (lsnFirstToClr >= pfrm->pvol->cSectsOnVol) ||
         (lsnFirstToClr + culBitsToClr > pfrm->pvol->cSectsOnVol) ||
         ((lsnFirstToClr % BANDSIZE) + culBitsToClr > BANDSIZE) ||
         ((lsnFirstToClr <= SEC_SPAREB) &&
          (lsnFirstToClr + culBitsToClr >= SEC_SUPERB)) ) {
      return (FALSE);
    }
                                                          //#101488 end

    /* Get the correct band */
    pbtb = pfrm->pvol->apbndList [USSHIFTRUL (lsnFirstToClr, BANDSHIFT)];

    /* Indicate less free sectors */
    pfrm->pvol->csecSpace -= culBitsToClr;

    if (pbtb->csecFree > (USHORT)culBitsToClr)
   	pbtb->csecFree -= (USHORT)culBitsToClr;
    else
	   pbtb->csecFree = 0;

    /*
     * Read in the bitmap and mark it dirty
     */

    /* get first bit in this band */
    lsnFirstToClr %= BANDSIZE;

    /* DEBUG - This is a good place for statistical stuff */
                                                               //#85759
	 if ((pbWork = LSDBM(&pbtb->scpMap, BP_KEEP, &pbuf, pfrm)) == NULL) {
	/* Reset number of free sectors */
      pfrm->pvol->csecSpace += culBitsToClr;
	   pbtb->csecFree += (USHORT)culBitsToClr;
      return (FALSE);
    }

    pbWork = &pbWork[(USHORT)lsnFirstToClr / 8];

    /*
     * If we are clearing less than 1 byte then, do it now
     * note we want to cast the lsn to a UINT BEFORE doing the %
     * since the result is the same and UINT % is much faster than ULONG %
     */

    if( (ui = ((UINT)lsnFirstToClr) % 8) + (UINT)culBitsToClr < 9 ) {
	*pbWork &= (abFillMask[ui] | ~abFillMask[ui + (UINT)culBitsToClr]);
    }
    else {

	/* Clear bits in the first byte */
	*pbWork &= abFillMask[ui];

	/* Clear all the middle bytes */
	memset( ++pbWork, 0, (ui = ((UINT)culBitsToClr - (8 - ui))/ 8) );
	pbWork += ui;

	/* Clear the leftover bits in the last byte */
	ui = ((UINT)lsnFirstToClr + (UINT)culBitsToClr) % 8;
	if( ui != 0 ) {
	    *pbWork &= ~abFillMask[ui];
	}
    }

    pbuf->bDirtMask = SPBBITS;

    if (fFile)
	   pbuf->flDMask |= pfrm->flDMask;

	 AddLW(pbuf,pfrm);

    return (TRUE);
}
