/* This file contains functions specific to version 2 and 3 status files. */ #include "precomp.h" #pragma hdrstop EnableAssert /* tries to determine if stuff in status buffer is a version 2 or greater status file. */ F FIsVer234or5( SD *psd) { return (((SH2 *)psd->hpbStatus)->version == 2 || ((SH2 *)psd->hpbStatus)->version == 3 || ((SH2 *)psd->hpbStatus)->version == 4 || ((SH2 *)psd->hpbStatus)->version == 5); } /* This function tries to determine if a file has been locked by SLM. * It returns the name of whomever has locked the file. * It must be fairly streamlined since the file is open exclusively * while we are testing. */ F FVer2Lock( AD *pad, SD *psd, NM *nm) { SH2 *psh2 = (SH2 *)psd->hpbStatus; if ((psh2->lck == lckNil && !psh2->fAdminLock) || (psh2->fAdminLock && NmCmp(psh2->nmLocker, pad->nmInvoker, cchUserMax) == 0)) return fFalse; /* Get name of locker and return, * printing any messages AFTER flushing */ if (!FEmptyNm(psh2->nmLocker)) NmCopy(nm, psh2->nmLocker, cchUserMax); else if (psh2->lck == lckEd) NmCopySz(nm, "ssync users", cchUserMax); else NmCopySz(nm, "unknown user", cchUserMax); return fTrue; } F FVer2Block( AD *pad, SD *psd) { char *hpbBlock = psd->hpbStatus; unsigned long cbReal, cbCalc; cbReal = CbStatusFromPsh((SH2 *)psd->hpbStatus); cbCalc = CbHugeDiff(psd->hpbStatMac, psd->hpbStatus); if (cbReal == cbCalc) { /* status file is correct size, so assume everything * is in the right place and set up pointers. */ psd->psh2 = (SH2 *)LpbFromHpb(hpbBlock); hpbBlock += sizeof(SH2); psd->rgfi2 = (FI2 *)LpbFromHpb(hpbBlock); hpbBlock = (char *)((FI2 *)hpbBlock + psd->psh2->ifiMac); psd->rged2 = (ED2 *)LpbFromHpb(hpbBlock); hpbBlock = (char *)((ED2 *)hpbBlock + psd->psh2->iedMac); psd->rgfs2 = (FS2 *)LpbFromHpb(hpbBlock); return fTrue; } Error("The status file for %&P/C\n" "\tis the wrong size and can't be fixed by SLMCK.\n" "\tIf subsequent commands continue to report this message,\n" "\tcontact TRIO or NUTS for assistance in resolving the problem.\n", pad); return fFalse; } #if 0 // Old version of FVer2Block, etc: F FVer2Block(pad, psd) /* This function attempts to block the status buffer into its component * pieces: SH, FI, ED, and FS. * At this stage, one major assumption is being made: the entire status file * is a contigous whole. I.e. there may be garbage in the file, the end * or beginning may be chopped off, but there are no missing bytes. Thus * we may increment our pointers in units greater than bytes once we * have blocked something in the file. * * File is blocked using pointers. Once blocking is done, we use * LpbFromHpb to normalize the pointers to before storing them in the * sd. This assumes that no single field of the status file (sh,rgfi,rged, * or rgfs) is greater than 64K, which is also assumed by SLM. * * REVIEW: we should have better recovery for "shift" errors. */ /* might want to check for data loss at the end of each 512 byte sector */ AD *pad; SD *psd; { char *hpbBlock = psd->hpbStatus; short fHaveSh2 = fTrue; /* true if found the SH */ short fHaveFi2 = fTrue; short fHaveEd2 = fTrue; IFI2 cfi2; IED2 ced2; char *hpb; if(fVerbose) PrErr("Blocking status file\n"); /* try to find SH at the start of the buffer */ psd->psh2 = (SH2 *)LpbFromHpb(psd->hpbStatus); if (!FFromSp(SpIsSh2(pad, psd, (SH2 *)psd->hpbStatus))) { // psd->psh2 = NULL; fHaveSh2 = fFalse; } else hpbBlock += sizeof(SH2); /* try to find the FI */ if (fHaveSh2) { psd->rgfi2 = (FI2 *)LpbFromHpb(hpbBlock); cfi2 = Cfi2Block(pad, psd, (FI2 *)hpbBlock); hpbBlock = (char *)((FI2 *)hpbBlock + cfi2); } else { /* start of status file missing or garbage, so search for FI * at every possible place. */ for (hpb = hpbBlock; hpb < psd->hpbStatMac && !FFromSp(SpIsFi2(pad, psd, (FI2 *)hpb, 4)); hpb++) ; if (hpb < psd->hpbStatMac) { psd->rgfi2 = (FI2 *)LpbFromHpb(hpb); cfi2 = Cfi2Block(pad, psd, (FI2 *)hpb); hpbBlock = (char *)((FI2 *)hpb + cfi2); } else { /* found no FI */ cfi2 = 0; fHaveFi2 = fFalse; } } CheckForBreak(); /* try to find ED */ if (fHaveFi2) { psd->rged2 = (ED2 *)LpbFromHpb(hpbBlock); ced2 = Ced2Block(pad, psd, (ED2 *)hpbBlock); hpbBlock = (char *)((ED2 *)hpbBlock + ced2); } else { for (hpb = hpbBlock; hpb < psd->hpbStatMac; hpb++) { CheckForBreak(); if (FFromSp(SpIsEd2(psd, (ED2 *)hpb, 3))) break; } if (hpb != psd->hpbStatMac) { psd->rged2 = (ED2 *)LpbFromHpb(hpb); ced2 = Ced2Block(pad, psd, (ED2 *)hpb); hpbBlock = (char *)((ED2 *)hpb + ced2); } else { ced2 = 0; fHaveEd2 = fFalse; } } /* rest should be FS */ psd->rgfs2 = (FS2 *)LpbFromHpb(hpbBlock); return (fHaveSh2 && fHaveFi2 && fHaveEd2); } private IFI2 Cfi2Block(pad, psd, pfi2Min) /* This function uses the value of pfi2Min to find a vector of FI2 in the * status file. We return the number in the vector. Note that some of * these may be garbage. */ AD *pad; SD *psd; FI2 *pfi2Min; { FI2 *pfi2; char *hpb = NULL; IFI2 ifi2; SP spT; /* for checking things */ for (pfi2 = pfi2Min; CbHugeDiff(pfi2, psd->hpbStatMac) < 0; pfi2++) { if(!FFromSp(SpIsFi2(pad, psd, pfi2, 2))) { if (FFromSp(SpIsEd2(psd, (ED2 *)pfi2, 2))) break; /* done with FI */ /* problem: something not FI or ED. * Must be a bad interval in the file. */ hpb = HpbVer2FindBlock(pad, psd, (char *)pfi2); /* check that have Fi and that it is aligned */ if (FFromSp(SpIsFi2(pad, psd, (FI2 *)hpb, 2))) break; else { pfi2 = (FI2 *)hpb; hpb = NULL; } } } /* Three ways to get out of loop: done with whole buffer; good vector * of FI, ending with an ED; and some FI followed by garbage, followed * by something that is not an FI. */ AssertF(CbHugeDiff(pfi2, psd->hpbStatMac) <= 0); if (CbHugeDiff(psd->hpbStatMac, pfi2) == 0) /* things exactly right, no ED */ return (IFI2)(long)(pfi2 - pfi2Min); /* if have ED, make sure really at end of rgfi */ else if (FFromSp(spT = (SpIsEd2(psd, (ED2 *)pfi2, 5)))) { if (spT == spDefYes || (IFI2)(pfi2 - pfi2Min) == (IFI2)(psd->psh2->ifiMac)) return (IFI2)(long)(pfi2 - pfi2Min); else { /* possibility of mistake, double check */ for (ifi2 = 0; ifi2 <= 8 && SpIsFi2(pad, psd, (FI2 *)pfi2 + ifi2, 3) != spDefYes; ifi2++) ; if (ifi2 > 8) /* no mistake */ return (IFI2)(long)(pfi2 - pfi2Min); else /* problem: found definite FI after the ED. * Assume that ED was incorrect, really bad * FI. Recurse to get rest of FI and return. */ if (pfi2 == pfi2Min) return (1+Cfi2Block(pad, psd, ++pfi2)); else return (IFI2)(long)((pfi2 - pfi2Min) + Cfi2Block(pad, psd, pfi2)); } } else { /* don't know exact end of FI so assume ifiMac is correct, * unless what we do know precludes this. In that case assume * FI end where garbage begins. */ AssertF(hpb && CbHugeDiff(hpb, pfi2) > 0); if ((IFI2)(psd->psh2->ifiMac) < (IFI2)((FI2 *)hpb - pfi2Min) && (IFI2)(psd->psh2->ifiMac) > (IFI2)(pfi2 - pfi2Min)) /* ifiMac says end of FI in garbage */ return psd->psh2->ifiMac; else return (IFI2)(long)(pfi2 - pfi2Min); } } private IED2 Ced2Block(pad, psd, ped2Min) /* This function is almost identical to Cfi2Block, except it works on ED. */ AD *pad; SD *psd; ED2 *ped2Min; { ED2 *ped2; char *hpb = NULL; IED2 ied2; SP spT; /* for checking things */ for (ped2 = ped2Min; CbHugeDiff(ped2, psd->hpbStatMac) < 0; ped2++) { if(!FFromSp(SpIsEd2(psd, ped2, 2))) { if (FFromSp(SpIsFs2(psd, (FS2 *)ped2, 8))) break; /* done with ED */ /* problem: something not ED or FS. * Must be a bad interval in the file. */ hpb = HpbVer2FindBlock(pad, psd, (char *)ped2); if (!FFromSp(SpIsEd2(psd, (ED2 *)hpb, 2))) break; else { ped2 = (ED2 *)hpb; hpb = NULL; } } } /* Three ways to get of loop: done with whole buffer; good vector of * of ED, ending with an FS; and some ED followed by garbage, followed * by something that is not an ED. */ AssertF(CbHugeDiff(ped2, psd->hpbStatMac) <= 0); if (CbHugeDiff(psd->hpbStatMac,ped2) == 0) /* things exactly right, no FS */ return (IED2)(long)(ped2 - ped2Min); /* if have FS, make sure really at end of rged */ else if (FFromSp(spT = (SpIsFs2(psd, (FS2 *)ped2, 8)))) { if (spT == spDefYes || ped2 - ped2Min == (int)psd->psh2->iedMac) return (IED2)(long)(ped2 - ped2Min); else { /* possibility of mistake, double check */ for (ied2 = 0; ied2 <= 8 && SpIsFs2(psd, (FS2 *)(ped2 + ied2), 8) != spDefYes; ied2++) ; if (ied2 > 8) /* no mistake */ return (IED2)(long)(ped2 - ped2Min); else /* problem: found definite FS after the ED. * Assume that FS was incorrect, really bad * ED. Recurse to get rest of ED and return. */ if (ped2 == ped2Min) return 0; return (IED2)(long)((ped2 - ped2Min) + Ced2Block(pad, psd, ped2)); } } else { /* don't know exact end of ED so assume iedMac is correct, * unless what we do know precludes this. In that case assume * ED end where garbage begins. */ AssertF(CbHugeDiff(hpb, ped2) > 0); if ((int)psd->psh2->iedMac < (ED2 *)hpb - ped2Min && (int)psd->psh2->iedMac > ped2 - ped2Min) /* iedMac says end of ED in garbage */ return (int)psd->psh2->iedMac; else return (IED2)(long)(ped2 - ped2Min); } } private char *HpbVer2FindBlock(pad, psd, hpb) /* This function goes over the status buffer until it encounters an FI2, ED2, * FS2, or the end of the buffer. We assume that we are "aligned" with the * structures. Thus we increment the index and check for structures if the * size of the structure in the buffer divides the index. * NB: We start the search after the current place in the status buffer * because the calling function should have checked the currrent position * for acceptable structures. Thus ret > pb. */ AD *pad; SD *psd; char *hpb; { long ib; /* position in buffer */ for(ib = 1, hpb++; CbHugeDiff(hpb, psd->hpbStatMac) < 0 && (ib % sizeof(FI2) || !FFromSp(SpIsFi2(pad, psd, (FI2 *)hpb, 2))) && (ib % sizeof(ED2) || !FFromSp(SpIsEd2(psd, (ED2 *)hpb, 2))) && (ib % sizeof(FS2) || !FFromSp(SpIsFs2(psd, (FS2 *)hpb, 9))) ; ib++, hpb++) ; return hpb; } private SP SpIsSh2(pad, psd, psh2) /* Tries to determine if psh2 really points to an SH2 or not. * At this point we KNOW the version number, we only wish to block the buffer, * so we only need to know if this is an SH2. */ AD *pad; SD *psd; SH2 *psh2; { F fTrailZ; WP wp; if (CbHugeDiff((char *)psh2 + sizeof(SH2), psd->hpbStatMac) > 0) return spDefNo; InitWp(&wp); AddWpF(&wp, twCrucial, psh2->magic == MAGIC); AddWpF(&wp, twCrucial, psh2->version == 2); fTrailZ = FAllZero(LpbFromHpb((char *)psh2->nmLocker), cchUserMax); AddWpF(&wp, twMedium, fTrailZ || FIsNm(psh2->nmLocker, cchUserMax, &fTrailZ)); AddWpF(&wp, fTrailZ ? twMedium : twLight, fTrailZ); AddWpF(&wp, twMedium, FAllZero(LpbFromHpb((char *)psh2->rgwSpare), sizeof(psh2->rgwSpare))); /* check for FI immeadiately after SH */ if (psh2->ifiMac > 1 && (int)psh2->iedMac > 1) AddWpSp(&wp, twHeavy, SpIsFi2(pad, psd, (FI2 *)(psh2 + 1), 2)); /* pv.szName is often empty */ if (FAllZero(LpbFromHpb((char *)psh2->pv.szName), cchPvNameMax)) AddWpF(&wp, twMedium, fTrue); AddWpF(&wp, twHeavy, FIsF(psh2->fRelease)); AddWpF(&wp, twHeavy, FIsF(psh2->fAdminLock)); AddWpF(&wp, twMedium, psh2->lck >= lckNil && psh2->lck < lckMax); AddWpF(&wp, twMedium, FIsPth(psh2->pthSSubDir, cchPthMax, &fTrailZ)); return SpFromWp(&wp); } private SP SpIsFi2(AD *pad, SD *psd, FI2 *pfi2, IFI2 cfiCheck) /* checks if pfi2 points to a version 2 FI. Part of the check involves * seeing if the next part of the buffer is either an FI2 xor an ED2. * The variable cfiCheck keeps track of the depth of the check so we don't * go through the entire buffer each time. */ { short fHaveEd2 = fFalse; short fHaveFs2 = fFalse; F fTrailZ; SP sp; PTH pth[cchPthMax]; struct stat st; char szFile[cchFileMax]; WP wp; InitWp(&wp); /* normalize so field accesses are guaranteed */ pfi2 = (FI2 *)LpbFromHpb((char *)pfi2); if (CbHugeDiff(pfi2, psd->hpbStatus) < 0|| CbHugeDiff(pfi2, psd->hpbStatMac - sizeof(FI2)) > 0) return spDefNo; AddWpF(&wp, twHeavy, FIsFileNm(pfi2->nmFile, cchFileMax, &fTrailZ)); AddWpF(&wp, fTrailZ ? twHeavy : twMedium, fTrailZ); /* if not Deleted, see if nmFile is the name of an existing file */ if (!pfi2->fDeleted) { SzCopyNm(szFile, pfi2->nmFile, cchFileMax); SzPrint(pth, szSrcPZ, pad, szFile); AddWpF(&wp, twCrucial, FStatPth(pth, &st)); } AddWpF(&wp, twMedium, pfi2->fk >= fkMin && pfi2->fk < fkMax); if (pfi2->fk == fkDir && !pfi2->fDeleted) AddWpF(&wp, twHeavy, (st.st_mode & S_IFDIR) == S_IFDIR); AddWpF(&wp, twLight, pfi2->wSpare == 0); while (cfiCheck--) { if (!fHaveEd2 && !fHaveFs2 && CbHugeDiff(pfi2+1, psd->hpbStatMac) < 0) { if (!FFromSp(sp = SpIsFi2(pad, psd, pfi2 + 1, 0))) fHaveEd2 = fTrue; else { AddWpSp(&wp, twMedium, sp); ++pfi2; } } } return SpFromWp(&wp); } private SP SpIsEd2(SD *psd, ED2 *ped2, IED2 cedCheck) /* This function checks if ped2 points to an ED2. As in the case for the FI, * we see if the thing after it is also an ED2 xor an FS2, and we use * the static variable cedCheck to count the depth of our check. */ { int fTrailZ; SP sp; short fHaveFs2 = fFalse; WP wp; InitWp(&wp); /* normalize so field accesses are guaranteed */ ped2 = (ED2 *)LpbFromHpb((char *)ped2); if (CbHugeDiff(ped2, psd->hpbStatus) < 0 || CbHugeDiff(ped2, psd->hpbStatMac-sizeof(ED2)) > 0) return spDefNo; /* make sure enough ED to test */ if ((IED2)psd->psh2->iedMac < cedCheck) cedCheck = psd->psh2->iedMac; AddWpF(&wp, twCrucial, FIsPth(ped2->pthEd, cchPthMax, &fTrailZ)); AddWpF(&wp, fTrailZ ? twCrucial : twMedium, fTrailZ); /* see if nmOwner is a valid Nm */ AddWpF(&wp, twCrucial, FIsNm(ped2->nmOwner, cchUserMax, &fTrailZ)); AddWpF(&wp, fTrailZ ? twCrucial : twMedium, fTrailZ); AddWpF(&wp, twMedium, FIsF(ped2->fNewVer)); /* these are 1 bit fields */ AddWpF(&wp, twLight, ped2->wSpare == 0); while (cedCheck--) { if (!fHaveFs2 && CbHugeDiff((ED2 *)ped2+1, psd->hpbStatMac) < 0) { if (!FFromSp(sp = SpIsEd2(psd, ped2, 0))) fHaveFs2 = fTrue; else { ++ped2; AddWpSp(&wp, twMedium, sp); } } if (fHaveFs2 && CbHugeDiff((FS2 *)ped2+1, psd->hpbStatMac) < 0) { ped2 = (ED2 *)((FS2 *)ped2 + 1); AddWpSp(&wp, twMedium, SpIsFs2(psd, (FS2 *)(FS2 *)ped2, 0)); } } return SpFromWp(&wp); } private SP SpIsFs2(SD *psd, FS2 *pfs2, IFS2 cfsCheck) /* This tests to see if pfs2 points to an FS2. As before, cfsCheck is used * to see how down the buffer we are going to check. Here we see if * the thing after the assumed FS2 is another FS xor past the end of the * status buffer. */ { WP wp; InitWp(&wp); // AssertF(cfsCheck >= 0); cfsCheck is unsigned /* normalize so field accesses are guaranteed */ pfs2 = (FS2 *)LpbFromHpb((char *)pfs2); if (CbHugeDiff(pfs2, psd->hpbStatus) < 0 || CbHugeDiff(pfs2, psd->hpbStatMac-sizeof(FS2)) > 0) return spDefNo; AddWpF(&wp, twHeavy, FValidFm(pfs2->fm)); if (pfs2->fm == fmIn || pfs2->fm == fmDelIn || pfs2->fm == fmCopyIn || pfs2->fm == fmGhost || pfs2->fm == fmNonExistent) { AddWpF(&wp, twHeavy, pfs2->bi == biNil); } else if (pfs2->fm == fmMerge || pfs2->fm == fmVerify || pfs2->fm == fmConflict) AddWpF(&wp, twHeavy, pfs2->bi != biNil); while (cfsCheck-- && CbHugeDiff(++pfs2, psd->hpbStatMac) < 0) AddWpSp(&wp, twMedium, SpIsFs2(psd, ++pfs2, 0)); return SpFromWp(&wp); } #endif /* 0 */