/*static char *SCCSID = "@(#)initfil.c  6.10 92/02/13";*/
#define _BTXT _BTXT
#include <os2def.h>

#include "const.h"
#include "chain.h"
#include "misc.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 "lw.h"
#include "frame.h"
#include "fsdata.h"

#include "assert.h"
#include "log.h"                                                 // @76193

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

/*
 ***    InitFil - Initialize File
 *
 *      Perform the initial allocation for a new file, including
 *      it's FNODE.  Initialize the FNODE.
 *
 *      NOTE that OPEN knows that InitFil will try to allocate INITFIL
 *      sectors to the file and has verified that these many sectors
 *      exist.  If INITFIL changes it's initial allocation OPEN must
 *      be changed, too.  BUGBUG - we don't reserve the sectors,
 *      so we're vulnerable to race conditions.
 *
 *      ENTRY   pdbNewBlk = start of dir block
 *              pdeNewEnt = address of directory entry
 *
 *      EXIT    Returns TRUE if enough room
 *                *pulLen = allocated length of file (bytes)
 *                *plsnFirst = 1st sector preallocated, 0 if none
 *                FNODE is held!
 *              Returns FALSE if error
 *
 *              Yields CPU
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 *          30-Sep-1988 12:47:52 by Jon Parati [jonpa]  Updated to 9/26 ASM
 */

USHORT
InitFil (pdbNewBlk, pdeNewEnt, pulLen, plsnFirst, pfrm)
PDIRBLK pdbNewBlk;              /* pointer to directory block */
PDIRENT pdeNewEnt;              /* pointer to directory entry */
PULONG  pulLen;                 /* allocated length returned to caller */
PLSN    plsnFirst;              /* 1st sector preallocated returned    */
PFRAME  pfrm;
{
BOOL    fFNodeOnly;
PBUFNODE    pbuf;
PFNODE      pfn;
PBUFNODE    pbufNewBlk = BH (pdbNewBlk);
LSN     lsnFNode;

    /*
     * Search for enough free space for the primary allocation
     * near this dirblock
     */

    IncrHoldsBUF(pbufNewBlk);  // @76193

    if( !AFB( *pulLen = PRIMARY_ALLOCATION,
              pdbNewBlk->lsnThisDir & ~(BANDMASK),
              plsnFirst,
              pfrm) ) {

        /*
         * We couldn't find enough sectors for an FNode + (PRIMARY_ALLOCATION -1),
         * so now we just try for any 1 sector on the disk for the FNode.
         */

        if (!AFB (*pulLen = 1, 0L, plsnFirst, pfrm)) {
            /* Isn't enough space for even an FNODE */

          DecrHoldsBUF(pbufNewBlk);  // @76193
          return (FALSE);
        }

        fFNodeOnly = TRUE;
    } else {
        /* Got the space */
        fFNodeOnly = FALSE;
    }

    /*
     * Setup the directory entry and then init the FNODE
     */
                                                  //#85759
    if (!ClrBit( *plsnFirst,*pulLen,TRUE,pfrm)) {
      DecrHoldsBUF(pbufNewBlk);  // @76193
      return NULL;
    }

    lsnFNode = pdeNewEnt->lsnFNode = *plsnFirst;

//#114986
#ifndef MINIFSD

    if ((pfn = InitLzRd (lsnFNode, &pbuf, pfrm)) == NULL)
      pfn = GetInBuf(lsnFNode, (USHORT)*pulLen, BP_KEEP, &pbuf, pfrm);

#else
    pfn = GetInBuf(lsnFNode, (USHORT)*pulLen, BP_KEEP, &pbuf, pfrm);
#endif

    if (pfn == NULL) {    // @78489
      SetBit(lsnFNode, *pulLen, pfrm);
      DecrHoldsBUF(pbufNewBlk);  // @76193
      return NULL;
    }

    /*
     * Hold the fnode; buffer
     * containing FNode gets unheld in open().
     */
    IncrHoldsBUF (pbuf);   // @76193

    DecrHoldsBUF(pbufNewBlk);  // @76193

    /*
     *  Clear all Fields of the FNode
     */
    BYTE_FILL ((PBYTE) pfn, 0, sizeof (FNODE));
    pfn->sig = FNSIGVAL;
    pfn->usACLBase = FIELDOFFSET (FNODE, abFree [0]);

    /* Copy length and first 15 bytes of name from new dirent to the fnode */
    memcpy (pfn->achName,               /* dest */
            &(pdeNewEnt->cchName),      /* source */
            MIN (pdeNewEnt->cchName + sizeof (pdeNewEnt->cchName),
                 FNODENAMELEN));

#ifndef MINIFSD
    if (pbuf->fFlag & BFL_LZREAD)
     /* Correct lazy read map for FNODE */
      memset ((PBYTE)pbuf->pLzRdBitMap +
              ((lsnFNode % SPB)*(SECSIZE/8)), 0x00,
               SECSIZE / 8);
#endif

    if( !fFNodeOnly ) {
        /* set up leaf in fnode to point to allocated file */
        pfn->fst.a.aall[0].csecRun = PRIMARY_ALLOCATION - 1;
        pfn->fst.a.aall[0].lsnPhys = lsnFNode + 1;

        /* covered by Byte_Fill, above
         *
         *  pfn->fst.a.aall[0].lsnLog = 0;
         */

        pfn->fst.alb.cFree = LEAFPERFNODE - 1;
        pfn->fst.alb.cUsed = 1;
        pfn->fst.alb.oFree = sizeof( ALBLK ) + sizeof( ALLEAF );
    } else {
        /* Indicate empty file (no slots used in the leaf) */
        pfn->fst.alb.cFree = LEAFPERFNODE;
        pfn->fst.alb.oFree = sizeof( ALBLK );

        /* covered by Byte_Fill, above
         *
         *  pfn->fst.alb.cUsed = 0;
         */
    }

    /* set the parent fnode field */
#ifdef DEBUG
    if (pfrm == NULL)
        INTERR ("InitFil: pfrm is null");

    if (pfrm->psbd->lsnFNode == 0)
        INTERR (__FILE__": pfrm->psbd->lsnFNode==0\n");
#endif

    pfn->lsnContDir = pfrm->psbd->lsnFNode;

    ASSERT_FN( pfn );

    /* *plsnFirst and *pulLen were filled in by the call to AFB  */
    *pulLen = (*pulLen - 1) << SECSHIFT;
    return  TRUE;
}
