/*static char *SCCSID = "@(#)upddsk.c   6.7 92/02/21";*/
#define ASWAP1 ASWAP1
#define INCL_ERRORS
#include <os2def.h>
#include <bse.h>
#include <fsd.h>

#include "api.h"
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "volume.h"
#include "storage.h"
#include "fnode.h"
#include "tables.h"
#include "pbmacros.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "assert.h"
#include "log.h"
#include "pr_CACHE.h"
#include "pr_DIR.h"
#include "pr_FCN.h"
#include "pr_FSSUB.h"
#include "pr_MISC.h"
#include "pr_debug.h"


/*
 ***    UpdateDisk - Commit File Handle
 *
 *      UpdateDisk is called to update an open file's size and
 *      allocation info on the disk - it's FNODE and DIRENT.  This
 *      is done in response to write-through changes to a file.
 *
 *      UpdateDisk looks at the directory entry first; if there's no
 *      size change then we skip the whole thing (we may have had a random
 *      write-in-place).  Otherwise, we update the directory and then see
 *      if the FNODE needs updating.  Note that if the dirblk is dirty,
 *      we'll go ahead and update the info and write it through, because
 *      it's too much trouble to see if our particular sector was the
 *      dirty one.  (Its not enough that the buffer value be current,
 *      it must be on the disk, which means marked "clean")
 *
 *      This means that the caller must make sure that someone hasn't
 *      updated the directory entry without writing it and the FNODE
 *      through.  No one does this, today, in the file system.
 *
 *      ENTRY   poft = poft for file to update
 *
 *      EXIT    returns TRUE if all went OK
 *              FALSE if hard error happened.
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 *  @58152  11-Jun-1993 DougA - hold dirblk bufnode while blocked
 *          13-Jul-1989 LeifP - optimized to improve write-thru performance.
 *          21-Apr-1989 JonPa - Renamed from Commit and changed param list.
 *          07-Feb-1989 MarkH - Initial code (stolen from Close).
 */

BOOL
UpdateDisk (POFT poft, BOOL fWrtSync, PFRAME pfrm)
{
   PDIRENT     pde;
   PBUFNODE    pbuf;
   PFNODE      pfn;            /* ptr to FNODE */
   BOOL        fNHold;         /* Check to see if hold is needed */
   BYTE        bFlag;

   ASSERT_OFT (poft);

   if (poft->bCorrupt != 0) {
       goto comit990;
   }

   if ((pde = RDE (poft, &pbuf, pfrm)) == NULL) {
comit45:
       poft->bCorrupt = 1;         /* mark the file no good. */
       return OFTCorrupt(poft,pfrm);    /* mark OFT as corrupt */
   }

   if (poft->bFlag & OTF_LCK) {

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

   } else {

    /*
     * Hold the OFT to make sure no-one is changing it
     */
    IncrHoldsBUF(pbuf); /* Hold pbuf in case HoldOFT blocks. @58152  @76193 */
    HoldOFT( poft,pfrm );
    IncrHoldsOFT( poft );
    fNHold = TRUE;
    DecrHoldsBUF(pbuf); /* @58152  @76193 */
   }

                                                           //#110457
   bFlag = poft->bMFlag; /* keep local copy of OFT MFlags */

    /*
     * If the dirent is dirty or if the file's len has changed then
     * write out the dirent
     */

        /*  If someone read file, update LastAccess time in DirEnt */
   if (bFlag & OFM_Read) {
      if (!(bFlag & OFM_FInfo_Lev1)) {
         pde->timLastAccess = timNow ();
      }
   }

   /*  If someone wrote file, update LastMod time in DirEnt */

   if (bFlag & OFM_Written) {
      /*
       * Update the archive bit since the file
       * was written.
       */
      pde->fAttr |= ATTR_ARCHIVE;

      if (!(bFlag & OFM_FInfo_Lev1)) {
         pde->timLastMod = timNow ();
         pde->timLastAccess = timNow ();
      }
   }

    /* Remember that dates are currently updated */
   poft->bMFlag &= ~(OFM_Read | OFM_Written | OFM_FInfo_Lev1);

    /*
     * If the directory block is dirty or if the file's len has changed or
     * if the file has been referenced then write out the directory
     * entry
     */

   if ((bFlag & (OFM_Read | OFM_Written)) ||
       (pde->cchFSize != poft->ulFActualLen) ||
       (pbuf->bDirtMask)) {

     /* update the file size */
        pde->cchFSize = poft->ulFActualLen;

     /* mark the dirent dirty and write to disk */
        SetDEDirt(pde, pbuf, fWrtSync, pfrm);
   }

    /*
     * OK, we had a length change and updated the directory entry.
     * Now see if we need to update the fnode.  We might not, because
     * we allocate space in chunks, so extending the file may not trigger
     * a reallocation.
     */

    /* update the fnode (allocation information) */
    if ((pfn = LSD(&poft->scpFNode, BP_KEEP, &pbuf, pfrm)) == NULL) {
      DecrHoldsSBD (poft->psbdDir);
      if (poft->psbdDir->bFlags & SDF_PND) {
        ChkHoldDir (poft->psbdDir);
      }
      goto comit45;               /* hard error */
    }

    ASSERT_FN (pfn);

    /*
     * Check to see if the filestorage in the OFT is different
     * from the filestorage in the fnode.  If so we need to update
     * the fnode on the disk.  Remember, memcmp returns 0 if
     * they compare.
     */
    if (memcmp (&(pfn->fst), &(poft->fst), sizeof (FILESTORAGE)) != 0) {

        /* Copy filestorage structure from OFT to FNODE */
        pfn->fst = poft->fst;

        SetDirt(pfn, pbuf, fWrtSync, pfrm);
    }

                                                           //end #110457

    DecrHoldsSBD (poft->psbdDir);
    if (poft->psbdDir->bFlags & SDF_PND) {
        ChkHoldDir (poft->psbdDir);
    }

    if (fNHold) {   /* If we held the oft at the top, let it go */

       /* release the OFT */
       UnHoldOFT( poft );
    }

    return (GetHardErr (NO_ERROR) == NO_ERROR ? TRUE : FALSE );

comit990:
#ifdef DEBUG
    dprintf (__FILE__": hard error at comit990\n");
    Int3();
#endif
    return (FALSE);
}
