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.
 
 
 
 
 
 

479 lines
15 KiB

#include "precomp.h"
#pragma hdrstop
EnableAssert
private void ScanTimeRange(P4(AD *, NE *, PFNL, SM));
private void ScanCountRange(P4(AD *, NE *, PFNL, SM));
private F FMoreNe(P1(NE *));
private F FUseLe(P5(AD *, NE *, F, LE *, NE **));
private char *SzComPne(P3(NE *pneFiles, char *sz, unsigned ichMax));
MF *pmfNewLog = 0; /* mf of new copy of log file */
void ScanLog(pad, pneFiles, pfnl, sm)
/* Scan items in log, calling *pfnl for log entries occuring between the two
* specified time or count ranges. Actions are modified by the scan mode flags:
* fsmInOnly - Only use in, addfile, or delfile events.
* fsmUseAll - Call pfn for every le, with fTrue if in range.
*/
AD *pad;
NE *pneFiles;
PFNL pfnl;
SM sm;
{
/* Open log read-only, initially scanning backwards from end of log. */
OpenLog(pad, fFalse);
if (pad->tdMin.tdt != tdtNone)
ScanTimeRange(pad, pneFiles, pfnl, sm);
else
ScanCountRange(pad, pneFiles, pfnl, sm);
CloseLog();
}
private void ScanTimeRange(pad, pneFiles, pfnl, sm)
/* Scan for log entries between pad->tdMin and pad->tdMac. */
AD *pad;
NE *pneFiles;
PFNL pfnl;
SM sm;
{
LE le;
F fGotLe;
POS posMin;
POS posMac;
NE *pne;
F fFirst = fTrue;
FV fvDummy;
/* Scan for end of range. */
posMac = PosScanTd(pad, pad->tdMac, (char *)0, (PFNL)0, &fvDummy);
/* Scan for beginning of range. */
SetLogPos(posMac, fFalse);
posMin = PosScanTd(pad, pad->tdMin, (char *)0, (PFNL)0, &fvDummy);
/* If fsmUseAll, rewind and do early entries. */
if (sm&fsmUseAll)
{
SetLogPos((POS)0, fTrue);
while ((fGotLe = FGetLe(&le)) && le.posLog < posMin)
{
(*pfnl)(pad, &le, fFirst, fFalse);
FreeLe(&le);
}
if (fGotLe)
FreeLe(&le);
}
SetLogPos(posMin, fTrue);
/* Do log entries between posMin and posMac. */
while ((fGotLe = FGetLe(&le)) && le.posLog < posMac)
{
if (FUseLe(pad, pneFiles, (sm&fsmInOnly) != 0, &le, &pne))
{
(*pfnl)(pad, &le, fFirst, fTrue);
fFirst = fFalse;
}
else if (sm&fsmUseAll)
(*pfnl)(pad, &le, fFirst, fFalse);
FreeLe(&le);
}
/* If fsmUseAll, do remaining entries. */
if (sm&fsmUseAll && fGotLe)
{
do
{
(*pfnl)(pad, &le, fFirst, fFalse);
FreeLe(&le);
}
while (FGetLe(&le));
}
}
POS PosScanTd(pad, td, szFile, pfnl, pfv)
/* Scan log entries (presumably in reverse) until we reach an entry whose
* td is less than or equal to the specified td. Return the position of
* the last le greater than or equal to the td. This routine factors code
* out of ScanLog and UnmergeSrc.
*/
AD *pad;
TD td;
char *szFile;
PFNL pfnl;
FV *pfv; /* earliest fv found for this file */
{
POS pos = PosOfLog(); /* in case we fail to find any */
int cLe = 0; /* count of le's for "file@v-3" */
TD tdLe;
char szPv[cchPvMax];
char szPv2[cchPvMax];
LE le;
F fGotLe;
PV pv;
*pfv = 0; /* no fv found yet */
/* Check if scanning for current version, issue warning if desired
* version is actually higher than current version.
*/
pv = (pad->iedCur != iedNil) ? PvLocal(pad, pad->iedCur): PvGlobal(pad);
if (td.tdt == tdtPV && CmpPv(td.u.pv, pv) >= 0)
{
SzForPv(szPv, td.u.pv, fFalse);
SzForPv(szPv2, pv, fFalse);
if (CmpPv(td.u.pv, pv) > 0)
Warn("%s is higher than current version (%s); using %s\n", szPv, szPv2, szPv2);
return pos;
}
/* Examine each log entry until we find one which occured no later than
* the time we are scanning for.
*/
while ((fGotLe = FGetLe(&le)) == fTrue)
{
/* If this is a file we've been looking for, save its fv. */
if (szFile && FSameSzFile(&le, szFile))
*pfv = le.fv;
/* Break if this le's pv-number or pv-name is less or equal
* to the desired one...
*/
if (strcmp(le.szLogOp, "release") == 0)
{
F fBreak = fFalse;
char *pchSemi;
char *pchSp;
/* Format of szComLog is: "#.#[.#][ name];comment". */
if ((pchSemi = index(le.szComLog, ';')) == 0)
continue;
*pchSemi = 0;
if ((pchSp = index(le.szComLog, ' ')) != 0)
*pchSp = 0;
if (td.tdt == tdtPV && FParsPv(&tdLe, le.szComLog) &&
CmpPv(tdLe.u.pv, td.u.pv) <= 0)
{
fBreak = fTrue;
/* Issue a warning if they aren't equal. */
if (CmpPv(tdLe.u.pv, td.u.pv) != 0)
Warn("version %s not found (using version %s)\n",
SzForPv(szPv, td.u.pv, fFalse),
SzForPv(szPv2, tdLe.u.pv, fFalse));
}
else if (td.tdt == tdtPN && pchSp &&
strcmp(pchSp + 1, td.u.pv.szName) == 0)
fBreak = fTrue;
/* Restore comment. */
if (pchSp)
*pchSp = ' ';
if (pchSemi)
*pchSemi = ';';
if (fBreak)
{
pos = le.posLog;
break;
}
}
/* ... or if this le's file@fv <= the desired one... */
else if (td.tdt == tdtFV && szFile &&
FSameSzFile(&le, szFile) &&
(td.u.fv >= 0 ? le.fv <= td.u.fv : ++cLe > -td.u.fv))
{
if (td.u.fv >= 0 && le.fv < td.u.fv)
Warn("%s v%d not found (using %s v%d)\n",
szFile, td.u.fv, szFile, le.fv);
pos = le.posLog;
break;
}
/* ... or if this le's time is < the desired one. */
if (td.tdt == tdtTime)
{
/* Save the le position. */
if (le.timeLog >= td.u.time)
pos = le.posLog;
/* If the times are equal, we unfortunately run into
* a conflict of interest between UnmergeSrc and
* ScanLog.
*
* If called from UnmergeSrc, we don't want to unmerge
* this entry; we'd like to break here.
*
* If called from ScanLog, we want to keep going, we
* might find other entries with the same time.
*/
if (le.timeLog < td.u.time ||
(pfnl && le.timeLog == td.u.time)) /* kludge */
break;
}
/* (For "FUnmergeSrc":) If pfnl defined and this is an
* appropriate log entry, call pfnl; break if it returns false.
*/
if ((strcmp(le.szLogOp, "addfile") == 0 ||
strcmp(le.szLogOp, "delfile") == 0 ||
strcmp(le.szLogOp, "in") == 0 ||
strcmp(le.szLogOp, "rename") == 0) &&
(szFile == 0 || FSameSzFile(&le, szFile)) &&
pfnl != 0 &&
!(*pfnl)(pad, &le, fFalse, fFalse))
break;
FreeLe(&le);
}
if (fGotLe)
FreeLe(&le);
else
{
/* Didn't find it, issue diagnostic. */
if (td.tdt == tdtPV)
Error("version %s not found\n",
SzForPv(szPv, td.u.pv, fFalse));
else if (td.tdt == tdtPN)
FatalError("version %s not found\n", td.u.pv.szName);
else if (td.tdt == tdtFV)
Error("version %s v%d not found\n", szFile, td.u.fv);
else if (td.tdt == tdtTime)
;
else
AssertF(fFalse);
}
return pos;
}
F FSameSzFile(ple, szFile)
/* Return fTrue if the log entry applies to the same file as szFile; this is
* true if szFile matches le.szFile, or if the log entry is a rename and the
* szFile matches the new name found in le.szComLog.
*/
LE *ple;
char *szFile;
{
AssertF(ple != 0 && szFile != 0);
return (SzCmp(ple->szFile, szFile) == 0 ||
(strcmp(ple->szLogOp, "rename") == 0 &&
NmCmpSz(ple->szComLog, szFile, strlen(szFile)) == 0));
}
private void ScanCountRange(pad, pneFiles, pfnl, sm)
/* Scan for log entries between pad->ileMin and pad->ileMac. */
AD *pad;
NE *pneFiles;
PFNL pfnl;
SM sm;
{
F fFreeNe = fFalse;
NE *pne;
LE le;
POS pos;
F fGotLe;
int clePrint;
F fFirst = fTrue;
pos = (POS) 0 ;
if (pneFiles == 0)
{
/* If !fsmNoneToAll, will match all names. We use a special
* name, "*", to indicate this, and to provide a place
* to store the count.
*/
pneFiles = PneNewNm((NM far *)"*", 1, faNormal);
fFreeNe = fTrue;
}
/* set count to # of earliest record */
ForEachNe(pne, pneFiles)
pne->u.cleNe = (short)(pad->ileMac-1);
while (FMoreNe(pneFiles) && FGetLe(&le))
{
if (FUseLe(pad, pneFiles, ((sm&fsmInOnly) != 0), &le, &pne))
{
pne->u.cleNe--;
pos = le.posLog;
}
FreeLe(&le);
}
/* for each ne, we found (ileMac-1)-cleNe records */
if (sm&fsmUseAll)
{
SetLogPos((POS)0, fTrue);
while ((fGotLe = FGetLe(&le)) && le.posLog < pos)
{
(*pfnl)(pad, &le, fFirst, fFalse);
FreeLe(&le);
}
if (fGotLe)
FreeLe(&le);
}
/* reset for forward movement */
SetLogPos(pos, fTrue);
/* set # to print; may be <= 0 if we did not find any;
may be > clePrint for some ne if we found more than
the amount desired.
*/
clePrint = pad->ileMac - pad->ileMin;
ForEachNe(pne, pneFiles)
pne->u.cleNe = (short)clePrint - pne->u.cleNe;
while ((fGotLe = FGetLe(&le)) && FMoreNe(pneFiles))
{
if (FUseLe(pad, pneFiles, (sm&fsmInOnly), &le, &pne))
{
if (pne->u.cleNe > 0 &&
(int)(--pne->u.cleNe) < clePrint)
{
(*pfnl)(pad, &le, fFirst, fTrue);
fFirst = fFalse;
}
else if (sm&fsmUseAll)
(*pfnl)(pad, &le, fFirst, fFalse);
}
else if (sm&fsmUseAll)
(*pfnl)(pad, &le, fFirst, fFalse);
FreeLe(&le);
}
if (sm&fsmUseAll && fGotLe)
{
do
{
(*pfnl)(pad, &le, fFirst, fFalse);
FreeLe(&le);
}
while (FGetLe(&le));
}
if (fFreeNe)
FreeNe(pneFiles);
}
private F FMoreNe(pneList)
/* return true if any ne has count > 0 */
NE *pneList;
{
NE *pne;
ForEachNe(pne, pneList)
{
if (pne->u.cleNe > 0)
return fTrue;
}
return fFalse;
}
private F FUseLe(pad, pneFiles, fInOnly, ple, ppne)
register AD *pad;
F fInOnly;
NE *pneFiles;
register LE *ple;
NE **ppne; /* set to pne found, if any */
{
if (pneFiles != 0)
*ppne = (*SzOfNe(pneFiles) == '*') ? pneFiles : PneLookup(pneFiles, ple->szFile);
return (!fInOnly ||
SzCmp(ple->szLogOp, "addfile") == 0 ||
SzCmp(ple->szLogOp, "in") == 0 ||
SzCmp(ple->szLogOp, "delfile") == 0 ||
SzCmp(ple->szLogOp, "rename") == 0 ||
SzCmp(ple->szLogOp, "release") == 0) &&
(pneFiles == 0 || *ppne != 0) &&
(FEmptyNm(pad->nmUser) ||
NmCmpSz(pad->nmUser, ple->szUser, cchUserMax) == 0);
}
private F FCopyLog(pad, pneFiles, pfnl, sm)
AD *pad;
NE *pneFiles;
PFNL pfnl;
SM sm;
{
PTH pthNewLog[cchPthMax];
pmfNewLog = PmfCreate(PthForLog(pad, pthNewLog), permSysFiles, fFalse,
fxGlobal);
ScanLog(pad, pneFiles, pfnl, sm);
CloseMf(pmfNewLog);
LogOpPne(pad, pneFiles);
return fTrue;
}
void LogOpPne(pad, pneFiles)
/* Log the operation */
AD *pad;
NE *pneFiles;
{
char szComment[150];
OpenLog(pad, fTrue);
AppendLog(pad, (FI far *)0, (char *)0,
SzComPne(pneFiles, szComment, sizeof szComment));
CloseLog();
}
private char *SzComPne(pneFiles, sz, ichMax)
/* Store the szOp and the list of filenames into the sz.
* e.g. "exfile files: foo baz bar ook"
*/
NE *pneFiles;
char *sz;
unsigned ichMax;
{
NE *pne;
if (pneFiles == 0)
{
SzPrint(sz, "%s all files", szOp);
return sz;
}
SzPrint(sz, "%s files:", szOp);
ForEachNe(pne, pneFiles)
{
if (strlen(sz) + strlen(SzOfNe(pne)) + 4 >= ichMax)
{
strcat(sz, "...");
break;
}
strcat(sz, " ");
strcat(sz, SzOfNe(pne));
}
return sz;
}