/*static char *SCCSID = "@(#)mfs_cfpt.c	6.1 90/11/18";*/
/*static char *SCCSID = "@(#)mfs_cfpt.c	13.2 90/01/25";*/
#define INCL_DOSERRORS
#include <os2.h>
#include <fsd.h>
#include <limits.h>

#include "heap.h"
#include "api.h"
#include "filemode.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 "pb_ifs.h"
#include "pbmacros.h"
#include "superb.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "tefti.h"
#include "pr_CACHE.h"
#include "pr_FCN.h"
#include "pr_HEAP.h"
#include "pr_MISC.h"
#include "pr_WRSUB.h"
#include "pr_DEBUG.h"
#include "pr_MFS.h"

/*
 ***	MFS_CHGFILEPTR - seek on a stage 1 file
 *
 *	This function is called to position the seek pointer of the open
 *	file during stage 1 of the boot sequence.  It returns a value of
 *	0 if successful, otherwise an error code.
 *
 *	Entry	offlSeek = signed DWORD to be added to the current file position
 *		type	 = 0 for seek relative to the beginning of the file
 *			   1 for seek relative to the current file pointer
 *			   2 for seek relative to the end of the file
 *
 *	Returns error code (0 for success)
 */

int far pascal
MFS_CHGFILEPTR (offlSeek, type)
ULONG offlSeek;
USHORT type;
{
    POFT    poft;

#ifdef DEBUG
    dprintf ("MFS_CHGFILEPTR (%ld, %d)\n", offlSeek, type);
    Int3();
#endif

    poft = Stage1PFHT->poft;

    switch ( type ) {

    case CFP_RELBEGIN:

	/* Absolute Seek */

	/*
	 * Allow negative seek for 3x Box
	 */
	if (offlSeek < 0) {
	    Stage1PFHT->offSeek = poft->ulFActualLen;
	    break;
	}

	/*
	 * Otherwise, just use the new offset as the seek pointer
	 */
	Stage1PFHT->offSeek = offlSeek;
	break;

    case CFP_RELCUR:

	/*
	 * It's a relative seek.
	 * The offset value is a signed number, so if it's negative
	 * we'll come up with a value which is less than the current
	 * position else we'll declare underflow and call the position
	 * 0.
	 *
	 * If the offset is positive, we'll come up with a value > then
	 * the current position or else we'll declare "off end" and
	 * set the value to the file size.
	 *
	 * All this grief comes up because we can have files > 2^31
	 * bytes long, at least in theory.
	 *
	 * We can't use 'C' or 'O' because we're an amalgam of signed
	 * and unsigned.
	 */

	if (offlSeek >= 0) {

	    /* if there's no overflow problem... */
	    if (ULONG_MAX - (Stage1PFHT->offSeek) >= offlSeek) {
		Stage1PFHT->offSeek += offlSeek;
	    } else {
		/* BUGBUG what should we do here? ( > 32Bit seek!) */
		Stage1PFHT->offSeek = poft->ulFActualLen;
	    }
	    break;
	}

	/* Have a negative offset */
	if ((ULONG) (-offlSeek) > Stage1PFHT->offSeek) {
	    /* Allow negative seek for 3x Box */
	    Stage1PFHT->offSeek = poft->ulFActualLen;
	} else
	    Stage1PFHT->offSeek += offlSeek;

	break;

    case CFP_RELEND:

	/*
	 * Seek is based from the end of the file.
	 * That means that we treat the offset as an unsigned number
	 * and subtract that from the file length
	 */

	/* BUGBUG - should we be checking for > 32 bit seek? */
	if (offlSeek > 0) {
	    Stage1PFHT->offSeek = poft->ulFActualLen + offlSeek;
	    break;
	}

	/* Have a negative offset */
	if ((ULONG) (-offlSeek) > poft->ulFActualLen) {
	    Stage1PFHT->offSeek = poft->ulFActualLen;
	    break;
	}

	Stage1PFHT->offSeek = poft->ulFActualLen + offlSeek;

	break;

    default:
	INTERR ("mfs_chgfileptr: bad mode");

    } /* switch */

    /* make both pointers agree */
    Stage1Pos = Stage1PFHT->offSeek;

    return NO_ERROR;
}
