mirror of https://github.com/lianthony/NT4.0
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
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;
|
|
}
|