/*static char *SCCSID = "@(#)cps.c	6.6 92/02/12";*/
#define INCL_DOSERRORS
#include <os2.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 "assert.h"
#include "frame.h"
#include "lw.h"
#include "fsdata.h"
#include "pbmsg.h"
#include "pbmacros.h"
#include "pr_cache.h"
#include "pr_debug.h"
#include "pr_read.h"
#include "pr_misc.h"



/***	CPS - Compute Physical Sector
 *
 *	CPS computes a physical sector number given an OFT
 *	pointer and a file seek position.
 *
 *	Note that CPS takes a seek pointer in bytes, but
 *	it returns values in sectors.  If the seek pointer
 *	is not sector aligned then the partial first sector
 *	is included in the count.
 *
 *	ENTRY	ulSeekPtr (edx) = seek pointer (bytes)
 *		poft (edi) = OFT address
 *
 *	EXIT	returns physical sector number
 *		*pulContig = number of contiguous sectors AFTER physical sector
 *		*pulRunLen = total number of sectors in the run
 *		*pulPhysStartRun = physical sector start of total run
 *
 *	EXIT	(eax) = physical sector number
 *		(ecx) = number of contiguous sectors at (eax)
 *		Yields CPU
 *
 *	defined in pr_read.h
 */


/***	CPS_ - Compute Physical Sector
 *
 *	CPS_ computes a physical sector number given an ALBLK
 *	pointer and a file seek position.
 *
 *	Note that CPS takes a seek pointer in bytes, but
 *	it returns values in sectors.  If the seek pointer
 *	is not sector aligned then the partial first sector
 *	is included in the count.
 *
 *	ENTRY	ulSeekPtr (edx) = seek pointer (bytes)
 *		palb (edi) = ALBLK address
 *
 *	EXIT	returns physical sector number
 *		*pulContig = number of contiguous sectors AFTER physical sector
 *		*pulRunLen = total number of sectors in the run
 *		*plsnPhysStartRun = physical sector start of total run
 *
 *	EXIT	(eax) = physical sector number
 *		(ecx) = number of contiguous sectors at (eax)
 *		Yields CPU
 *
 *	HISTORY
 *	    05-Oct-1988 10:13 by Bill McJohn [t-billm]
 *				translated from 10/4/88 assembly code
 */

ULONG
CPS_ (ulSeekPtr, palb, pulContig, pulRunLen, plsnPhysStartRun, fDASDOpen, pfrm)
ULONG ulSeekPtr;
ALBLK far *palb;
PULONG pulContig;
PULONG pulRunLen;
PLSN plsnPhysStartRun;
BOOL fDASDOpen;
PFRAME pfrm;
{
	PALSEC palsCur; /*  Used to traverse allocation tree	*/
	LSN lsnFile;	/*  File Logical Sector Number		*/
	LSN lsnDiff;
	USHORT i;	/*  Generic index variable		*/

	ASSERT_ALB (palb);

	lsnFile = ulSeekPtr / SECSIZE;

	if ( !(palb->bFlag & ABF_NODE) ){

	    ALLEAF far *pall;	/*  temp pointer to current leaf	*/

	    /*
	     *	All of the extents fit in the root node, so we'll
	     *	just scan it.  We scan forward until we find the
	     *	last leaf whose logical sector number is less than
	     *	or equal to lsnFile.
	     */
	    if (palb->cUsed == 0) {
//		INTERR (PBMSG_CPS_ALBLK_EMPTY);
         SETHARDERR (MSG_HPFS_FNODE_ERROR_WARN);   //#86865
		   return (LSN_BOGUS);
	    }

	    pall = PALLFROMPALB (palb);

	    for (i = 0; i < palb->cUsed; i++) {
		if (pall->lsnLog <= lsnFile) {

		    if (lsnFile < pall->lsnLog + pall->csecRun) {
			break;
		    }
		} else {
//		    INTERR (PBMSG_CPS_SPARSE_ALLOC);
         SETHARDERR (MSG_HPFS_FNODE_ERROR_WARN);   //#86865
		   return (LSN_BOGUS);
		}
		pall++;
	    }

	    /*	Now we've found the allocation leaf we want.
	     *	If the run is insufficient to reach lsnFile,
	     *	we have an error.
	     */
#ifdef DEBUG
	    if (lsnFile < pall->lsnLog) {
		dprintf ("CPS: lsnFile (0x%lx) < pall[%d]->lsnLog (0x%lx)\n",
			 lsnFile, i, pall->lsnLog);
	    }
#endif
	    if ( (pall->csecRun < (lsnDiff = (lsnFile - pall->lsnLog))) ||
	         (!fDASDOpen && (pall->lsnPhys <= SEC_SPAREB)) ) {  //#101488
//		INTERR (PBMSG_CPS_EXTENTNOTOFOUND);
         SETHARDERR (MSG_HPFS_FNODE_ERROR_WARN);   //#86865
		   return (LSN_BOGUS);
	    }

	    /*	Set up the return values.  The remaining run length
	     *	and starting physical sector taken from the allocation
	     *	leaf are adjusted by the offset from the first logical
	     *	file sector in the run to lsnFile, the logical file
	     *	sector of the seek pointer.
	     *
	     */
	    *pulContig = pall->csecRun - lsnDiff;

	    if (pulRunLen != NULL) {
	       *pulRunLen = pall->csecRun;
	       *plsnPhysStartRun = pall->lsnPhys;
	    }

	    return ( pall->lsnPhys + lsnDiff );
	}
	else {

	    ALNODE far *paln;
	    PBUFNODE pbuf;	/*  Dummy to satisfy RdBuf		*/
	    PALLEAF palf;

	    /*	The ALBLK info is a node table - the root
	     *	of a B+TREE. Traverse the tree to find our guy.
	     *
	     *	BUGBUG - gotta use hints for previous block, not
	     *	rdbuf all the way down each time!
	     *
	     *	Find the correct node in the ALBLK list and
	     *	follow it down to the first ALSEC...
	     *
	     */
	    paln = PALNFROMPALB (palb);
	    while ( lsnFile >= paln->lsnLog ) {
		paln++;
	    }

	    /*	We've found the correct node;  read its child.  */
	    palsCur = RdBuf(paln->lsnPhys,BP_KEEP,&pbuf,pfrm);

	    if (palsCur == NULL) {
#ifdef DEBUG
		dprintf ("CPS: palsCur is NULL, returning LSN_BOGUS\n");
#endif
         SETHARDERR (ERROR_READ_FAULT);   //#85759
		   return (LSN_BOGUS);
	    }

#ifndef MINIFSD
       if (pbuf->fFlag & BFL_LZREAD) {
         if (LazyRead (pbuf, pfrm))
		     return (LSN_BOGUS);
       }
#endif

	    ASSERT_ALS (palsCur);

	    while ( palsCur->alb.bFlag & ABF_NODE ) {

		i = 0;
		while ( lsnFile >= palsCur->a.aaln[ i ].lsnLog ) {
		    i++;
		}

		/*  We've found the correct node;  move down another
		 *  level in the allocation tree.
		 *
		 */
		palsCur = RdBuf (palsCur->a.aaln[ i ].lsnPhys,
				 BP_KEEP,
				 &pbuf,pfrm);

		if (palsCur == NULL) {

		    /* BUGBUG: what do I do now? */
#ifdef DEBUG
		    dprintf ("CPS: palsCur is NULL, i=%d\n", i);
		    Int3 ();
#endif

          SETHARDERR (ERROR_READ_FAULT);  //#85759
		    return (LSN_BOGUS);
		}

#ifndef MINIFSD
      if (pbuf->fFlag & BFL_LZREAD) {
        if (LazyRead (pbuf, pfrm))
		    return (LSN_BOGUS);
      }
#endif

		ASSERT_ALS (palsCur);         //#85759
	    }

	    /*	OK, we've made it down to a leaf block.  Search
	     *	it for the leaf which contains lsnFile.
	     *
	     */
	    if (palsCur->alb.cUsed == 0) {
//		INTERR (PBMSG_CPS_ALBLK_EMPTY);
         SETHARDERR (MSG_HPFS_FNODE_ERROR_WARN);   //#86865
		   return (LSN_BOGUS);
	    }

	    i = 0;
	    while ( (i < palsCur->alb.cUsed - 1) &&
		    (palsCur->a.aall [i+1].lsnLog <= lsnFile) ) {
		  i++;
	    }

	    /*	Now we've found the allocation leaf we want.
	     *	If the run is insufficient to reach lsnFile,
	     *	we have an error.
	     */
	    palf = &(palsCur->a.aall [i]);
	    if ( (palf->csecRun <= (lsnDiff = (lsnFile - palf->lsnLog))) ||
	         (!fDASDOpen && (palf->lsnPhys <= SEC_SPAREB)) ) {  //#101488

//		INTERR (PBMSG_CPS_EXTENTNOTOFOUND2);
         SETHARDERR (MSG_HPFS_FNODE_ERROR_WARN);   //#86865
		   return (LSN_BOGUS);
	    }

	    /*	Set up the return values.  The remaining run length
	     *	and starting physical sector taken from the allocation
	     *	leaf are adjusted by the offset from the first logical
	     *	file sector in the run to lsnFile, the logical file
	     *	sector of the seek pointer.
	     *
	     */
	    if (palf->csecRun <= lsnDiff) {

		   SETHARDERR (ERROR_BAD_ENVIRONMENT);
		   return (LSN_BOGUS);
	    }
	    *pulContig = palf->csecRun - lsnDiff;

	    if (pulRunLen != NULL) {
	       *pulRunLen = palf->csecRun;
	       *plsnPhysStartRun = palf->lsnPhys;
	    }

	    return ( palf->lsnPhys + lsnDiff );
	}
}
