/*static char *SCCSID = "@(#)delea.c    6.2 92/01/31";*/
#define BSWAP0 BSWAP0

#define SLOWSPEED_NO_MEMERR

    /* FASTSPEED_BIGMEM
     *
     * this version could need lots of RAM but is REALLY fast
     * and could conceivably fail on low ram conditions
     * (if it can't FSH_SEGALLOC the mem needed for the EA list)
     */

    /* SLOWSPEED_POSSIBLE_MEMERR
     *
     * this version is slower but is not as likely to cause a
     * FSH_SEGALLOC to happen.  It is more likely to run out of
     * memory, however, than the next algorythm.
     */

    /* SLOWSPEED_NO_MEMERR
     *
     * this version is slower, but can never fail on low memory errors
     * (except for possible out of heap space errors which the other
     * algorythms could also be hit by) but will tend to put
     * lots of buffers on the LSN_BOGUS chain.
     *
     * This algorythm is the most like what we did up to now.
     *
     * Note that since we are only using about 400 bytes out of the
     * cache block, we could concievably get rid of the rest of the
     * functions that call GHS() (such as AAH() and BuildAlBlk()) and
     * use the left over cache block area which would assure that only
     * a disk hard error would cause us to return an error.
     *
     * Note also that implementing the above note would be SUPER EASY
     * and would SPEED UP SetEA as well!
     *
     * BUGBUG - do the optimization later when we have time
     */

#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>

#include "heap.h"
#include "const.h"
#include "misc.h"
#include "storage.h"
#include "fnode.h"
#include "buf.h"
#include "ea.h"
#include "chain.h"
#include "dir.h"
#include "volume.h"
#include "tables.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "pbmacros.h"
#include "log.h"                                                 // @76193

#include "pr_alloc.h"
#include "pr_cache.h"
#include "pr_debug.h"
#include "pr_ea.h"
#include "pr_heap.h"
#include "pr_misc.h"

/*
 ***    DelEA - Delete Extended Attributes from FNode
 *
 *      DelEA is called to delete extended attributes
 *      from the fnode.  The caller guarantees that there are EAs.
 *      The caller must lock or otherwise secure the file.
 *
 *      ENTRY   pfn    (ebx) = pointer to fnode
 *              fAlTree (Z)   = flag indicating that some EAs have their
 *                              data fields stored in allocation trees.
 *                              (otherwise all data is in line)
 *
 *      RETURNS
 *          NO_ERROR                    if no error
 *          ERROR_NOT_ENOUGH_MEMORY     if not enough mem to complete
 *          ERROR_READ_FAULT            if hard error
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 *          08-Mar-1990 by JR (John Rogers, JohnRo@Microsoft)
 *              - PTR B788488: avoid non-async I/O swap deadlock.
 *          23-Feb-1990 by JR (John Rogers, JohnRo@Microsoft)
 *              - PTR B788262: fix FS_DoPageIO probs (e.g. nested swap).
 *          12-May-1989 19:25:26 by Jon Parati [jonpa]
 *                  rewrote to use a 'fancy algorythm that grovels around'
 */


UINT far
DelEA( PFNODE pfn , PFRAME pfrm )
{
    PFEA        pfeaDelLst;
    PAUXHAND    pah;
    UINT        erc;
#ifdef FASTSPEED_BIGMEM
    PBUFNODE    pbufDelLst;
    PFEA        pfeaDelEnd;
    USHORT      cbList;

    if( (cbList = pfn->aiEA.usFNL + (USHORT)pfn->aiEA.sp.cbRun) == 0 ) {
        return NO_ERROR;
    }

    /* get a buffer big enough to hold the entire inline ea list */
    if( (pfeaDelLst = (PFEA)GetBuf(cbList,&pbufDelLst,pfrm)) == NULL ) {
        /* Can't get the buffer so set erc and exit */
        return ERROR_NOT_ENOUGH_MEMORY;
    }

#elif defined( SLOWSPEED_NO_MEMERR )
    PBUFNODE    pbufDelLst;

    /* get a cache block to use as a scratch buffer */
    while( fGFBActive ) {
        GFBWait(pfrm);
    }
    pbufDelLst = GFB(pfrm);
    pbufDelLst->lsnSec = LSN_BOGUS;
    CreateBUF(pbufDelLst);  //@114986
    IncrHoldsBUF( pbufDelLst );  // @76193
    pfeaDelLst = (PFEA)pbufDelLst->pblkData;

#else
#error  You gotta define one of them!
#endif

    /* assume no error */
    erc = NO_ERROR;

    /* set up the auxhand */
    CHECKSWAP(&swapBSWAP0);
    if( (pah = AAH(pfrm)) == NULL ) {
        /* No Mem! */
        erc = ERROR_NOT_ENOUGH_MEMORY;
        goto DEAError;
    }

#ifdef FASTSPEED_BIGMEM
    pah->cbFile = pah->cbRem = cbList;
#else
    /*
     * BUGBUG - would it be better to do this inside the
     *      'if (pfn->aiEA.usFNL != 0) {..}else{..}' code?
     */
    pah->cbFile = pah->cbRem = pfn->aiEA.usFNL + (USHORT)pfn->aiEA.sp.cbRun;
#endif

    if (pfn->aiEA.usFNL != 0) {

        /*
         * Have some EA stuff, and it's in the fnode
         *
         * pfn      = fnode address
         * pfn->ai.cbFNL (ebx) = size of EA stuff
         * pah      = address of AUXHAND structure
         */
        pah->pbDataBuf = ((PBYTE)pfn + pfn->usACLBase + pfn->aiACL.usFNL);

    } else {

        /*
         * Have some EA stuff, and it's in an allocation tree
         */

        CHECKSWAP(&swapBSWAP0);
        pah->palb =
            BuildAlBlk(&(pfn->aiEA.sp), pfn->aiEA.bDat == 0, pfrm);
        pah->cbRem = 0;

    }

#ifdef FASTSPEED_BIGMEM

    /* read the list into memory */
    pfeaDelEnd = pfeaDelLst;
    CHECKSWAP(&swapBSWAP0);
    if( (erc = RdAH(pah, &cbList, &(pah->pbDataBuf),
                    (PBYTE FAR *)&pfeaDelEnd, pfrm )) == NO_ERROR ) {

        /* step through it deleting any FF_BIGD trees */
        CHECKSWAP(&swapBSWAP0);
        DelEAData( pfeaDelLst, pfeaDelEnd, pfrm );
    }
#else /* SLOWSPEED_NO_MEMERR || SLOWSPEED_POSSIBLE_MEMERR */
    /*
     * read each ea into the buffer one by one and
     * delete any big data associated with it
     */
    while( !EndOfEA( pah ) ) {
        USHORT cbEA;

        /* read the next fea into the buffer */
        cbEA = CB_MAX_DISKFEA;
        CHECKSWAP(&swapBSWAP0);
        ReadEA(pah, (PBYTE)pfeaDelLst, &cbEA, pfrm);

        /*
         * If this FEA has an external allocation for its data,
         * than delete that allocation.
         */
        if( (pfeaDelLst->fEA & FF_BIGD) != 0 ) {
            PALBLK  palbTmp;

            CHECKSWAP(&swapBSWAP0);
            palbTmp = BuildAlBlk((PEAAT)FEA_AVALUE( *pfeaDelLst ),
                                  !((pfeaDelLst)->fEA & FF_DAT),pfrm);

            /*
             * Delete the allocation
             *   (This was a DelAlloc originally)
             */
            TFA (palbTmp, 0L, FALSE, pfrm);

            /*  Note that we ignore hard errors from TFA.
             *  They'll orphan disk space, which CHKDSK
             *  will recover.
             */
            RetHeap (palbTmp);
        }

    }
#endif

    /* release the auxhand and it's heap space */
    RelAuxHand( pah );

DEAError:

    /* free the buffer */
#ifdef FASTSPEED_BIGMEM
    RelBuf((PBYTE)pfeaDelLst,pbufDelLst,pfrm);
#elif defined( SLOWSPEED_POSSIBLE_MEMERR )
    RetHeap( pfeaDelLst );
#elif defined( SLOWSPEED_NO_MEMERR )
    /* RetBuf removes HOLD from buffer */
    RetBuf( pbufDelLst );
#endif

    if( erc == NO_ERROR ) {

        /* delete the list itself and return */
        CHECKSWAP(&swapBSWAP0);
        if( !DelAux (&pfn->aiEA, pfn, pfrm) ) {
            erc = ERROR_READ_FAULT;
        }

    }

    return erc;
}
