bool C4Group_ApplyUpdate(C4Group &hGroup) { // Process object update group (GRPUP_Entries.txt found) C4UpdatePackage Upd; if (hGroup.FindEntry(C4CFN_UpdateEntries)) if (Upd.Load(&hGroup)) { // Do update check first (ensure packet has everything it needs in order // to perfom the update) int iRes = Upd.Check(&hGroup); switch (iRes) { // Bad version - checks against version of the applying executable // (major version must match, minor version must be equal or higher) case C4UPD_CHK_BAD_VERSION: fprintf(stderr, "This update %s can only be applied using version " "%d.%d.%d.%d or higher.\n", Upd.Name, Upd.RequireVersion[0], Upd.RequireVersion[1], Upd.RequireVersion[2], Upd.RequireVersion[3]); return false; // Target not found: keep going case C4UPD_CHK_NO_SOURCE: fprintf(stderr, "Target %s for update %s not found. Ignoring.\n", Upd.DestPath, Upd.Name); return true; // Target mismatch: abort updating case C4UPD_CHK_BAD_SOURCE: fprintf(stderr, "Target %s incorrect version for update %s. Ignoring.\n", Upd.DestPath, Upd.Name); return true; // Target already updated: keep going case C4UPD_CHK_ALREADY_UPDATED: fprintf(stderr, "Target %s already up-to-date at %s.\n", Upd.DestPath, Upd.Name); return true; // Ok to perform update case C4UPD_CHK_OK: printf("Updating %s to %s... ", Upd.DestPath, Upd.Name); // Make sure the user sees the message while the work is in progress fflush(stdout); // Execute update if (Upd.Execute(&hGroup)) { printf("Ok\n"); return true; } else { printf("Failed\n"); return false; } // Unknown return value from update default: fprintf(stderr, "Unknown error while updating.\n"); return false; } } // Process binary update group (AutoUpdate.txt found, additional binary files // found) if (hGroup.EntryCount(C4CFN_UpdateCore)) if (hGroup.EntryCount() - hGroup.EntryCount(C4CFN_UpdateCore) - hGroup.EntryCount("*.c4u") > 0) { // Notice: AutoUpdate.txt is currently not processed... char strEntry[_MAX_FNAME + 1] = ""; StdStrBuf strList; printf("Updating binaries...\n"); hGroup.ResetSearch(); // Look for binaries while (hGroup.FindNextEntry("*", strEntry)) // Accept everything except *.c4u, AutoUpdate.txt, and c4group.exe // (which is assumed not to work under Windows) if (!WildcardMatch("*.c4u", strEntry) && !WildcardMatch(C4CFN_UpdateCore, strEntry) && !WildcardMatch("c4group.exe", strEntry)) { strList += strEntry; strList += ";"; } // Extract binaries to current working directory if (!hGroup.Extract(strList.getData())) return false; // If extracted file is a group, explode it (this is meant for Clonk.app // on Mac) for (int i = 0; SGetModule(strList.getData(), i, strEntry); i++) if (C4Group_IsGroup(strEntry)) { printf("Exploding: %s\n", strEntry); if (!C4Group_ExplodeDirectory(strEntry)) return false; } } // Process any child updates (*.c4u) if (hGroup.FindEntry("*.c4u")) { // Process all children char strEntry[_MAX_FNAME + 1] = ""; C4Group hChild; hGroup.ResetSearch(); while (hGroup.FindNextEntry("*.c4u", strEntry)) if (hChild.OpenAsChild(&hGroup, strEntry)) { bool ok = C4Group_ApplyUpdate(hChild); hChild.Close(); // Failure on child update if (!ok) return false; } } // Success return true; }
bool C4Group_ApplyUpdate(C4Group &hGroup, unsigned long ParentProcessID) { // Wait for parent process to terminate (so we can safely replace the executable) #ifdef _WIN32 if(ParentProcessID) { HANDLE ParentProcess = OpenProcess(SYNCHRONIZE, FALSE, ParentProcessID); if(ParentProcess) { // If we couldn't find a handle then either // a) the process terminated already, which is great. // b) OpenProcess() failed, which is not so great. But let's still try to do // the update. printf("Waiting for parent process to terminate..."); DWORD res = WaitForSingleObject(ParentProcess, 10000); if(res == WAIT_TIMEOUT) fprintf(stderr, "Parent process did not terminate after 10 seconds. Continuing..."); } } #else // We could use waitpid on Unix, but we don't need that functionality there anyway... #endif // Process object update group (GRPUP_Entries.txt found) C4UpdatePackage Upd; if (hGroup.FindEntry(C4CFN_UpdateEntries)) if (Upd.Load(&hGroup)) { // Do update check first (ensure packet has everything it needs in order to perfom the update) int iRes = Upd.Check(&hGroup); switch (iRes) { // Bad version - checks against version of the applying executable (major version must match, minor version must be equal or higher) case C4UPD_CHK_BAD_VERSION: fprintf(stderr, "This update %s can only be applied using version %d.%d.%d.%d or higher.\n", Upd.Name, Upd.RequireVersion[0], Upd.RequireVersion[1], Upd.RequireVersion[2], Upd.RequireVersion[3]); return false; // Target not found: keep going case C4UPD_CHK_NO_SOURCE: fprintf(stderr, "Target %s for update %s not found. Ignoring.\n", Upd.DestPath, Upd.Name); return true; // Target mismatch: abort updating case C4UPD_CHK_BAD_SOURCE: fprintf(stderr, "Target %s incorrect version for update %s. Ignoring.\n", Upd.DestPath, Upd.Name); return true; // Target already updated: keep going case C4UPD_CHK_ALREADY_UPDATED: fprintf(stderr,"Target %s already up-to-date at %s.\n", Upd.DestPath, Upd.Name); return true; // Ok to perform update case C4UPD_CHK_OK: printf("Updating %s to %s... ", Upd.DestPath, Upd.Name); // Make sure the user sees the message while the work is in progress fflush(stdout); // Execute update if (Upd.Execute(&hGroup)) { printf("Ok\n"); return true; } else { printf("Failed\n"); return false; } // Unknown return value from update default: fprintf(stderr,"Unknown error while updating.\n"); return false; } } // Process binary update group (AutoUpdate.txt found, additional binary files found) if (hGroup.EntryCount(C4CFN_UpdateCore)) if (hGroup.EntryCount() - hGroup.EntryCount(C4CFN_UpdateCore) - hGroup.EntryCount("*.ocu") > 0) { // Notice: AutoUpdate.txt is currently not processed... char strEntry[_MAX_FNAME + 1] = ""; StdStrBuf strList; printf("Updating binaries...\n"); hGroup.ResetSearch(); // Look for binaries while (hGroup.FindNextEntry("*", strEntry)) // Accept everything except *.ocu, AutoUpdate.txt, and c4group.exe (which is assumed not to work under Windows) if (!WildcardMatch("*.ocu", strEntry) && !WildcardMatch(C4CFN_UpdateCore, strEntry) && !WildcardMatch("c4group.exe", strEntry)) { strList += strEntry; strList += ";"; } // Extract binaries to current working directory if (!hGroup.Extract(strList.getData())) return false; // If extracted file is a group, explode it (this is meant for Clonk.app on Mac) for (int i = 0; SGetModule(strList.getData(), i, strEntry); i++) if (C4Group_IsGroup(strEntry)) { printf("Exploding: %s\n", strEntry); if (!C4Group_ExplodeDirectory(strEntry)) return false; } } // Process any child updates (*.ocu) if (hGroup.FindEntry("*.ocu")) { // Process all children char strEntry[_MAX_FNAME + 1] = ""; C4Group hChild; hGroup.ResetSearch(); while (hGroup.FindNextEntry("*.ocu", strEntry)) if (hChild.OpenAsChild(&hGroup, strEntry)) { bool ok = C4Group_ApplyUpdate(hChild, 0); hChild.Close(); // Failure on child update if (!ok) return false; } } // Success return true; }