/*static char *SCCSID = "@(#)freedat.c	6.3 92/01/31";*/
#define _BTXT _BTXT
#include <os2def.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "fnode.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 "pbmsg.h"
#include "log.h"

#include "assert.h"

#include "pr_ALLOC.h"
#include "pr_BITMP.h"
#include "pr_CACHE.h"
#include "pr_MISC.h"
#include "pr_debug.h"
#include "pr_fssub.h"

/*
 ***	FreeDat - Free File Data Sectors
 *
 *	FreeDat is called to free a file's data sectors.
 *	FreeDat may leave as much as GROWDELT sectors of the first
 *	extent allocated, as a performance optimization.
 *
 *	FreeDat frees the sectors and updates the OFT and FNODE.
 *	It does not update the directory entry, nor does it mark the
 *	FNODE dirty in the buffer cache, nor does it write it.
 *
 *	FreeDat may block, so the FNODE needs to be locked since it may
 *	be inconsistant.	BUGBUG - do this lock
 *
 *	Note that it's OK that we don't flush the edited bit map
 *	to the disk, nor do we write through the deleted indirect blocks,
 *	even if so requested.  The disk repair utility will handle all of
 *	that, in the case of a crash, so long as the directory and fnode
 *	info *is* written through, which our caller will do if appropriate.
 *
 *	ENTRY	poft = OFT address
 *		ulSave = number of bytes to leave in file,
 *			 MUST BE < CURRENT SIZE OF FILE!!!
 *
 *	EXIT	Returns FALSE if error
 *		Returns TRUE if OK
 *
 *	HISTORY
 *	    19-Sep-89 by JR (John Rogers, JohnRo@Microsoft)
 *		- Avoid warnings from Microsoft C 5.2 (on slash-slash comments).
 *	    16-May-1989 by John Rogers [JohnRo@Microsoft]
 *		- Changed names of rounding macros in <pbmacros.h>.
 *		- PTR B783576: prevent overflow.
 *		- Minor #include changes per Leif Pederson.
 *	    25-Oct-1988 10:01:40 by Mark Hitch [markh] - updated to 10/19 version
 *
 *	NOTE:	Since we call TFA instead of DelAlloc, we have to do things a
 *		little differently to get rid of the allocation tree or
 *		multiple extents.
 */

BOOL
FreeDat (poft, cbSave, pfrm )
POFT poft;	/* pointer to the oft struct */
ULONG cbSave;	/* number of bytes to leave in the file */
PFRAME pfrm;
{
	ULONG  ulSave;	    /*	Number of sectors to retain  */
	BOOL   fWeLocked;   /*	Remember whether FreeDat locked to OFT	*/

	ASSERT_OFT (poft);

	if( poft->bFlag & OTF_LCK ) {

	    /*
	     *	The caller already has the OFT locked.
	     */
	    fWeLocked = FALSE;

	} else {

	    /*
	     *	We only have the OFT held, so we need to
	     *	release our hold and lock it instead.
	     */
	    fWeLocked = TRUE;
	    DecrHoldsOFT (poft);
	    if ( poft->bFlag & OTF_PND ) {
		ChkHoldOFT ( poft );
	    }
	    LockOFT( poft,pfrm );
	    SetLockOFT(poft);
	}

	if( cbSave == 0 ) {

	    /*
	     * If the file is to be totally deleted, try to save
	     * the lesser of GROWDELT sectors or the present allocated
	     * size of the file.
	     */
	    ulSave = MIN( (ULONG)GROWDELT,
			  ( poft->ulFAllocLen / (ULONG)SECSIZE ) );


	    /*
	     *	If the allocation is a leaf, only save the first run.
	     *	If it's a tree, we'll go ahead and save ulSave sectors.
	     */

	    if ((poft->fst.alb.bFlag & ABF_NODE) == 0) {

		if (poft->fst.alb.cUsed >= 1)
		    ulSave =  MIN( poft->fst.a.aall[0].csecRun, GROWDELT );

	    } else {

		/*
		 *  It's a tree--leave ulSave alone.
		 *  Should we just throw the tree away
		 *  (i.e. set ulSave to zero)?
		 */
	    }

	} else {

	    /*
	     * Save enough sectors to hold cbSave.
	     */
	    ulSave = SAFE_ROUND_UP_DIV( cbSave, SECSIZE );
	}

#ifdef DEBUG
	if ( ulSave * SECSIZE > poft->ulFAllocLen ) {

	    dprintf( "freedat.c:  Trying to retain more than we have.\n" );
	    Int3();
	}
#endif

	if( ulSave * SECSIZE < poft->ulFAllocLen ) {

	    if(TFA(&(poft->fst.alb),ulSave,FALSE,pfrm) == TFA_RET_BIT_ERROR)
		INTERR (PBMSG_FREEDAT_TFAERROR);
	}
	/*
	 * We've released all of the space except the part that we wanted
	 * to keep
	 *
	 * The fst structure is all set up.  But we still have some cleanup
	 * to do in the OFT.
	 */

	/* set this to 0 so it will be recomputed */
	poft->lsnLast = 0;

	poft->ulFAllocLen = ulSave * SECSIZE;

/* fred20: */

	if ( fWeLocked ) {

	    /* We've got to convert our lock back to a hold */
	    ClrLockOFT(poft);
	    IncrHoldsOFT (poft);
	    if (poft->cWaits != 0)
		WakeupOFT( poft );
	}

	return (TRUE);
}
