/*static char *SCCSID = "@(#)read.c	6.9 92/01/31";*/
#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include <fsh.h>
#include <pvwxport.h>
#include "const.h"
#include "api.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "filemode.h"
#include "tables.h"
#include "assert.h"
#include "pb_ifs.h"
#include "pbmacros.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "log.h"
#include "rahead.h"
#include "pvw.h"
#include "pr_cache.h"
#include "pr_debug.h"
#include "pr_dir.h"
#include "pr_fcn.h"
#include "pr_fssub.h"
#include "pr_misc.h"
#include "pr_read.h"
#include "pr_ra.h"


/*
 ***	READ - Read Data From File
 *
 *	ENTRY	pfht = file handle
 *		pcusBytes = transfer count
 *		culNeeded = total amount needed advisory
 *		ulPosition = seek position
 *		pbTarget = target address
 *
 *	EXIT	Returns 0 if OK
 *		  *pcusBytes = amount read
 *		Returns error code if error
 */

USHORT
Read (PFHT pfht,		/* file handle returned here */
      PUSHORT pcusBytes,	/* transfer count */
      ULONG ulPosition,		/* seek postion */
      PBYTE pbTarget,		/* target address */
      PFRAME pfrm)
{
    POFT    poft = pfht->poft;
    UINT    cusBytes = *pcusBytes;
    USHORT  usRet = NO_ERROR;
    BOOL    fSectorIO = FALSE;

    if ((poft->bSFlag & (OFS_SECTORIO | OFS_ONLYSECIO)) == OFS_ONLYSECIO) {
       /* This handle is valid only with sector I/O, and the application */
       /* has not requested it. Disallow the operation because this means */
       /* the application does not support large volumes */

       return (ERROR_ACCESS_DENIED);
    }

    pfrm->pvol = poft->pVolume;	    /* set pvol for lower level IO */
    pfrm->flDMask = poft->flDMask;  /* set dirt mask to this file */

    /* Check if the OFT is marked corrupted or if drive is bad, and */
    /* punt if it is.                                               */

    if (poft->bCorrupt)
   	return GetHardErr(ERROR_READ_FAULT);

    /*
     * If there are bytes to read (i.e. it is not just a read ahead
     * request) then do it.
     */
    if (cusBytes) {
#ifdef DEBUG
	if ((poft->bSFlag & OFS_DASD) == 0)
	    ASSERT_OFT (poft);
#endif

	if ((poft->bFlag & (OTF_LCK + OTF_PLK)) != 0)
	    HoldOFT (poft,pfrm);

	IncrHoldsOFT (poft);


#ifdef RAHEAD

	/* Read Ahead Test for both normal byte and sector I/O
	 *
	 * For sector I/O:
	 *
	 * Convert cusBytes(which is really cusSectors
	 * in this case) to a count of bytes
	 *
	 * Do common code
	 *
	 * Convert cusBytes back to a count of sectors
	 *
	 * Overflows are not possible while our largest
	 * I/O possible remains 64K
	 */

	if ((poft->bSFlag & OFS_SECTORIO) != 0) {
	   cusBytes *= SECSIZE;
	}

	if (cusBytes >= MIN_READLEN && cusBytes <= MAX_READLEN) {
	    if (!(pfht->bRAFlags & RA_ON)) {
		   if (++pfht->bRAReads >= RA_HI) {
		     pfht->bRAFlags |= RA_ON;
		/*    pfht->ulNextRA = pfht->offSeek; */
		     pfht->ulNextRA = ulPosition;
		     pfht->ulBufRun = 1;
		   }
	    }

//#114986
	    if (cusBytes >= MID_READLEN) {
		   if (!(pfht->bRAFlags & RA_BIG)) {
		     if (++pfht->bRABigReads >= RA_HI)
			    pfht->bRAFlags |= RA_BIG;
		   }
	    }	
	    else {
		  if (pfht->bRAFlags & RA_BIG) {
		    if (--pfht->bRABigReads <= RA_LOW)
            pfht->bRAFlags &= ~RA_BIG;
		  }
	    }

	}
	else {
	    if (pfht->bRAFlags & RA_ON) {
         if (--pfht->bRAReads <= RA_LOW)
		     pfht->bRAFlags &= ~RA_ON;
	    }

	    if (pfht->bRAFlags & RA_BIG) {
	   	if (--pfht->bRABigReads <= RA_LOW)
           pfht->bRAFlags &= ~RA_BIG;
	    }
	}
	if ((poft->bSFlag & OFS_SECTORIO) != 0) {
	   cusBytes /= SECSIZE;
	}
#endif


#ifdef DEBUG
	/*
	 * sanity check for length of valid data verses
	 * length of actual data
	 */
	if( poft->fst.ulVLen > poft->ulFActualLen ) {
	    INTERR( __FILE__": Valid length is greater than Actual len" );
	}
#endif
	/*
	 * If trying to read more bytes than there are in the file...
	 */
	{
	    UINT cbRead = cusBytes;

	    if( ulPosition + cbRead > poft->fst.ulVLen ) {
		/*
		 * since the read goes past the valid data
		 * in the file, chances are it also goes off the
		 * file itself, check for this and fix the
		 * read up if it does.
		 */

   		if( ulPosition + cbRead > poft->ulFActualLen ) {
	   	    cusBytes = (USHORT)(poft->ulFActualLen - ulPosition);
		   }

		/*
		 * Read trying to go past data that was written,
		 * chop it down to only valid data for security
		 * reasons.
		 */

		if( ulPosition >= poft->fst.ulVLen ) {

		   if( ulPosition >= poft->ulFActualLen ) {
			/*
			 * Trying to read past the end of the file,
			 * tell the reader that the bytes are not there
			 */

			UnHoldOFT( poft );
#ifdef DEBUG
			VBS();
#endif
			*pcusBytes = 0;
			return NO_ERROR;
		    }
		    /*
		     * Oh, so he's trying to break security is he?
		     * well, we'll show him!
		     */
		    cbRead = 0;
		    goto readNoRead;

		} else {

		    /*
		     * Read overlaps end of written data, just
		     * let the reader see what they wrote
		     */

		    cbRead = (USHORT)(poft->fst.ulVLen - ulPosition);
		}

	    }

/* read4: */

#ifdef DEBUG
	    if( cbRead == 0 ) {
		INTERR(__FILE__": cbRead == 0, should not have happened!");
		/*
		 * KLUDGE! if user decides to go on after INTERR then
		 * skip over the SDR since it would cause a GP fault
		 */
		goto readNoRead;
	    }
#endif
#ifdef PERFVIEW2
		PVWSTART(Rd,SDR);
#endif
		/*  Perform the synchronous read  */

		if ((poft->bSFlag & OFS_SECTORIO) != 0) {
		   fSectorIO = TRUE;
		}

		usRet = SDR(cbRead,ulPosition,pbTarget,fSectorIO,pfht,pfrm);

#ifdef PERFVIEW2
		PVWSTOP(Rd,SDR);
#endif

		if (usRet != NO_ERROR) {
		  UnHoldOFT (poft);
#ifdef DEBUG
		  VBS();
#endif
        *pcusBytes = 0;
        return GetHardErr(usRet);
      }

readNoRead:
	    /*
	     * now zero out the rest of the buffer
	     */
	   if( cusBytes != cbRead ) {
		UINT erc;

		pbTarget += cbRead;
		cbRead = cusBytes - cbRead;

		MAYBLOCK(
		    erc = FSH_PROBEBUF( PB_OPWRITE, pbTarget, cbRead )
		);

		if( erc != NO_ERROR ) {
		    /* GP Fault! */
		    UnHoldOFT( poft );
#ifdef DEBUG
		    VBS();
#endif
		    return erc;
		}

#ifdef DEBUG
		dprintf( __FILE__": zerofilling %d bytes\n", cbRead );
#endif
		BYTE_FILL( pbTarget, CH_SECURE_FILL, cbRead );
	    }

	} /* end scope cbRead */

    }

    /* keep track that we've done at least one read */
    poft->bMFlag |= OFM_Read;

    /*	Initiate Read Ahead, if requested.	*/
    /* read20: */

    /* offseek is where I expect to start the next read */
    pfht -> offSeek = ulPosition + cusBytes;

    UnHoldOFT( poft );

#ifdef RAHEAD
    if ((pfht->bRAFlags & RA_ON) && !(pfht->bRAFlags & RA_PEND)) {
     if ( (pfht->offSeek >= pfht->ulNextRA) &&
	      /* not already caching the whole file on behalf of another fht */
          (!(pfht->poft->bMFlag & OFM_Cache)) ) {
         QueueReadAhead(pfht,pfrm);
     }
    }
#endif
#if defined(PERFVIEW) && defined(RAHEAD)
	/* Update read ahead flag in frame */
	pfrm->u.fReadAhead = (pfht->bRAFlags & RA_ON);
#endif

#ifdef DEBUG
    VBS ();
#endif
    *pcusBytes = cusBytes;

    return GetHardErr(usRet);
}
