/*static char *SCCSID = "@(#)afb.c	6.5 92/01/31";*/
#define ASWAP0 ASWAP0
#define INCL_DOSINFOSEG
#include <os2.h>
#include "chain.h"
#include "const.h"
#include "misc.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "pbmacros.h"
#include "pb_ifs.h"
#include "superb.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "pr_ALLOC.h"
#include "pr_BITMP.h"
#include "pr_CACHE.h"

/*
 ***	AFB - Allocate FreeSpace Block
 *
 *	AFB allocates a block of free space.  AFB is called when the caller
 *	wants a new block not attached to some specific old one - either
 *	file creation, or when we can't grow an existing extent anymore.
 *
 *	The caller may specify a preferred location; we'll start looking
 *	after that spot first unless the allocation heuristics give a
 *	preference to another spot.
 *
 *	==WARNING== AFB finds the bits, but it does not clear them from
 *		    the map.  The caller must claim his bits before he yields.
 *
 *	ENTRY	culSec = # of sectors wanted (non-zero)
 *		lsnPrefer = sector # of preferred sector
 *	EXIT	Returns
 *		FALSE if space could not be found
 *		TRUE if space located
 *		  *plsnRet = starting sector #
 */

BOOL
AFB (ULONG culSec, LSN lsnPrefer, PLSN plsnRet, PFRAME pfrm)
			/* count of sectors to allocate */
			/* preferred starting sector number */
			/* ptr to starting sector number returned */
{
    PBANDTAB pbtb1;	/* first choice of band */
    PBANDTAB pbtb2;	/* second choice of band */
    PSECTOR psecBM;	/* ptr to bitmap sectors */
    PBUFNODE pbufBM;	/* ptr to bitmap buffer node */
    PBYTE pbHighWater;	/* ptr to high water mark (1st non-zero byte) */
    USHORT cbDryLand;	/* # bytes from high water mark to end of bitmap */
    USHORT obLSN;	/* offset of lsn byte */
    USHORT obitLSN;	/* offset of lsn bit */

    /* get 1st and 2nd choices for bands */

    /*
     * BUGBUG - if we call AFB looking for >= 64K of sectors, then
     * the following cast will be messy,  it will still work, though
     * because the wrong pbtb's will be returned by chooseband, and
     * the 'if' after the 'do' will catch that.
     */
    ChooseBand ((USHORT)culSec, lsnPrefer, pfrm->pvol, &pbtb1, &pbtb2);

    /* OK, we have the most promising bands for this file.  Try
     * to take our initial allocation, contiguously, from these bands.
     */

    do {
	if (culSec <= pbtb1->csecFree)
	{
	    /* there is enough space in this bitmap, so get bitmap */
                                                                 //#85759
	    if ((psecBM = LSDBM(&pbtb1->scpMap, BP_KEEP, &pbufBM, pfrm)) == NULL)
         return FALSE;

	    /*
	     * Scan from preferred lsn to end of bitmap
	     */
	    if (lsnPrefer != 0 &&
		lsnPrefer >= pbtb1->lsnBase &&
		lsnPrefer < pbtb1->lsnBase + (pbtb1->cbMapLen * 8) )
	    {
		/* preferred lsn is in this bitmap */

		obitLSN = (USHORT)(lsnPrefer - pbtb1->lsnBase);

		obLSN = obitLSN / 8;

		if ( SFB ((USHORT)culSec,
			pbtb1->cbMapLen - obLSN,
			(PBYTE) pbufBM->pblkData + obLSN,
			&obitLSN ) )
		{

		    *plsnRet = pbtb1->lsnBase + (obLSN * 8) + obitLSN;
		    return TRUE;	/* bitmap block was found */
		}

	    }

	    /*
	     * Update high water offset if it has changed
	     * (there is no free space below the high water mark)
	     */
	    cbDryLand = pbtb1->cbMapLen - pbtb1->ibHighWaterOffset;
	    pbHighWater = (PBYTE)psecBM + pbtb1->ibHighWaterOffset;
	    if ( cbDryLand != 0 && *pbHighWater == 0)
	    {
		while ((cbDryLand != 0) && (*pbHighWater == 0))
		{
			cbDryLand--;
			pbHighWater++;
		}
		pbtb1->ibHighWaterOffset = pbHighWater - (PBYTE)psecBM;
	    }
	    /*
	     * Scan from high water mark to end of bitmap
	     */

	    if (SFB((USHORT)culSec,cbDryLand,pbHighWater,&obitLSN))
	    {
		*plsnRet = pbtb1->lsnBase +
			(pbtb1->ibHighWaterOffset * 8) + obitLSN;

		return TRUE;
	    }
	}

	/*
	 * Get the next choice of bitmap - return if there are no more
	 */
	pbtb1 = pbtb2;
	pbtb2 = NULL;

    } while (pbtb1 != NULL);

    return FALSE;
}
