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.
 
 
 
 
 
 

896 lines
25 KiB

/* This module handles the check syntax/reconstruct, upgrade process for
* version 2 and 3 SLM status files.
*/
#include "precomp.h"
#pragma hdrstop
EnableAssert
#define FDirFi2(pfi2) ((pfi2)->fk == fkDir)
#define FTypeFi2(pfi2) ((pfi2)->fk)
#define FNonBinFi2(pfi2) \
((pfi2)->fk == fkText || (pfi2)->fk == fkUnrec || \
(pfi2)->fk == fkVersion || pfi2->fk == fkUnicode)
#define FVerifyFm(fm) ((fm) == fmVerify || (fm) == fmConflict)
#define FOutFm(fm) ((fm) == fmOut || (fm) == fmDelOut ||\
(fm) == fmMerge || FVerifyFm(fm))
#define FDelFm(fm) ((fm) == fmNonExistent || (fm) == fmDelOut ||\
(fm) == fmDelIn)
#define FOSyncFm(fm) ((fm) == fmAdd || (fm) == fmCopyIn ||\
(fm) == fmDelIn || (fm) == fmDelOut ||\
(fm) == fmMerge || (fm) == fmVerify ||\
(fm) == fmConflict)
private void CkSh2(AD *, SD *);
private F FQStat(SD *, char *, ...);
// private F FQStat(SD *, char *, AD *, ...);
private void CkFi2(AD *, SD *, FI2 *);
private void CheckName(AD *, SD *, char *, char *, int, F (*)(char *, int, int *), char *);
private F FQFile(SD *, char *, ...);
// private F FQFile(SD *, char *, AD *, char *, ...);
private void CkEd2(AD *, SD *, ED2 *);
// private F FQPth(SD *, char *, AD *, char *, ...);
private F FQPth(SD *, char *, ...);
private F FMapFi2Fs2(AD *, SD *);
private void Match2(AD *, SD *, NE *, FI2 *);
private F FFixFi2(AD *, SD *, FI2 *, NE *);
private void Fi2UnMarkAll(SD *);
private F FSortFi2(SD *);
private F FSrtdFi2(SD *);
private SP SpFi2Del(SD *, FI2 *);
private void CkFi2Fs2(AD *, SD *, FI2 *, NE *);
private void CkFs2(AD *, SD *, NE *, ED2 *, FI2 *, FS2 *);
// private F FQFOwn(SD *, char *, AD *, char *, char *, ...);
private F FQFOwn(SD *, char *, ...);
private int CmpIfi2(SD *, IFI2, IFI2);
static short wStart; // start time
/* The general layout of this process is quite simple. First, we see if given
* structure satisfies the SpIs... predicate. If it does, we check its syntax,
* if not we try to reconstruct it using whatever information that has been
* verified to be correct.
* NB: At this time, the reconstruction option is not implemented.
*/
F
FVer2Semantics(
AD *pad,
SD *psd)
{
ED2 *ped2;
wStart = (short) (time(NULL) >> 16);
if (fVerbose)
PrErr("Checking contents of status file\n");
/* do the SH */
CkSh2(pad, psd);
CheckForBreak();
/* now the ED */
for (ped2 = psd->rged2; ped2 < psd->rged2 + psd->psh2->iedMac; ped2++)
{
CheckForBreak();
CkEd2(pad, psd, ped2);
}
/* the FI and FS are done simultaneously so we can verify one against
* the other.
*/
return FMapFi2Fs2(pad, psd);
}
/* Do semantics check on the SH */
private void
CkSh2(
AD *pad,
SD *psd)
{
IFI2 ifiT; /* temp constant for holding data */
IED2 iedT;
BI biNext;
SH2 *psh2 = psd->psh2;
PTH pthBase[cchPthMax];
if (psh2->magic != MAGIC && FQStat(psd, "magic is incorrect", pad))
psh2->magic = MAGIC;
// Version 2 must handle ver 2 and ver 3 and ver 4 and ver 5 status files.
// However, don't force version 4 or 5. Let slmck or slmed do it.
if (psh2->version != 2 &&
psh2->version != 3 &&
psh2->version != 4 &&
psh2->version != 5 &&
FQStat(psd, "version is incorrect; should probably be 3", pad))
psh2->version = 3;
if (psh2->lck != lckNil && FQStat(psd, "lck is not lckNil", pad))
psh2->lck = lckNil;
if (!(psh2->lck == lckAll || psh2->fAdminLock) &&
!FAllZero(psh2->nmLocker, cchUserMax) &&
FQStat(psd, "unlocked but nmLocker non-zero", pad))
ClearLpbCb((char *)psh2->nmLocker, cchUserMax);
/* if it's locked, there's nothing we can do to verify the locker's name */
ifiT = (IFI2)(long)((FI2 *)psd->rged2 - (FI2 *)psd->rgfi2);
if ((IFI2)(psh2->ifiMac) != ifiT &&
FQStat(psd, "ifiMac is %d; should be %d", pad, psh2->ifiMac, ifiT))
psh2->ifiMac = ifiT;
iedT = (IED2)(long)((ED2 *)psd->rgfs2 - (ED2 *)psd->rged2);
if ((IED2)psh2->iedMac != iedT &&
FQStat(psd, "iedMac is %d; should be %d", pad, psh2->iedMac, iedT))
psh2->iedMac = iedT;
if (psh2->pv.rmj < 0 && FQStat(psd, "pv.rmj is < 0", pad))
psh2->pv.rmj = 0;
if (psh2->pv.rmm < 0 && FQStat(psd, "pv.rmm is < 0", pad))
psh2->pv.rmm = 0;
if (psh2->pv.rup < 0 && FQStat(psd, "pv.rup is < 0", pad))
psh2->pv.rup = 0;
if (strlen(psh2->pv.szName) > cchPvNameMax)
psh2->pv.szName[0] = '\0';
if (psh2->rgfSpare)
{
psh2->rgfSpare = 0;
psd->fAnyChanges = fTrue;
PrErr("rgfSpare cleared in Status Header\n");
}
if (!FAllZero((char *)psh2->rgwSpare, sizeof(psh2->rgwSpare)))
{
ClearLpbCb((char *)psh2->rgwSpare, sizeof(psh2->rgwSpare));
psd->fAnyChanges = fTrue;
PrErr("rgwSpare cleared in Status Header\n");
}
/* make sure biNext is correct */
SzPrint(pthBase, szEtcPZ, pad, (char *)NULL);
if ((BI)psh2->biNext < (biNext = GetBiNext(pthBase)) &&
FQStat(psd, "biNext incorrect; should be %d", pad, biNext))
psh2->biNext = biNext;
if (!FIsF(psh2->fRelease) && FQStat(psd, "fRelease not Boolean", pad))
psh2->fRelease = fFalse;
if (psh2->wSpare)
{
psh2->wSpare = 0;
psd->fAnyChanges = fTrue;
PrErr("wSpare cleared in Status Header\n");
}
if (PthCmp(pad->pthSSubDir, psh2->pthSSubDir) != 0 &&
FQStat(psd, "pthSSubDir (%ls) differs from current pthSSubDir (%s)",
pad, psh2->pthSSubDir, pad->pthSSubDir))
{
ClearLpbCb(psh2->pthSSubDir, cchPthMax);
PthCopy(psh2->pthSSubDir, pad->pthSSubDir);
}
}
/* This does a preliminary syntactic check on the FI */
private void
CkFi2(
AD *pad,
SD *psd,
FI2 *pfi2)
{
char szFile[cchFileMax+1];
AssertF(cchFileMax == 14);
MakePrintLsz((char *)SzPrint(szFile, "%.14ls", pfi2->nmFile));
CheckName(pad, psd, "file name", pfi2->nmFile, cchFileMax, FIsFileNm,
szFile);
if ((pfi2->fv < fvInit || pfi2->fv >= fvLim) &&
FQFile(psd, "fv out of range", pad, pfi2->nmFile))
pfi2->fv = fvInit;
if ((pfi2->fk != fkDir && pfi2->fk != fkText
&& pfi2->fk != fkBinary && pfi2->fk != fkUnrec
&& pfi2->fk != fkVersion) &&
FQFile(psd, "fk invalid", pad, pfi2->nmFile))
{
//LATER: check actual type of file?
pfi2->fk = fkUnrec;
}
/* can't check fMarked, we're using it */
if (pfi2->rgfSpare)
{
pfi2->rgfSpare = 0;
psd->fAnyChanges = fTrue;
PrErr("rgfSpare cleared in File Info\n");
}
if (pfi2->wSpare)
{
pfi2->wSpare = 0;
psd->fAnyChanges = fTrue;
PrErr("wSpare cleared in File Info\n");
}
}
private void
CkEd2(
AD *pad,
SD *psd,
ED2 *ped2)
{
char szT[cchPthMax];
/* no real way to check the pthEd and nmOwner, but make sure legal */
MakePrintLsz(SzCopyPth(szT, ped2->pthEd));
CheckName(pad, psd, "path", ped2->pthEd, cchPthMax, FIsPth, szT);
MakePrintLsz((char *)SzPrint(szT, "%.14ls", ped2->nmOwner));
CheckName(pad, psd, "owner", ped2->nmOwner, cchUserMax, FIsNm, szT);
if (ped2->fLocked && FQPth(psd, "fLock set", pad, ped2->pthEd))
ped2->fLocked = fFalse;
if (!FIsF(ped2->fNewVer) &&
FQPth(psd, "fNewVer not Boolean", pad, ped2->pthEd))
ped2->fNewVer = fFalse;
if (ped2->fNewVer && !psd->psh2->fRelease &&
FQPth(psd, "not a fresh release, but fNewVer is set", pad,
ped2->pthEd))
ped2->fNewVer = fFalse;
if (ped2->rgfSpare)
{
ped2->rgfSpare = 0;
psd->fAnyChanges = fTrue;
PrErr("rgfSpare cleared in Enlisted Dir\n");
}
if (ped2->wSpare > wStart)
{
ped2->wSpare = wStart;
psd->fAnyChanges = fTrue;
PrErr("wSpare set to current time in Enlisted Dir\n");
}
}
/* This function tries to pair up the FI with the entries in the src directory.
* We base the algorithm on the fact that the FI are supposed to be in
* increasing alphanumerical order. Essentially, we merge the rgfi with a
* sorted list of the directory contents, and then see where the problems occur.
*/
private F
FMapFi2Fs2(
AD *pad,
SD *psd)
{
NE *pneNil = (NE *)0; /* null pointer */
PTH pth[cchPthMax];
NE *pneDirList;
FI2 *pfi2;
FI2 *pfi2Cur;
NE *pneCmp; /* NE being compared now */
NE *pneCur; /* holds depth finished in DirList */
pneDirList = PneSortDir(SzPrint(pth, szSrcPZ ,pad, (char *)NULL));
for (pfi2 = psd->rgfi2; CbHugeDiff(pfi2, psd->rged2) < 0; pfi2++)
{
CheckForBreak();
CkFi2(pad, psd, pfi2);
}
if (!FSrtdFi2(psd) &&
(!FQueryPsd(psd,"%&P/C: file entries in status file are unsorted",pad) ||
!FSortFi2(psd)))
{
/*
* if the rgfi isn't already sorted, and the user doesn't let
* us sort it, or the sort fails, return false.
*/
return fFalse;
}
Fi2UnMarkAll(psd);
/* First we try to pair up directory entries and FI
* and mark those FI and NE that match up.
*/
pneCur = pneDirList;
for (pfi2 = psd->rgfi2; CbHugeDiff(pfi2, psd->rged2) < 0; pfi2++)
{
CheckForBreak();
ForEachNeWhileF(pneCmp, pneCur, NeCmpiNm(pneCmp, pfi2->nmFile) < 0)
;
if (pneCmp && NeCmpiNm(pneCmp, pfi2->nmFile) == 0)
{
/* Found it! Now check syntax */
CkFi2Fs2(pad, psd, pfi2, pneCmp);
pfi2->fMarked = fTrue;
MarkNe(pneCmp);
pneCur = pneCmp->pneNext;
}
else if (FFromSp(SpFi2Del(psd, pfi2)))
{
/* file is deleted */
CkFi2Fs2(pad, psd, pfi2, pneNil);
pfi2->fMarked = fTrue;
}
}
/* Now we process those FI and NE that are unmarked.
* This section is just a large case analysis inside a loop.
* We go through both lists until we are done with both.
*/
pneCur = pneDirList;
pfi2Cur = psd->rgfi2;
/* go through both lists */
while (pneCur || CbHugeDiff(pfi2Cur, psd->rged2) < 0)
{
CheckForBreak();
AssertF(CbHugeDiff(pfi2Cur, psd->rged2) <= 0);
if (pneCur && FMarkedNe(pneCur) &&
CbHugeDiff(pfi2Cur, psd->rged2) < 0 && pfi2Cur->fMarked)
{
/* Both are marked so increment, unless file is
* deleted and nmFile != SzOfNe.
* The file may be deleted, and may match a NE iff
* the user has answered no about a bad fDeleted.
*/
if (!pfi2Cur->fDeleted ||
NeCmpiNm(pneCur, (char *)pfi2Cur) == 0)
pneCur = pneCur->pneNext;
pfi2Cur++;
}
else if (CbHugeDiff(pfi2Cur, psd->rged2) < 0 &&
!pfi2Cur->fMarked && (!pneCur || FMarkedNe(pneCur)))
{
/* Only FI unmarked => file must be deleted or erased,
* but checked for deleted above.
*/
CkFi2Fs2(pad, psd, pfi2Cur, pneNil);
(pfi2Cur++)->fMarked = fTrue;
}
else if (!pneCur && pfi2Cur->fMarked)
{
/* Must be a deleted FI at end of rgfi */
AssertF(pfi2Cur->fDeleted);
pfi2Cur++;
}
else if ((CbHugeDiff(pfi2Cur, psd->rged2) == 0 ||
pfi2Cur->fMarked) && pneCur && !FMarkedNe(pneCur))
{
/* only NE unmarked => file added directly to src */
if (!FDirNe(pneCur))
Error("%!&/S/src/P/C/Z added without addfile command; delete and use addfile\n",
pad, SzOfNe(pneCur));
else
Warn("found directory %!&/S/src/P/C/Z\n",
pad, SzOfNe(pneCur));
MarkNe(pneCur);
pneCur = pneCur->pneNext;
}
else if (pneCur && !FMarkedNe(pneCur) &&
CbHugeDiff(pfi2Cur, psd->rged2) < 0 &&
!(pfi2Cur->fMarked))
Match2(pad, psd, pneCur, pfi2Cur);
/* The above code should have covered each possibility */
else
FatalError("Impossible case in FMapFi2Fs2\n");
}
/* must end with the fi in alphabetical order */
AssertF(FSrtdFi2(psd));
FreeNe(pneDirList);
return fTrue;
}
/* Both NE and FI unmarked. The obvious conclusion is
* that the nmFile is garbage, but first we will try to
* match all contiguous unmarked NEs that have special
* traits to similar FI. I.e., match Dirs and binary
* files. Eventually get to one of above cases or have
* no other choice so assume garbage nmFile.
*/
private void
Match2(
AD *pad,
SD *psd,
NE *pneCur,
FI2 *pfi2Cur)
{
NE *pneCmp;
FI2 *pfi2;
PTH pth[cchPthMax];
F fDir;
ForEachNeWhileF(pneCmp, pneCur, !FMarkedNe(pneCmp))
{
if ((fDir = FDirNe(pneCmp)) ||
FBinaryPth(SzPrint(pth, szSrcPZ, pad, SzOfNe(pneCmp))) == fBinary)
{
for (pfi2 = pfi2Cur; CbHugeDiff(pfi2, psd->rged2) < 0; pfi2++)
if ((fDir ? FDirFi2(pfi2) : FTypeFi2(pfi2) == fkBinary) &&
FFixFi2(pad, psd, pfi2, pneCmp))
break;
}
}
/* couldn't get any extra matching info, so assume
* garbage, but ask user to be sure. If not go through
* rest of contiguous unMarked FI.
*/
ForEachNeWhileF(pneCmp, pneCur, !FMarkedNe(pneCmp))
{
for (pfi2 = pfi2Cur;
CbHugeDiff(pfi2, psd->rged2) < 0 && !pfi2->fMarked;
pfi2++)
if (FFixFi2(pad, psd, pfi2, pneCmp))
break;
if (FMarkedNe(pneCmp))
/* break out if found a match */
break;
}
}
private F
FFixFi2(
AD *pad,
SD *psd,
FI2 *pfi2,
NE *pne)
{
AssertF(cchFileMax == 14);
if (!FQueryPsd(psd,"%&P/C: file name %.14ls is incorrect; should be %s",
pad, pfi2->nmFile, SzOfNe(pne)))
return fFalse;
else
{
NmCopySz(pfi2->nmFile, SzOfNe(pne), cchFileMax);
CkFi2Fs2(pad, psd, pfi2, pne);
MarkNe(pne);
pfi2->fMarked = fTrue;
return fTrue;
}
}
private void
Fi2UnMarkAll(
SD *psd)
{
register FI2 *pfi2;
for (pfi2 = psd->rgfi2; CbHugeDiff(pfi2, psd->rged2) < 0; pfi2++)
pfi2->fMarked = fFalse;
}
/* make sure list is in increasing alphabetical order, with no duplicates */
private F
FSrtdFi2(
SD *psd)
{
register FI2 *pfi2Cur;
register FI2 *pfi2;
pfi2Cur = psd->rgfi2;
for (pfi2 = pfi2Cur++; CbHugeDiff(pfi2Cur, psd->rged2) < 0; pfi2 = pfi2Cur++)
{
if (NmCmpi(pfi2->nmFile, pfi2Cur->nmFile, cchFileMax) >= 0)
return fFalse;
}
return fTrue;
}
/*
* Compare the name of the file with the given index with the name of the
* file with the other index. Used by generic index ordering functions.
*/
private int
CmpIfi2(
SD *psd,
IFI2 ifi2,
IFI2 ifi2Other)
{
return NmCmpi(psd->rgfi2[ifi2].nmFile,
psd->rgfi2[ifi2Other].nmFile,
cchFileMax);
}
/*
* Sort the rgfi, and associated rgfs. The sort is case insensitive.
* We first build a mapping array from the old order to the new, then apply
* this transformation to the rgfi, and to each rgfs.
*/
private F
FSortFi2(
SD *psd)
{
register INO *pino;
register FI2 *pfi2;
pino = PinoNew(psd->psh2->ifiMac, CmpIfi2);
for (pfi2 = psd->rgfi2; CbHugeDiff(pfi2, psd->rged2) < 0; pfi2++)
{
InsertInd(psd, (IND)(pfi2 - psd->rgfi2), pino);
}
BLOCK
{
/*
* Apply the ordering to each rgfs in turn.
*/
IED ied;
FS2 *rgfs2;
for (ied = 0, rgfs2 = psd->rgfs2;
ied < psd->psh2->iedMac;
ied++, rgfs2 = (FS2 *)LpbFromHpb((char *)(rgfs2 + psd->psh2->ifiMac)))
{
ApplyIno(pino, (char *)rgfs2, sizeof(FS2));
}
}
/* Apply the ordering to the rgfi */
ApplyIno(pino, (char *)psd->rgfi2, sizeof(FI2));
FreeIno(pino);
return fTrue;
}
/****************************************************************/
/* This function examines an FI2 and its associated FS2 to decide if the file
* they refer to was deleted properly (via delfile).
*/
private SP
SpFi2Del(
SD *psd,
FI2 *pfi2)
{
register FS2 *pfs2;
WP wp;
InitWp(&wp);
AddWpF(&wp, twHeavy, pfi2->fDeleted);
/* check the fs. We have to re-normalize each time we increment pfs2
* because the whole rgrgfs may be > 64k. We can still use ptrs
* because we know that each rgfs is < 64k.
*/
for (pfs2 = (FS2 *)LpbFromHpb((char *)((FS2 *)psd->rgfs2 + ((FI2 *)pfi2 - (FI2 *)psd->rgfi2)));
CbHugeDiff(pfs2, psd->hpbStatMac) < 0;
pfs2 = (FS2 *)LpbFromHpb((char *)((FS2 *)pfs2 + psd->psh2->ifiMac)))
AddWpF(&wp, twMedium, FDelFm(pfs2->fm));
return SpFromWp(&wp);
}
/* This function does the semantics check on an fi and its associated fs */
private void
CkFi2Fs2(
AD *pad,
SD *psd,
FI2 *pfi2,
NE *pne)
{
FS2 *pfs2;
F fDir;
F fType;
PTH pth[cchPthMax];
IED2 ied;
FK fk;
AssertF(cchFileMax == 14);
AssertF(cchUserMax == 14);
if (!pne && !(CbHugeDiff(pfi2, psd->rged2) < 0))
return;
if (pne)
{
/* check that pfi bits correspond to file type. */
/* N.B.: directories are present even if fDeleted */
if (pfi2->fDeleted && !FDirNe(pne) &&
FQFile(psd, "fDeleted set, but file exists", pad,
pfi2->nmFile))
pfi2->fDeleted = fFalse;
fDir = FDirNe(pne);
fType = FBinaryPth(SzPrint(pth, szSrcPZ, pad, SzOfNe(pne)));
if (fDir ? !FDirFi2(pfi2) :
(fType == fkBinary ? !FTypeFi2(pfi2) : !FNonBinFi2(pfi2)))
{
if (fDir)
fk = fkDir;
else if (fType == fkText)
fk = fkText;
else if (fType == fkUnicode)
fk = fkUnicode;
else
fk = fkUnrec;
if (FQFile(psd, "fk %s incorrect; should be %s", pad,
pfi2->nmFile, mpfksz[pfi2->fk], mpfksz[fk]))
pfi2->fk = fk;
}
}
else
{
/* file is deleted or erased */
if (FFromSp(SpFi2Del(psd, pfi2)))
{
if (!pfi2->fDeleted &&
FQFile(psd, "fDeleted not set, but file is deleted",
pad, pfi2->nmFile))
pfi2->fDeleted = fTrue;
}
else if (pfi2->fDeleted &&
FQFile(psd, "fDeleted bit is set but file is erased, not delfiled",
pad, pfi2->nmFile))
pfi2->fDeleted = fFalse; /* REVIEW! */
}
/* check the fs for a particular FI */
for (ied = 0, pfs2 = (FS2 *)LpbFromHpb((char *)((FS2 *)psd->rgfs2 + ((FI2 *)pfi2 - (FI2 *)psd->rgfi2)));
ied < psd->psh2->iedMac;
ied++, pfs2 = (FS2 *)LpbFromHpb((char *)((FS2 *)pfs2 + psd->psh2->ifiMac)))
CkFs2(pad, psd, pne, psd->rged2 + ied, pfi2, pfs2);
}
private void
CkFs2(
AD *pad,
SD *psd,
NE *pne,
ED2 *ped2,
FI2 *pfi2,
FS2 *pfs2)
{
PTH pth[cchPthMax];
struct _stat st;
if (!FValidFm(pfs2->fm) &&
FQFOwn(psd, "file mode unknown", pad, pfi2->nmFile, ped2->nmOwner))
pfs2->fm = fmIn;
if (!FDirFi2(pfi2) && pfi2->fDeleted && !FDelFm(pfs2->fm) &&
FQFOwn(psd, "src file deleted, but local mode not Del", pad,
pfi2->nmFile, ped2->nmOwner))
{
/* change to appropriate Del mode */
if (pfs2->fm == fmIn || pfs2->fm == fmCopyIn)
pfs2->fm = fmDelIn;
else if (FOutFm(pfs2->fm))
pfs2->fm = fmDelOut;
else
pfs2->fm = fmNonExistent;
}
else if (FDirFi2(pfi2) &&
!(pfs2->fm == fmNonExistent || pfs2->fm == fmIn ||
pfs2->fm == fmDelIn || pfs2->fm == fmAdd) &&
FQFOwn(psd, "directory not Del, Add, In or DelIn", pad,
pfi2->nmFile, ped2->nmOwner))
{
/* change to appropriate mode */
if (!pne)
pfs2->fm = fmNonExistent;
else if (pfs2->fm == fmOut || pfs2->fm == fmDelIn)
pfs2->fm = fmIn;
else if (pfs2->fm == fmCopyIn || pfs2->fm == fmMerge ||
FVerifyFm(pfs2->fm))
pfs2->fm = fmAdd;
else
pfs2->fm = fmNonExistent;
}
if (pfi2->fk == fkVersion && FOutFm(pfs2->fm) &&
FQFOwn(psd, "version file has out mode", pad, pfi2->nmFile,
ped2->nmOwner))
pfs2->fm = fmOut;
/* check if bi is legal */
if (pfs2->bi != bi2Nil)
{
if (pfs2->bi >= psd->psh2->biNext &&
FQFOwn(psd, "bi out of bounds", pad, pfi2->nmFile, ped2->nmOwner))
pfs2->bi = bi2Nil;
else if (pfs2->fm == fmMerge &&
!FStatPth(PthForBase(pad, pfs2->bi, pth), &st) &&
FQFOwn(psd, "bi refers to nonexistent base file %d;\nshould clear bi and change to out",
pad, pfi2->nmFile, ped2->nmOwner, pfs2->bi))
{
pfs2->fm = fmOut;
pfs2->bi = bi2Nil;
}
else if (pfs2->fm != fmOut && !FVerifyFm(pfs2->fm) &&
pfs2->fm != fmMerge && pfs2->fm != fmDelOut &&
FQFOwn(psd, "mode not merge or out, but file has bi; should clear bi",
pad, pfi2->nmFile, ped2->nmOwner))
pfs2->bi = bi2Nil;
}
else if (pfs2->fm == fmMerge &&
FQFOwn(psd, "mode is merge, but no base file; should have mode out",
pad, pfi2->nmFile, ped2->nmOwner))
pfs2->fm = fmOut;
if (pfs2->fv > pfi2->fv &&
FQFOwn(psd, "local file version greater than master version",
pad, pfi2->nmFile, ped2->nmOwner))
pfs2->fv = pfi2->fv;
if (pfi2->fv > fvInit && pfs2->fv == pfi2->fv && FOSyncFm(pfs2->fm) &&
FQFOwn(psd, "local file version not less than master version",
pad, pfi2->nmFile, ped2->nmOwner))
pfs2->fv = fvInit;
}
/*VARARGS3*/
private F
FQStat(
SD *psd,
char *szMsg,
// AD *pad,
...)
{
char szBuf[cchMsgMax];
va_list ap;
F f;
strcpy(szBuf, "%&P/C status: ");
strcat(szBuf, szMsg);
va_start(ap, szMsg); //yes, szMsg. VaFqueryPsd only expects 3 parms
f = VaFQueryPsd(psd, szBuf, ap);
va_end(ap);
return f;
}
private void
CheckName(
AD *pad,
SD *psd,
char *szWhat,
char *lsz,
int cchMax,
F (*pfnf)(char *, int, int *),
char *szPrint)
{
F fTrailZ;
char *lpch;
if (!(*pfnf)(lsz, cchMax, &fTrailZ))
{
if (FForce())
{
Error("%s \"%s\" is not proper; not fixed\n", szWhat, szPrint);
fNeedInter = fTrue;
}
else if (FQStat(psd, "%s \"%s\" is not proper", pad, szWhat, szPrint))
{
do
{
ClearLpbCb(lsz, cchMax);
NmCopySz(lsz, SzQuery("Give correct %s: ", szWhat), cchMax);
}
while (!(*pfnf)(lsz, cchMax, &fTrailZ) || !fTrailZ);
return; /* it is valid now */
}
}
if (!fTrailZ &&
FQueryPsd(psd, "%&P/C, %s: non-zero data after %s",
pad, szPrint, szWhat))
{
/* since there is garbage after the name, it must be
* terminated by at least one zero
*/
lpch = LszIndex(lsz, '\0') + 1;
ClearLpbCb(lpch, cchMax - (lpch - lsz));
}
}
/*VARARGS4*/
private F
FQFile(
SD *psd,
char *szMsg,
// AD *pad,
// char *lszFile,
...)
{
char szBuf[cchMsgMax];
va_list ap;
F f;
strcpy(szBuf, "%&P/C, %.14ls: ");
strcat(szBuf, szMsg);
va_start(ap, szMsg); //yes, szMsg. VaFqueryPsd only expects 3 parms
f = VaFQueryPsd(psd, szBuf, ap);
va_end(ap);
return f;
}
/*VARARGS4*/
private F
FQPth(
SD *psd,
char *szMsg,
// AD *pad,
// char *lszPth,
...)
{
char szBuf[cchMsgMax];
va_list ap;
F f;
strcpy(szBuf, "%&P/C, %ls: ");
strcat(szBuf, szMsg);
va_start(ap, szMsg); //yes, szMsg. VaFqueryPsd only expects 3 parms
f = VaFQueryPsd(psd, szBuf, ap);
va_end(ap);
return f;
}
/*VARARGS5*/
private F
FQFOwn(
SD *psd,
char *szMsg,
// AD *pad,
// char *lszFile,
// char *lszOwner,
...)
{
char szBuf[cchMsgMax];
va_list ap;
F f;
strcpy(szBuf, "%&P/C, %.14ls %.14ls: ");
strcat(szBuf, szMsg);
va_start(ap, szMsg); //yes, szMsg. VaFqueryPsd only expects 3 parms
f = VaFQueryPsd(psd, szBuf, ap);
va_end(ap);
return f;
}