/***************************************************************************\
*
*  FSREAD.C
*
*  Copyright (C) Microsoft Corporation 1990.
*  All Rights reserved.
*
*****************************************************************************
*
*  Program Description: File System Manager functions for read and seek
*
*****************************************************************************
*
*  Revision History: Created 03/12/90 by JohnSc
*
*
*****************************************************************************
*
*  Known Bugs: None
*
\***************************************************************************/

#include  "help.h"
#include  "inc\fspriv.h"

#pragma hdrstop

/***************************************************************************\
*
* Function: 	FPlungeQfshr( qfshr )
*
* Purpose:		Get back a qfshr->fid that was flushed
*
* ASSUMES
*
*	args IN:	qfshr - fid need not be valid
*
* PROMISES
*
*	returns:	fTruth of success
*
*	args OUT:	qfshr->fid is valid (or we return FALSE)
*
*	globals OUT: rcFSError
*
\***************************************************************************/

BOOL STDCALL FPlungeQfshr(QFSHR qfshr)
{
	if (qfshr->fid == HFILE_ERROR) {
		qfshr->fid = FidOpenFm((qfshr->fm), (WORD)
			(qfshr->fsh.bFlags & fFSOpenReadOnly ? OF_READ : OF_READWRITE));
		if (qfshr->fid == HFILE_ERROR) {
			SetFSErrorRc(RcGetIOError());
			return FALSE;
		}

		/*
		 * Check size of file, then reset file pointer. Certain 0-length
		 * files (eg con) give us no end of grief if we try to read from them,
		 * and since a 0-length file could not possibly be a valid FS, we
		 * reject the notion.
		 */

		if (_llseek(qfshr->fid, 0, FILE_END) < sizeof(FSH)) {
			SetFSErrorRc(rcInvalid);
			return FALSE;
		}
		else
			_llseek(qfshr->fid, 0, FILE_BEGIN);
	}

	SetFSErrorRc(rcSuccess);
	return TRUE;
}

/***************************************************************************\
*
* Function: 	LcbReadHf()
*
* Purpose:		read bytes from a file in a file system
*
* ASSUMES
*
*	args IN:	hf	- file
*				lcb - number of bytes to read
*
* PROMISES
*
*	returns:	number of bytes actually read; -1 on error
*
*	args OUT:	qb	- data read from file goes here (must be big enough)
*
* Notes:		These are signed longs we're dealing with.  This means
*				behaviour is different from read() when < 0.
*
\***************************************************************************/

LONG STDCALL LcbReadHf(HF hf, LPVOID qb, LONG lcb)
{
	QRWFO	  qrwfo;
	LONG	  lcbTotalRead;
	FID 	  fid;
	LONG	  lifOffset;

	ASSERT(hf != NULL);
	qrwfo = PtrFromGh(hf);

	SetFSErrorRc(rcSuccess);

	if (lcb < 0) {
	  SetFSErrorRc(rcBadArg);
	  return (LONG) -1;
	}

	if (qrwfo->lifCurrent + lcb > qrwfo->lcbFile) {
	  lcb = qrwfo->lcbFile - qrwfo->lifCurrent;
	  if (lcb <= (LONG) 0) {
		return (LONG) 0;
	  }
	}

	// position file pointer for read

	if (qrwfo->bFlags & fFSDirty) {
	  fid = qrwfo->fidT;
	  lifOffset = (LONG) 0;
	}
	else {
	  QFSHR qfshr = PtrFromGh(qrwfo->hfs);

	  if (!FPlungeQfshr(qfshr)) {
		return (LONG) -1;
	  }

	  fid = qfshr->fid;
	  lifOffset = qrwfo->lifBase;
	}
#ifdef _X86_
	if (LSeekFid(fid, lifOffset + sizeof(FH) + qrwfo->lifCurrent, SEEK_SET)
		  !=
		 lifOffset + (LONG) sizeof(FH) + qrwfo->lifCurrent) {
	  if (RcGetIOError() == rcSuccess)
		SetFSErrorRc(rcInvalid);
	  else
		SetFSErrorRc(RcGetIOError());
	  return (LONG) -1;
	}
#else
    { LONG lcbSizeofFH;
    lcbSizeofFH = LcbStructSizeSDFF( ISdffFileIdHfs( qrwfo->hfs ), SE_FH);

	if (LSeekFid(fid, lifOffset + lcbSizeofFH + qrwfo->lifCurrent, SEEK_SET)
		  !=
		 lifOffset + (LONG) lcbSizeofFH + qrwfo->lifCurrent) {
	  if (RcGetIOError() == rcSuccess)
		SetFSErrorRc(rcInvalid);
	  else
		SetFSErrorRc(RcGetIOError());
	  return (LONG) -1;
	}
    }
#endif

	// read the data

	lcbTotalRead = LcbReadFid(fid, qb, lcb);
	SetFSErrorRc(RcGetIOError());

	// update file pointer

	if (lcbTotalRead >= 0)
	  qrwfo->lifCurrent += lcbTotalRead;

	return lcbTotalRead;
}

/***************************************************************************\
*
* Function: 	LSeekHf( hf, lOffset, wOrigin )
*
* Purpose:		set current file pointer
*
* ASSUMES
*
*	args IN:	hf		- file
*				lOffset - offset from origin
*				wOrigin - origin (SEEK_SET, SEEK_CUR, or SEEK_END)
*
* PROMISES
*
*	returns:	new position offset in bytes from beginning of file
*				if successful, or -1L if not
*
*	state OUT:	File pointer is set to new position unless error occurs,
*				in which case it stays where it was.
*
\***************************************************************************/

LONG STDCALL LSeekHf(HF hf, LONG lOffset, WORD wOrigin)
{
	QRWFO qrwfo;
	LONG  lif;

	ASSERT(hf != NULL);
	qrwfo = PtrFromGh(hf);

	switch (wOrigin) {
	  case wFSSeekSet:
		lif = lOffset;
		break;

	  case wFSSeekCur:
		lif = qrwfo->lifCurrent + lOffset;
		break;

	  case wFSSeekEnd:
		lif = qrwfo->lcbFile + lOffset;
		break;

	  default:
		lif = (LONG)-1;
		break;

	}

	if (lif >= 0) {
	  qrwfo->lifCurrent = lif;
	  SetFSErrorRc(rcSuccess);
	}
	else {
	  lif = (LONG) -1;
	  SetFSErrorRc(rcInvalid);
	}

	return lif;
}

/* EOF */