/*static char *SCCSID = "@(#)assert.c   6.1 90/11/17";*/
/*static char *SCCSID = "@(#)assert.c   13.5 90/02/16";*/

#if defined (LOGGING)
#define ASSERT
#define LOGASSERT
#endif

/*
 *** Assert.c
 *
 * This module contains the code for any debug assert that was too big
 * or too complex to be written as a macro.
 *
 * History:
 *  08-Dec-1988 11:32:41 by Jon Parati [jonpa]  Removed loop from AssertSDB
 *
 */
#include <os2def.h>
#include <strat2.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 "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "fnode.h"
#include "assert.h"
#include "pbmacros.h"
#include "heap.h"
#include "asyncio.h"
#include "log.h"         // @76193
#include "pr_DEBUG.h"
#include "pr_MISC.h"

void far AssertFST (PFILESTORAGE pfst, PVOID pv, BOOL fOFT);
void far CheckForBTP (BOOL fItShould, PDIRENT pde, PDIRBLK pdb, PSZ psz);
void far PrintPtrs (PVOID pvStart, PFILESTORAGE pfst, BOOL fOFT);

// @76193 - Do Assertion if ASSERT defined
#if defined (ASSERT)

void far
AssertALS (psz, usLine, pals)
PSZ psz;
USHORT usLine;
PALSEC pals;
{
#if defined (LOGASSERT)
    LogEvent( psz, usLine, LOP_ASSERT, LOB_ALS, pals, 0 );
#endif

    if (pals == NULL) {
        INTERR("AssertALS: Null pals");
    } else if (pals->sig != ABSIGVAL) {
        INTERR("AssertALS: pals not pointing to alsec");
    }
}

void far
AssertBuf (psz, usLine, pbuf)
PSZ psz;
USHORT usLine;
PBUFNODE pbuf;
{
#if defined (LOGASSERT)
    LogEvent( psz, usLine, LOP_ASSERT, LOB_BUF, pbuf, 0 );
#endif
    if (pbuf->lsnSec != LSN_BOGUS) {

        if ((pbuf->lsnSec & ~SECMASK) == 0) {
                INTERR( "AssertBuf: vol bits of lsn are 0");
        }
        if (VolPtr [IVOLFROMLSN (pbuf->lsnSec)] == NULL) {
            INTERR ("AssertBuf: volbits refer to NULL VolPtr");
        }
        else
            if (VolPtr [IVOLFROMLSN (pbuf->lsnSec)]->cSectsOnVol <=
                (pbuf->lsnSec & SECMASK)) {
                    INTERR ( "AssertBuf: lsn is out of range for volume");
            }
    }
        if (((ULONG) cBufs) * ((ULONG) sizeof (BUFNODE)) > 0x0000ffffU)
                INTERR ( "AssertBuf: array of bufnodes is greater than 0xffff");

        if (!( (pbuf >= abufCache) && (pbuf <= &(abufCache [cBufs - 1]) )))
                INTERR ("pbuf is not a buff hdr");

        (void)psz;
}

void far
CheckForBTP (BOOL fItShould, PDIRENT pde, PDIRBLK pdb, PSZ psz)
{
    if (pde->fFlags & DF_BTP) {
        if (!fItShould) {
            INTERR ("AssertDB: pde has down pointer and shouldn't");
        }
        if (BTP(pde) == pdb->lsnThisDir) {
            INTERR ("AssertDB: pde has down pointer pointing to same pdb");
        }
    } else {
        if (fItShould) {
            INTERR ("AssertDB: pde has no down pointer and should");
        }
    }
}

void far
AssertDB (psz, usLine, pdb)
PSZ psz;
USHORT usLine;
PDIRBLK pdb;
{
    PDIRENT pde;
    BOOL fDownPtrs = FALSE;

#if defined (LOGASSERT)
    LogEvent( psz, usLine, LOP_ASSERT, LOB_DIRBLK, pdb, 0 );
#endif

    if (pdb == NULL) {
        INTERR ("AssertDB: Null pdb");
    } else if (pdb->sig != DBSIGVAL) {
        INTERR ("AssertDB: pdb not pointing to dirblk");
    }

    /*
     * Start at the first entry, go down the list of entries til
     * we get to the end entry.
     */
    pde = (PDIRENT) (&(pdb->bFirst));

    /*
     * If the BTP bit is turned on in the first entry then they must
     * be on for all of the dirents.
     */
    if (pde->fFlags & DF_BTP) {
        fDownPtrs = TRUE;
    }

    AssertDE (psz, 0, pde);

    while (!(pde->fFlags & DF_END)) {
        pde = NEXT_ENTRY (pde);
        AssertDE (psz, 0, pde);

        /*
         * Check to see that all dirents either have or all do
         * not have down pointers.
         */
        CheckForBTP (fDownPtrs, pde, pdb, psz);
    }

    /* pde now points to the end dirent */

    {
        PBYTE pbLast = (PBYTE) pde - 1 + pde->cchThisEntry;
        PBYTE pbDBLast = (PBYTE) pdb + (pdb->offulFirstFree - 1);

        if (pbLast > pbDBLast) {
            INTERR ("AssertDB: pdb inconsistent");
        }
    }
}

void far
AssertDE (psz, usLine, pde)
PSZ psz;
USHORT usLine;
PDIRENT pde;
{
    PBYTE pbDEEnd;
    PBYTE pbLastNameChar;
    PDIRBLK pdb;
    PDIRENT pdeTmp;

#if defined (LOGASSERT)
    if (usLine != 0)                 // Line = 0 means we're helping AssertDB
       LogEvent( psz, usLine, LOP_ASSERT, LOB_DIRENT, pde, 0 );
#endif

    /*  Verify that we have a good pointer to begin with
     */
    if (pde == NULL) {
        INTERR ("AssertDE: Null pde");
    }

    /*  Verify that we are pointing inside some DIRBLK
     */
    pdb = (PDIRBLK) (BH (pde) -> pblkData);
#if DIRBLKS * 2 == SPB * SECSIZE
    if (((PBYTE) pde) - ((PBYTE) pdb) >= DIRBLKS)
        pdb = (PDIRBLK) (((PBYTE) pdb) + DIRBLKS);
#elif DIRBLKS != SPB * SECSIZE
#error ASSERT.C: AssertDE will fail.
#endif

    if (pdb->sig != DBSIGVAL) {
        INTERR ("AssertDE: pdb not pointing to dirblk");
    }

    /*  Verify that this dirent is reachable in the dirblk
     */
    pdeTmp = (PDIRENT) & (pdb->bFirst);
    while (pdeTmp != pde) {
        if ((pdeTmp->fFlags & DF_END) != 0) {
            INTERR ("AssertDE: direntry not found in dirblk");
            }
        pdeTmp = NEXT_ENTRY (pdeTmp);
        }

    /*  Verify that this entry has a valid length
     */
    if (pde->cchThisEntry == 0) {
        INTERR ("AssertDE: pde->cchThisEntry is 0");
    }

    /* get a pointer to the last byte in the dir ent */
    pbDEEnd = (PBYTE) pde - 1 + pde->cchThisEntry;

    /* if the next guy is not quad aligned then error */
    if ((OFFSETOF (pde) & 0x3) != 0) {
        INTERR ("AssertDE: pde not quad aligned");
    }

    /*
     * If the name spills over to the next dirent then error.
     */
    pbLastNameChar = &(pde->bName [pde->cchName - 1]);
    if (OFFSETOF (pbLastNameChar) > OFFSETOF (pbDEEnd)) {
        INTERR ("AssertDE: name extends into next dir ent");
    }

    /*
     * If there is a btree down pointer make sure there is
     * room for it after the end of the name and before
     * the end of the dirent.
     */
    if (pde->fFlags & DF_BTP) {

        /*
         * make sure that there is enough room for the BTP.
         */
        if ((pbDEEnd - pbLastNameChar) < sizeof (LSN)) {
            INTERR("AssertDE: no room for BTP");
        }

        /*
         * Make sure that there is no more than 3 bytes of padding
         * after the name and before the BTP.
         */
        if ((pbDEEnd - pbLastNameChar) > sizeof (LSN) + 3) {
            INTERR ("AssertDE: too many bytes after name");
        }
    }
    else {
        if ((pbDEEnd - pbLastNameChar) > 3) {
            INTERR ("AssertDE: too many bytes after name");
        }
    }
}

void far
AssertDcp (psz, usLine, pdcp)
PSZ psz;
USHORT usLine;
PDOUBLYCHAINEDPTRS pdcp;
{
        USHORT usTraversals, us;
        PDOUBLYCHAINEDPTRS pdcpStart = pdcp;

#if defined (LOGASSERT)
LogEvent( psz, usLine, LOP_ASSERT, LOB_DCP, pdcp, 0 );
#endif

        if (pdcp == NULL) INTERR ("pdcp is null");

        pdcp = pdcp -> pFwd;
        usTraversals = 1;

        while (pdcp != pdcpStart) {

                if (usTraversals++ >= cBufs)
                        INTERR ("too many nodes (>cBufs) in fwd chain");

                pdcp = pdcp -> pFwd;
        }
        us = usTraversals;

        pdcp = pdcpStart -> pBak;

        while (pdcp != pdcpStart) {

                if (usTraversals++ >= cBufs)
                        INTERR ("too many nodes (>cBufs) in bak chain");

                pdcp = pdcp -> pBak;
        }
        if (usTraversals != us) {
                INTERR ("fwd and bak chains not consistant");
        }

        (void)psz;
}

void far
AssertFN (psz, usLine, pv)
PSZ psz;
USHORT usLine;
PVOID pv;
{
        PFNODE pfn = (PFNODE) pv;

#if defined (LOGASSERT)
LogEvent( psz, usLine, LOP_ASSERT, LOB_FNODE, pv, 0 );
#endif

        if (pfn == NULL)
            INTERR ("AssertFN: Null pfn");
        else if (pfn->sig != FNSIGVAL)
            INTERR ("AssertFN: pfn not pointing to fnode");

        /* if the fnode is not for a directory then assert the fst */
//        if (!(pfn->bFlag & FNF_DIR)) {
//            AssertFST (&(pfn->fst), pfn, FALSE);
//        }

        /* for the compiler */
        psz;
}

//@76193 - these Assert functions haven't been tested yet!
//
// /*
//  *** PrintPtrs--prints pointer values
//  */
//
// void far
// PrintPtrs (PVOID pvStart, PFILESTORAGE pfst, BOOL fOFT)
// {
//     fOFT ? dprintf ("poft=") : dprintf ("pfn=");
//     dprintf ("%p, ", pvStart);
//     dprintf ("pfst=%p\n", pfst);
// }
//
//
// void far
// AssertFST (PFILESTORAGE pfst, PVOID pv, BOOL fOFT)
// {
//     BYTE cUsed;
//
//     /* make sure fst is not for directory */
//     if( (pfst->alb.cUsed + pfst->alb.cFree) == 0 ) {
//         /* must be dir fst, ret now */
//         return;
//     }
//
//     /* check that the allocation information looks sane */
//     if (!(pfst->alb.bFlag & ABF_NODE)) {
//
//         LSN lsnNext = 0L;
//         UINT i;
//
//         /* make sure that the count of leaves used is within range */
//         if ((cUsed = pfst->alb.cUsed) > LEAFPERFNODE) {
//             dprintf ("AssertFST: too many leaves, ");
//             PrintPtrs (pv, pfst, fOFT);
//             Int3 ();
//         }
//         if (cUsed + pfst->alb.cFree != LEAFPERFNODE) {
//             dprintf ("AssertFST: cFree+cUsed not == 8, ");
//             PrintPtrs (pv, pfst, fOFT);
//             Int3 ();
//         }
//
//         /* make sure that the File LSNs make sense */
//         for (i = 0; i < cUsed; i++) {
//             if (lsnNext != pfst->a.aall [i].lsnLog) {
//                 dprintf ("AssertFST: bad leaves, ");
//                 PrintPtrs (pv, pfst, fOFT);
//                 Int3 ();
//             }
//             lsnNext += pfst->a.aall [i].csecRun;
//         }
//     } else {
//         /* make sure that the count of nodes used is within range */
//         if ((cUsed = pfst->alb.cUsed) > NODEPERFNODE) {
//             dprintf ("AssertFST: too many leaves, ");
//             PrintPtrs (pv, pfst, fOFT);
//             Int3 ();
//         }
//         if (cUsed + pfst->alb.cFree != NODEPERFNODE) {
//             dprintf ("AssertFST: cFree+cUsed too large, ");
//             PrintPtrs (pv, pfst, fOFT);
//             Int3 ();
//         }
//     }
// }
//
// void far
// AssertOFT (poft)
// POFT poft;
// {
//     if ((INT)poft->cWaits < 0)
//         INTERR ("Waits < 0");
//
//     /* check that the allocation information looks sane */
//     AssertFST (&(poft->fst), poft, TRUE);
//
//     {
//         /* see that the oft is on the chain */
//         POFT poftWalker = (POFT) oftHead.pFwd;
//
//         while (poftWalker != (POFT) &oftHead) {
//             if (poftWalker == poft) {
//                 return;
//             }
//             poftWalker = poftWalker -> dcpOFTList.pFwd;
//         }
//         INTERR ("Bad poft");
//     }
// }
//
// /**     AssertSBD - recursively descend subdir tree looking for psbd
//  */
// void far
// AssertSBD (PSUBDIR psbd)
// {
//
//     if (FF_CHKSBDIR & flFastFile) {
//         USHORT i;
//
//         AssertSBDTree (psbd);
//
//         i = IVOLFROMLSN (psbd->lsnFNode);
//
//         if (i != 0)
//             dprintf ("AssertSDB: Warning! the lsnFNode is actually a vlsn (%lx)\n",
//                     psbd->lsnFNode);
//
//         i = IVOLFROMLSN (psbd->scpTopDirBlkHint.lsn);
//         if (i == 0 ) {
//             dprintf ("AssertSDB: scpTopDBHint does not have vol bits turned on\n");
//             Int3();
//         }
//
//         if (VolPtr [i] != NULL) {
//             if (!fFindSBD (psbd, VolPtr [i]->psbdRoot)) {
//                 dprintf ("AssertSBD: can't find %p\n", psbd);
//                 Int3 ();
//             }
//         }
//         else {
//             dprintf( "AssertSDB: VolPtr[%d] is NULL!", i );
//             Int3();
//         }
//     }
// }
//
// /**     AssertNotSBD - recursively descend subdir tree looking for psbd -
//  *                     should not find it
//  */
// void far
// AssertNotSBD (PSUBDIR psbd)
// {
//     if (FF_CHKSBDIR & flFastFile) {
//         USHORT i;
//
//         i = IVOLFROMLSN (psbd->lsnFNode);
//
//         if (i != 0)
//             dprintf ("AssertSDB: Warning! the lsnFNode is actually a vlsn (%lx)\n",
//                     psbd->lsnFNode);
//
//         i = IVOLFROMLSN (psbd->scpTopDirBlkHint.lsn);
//         if (i == 0 ) {
//             dprintf ("AssertSDB: scpTopDBHint does not have vol bits turned on\n");
//             Int3();
//         }
//
//         if (VolPtr [i] != NULL) {
//             if (fFindSBD (psbd, VolPtr [i]->psbdRoot)) {
//                 dprintf ("AssertNotSBD: psbd=%p was found!\n", psbd);
//                 Int3 ();
//             }
//         }
//         else {
//             dprintf( "AssertNotSDB: VolPtr[%d] is NULL!", i );
//             Int3();
//         }
//
//         /*
//          * If the sbd has a non-null kid pointer, make sure that
//          * if the kid's parent pointer points to us, it too has
//          * been RetHeap'ed.
//          */
//         {   PSUBDIR psbdKid;
//
//             if ((psbdKid = psbd->psbdKids) != NULL) {
//
//                 /* get a pointer to the heap object including it's heap header */
//                 PHEAPOBJ pHeapObjKid = (PHEAPOBJ) &(((PUSHORT) psbdKid) [-1]);
//
//                 if (!ISFREE (pHeapObjKid) &&
//                     (DATALENGTH(pHeapObjKid) == sizeof (SUBDIR)) &&
//                     (psbdKid->psbdParent == psbd)) {
//
//                     dprintf( "AssertNotSDB: psbd=%p, kid not free and points to us\n", psbd);
//                     Int3();
//                 }
//             }
//         }
//
//         /*
//          * Now, make sure that the sbd we are asserting is not really a
//          * subdir is NOT on the LRU chain.
//          */
//
//         {   PSUBDIR psbdRover = sbdLruHead.dcpLru.pFwd;
//
//             while (psbdRover != &sbdLruHead) {
//                 if (psbdRover == psbd) {
//                     dprintf( "AssertNotSDB: psbd=%p on LRU!\n", psbd);
//                     Int3();
//                 }
//
//                 psbdRover = psbdRover->dcpLru.pFwd;
//             }
//         }
//     }
// }
//
//
//
// BOOL far
// fFindSBD (PSUBDIR psbd, PSUBDIR psbdNode)
// {
//     PSUBDIR psbdKid;
//
//     /***************************************\
//      * start of aggressive subdir checking *
//     \***************************************/
//
//     if( SELECTOROF( psbdNode->dcpSib.pBak ) == 0 ) {
//         dprintf("AssertDB(findsbd): Sib.pBak of psbd(%p) has null sel\n",psbd);
//         Int3();
//     }
//
//     if( SELECTOROF( psbdNode->dcpSib.pFwd ) == 0 ) {
//         dprintf("AssertDB(findsbd): Sib.pFwd of psbd(%p) has null sel\n",psbd);
//         Int3();
//     }
//
// #ifdef NEVER
//
//     {
//         PBUFNODE pbufTopDB = psbd->scpTopDirBlkHint.pbufHint;
//
//         if( pbufTopDB->lsnSec == psbd->scpTopDirBlkHint.lsn ) {
//             /*
//              * check to make sure this is a real dirblock
//              */
//             AssertDB( "AssertSBD(ffindsbd)", (PDIRBLK)pbufTopDB->pblkData );
//         }
//     }
// #endif
//
//
//
//     /***************************************\
//      * end of aggressive subdir checking   *
//     \***************************************/
//
//
//     if (psbd == psbdNode)
//         return TRUE;
//
//     psbdKid = psbdNode->psbdKids;
//     if (psbdKid != NULL) {
//         do {
//             /* begin aggressive */
//             if( psbdKid->psbdParent != psbdNode ) {
//                 dprintf(
//                 "AssertSBD(ffindsbd): kid(%p) does not point to parent(%p)\n",
//                         psbdKid, psbdNode
//                 );
//                 Int3();
//             }
//             /* end of aggessive */
//
//             if (fFindSBD (psbd, psbdKid))
//                 return TRUE;
//             psbdKid = psbdKid->dcpSib.pFwd;
//         } while (psbdKid != psbdNode->psbdKids);
//     }
//     return FALSE;
// }
//
// /**     AssertSBDTree - recursively descend entire subdir tree checking each
//  *      subdir for bad pointers
//  */
// void far
// AssertSBDTree (PSUBDIR psbd)
// {
//     if (FF_CHKSBDIR & flFastFile) {
//         USHORT i;
//
//
//         i = IVOLFROMLSN (psbd->scpTopDirBlkHint.lsn);
//         if (i == 0 ) {
//             dprintf ("AssertSDB: psbd->scpTopDBHint does not have vol bits turned on\n");
//             Int3();
//         }
//
//         if (VolPtr [i] != NULL) {
//             /*
//              * Since NULL will never be in the subdir tree,
//              * fFindSBD will travers the entire tree!
//              */
//             fFindSBD (NULL, VolPtr [i]->psbdRoot);
//         } else {
//             dprintf( "AssertSDB: VolPtr[%d] is NULL!", i );
//             Int3();
//         }
//     }
// }
//
//
// /**     AssertNoteRec - Verifies a NOTEREC structure
//  */
// void far
// AssertNoteRec (PNOTEREC pnr)
//
// {
//     if (pnr == NULL) {
//         dprintf ("AssertNoteRec: pnr == NULL\n");
//         Int3 ();
//     }
//
//     if (memcmp (pnr->sig, SIGNR, sizeof (pnr->sig))) {
//         dprintf ("AssertNoteRec: pnr (%p)->sig != SIGNR\n", pnr);
//         Int3 ();
//     }
// }
//
//
// /**     AssertIOH - Verifies a IOHANDLE structure
//  */
// void far
// AssertIOH (PIOH pioh)
//
// {
//     if (pioh == NULL) {
//         dprintf ("AssertNoteRec: pnr == NULL\n");
//         Int3 ();
//     }
//
//     if (memcmp (pioh->sig, SIGIOH, sizeof (pioh->sig))) {
//         dprintf ("AssertPOIH: pioh (%p)->sig != SIGIOH\n", pioh);
//         Int3 ();
//     }
// }

#endif
