/*static char *SCCSID = "@(#)rde.c      6.2 92/01/31";*/
#define _BTXT _BTXT
#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include <cdib.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 "heap.h"
#include "codepage.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "pbmacros.h"
#include "assert.h"
#include "log.h"                                                 // @76193
#include "pr_CACHE.h"
#include "pr_DIR.h"
#include "pr_heap.h"
#include "pr_MISC.h"
#include "pr_debug.h"


/*
 **     RDE - Re-find Directory Entry
 *
 *      RDE re-finds the directory entry for a file which is
 *      in the OFT.
 *
 *      ENTRY   poftToSearch = OFT address
 *
 *      EXIT    Returns address of directory entry if okay
 *                      *ppbufDirBlk = pointer to buffer header of directory
 *                              block in cache
 *                      Yields CPU
 *                      SBDIR is held!
 *
 *              Returns NULL iff error
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 *          28-Sep-1988 13:57 by Bill McJohn [t-billm]
 *                              brought up to date with 9/27/88 assembly code
 */

PDIRENT
RDE (poftToSearch, ppbufDirBlk, pfrm)
POFT            poftToSearch;           /* pointer to the oft struct */
PBUFNODE far *  ppbufDirBlk;            /* hdr addr of dir blk in cache */
PFRAME          pfrm;
{
    PDIRBLK pdbTop;
    PDIRBLK pdbFound;
    PBUFNODE pbufTop;
    USHORT usRet;

#ifdef BUFZAP
    DoZap();
#endif

    {   PSUBDIR psbd;

        ASSERT_OFT (poftToSearch);

        psbd = pfrm->psbd = poftToSearch->psbdDir;

        /*
         * Check if dir is corrupt
         */
        if( (psbd->bFlags & SDF_UNU) != 0 ) {
            SETHARDERR( ERROR_GEN_FAILURE );
            return NULL;
        }

        /*
         *  If the directory is locked, block until it is free.
         *  When it becomes available, put a hold on it.
         */

        HoldDir (psbd,pfrm);
        ASSERT_OFT (poftToSearch);

        /*  If the FreeDB count in the OFT matches that in the SUBDIR,
         *  and if the change counts in the directory block and the
         *  OFT are the same, then the directory entry is still in the
         *  same relative position in the DIRBLK.
         */
        if (poftToSearch->culFreeDB == psbd->culFreeDB) {

            /*
             * Locate the sector of data in the buffer cache
             * that contains the directory block pointed to by
             * the poft scpDirBlk field.
             */

            pdbTop = LSDDB (&(poftToSearch -> scpDirBlk), BP_KEEP,
                          ppbufDirBlk, pfrm);

            if (pdbTop == NULL) {
#ifdef DEBUG
                dprintf ("RDE: LSDDB 1 failed");
#endif
                goto rde20;
            }

            /* if it's still there, then just return */
            if (poftToSearch -> culChange == pdbTop -> culChange) {

                /* Our directory entry is still where it was
                 * in the DIRBLK.  The pde returned is the dirblk
                 * address + offset field stored in OFT entry.
                 */

#ifdef DEBUG
                {
                    PDIRENT pde;
                    pde = (PDIRENT)(((PBYTE) pdbTop) +
                                    poftToSearch->offusDirEnt);
                    if (poftToSearch->iCPVol != pde->bCodePage) {
                        dprintf ("%s: poft(%p)->iCPVol != pde(%p)->bCodePage\n",
                                 __FILE__, poftToSearch, pde);
                        Int3 ();
                    }
                }
#endif

                return (PDIRENT)
                        (((PBYTE) pdbTop) + poftToSearch -> offusDirEnt);
            }
        }

        /*
         * Guess what! Somebody has been editing that directory and we have
         * to find our entry again.  We know that it's there, we just gotta
         * go looking for it again.
         */

/* rde5: */

        /*  Update the OFT culFreeDB field  */
        poftToSearch -> culFreeDB = psbd -> culFreeDB;

        pdbTop = LSDDB(&(psbd -> scpTopDirBlkHint),BP_KEEP,&pbufTop,pfrm);

        if (pdbTop == NULL) {
#ifdef DEBUG
            dprintf ("RDE: LSDDB call #2 failed");
#endif
            goto rde20;
        }
    } /* end scope psbd */

    /* We have to upcase the name in the OFT to pass to LDE.  We get a heap
     * area to put the up-cased name.
     */

    {
        PDIRENT pde;

        {
            PPASCALSTRING ppsTemp;

            IncrHoldsBUF(pbufTop);  // @76193

            /* Get enough space to include the length byte */
            ppsTemp = GHS(poftToSearch->cchName +
                          sizeof(poftToSearch->cchName),pfrm);

            DecrHoldsBUF(pbufTop);  // @76193

            if (ppsTemp == NULL) {
#ifdef DEBUG
                dprintf (__FILE__": GHS returned NULL\n");
#endif
                goto rde20;
            }

            /* set up length to include length byte */
            ppsTemp->c = poftToSearch->cchName + (BYTE)1;

            NameUpCase (&(poftToSearch->cchName) + 1,
                        poftToSearch->cchName,
                        &paCodePageEnt [pfrm->pvol->
                        paiCodePage [poftToSearch->iCPVol]],
                        ppsTemp->b);

#ifdef DEBUG2
            {
                INT i;
                PBYTE p = ((PBYTE) poftToSearch) + sizeof (OFT);

                dprintf ("RDE: calling LDE (..., ");
                for (i = 0; i < ppsTemp->c-1; i++) {
                    if ((ppsTemp->b [i] == 0xff) ||
                        (ppsTemp->b [i] == 0xfe)) {
                        dprintf ("0x%x", 0x00ff & ppsTemp->b [i]);
                    } else {
                        dprintf ("%c", 0x00ff & ppsTemp->b [i]);
                    }
                }
                dprintf (", ...)\n");
                dprintf ("          poft->name=");
                for (i = 0; i < poftToSearch->cchName; i++) {
                    if ((*p == 0xff) ||
                        (*p == 0xfe)) {
                        dprintf ("0x%x", 0x00ff & *p++);
                    } else {
                        dprintf ("%c", 0x00ff & *p++);
                    }
                }
                dprintf ("\n\n");
            }
#endif

            usRet = LDE (pdbTop,
                         0,
                         FALSE,
                         pbufTop,
                         ppsTemp,
                         ppbufDirBlk,
                         &pdbFound,
                         &pde,
                         FALSE,                             //#90495
                         pfrm);

            RetHeap (ppsTemp);
        }

        DecrHoldsBUF (*ppbufDirBlk);  // @76193

        /* check return code */
        if (usRet != LDE_FOUND) {

#ifdef DEBUG
            dprintf ("RDE: Directory entry not found\n");
            Int3 ();
#endif
            goto rde20;
        }

#ifdef DEBUG
        if (poftToSearch->iCPVol != pde->bCodePage) {
            dprintf ("%s: poft(%p)->iCPVol != pde(%p)->bCodePage\n",
                     __FILE__, poftToSearch, pde);
            Int3 ();
        }
#endif

        poftToSearch -> culChange = pdbFound -> culChange;

        /*
         * We have the address of the start of the dir block.  Use it to
         * compute the directory entry sector number and the entry's cache
         * header address.
         */

        poftToSearch -> scpDirBlk.lsn = pdbFound->lsnThisDir;

        poftToSearch -> scpDirBlk.pbufHint = *ppbufDirBlk;
        poftToSearch -> offusDirEnt = DIRENT_OFFSET (pdbFound, pde);

        return pde;

rde20:
        UnHoldDir ();
        return NULL;

    } /* end scope pde */
}
