Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

644 lines
16 KiB

/*****************************************************************************
* *
* ADDRESS.C *
* *
* Copyright (C) Microsoft Corporation 1990, 1991. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* *
* The module intent goes here. *
* *
******************************************************************************
* *
* Testing Notes *
* *
* This is where testing notes goes. Put stuff like Known Bugs here. *
* *
******************************************************************************
* *
* Current Owner: KevynCT *
* *
******************************************************************************
* *
* Released by Development: --/--/-- *
* *
*****************************************************************************/
/*****************************************************************************
*
* Revision History: Created 07/07/90 by KevynCT
*
* 90/11/04 Tomsn Use new VA address type (enabling zeck compression)
* 90/11/26 Tomsn Blocks are now 4K, Use 3.0 specific macro
* AddressToVA30() when performing address translation.
* 90/11/90 RobertBu #ifdef'ed out a dead routine
* 90/12/03 LeoN PDB changes
* 91/01/28 LeoN Add FixUpBlock
* 91/01/30 Maha VA nameless stuct named.
* 02/01/91 JohnSc new comment header; fixed version logic to test for
* ver != wVersion3_0 rather than ver == wVersion3_1
*
*****************************************************************************/
#include "help.h"
#include "inc\fcpriv.h"
#include "inc\adrspriv.h"
/*****************************************************************************
* *
* Prototypes *
* *
*****************************************************************************/
static RC STDCALL RcScanBlockOffset(QDE, GH, DWORD, DWORD, DWORD, QVA, QOBJRG);
/*--------------------------------------------------------------------------*
| Public functions |
*--------------------------------------------------------------------------*/
void STDCALL VAandOBJRGfromQLA(QLA qla, QDE qde, VA* pva, OBJRG* pobjrg)
{
ASSERT(FVerifyQLA(qla));
if (RcResolveQLA(qla, qde) == rcSuccess) {
*pva = qla->mla.va;
*pobjrg = qla->mla.objrg;
}
else {
VA vanil;
vanil.dword = vaNil;
*pva = vanil;
*pobjrg = objrgNil;
}
}
#ifdef RAWHIDE
VA STDCALL VAFromQLA(QLA qla, QDE qde)
{
ASSERT(FVerifyQLA(qla));
if (RcResolveQLA(qla, qde) == rcSuccess)
return qla->mla.va;
else {
VA vanil;
vanil.dword = vaNil;
return vanil;
}
}
#endif
// Perform 3.0 -> 3.5 addressing translation:
#ifdef _X86_
VOID STDCALL TranslateMBHD(LPVOID qvDst, LPVOID qvSrc, DWORD wVersion)
#else
VOID STDCALL TranslateMBHD(LPVOID qvDst, LPVOID qvSrc, DWORD wVersion, int isdff)
#endif
{
#ifdef _X86_
QMBHD qmbhdSrc = qvSrc;
QMBHD qmbhdDst = qvDst;
#else
QMBHD qmbhdSrc;
QMBHD qmbhdDst = qvDst;
MBHD mbhd;
#endif
if (wVersion != wVersion3_0)
#ifdef _X86_
*qmbhdDst = *qmbhdSrc;
#else
LcbMapSDFF(isdff, SE_MBHD, qvDst, qvSrc);
#endif
else {
#ifdef _X86_
OffsetToVA30(&(qmbhdDst->vaFCPPrev), qmbhdSrc->vaFCPPrev.dword);
OffsetToVA30(&(qmbhdDst->vaFCPNext), qmbhdSrc->vaFCPNext.dword);
OffsetToVA30(&(qmbhdDst->vaFCPTopic), qmbhdSrc->vaFCPTopic.dword);
#else
mbhd = *((QMBHD)qvSrc);
qmbhdSrc = &mbhd;
LcbMapSDFF( isdff, SE_MBHD, qmbhdSrc, qmbhdSrc );
OffsetToVA30( &(qmbhdDst->vaFCPPrev), qmbhdSrc->vaFCPPrev.dword );
OffsetToVA30( &(qmbhdDst->vaFCPNext), qmbhdSrc->vaFCPNext.dword );
OffsetToVA30( &(qmbhdDst->vaFCPTopic), qmbhdSrc->vaFCPTopic.dword );
#endif
}
}
/***************************************************************************
*
- Name: FixUpBlock
-
* Purpose:
* Fixes up the Prev and Next pointers in the in-memory block image
* from the MBHD. Once upon a time the compiler would generate the
* wrong next and previous pointers in the block header. This routine
* is called after calculating the correct values to place them into
* the cached block image, so as not to again need recalculation should
* the block again be requested while still in memory.
*
* Arguments:
* qmbhd - pointer to MBHD containing the correct Next/Prev info
* qbBuf - pointer to cached block, containing erroneous Next/Prev
* wVersion - version number of the file we're dealing with
*
* Returns:
* nothing
*
***************************************************************************/
#ifdef _X86_
void STDCALL FixUpBlock(LPVOID qmbhd, LPVOID qbBuf, DWORD wVersion)
#else
void STDCALL FixUpBlock(LPVOID qmbhd, LPVOID qbBuf, DWORD wVersion, SDFF_FILEID fileid)
#endif
{
#ifdef _X86_
if (wVersion != wVersion3_0) {
((QMBHD)qbBuf)->vaFCPPrev = ((QMBHD)qmbhd)->vaFCPPrev;
((QMBHD)qbBuf)->vaFCPNext = ((QMBHD)qmbhd)->vaFCPNext;
}
else {
((QMBHD)qbBuf)->vaFCPPrev.dword =
VAToOffset30 (&((QMBHD)qmbhd)->vaFCPPrev);
((QMBHD)qbBuf)->vaFCPNext.dword =
VAToOffset30 (&((QMBHD)qmbhd)->vaFCPNext);
}
#else
if (wVersion != wVersion3_0) {
((QMBHD)qbBuf)->vaFCPPrev.dword = LQuickMapSDFF( fileid, TE_LONG,
&((QMBHD)qmbhd)->vaFCPPrev.dword );
((QMBHD)qbBuf)->vaFCPNext.dword = LQuickMapSDFF( fileid, TE_LONG,
&((QMBHD)qmbhd)->vaFCPNext.dword );
}
else {
DWORD dw;
dw = VAToOffset30 (&((QMBHD)qmbhd)->vaFCPPrev);
((QMBHD)qbBuf)->vaFCPPrev.dword = LQuickMapSDFF( fileid, TE_LONG, &dw );
dw = VAToOffset30 (&((QMBHD)qmbhd)->vaFCPNext);
((QMBHD)qbBuf)->vaFCPNext.dword = LQuickMapSDFF( fileid, TE_LONG, &dw );
}
#endif
}
#ifdef _X86_
void STDCALL TranslateMFCP(LPVOID qvDst, LPVOID qvSrc, VA va, DWORD wVersion)
#else
void STDCALL TranslateMFCP(LPVOID qvDst, LPVOID qvSrc, VA va, DWORD wVersion, int isdff)
#endif
{
#ifdef _X86_
QMFCP qmfcpSrc = qvSrc;
QMFCP qmfcpDst = qvDst;
ASSERT(wVersion == wVersion3_0);
// We're dead meat if we get here and wVersion != wVersion3_0
// First copy whole structure to get the non-translated fields:
*qmfcpDst = *qmfcpSrc;
OffsetToVA30(&(qmfcpDst->vaPrevFc),
VAToOffset30(&va) - qmfcpSrc->vaPrevFc.dword);
OffsetToVA30(&(qmfcpDst->vaNextFc),
VAToOffset30(&va) + qmfcpSrc->vaNextFc.dword);
#else
QMFCP qmfcpSrc ;
QMFCP qmfcpDst = qvDst;
MFCP mfcp;
if (wVersion != wVersion3_0) {
LcbMapSDFF(isdff, SE_MFCP, qvDst, qvSrc);
}
else {
/* QvCopy() used because qvSrc may be misaligned & we run on a MIPS */
memmove( &mfcp, qvSrc, sizeof( MFCP ) );
qmfcpSrc = &mfcp;
LcbMapSDFF( isdff, SE_MFCP, qmfcpSrc, qmfcpSrc );
/* *qmfcpDst = *qmfcpSrc; */
memmove( qmfcpDst, qmfcpSrc, sizeof( MFCP ) );
OffsetToVA30( &(qmfcpDst->vaPrevFc),
VAToOffset30(&va) - qmfcpSrc->vaPrevFc.dword );
OffsetToVA30( &(qmfcpDst->vaNextFc),
VAToOffset30(&va) + qmfcpSrc->vaNextFc.dword );
}
#endif
}
RC STDCALL RcReadFileQLA(QLA qla, HF hf, WORD wHelpVersion)
{
DWORD fcl;
#ifdef _DEBUG
qla->wMagic = wLAMagic;
#endif
switch (wHelpVersion) {
case wVersion3_0:
qla->wVersion = wAdrsVerHelp3_0;
SetInvalidPA(qla->pa);
/*
* Help 3.0 used a LONG called an FCL. This maps directly
* to a logical address with FCID = FCL, OBJRG = 0.
*
* Which then maps to a VA via the macro OffsetToVA():
*/
if (LcbReadHf(hf, (LPSTR)&fcl, (LONG) sizeof(LONG)) != (LONG) sizeof(LONG))
return RcGetFSError();
OffsetToVA30( &(qla->mla.va), fcl );
qla->mla.objrg = 0;
break;
case wVersion3_1:
default:
// Help 3.5 (and above) uses a LONG called a PA (Physical Address).
qla->wVersion = wAdrsVerHelp3_5;
if (LcbReadHf(hf, &qla->pa, sizeof(PA)) != (LONG) sizeof(PA))
return RcGetFSError();
qla->mla.va.dword = 0; // Note: 0 is very magic -- first topic.
qla->mla.objrg = objrgNil;
break;
}
ASSERT(FVerifyQLA(qla));
return rcSuccess;
}
void FASTCALL CbReadMemQLA(QLA qla, LPBYTE qb, WORD wHelpVersion)
{
#ifdef _DEBUG
qla->wMagic = wLAMagic;
#endif
if (wHelpVersion == wVersion3_0) {
qla->wVersion = wAdrsVerHelp3_0;
SetInvalidPA(qla->pa);
/*
* Help 3.0 used a LONG called an FCL. This maps directly
* to a logical address with FCID = FCL, OBJRG = 0.
*
* Which then maps to a VA:
*/
OffsetToVA30(&qla->mla.va, *(QL) qb);
qla->mla.objrg = 0;
}
else {
// Help 3.5 uses a LONG called a PA (Physical Address).
qla->wVersion = wAdrsVerHelp3_5;
#ifdef _X86_
qla->pa = *(QPA) qb;
#else
MoveMemory(&qla->pa,qb,sizeof(QPA));
#endif
qla->mla.va.dword = 0; // Note: zero is special real address
qla->mla.objrg = objrgNil;
}
ASSERT(FVerifyQLA(qla));
}
/***************************************************************************
FUNCTION: AddrFromVA
PURPOSE: Given a VA, get an address (PA)
PARAMETERS:
va
qde
RETURNS:
ADDR on success, -1 on failure
COMMENTS:
The return result can be used to lookup a window definition in the
|VIOLA table.
MODIFICATION DATES:
09-Nov-1994 [ralphw]
***************************************************************************/
// REVIEW: Lynn, this function is new
ADDR STDCALL AddrFromVA(VA va, QDE qde)
{
DWORD dwOffset;
int wErr;
GH gh;
DWORD lcbRead;
PA pa;
if (QDE_HFTOPIC(qde) == NULL || va.dword == vaNil)
return -1;
dwOffset = 0L;
// REVIEW: error return types?
gh = GhFillBuf(qde, va.bf.blknum, &lcbRead, &wErr);
if (gh == NULL)
return -1;
if (RcScanBlockVA(gh, lcbRead, NULL, va, (OBJRG) 0, &dwOffset,
QDE_HHDR(qde).wVersionNo) != rcSuccess)
return -1;
pa.blknum = va.bf.blknum;
pa.objoff = dwOffset;
return *(ADDR*) &pa;
}
#if 0
RC STDCALL RcCreateQLA(QLA qla, VA va, OBJRG objrg, QDE qde)
{
DWORD dwOffset;
int wErr;
GH gh;
RC rc;
DWORD lcbRead;
if (QDE_HFTOPIC(qde) == NULL || va.dword == vaNil || objrg == objrgNil)
return rcBadArg;
dwOffset = 0L;
// REVIEW: error return types?
gh = GhFillBuf(qde, va.bf.blknum, &lcbRead, &wErr);
if (gh == NULL)
return rcFailure;
rc = RcScanBlockVA(gh, lcbRead, NULL, va, objrg, &dwOffset,
QDE_HHDR(qde).wVersionNo);
if (rc != rcSuccess)
return rc;
#ifdef _DEBUG
qla->wMagic = wLAMagic;
#endif
qla->wVersion = wAdrsVerHelp3_5;
qla->pa.blknum = va.bf.blknum;
qla->pa.objoff = dwOffset;
qla->mla.va = va;
qla->mla.objrg = objrg;
ASSERT(FVerifyQLA(qla));
return rcSuccess;
}
#endif
/* REVIEW: Non-API public functions. Perhaps these function go somewhere else */
/* REVIEW: Do the Scan functions belong in the fcmanager? */
/* Takes a block, and given an FC with an FC object space co-ordinate
* within the block, returns the block object space co-ordinate in qwOffset.
*/
RC STDCALL RcScanBlockVA(GH gh, DWORD lcbRead, LPVOID qmbhd, VA va,
OBJRG objrg, DWORD* qdwOffset, DWORD wVersion)
{
DWORD dwCount = (DWORD) 0;
VA vaCur;
MOBJ mobj;
#ifdef _X86_
QMFCP qmfcp;
#endif
MFCP mfcp;
DWORD dwBlock;
QB qb;
MBHD mbhd;
#ifndef _X86_
LONG lcbMFCP;
QDE qde = QdeFromGh(HdeGetEnv());
lcbMFCP = LcbStructSizeSDFF(QDE_ISDFFTOPIC(qde), SE_MFCP);
#endif
dwBlock = va.bf.blknum;
qb = PtrFromGh( gh );
if (!qmbhd) {
#ifdef _X86_
TranslateMBHD(&mbhd, qb, wVersion);
#else
TranslateMBHD(&mbhd, qb, wVersion, QDE_ISDFFTOPIC(qde));
#endif
vaCur = mbhd.vaFCPNext;
}
else {
vaCur = ((QMBHD)qmbhd)->vaFCPNext;
}
qb += vaCur.bf.byteoff;
while (vaCur.bf.blknum == va.bf.blknum && vaCur.bf.byteoff < lcbRead ) {
if (vaCur.dword == va.dword)
break;
/*
* Move on to the next FC in the block, adding the current FC's
* object space size to the running total.
*/
#ifdef _X86_
qmfcp = (QMFCP) qb;
if (wVersion != wVersion3_0)
CopyMemory(&mfcp, qmfcp, sizeof(MFCP));
else
TranslateMFCP( &mfcp, qmfcp, vaCur, wVersion );
CbUnpackMOBJ((QMOBJ)&mobj, (QB)qmfcp + sizeof(MFCP));
#else
TranslateMFCP( &mfcp, qb, vaCur, wVersion, QDE_ISDFFTOPIC(qde));
CbUnpackMOBJ((QMOBJ)&mobj, qb + lcbMFCP, QDE_ISDFFTOPIC(qde));
#endif
dwCount += mobj.wObjInfo;
//ASSERT(qmfcp->ldichNextFc != (LONG) 0);
qb += mfcp.vaNextFc.bf.byteoff - vaCur.bf.byteoff;
vaCur = mfcp.vaNextFc;
}
if (vaCur.dword != va.dword) {
*qdwOffset = (DWORD) 0;
return rcBadArg;
}
*qdwOffset = dwCount + objrg;
return rcSuccess;
}
/*--------------------------------------------------------------------------*
| Private functions |
*--------------------------------------------------------------------------*/
RC STDCALL RcResolveQLA(QLA qla, QDE qde)
{
RC rc;
int wErr;
GH gh;
DWORD lcbRead;
ASSERT(FVerifyQLA(qla));
if (FResolvedQLA(qla))
return rcSuccess;
if (QDE_HFTOPIC(qde) == NULL)
return rcBadHandle;
/* Read in the (possibly cached) block */
/* REVIEW: error return types? */
gh = GhFillBuf(qde, qla->pa.blknum, &lcbRead, &wErr);
if (gh == NULL)
return rcFailure;
rc = RcScanBlockOffset(qde, gh, lcbRead, qla->pa.blknum,
qla->pa.objoff, &qla->mla.va, &qla->mla.objrg);
if (rc != rcSuccess)
return rc;
ASSERT(FVerifyQLA(qla));
return rcSuccess;
}
/* Given a block and an offset, return the FCID and OBJRG */
/* OBJRG is relative to the FC */
/***************************************************************************
*
- Name: RcScanBlockOffset
-
* Purpose: ?
*
* Arguments: hf ?
* qb This is originally a QchFillBuf() object, which
* must be released by this procedure.
* fcidMax ?
* dwBlock ?
* dwOffset ?
* qfcid ?
* qobjrg ?
*
* Returns: rcSuccess or rcFailure
*
* Globals Used: rcFailure, rcSuccess, etc?
*
* +++
*
* Notes:
*
***************************************************************************/
static RC STDCALL RcScanBlockOffset(QDE qde, GH gh, DWORD lcbRead, DWORD dwBlock,
DWORD dwOffset, QVA qva, QOBJRG qobjrg)
{
DWORD dwPrev;
VA vaCur, vaT;
MOBJ mobj;
QMFCP qmfcp;
MFCP mfcp;
int wErr;
QB qb, qbBlock;
MBHD mbhd;
#ifndef _X86_
LONG lcbMFCP;
lcbMFCP = LcbStructSizeSDFF(QDE_ISDFFTOPIC(qde), SE_MFCP);
#endif
qbBlock = (LPBYTE) PtrFromGh(gh);
#ifdef _X86_
TranslateMBHD(&mbhd, qbBlock, QDE_HHDR(qde).wVersionNo);
#else
TranslateMBHD( &mbhd, qbBlock, QDE_HHDR(qde).wVersionNo, QDE_ISDFFTOPIC(qde));
#endif
vaCur = mbhd.vaFCPNext;
dwPrev = 0;
for (;;) {
// Before using qb, we ensure that we will still be looking inside the blk
while (vaCur.bf.blknum == dwBlock && vaCur.bf.byteoff < lcbRead) {
qb = qbBlock + vaCur.bf.byteoff;
qmfcp = (QMFCP) qb;
#ifdef _X86_
if (QDE_HHDR(qde).wVersionNo != wVersion3_0)
CopyMemory(&mfcp, qmfcp, sizeof(MFCP));
else
TranslateMFCP(&mfcp, qmfcp, vaCur, QDE_HHDR(qde).wVersionNo);
CbUnpackMOBJ((QMOBJ)&mobj, (QB)qmfcp + sizeof(MFCP));
#else
TranslateMFCP( &mfcp, qb, vaCur, QDE_HHDR(qde).wVersionNo, QDE_ISDFFTOPIC (qde));
CbUnpackMOBJ((QMOBJ)&mobj, qb + lcbMFCP, QDE_ISDFFTOPIC(qde));
#endif
/*
* Does our given offset fall in this FC's range of object-region
* numbers?
*/
if (dwOffset < dwPrev + mobj.wObjInfo)
goto found_it;
dwPrev += mobj.wObjInfo;
vaT = vaCur;
//ASSERT(qmfcp->ldichNextFc != (LONG) 0);
vaCur = mfcp.vaNextFc;
}
/* NOTE:
* In the case that a topic FC begins in the given block and ends
* in the next, the object FC following it will also begin in the NEXT
* block. But to make Larry's life easier we say that this object FC
* belongs to our given block (as well as the block it lives in). So
* if we are given an object offset bigger than the total object space
* of the given block, we continue counting in the next block(s).
*
* So we increment the block num, read the next block, and prepare to
* re-do the above WHILE loop until we find the FC we need.
*/
++dwBlock;
gh = GhFillBuf(qde, dwBlock, &lcbRead, &wErr);
if (gh == NULL) {
qva->dword = vaNil;
*qobjrg = objrgNil;
return rcFailure;
}
qbBlock = (LPBYTE) PtrFromGh(gh);
}
found_it:
ASSERT(dwOffset >= dwPrev);
*qva = vaCur;
*qobjrg = (OBJRG)(dwOffset - dwPrev);
return rcSuccess;
}
#if defined(_DEBUG)
BOOL STDCALL FVerifyQLA(QLA qla)
{
ASSERT(qla != NULL);
if (FResolvedQLA(qla)) {
ASSERT(qla->mla.va.dword != vaNil);
ASSERT(qla->mla.objrg != objrgNil);
if (qla->wVersion != wAdrsVerHelp3_0)
ASSERT(!FIsInvalidPA(qla->pa));
}
return TRUE;
}
#endif