From 8b29199ddd498ee4a8404891208453416fab1345 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Wed, 2 Oct 2024 18:36:58 +0200 Subject: [PATCH 1/4] c4group: Add AddMissingTarget to AutoUpdate.txt and expose it in c4group to allow update groups to work even if the target is missing --- src/C4Update.cpp | 70 ++++++++++++++++++++++++++++++++-------------- src/C4Update.h | 3 +- src/c4group_ng.cpp | 4 +-- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/src/C4Update.cpp b/src/C4Update.cpp index ff154eef8..27f6685ba 100644 --- a/src/C4Update.cpp +++ b/src/C4Update.cpp @@ -226,6 +226,7 @@ void C4UpdatePackageCore::CompileFunc(StdCompiler *pComp) pComp->Value(mkNamingAdapt(toC4CStr(DestPath), "DestPath", "")); pComp->Value(mkNamingAdapt(GrpUpdate, "GrpUpdate", 0)); pComp->Value(mkNamingAdapt(UpGrpCnt, "TargetCount", 0)); + pComp->Value(mkNamingAdapt(AllowMissingTarget, "AllowMissingTarget", false)); pComp->Value(mkNamingAdapt(mkArrayAdapt(GrpChks1, 0u), "GrpChks1")); pComp->Value(mkNamingAdapt(GrpChks2, "GrpChks2", 0u)); pComp->Value(mkNamingAdapt(mkArrayAdapt(GrpContentsCRC1, 0u), "GrpContentsCRC1")); @@ -325,31 +326,44 @@ bool C4UpdatePackage::Execute(C4Group *pGroup) } // try to open it + bool targetMissing{false}; if (!TargetGrp.Open(strTarget, !GrpUpdate)) - return false; + { + if (AllowMissingTarget && !ItemExists(strTarget) && TargetGrp.Open(strTarget, true)) + { + targetMissing = true; + } + else + { + return false; + } + } // check if the update is allowed if (GrpUpdate) { - // check checksum - uint32_t iContentsCRC32; - if (!C4Group_GetFileContentsCRC(TargetGrp.GetFullName().getData(), &iContentsCRC32)) - return false; - int i = 0; - for (; i < UpGrpCnt; i++) - if (GrpContentsCRC1[i] && iContentsCRC32 == GrpContentsCRC1[i]) - break; - if (i >= UpGrpCnt) + if (!targetMissing) { - uint32_t iCRC32; - if (!C4Group_GetFileCRC(TargetGrp.GetFullName().getData(), &iCRC32)) + // check checksum + uint32_t iContentsCRC32; + if (!C4Group_GetFileContentsCRC(TargetGrp.GetFullName().getData(), &iContentsCRC32)) return false; int i = 0; for (; i < UpGrpCnt; i++) - if (iCRC32 == GrpChks1[i]) + if (GrpContentsCRC1[i] && iContentsCRC32 == GrpContentsCRC1[i]) break; if (i >= UpGrpCnt) - return false; + { + uint32_t iCRC32; + if (!C4Group_GetFileCRC(TargetGrp.GetFullName().getData(), &iCRC32)) + return false; + int i = 0; + for (; i < UpGrpCnt; i++) + if (iCRC32 == GrpChks1[i]) + break; + if (i >= UpGrpCnt) + return false; + } } } else @@ -438,7 +452,17 @@ C4UpdatePackage::CheckResult C4UpdatePackage::Check(C4Group *pGroup) // check source file C4Group TargetGrp; if (!TargetGrp.Open(DestPath)) - return CheckResult::NoSource; + { + // make sure corrupted target files aren't overwritten + if (AllowMissingTarget && !ItemExists(DestPath)) + { + return CheckResult::Ok; + } + else + { + return CheckResult::NoSource; + } + } if (!TargetGrp.IsPacked()) return CheckResult::BadSource; TargetGrp.Close(); @@ -624,7 +648,7 @@ bool C4UpdatePackage::Optimize(C4Group *pGrpFrom, C4GroupEx *pGrpTo, const char return true; } -bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName) +bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName, const bool allowMissingTarget) { // open Log if (!Log.Create("Update.log")) @@ -699,6 +723,7 @@ bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, con } UpGrpCnt++; + AllowMissingTarget = allowMissingTarget; // save core if (!C4UpdatePackageCore::Save(UpGroup)) @@ -749,7 +774,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo if (!entryList.empty()) entryList += '|'; entryList += std::format("{}={}", strItemName, pGrp2->EntryTime(strItemName)); // no modification detected yet? then check order - if (!*fModified) + if (!AllowMissingTarget && !*fModified) { if (!pGrp1->FindNextEntry("*", strItemName2, nullptr, nullptr, !!strItemName2[0])) *fModified = true; @@ -786,8 +811,9 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo extern const char **C4Group_SortList; UpdGroup.SortByList(C4Group_SortList, ChildGrp2.GetName()); UpdGroup.Close(false); - // check entry times - if (!pGrp1 || (pGrp1->EntryTime(strItemName) != pGrp2->EntryTime(strItemName))) + // always add the entire group if mising targets are allowed + // otherwise check entry times + if (AllowMissingTarget || !pGrp1 || (pGrp1->EntryTime(strItemName) != pGrp2->EntryTime(strItemName))) Modified = true; // add group (if modified) if (fSuccess && Modified) @@ -818,7 +844,8 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo else { // compare them (size & crc32) - if (!pGrp1 || + if (AllowMissingTarget || + !pGrp1 || pGrp1->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) || pGrp1->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName)) { @@ -828,7 +855,8 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo pUpGrp->SaveEntryCore(*pGrp2, strItemName); // already in update grp? - if (pUpGrp->EntryTime(strItemName) != pGrp2->EntryTime(strItemName) || + if (AllowMissingTarget || + pUpGrp->EntryTime(strItemName) != pGrp2->EntryTime(strItemName) || pUpGrp->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) || pUpGrp->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName)) { diff --git a/src/C4Update.h b/src/C4Update.h index e2c2d015d..b3b12779e 100644 --- a/src/C4Update.h +++ b/src/C4Update.h @@ -34,6 +34,7 @@ class C4UpdatePackageCore char DestPath[_MAX_PATH + 1]; int32_t GrpUpdate; int32_t UpGrpCnt; // number of file versions that can be updated by this package + bool AllowMissingTarget; // if true, missing target files are not considered an error uint32_t GrpChks1[C4UP_MaxUpGrpCnt], GrpChks2; uint32_t GrpContentsCRC1[C4UP_MaxUpGrpCnt], GrpContentsCRC2; @@ -59,7 +60,7 @@ class C4UpdatePackage : public C4UpdatePackageCore bool Execute(C4Group *pGroup); static bool Optimize(C4Group *pGrpFrom, const char *strTarget); CheckResult Check(C4Group *pGroup); - bool MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName = nullptr); + bool MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName, bool allowMissingTarget); protected: bool DoUpdate(C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName); diff --git a/src/c4group_ng.cpp b/src/c4group_ng.cpp index e67a7cfba..793499527 100644 --- a/src/c4group_ng.cpp +++ b/src/c4group_ng.cpp @@ -363,7 +363,7 @@ bool ProcessGroup(const char *FilenamePar) std::println(stderr, "Closing failed: {}", hGroup.GetError()); } // generate - else if (!Upd.MakeUpdate(argv[iArg + 1], argv[iArg + 2], szFilename, argv[iArg + 3])) + else if (!Upd.MakeUpdate(argv[iArg + 1], argv[iArg + 2], szFilename, argv[iArg + 3], argv[iArg][2] == 'a')) { std::println(stderr, "Update generation failed."); } @@ -645,7 +645,7 @@ int main(int argc, char *argv[]) std::println(" -v View -l List -d Delete -r Rename -s Sort"); std::println(" -p Pack -u Unpack -x Explode"); std::println(" -k Print maker"); - std::println(" -g [source] [target] [title] Make update"); + std::println(" -g[a] [source] [target] [title] Make update [allow missing target]"); std::println(" -y[d] Apply update [and delete group file]"); std::println(""); std::println("Options: -v Verbose -r Recursive -p Prompt at end"); From 994055c142b4bf970cc859b14926e4b35ee3a0ed Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Sun, 13 Oct 2024 16:11:46 +0200 Subject: [PATCH 2/4] Rename fModified to includeInUpdate --- src/C4Update.cpp | 30 +++++++++++++++--------------- src/C4Update.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/C4Update.cpp b/src/C4Update.cpp index 27f6685ba..4ffe76fdb 100644 --- a/src/C4Update.cpp +++ b/src/C4Update.cpp @@ -732,8 +732,8 @@ bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, con } // compare groups, create update - bool fModified = false; - bool fSuccess = MkUp(&Group1, &Group2, &UpGroup, &fModified); + bool includeInUpdate{false}; + bool fSuccess = MkUp(&Group1, &Group2, &UpGroup, includeInUpdate); // close (save) it UpGroup.Close(false); // error? @@ -748,7 +748,7 @@ bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, con return true; } -bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bool *fModified) +bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bool &includeInUpdate) { // (CAUTION: pGrp1 may be nullptr - that means that there is no counterpart for Grp2 // in the base group) @@ -759,14 +759,14 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo pGrp1->GetOriginal() != pGrp2->GetOriginal() || !SEqual(pGrp1->GetMaker(), pGrp2->GetMaker()) || !SEqual(pGrp1->GetPassword(), pGrp2->GetPassword())) - *fModified = true; + includeInUpdate = true; // set header pUpGrp->SetHead(*pGrp2); // compare entries char strItemName[_MAX_PATH], strItemName2[_MAX_PATH]; std::string entryList; strItemName[0] = strItemName2[0] = 0; - pGrp2->ResetSearch(); if (!*fModified) pGrp1->ResetSearch(); + pGrp2->ResetSearch(); if (!includeInUpdate) pGrp1->ResetSearch(); int iChangedEntries = 0; while (pGrp2->FindNextEntry("*", strItemName, nullptr, nullptr, !!strItemName[0])) { @@ -774,12 +774,12 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo if (!entryList.empty()) entryList += '|'; entryList += std::format("{}={}", strItemName, pGrp2->EntryTime(strItemName)); // no modification detected yet? then check order - if (!AllowMissingTarget && !*fModified) + if (!AllowMissingTarget && !includeInUpdate) { if (!pGrp1->FindNextEntry("*", strItemName2, nullptr, nullptr, !!strItemName2[0])) - *fModified = true; + includeInUpdate = true; else if (!SEqual(strItemName, strItemName2)) - *fModified = true; + includeInUpdate = true; } // TODO: write DeleteEntries.txt @@ -805,8 +805,8 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo if (!UpdGroup.Open(strTempGroupName, true)) { delete pChildGrp1; WriteLog("Error: could not create temp group\n"); return false; } } // do nested MkUp-search - bool Modified = false; - bool fSuccess = MkUp(pChildGrp1, &ChildGrp2, &UpdGroup, &Modified); + bool childIncludeInUpdate{false}; + bool fSuccess = MkUp(pChildGrp1, &ChildGrp2, &UpdGroup, childIncludeInUpdate); // sort & close extern const char **C4Group_SortList; UpdGroup.SortByList(C4Group_SortList, ChildGrp2.GetName()); @@ -814,9 +814,9 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo // always add the entire group if mising targets are allowed // otherwise check entry times if (AllowMissingTarget || !pGrp1 || (pGrp1->EntryTime(strItemName) != pGrp2->EntryTime(strItemName))) - Modified = true; + childIncludeInUpdate = true; // add group (if modified) - if (fSuccess && Modified) + if (fSuccess && childIncludeInUpdate) { if (strTempGroupName[0]) if (!pUpGrp->Move(strTempGroupName, strItemName)) @@ -828,7 +828,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo pUpGrp->SaveEntryCore(*pGrp2, strItemName); pUpGrp->SetSavedEntryCore(strItemName); // got a modification in a subgroup - *fModified = true; + includeInUpdate = true; iChangedEntries++; } else @@ -869,7 +869,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo // set entry core pUpGrp->SetSavedEntryCore(strItemName); // modified... - *fModified = true; + includeInUpdate = true; fCopied = true; } iChangedEntries++; @@ -887,7 +887,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo } if (iChangedEntries > 0) - WriteLog("{}: {}/{} changed ({})\n", pGrp2->GetFullName().getData(), iChangedEntries, pGrp2->EntryCount(), *fModified ? "update" : "skip"); + WriteLog("{}: {}/{} changed ({})\n", pGrp2->GetFullName().getData(), iChangedEntries, pGrp2->EntryCount(), includeInUpdate ? "update" : "skip"); // success return true; diff --git a/src/C4Update.h b/src/C4Update.h index b3b12779e..173dd8174 100644 --- a/src/C4Update.h +++ b/src/C4Update.h @@ -67,7 +67,7 @@ class C4UpdatePackage : public C4UpdatePackageCore bool DoGrpUpdate(C4Group *pUpdateData, class C4GroupEx *pGrpTo); static bool Optimize(C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName); - bool MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGr, bool *fModified); + bool MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGr, bool &includeInUpdate); CStdFile Log; From 239902bc883dd1d70d237c719e0d11ab6807c9de Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Sun, 13 Oct 2024 16:11:59 +0200 Subject: [PATCH 3/4] Fix typo in comment --- src/C4Update.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C4Update.cpp b/src/C4Update.cpp index 4ffe76fdb..ae7626cbc 100644 --- a/src/C4Update.cpp +++ b/src/C4Update.cpp @@ -811,7 +811,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo extern const char **C4Group_SortList; UpdGroup.SortByList(C4Group_SortList, ChildGrp2.GetName()); UpdGroup.Close(false); - // always add the entire group if mising targets are allowed + // always add the entire group if missing targets are allowed // otherwise check entry times if (AllowMissingTarget || !pGrp1 || (pGrp1->EntryTime(strItemName) != pGrp2->EntryTime(strItemName))) childIncludeInUpdate = true; From efd162e171de60f1880b9f68da663d0e2d021d8a Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Sun, 13 Oct 2024 16:13:09 +0200 Subject: [PATCH 4/4] c4group: Improve help message of -ga --- src/c4group_ng.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c4group_ng.cpp b/src/c4group_ng.cpp index 793499527..a13a325f1 100644 --- a/src/c4group_ng.cpp +++ b/src/c4group_ng.cpp @@ -645,7 +645,7 @@ int main(int argc, char *argv[]) std::println(" -v View -l List -d Delete -r Rename -s Sort"); std::println(" -p Pack -u Unpack -x Explode"); std::println(" -k Print maker"); - std::println(" -g[a] [source] [target] [title] Make update [allow missing target]"); + std::println(" -g[a] [source] [target] [title] Make update [and allow missing target group when applying update]"); std::println(" -y[d] Apply update [and delete group file]"); std::println(""); std::println("Options: -v Verbose -r Recursive -p Prompt at end");