diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 0f5ee47ff..63b2d5a37 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -1860,6 +1860,7 @@ static package_t *PM_MarkedPackage(const char *packagename, int markflag) static void PM_RevertChanges(void) { package_t *p; + int us = parse_revision_number(enginerevision, true), them; if (pkg_updating) return; @@ -1868,7 +1869,8 @@ static void PM_RevertChanges(void) { if (p->flags & DPF_ENGINE) { - if (!(p->flags & DPF_HIDDEN) && !strcmp(enginerevision, p->version) && (p->flags & DPF_PRESENT)) + them = parse_revision_number(p->version, true); + if (!(p->flags & DPF_HIDDEN) && us && us==them && (p->flags & DPF_PRESENT)) p->flags |= DPF_AUTOMARKED; else p->flags &= ~DPF_MARKED; @@ -2102,6 +2104,8 @@ unsigned int PM_MarkUpdates (void) { unsigned int changecount = 0; package_t *p, *o, *b, *e = NULL; + int bestengine = parse_revision_number(enginerevision, true); + int them; if (manifestpackages) { @@ -2130,12 +2134,15 @@ unsigned int PM_MarkUpdates (void) for (p = availablepackages; p; p = p->next) { - if ((p->flags & DPF_ENGINE) && !(p->flags & DPF_HIDDEN)) + if ((p->flags & DPF_ENGINE) && !(p->flags & DPF_HIDDEN) && bestengine>0 && PM_SignatureOkay(p)) { + them = parse_revision_number(p->version, true); if (!(p->flags & DPF_TESTING) || pkg_autoupdate.ival >= UPD_TESTING) - if (!e || strcmp(e->version, p->version) < 0) //package must be more recent than the previously found engine - if (strcmp(enginerevision, "-") && strcmp(enginerevision, p->version) < 0) //package must be more recent than the current engine too, there's no point auto-updating to an older revision. - e = p; + if (them > bestengine) + { + e = p; + bestengine = them; + } } if (p->flags & DPF_MARKED) { @@ -4258,6 +4265,11 @@ qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize) struct packagedep_s *dep; package_t *e = NULL, *p; char *pfname; + + int best = parse_revision_number(enginerevision, true); + int them; + if (best <= 0) + return false; //no idea what revision we are, we might be more recent. //figure out what we've previously installed. PM_PreparePackageList(); @@ -4265,8 +4277,8 @@ qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize) { if ((p->flags & DPF_ENGINE) && !(p->flags & DPF_HIDDEN) && p->fsroot == FS_ROOT) { - if ((p->flags & DPF_ENABLED) && (!e || strcmp(e->version, p->version) < 0)) - if (strcmp(enginerevision, "-") && strcmp(enginerevision, p->version) < 0) //package must be more recent than the current engine too, there's no point auto-updating to an older revision. + them = parse_revision_number(p->version, true); + if ((p->flags & DPF_ENABLED) && them>best) { for (dep = p->deps, pfname = NULL; dep; dep = dep->next) { @@ -4283,7 +4295,10 @@ qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize) if (pfname && PM_CheckFile(pfname, p->fsroot)) { if (FS_NativePath(pfname, p->fsroot, syspath, syspathsize)) + { e = p; + best = them; + } } } } diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 5447b9c1b..651d06371 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -3005,14 +3005,7 @@ qboolean Sys_EngineMayUpdate(void) if (!COM_CheckParm("-allowupdate")) { - //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. - if (!strcmp(SVNREVISIONSTR, "-")) - return false; - - //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified. - //either way, its bad and autoupdates when we don't know what we're updating from is a bad idea. - strtoul(SVNREVISIONSTR, &e, 10); - if (!*SVNREVISIONSTR || *e) + if (revision_number(true) <= 0) return false; } diff --git a/engine/common/common.c b/engine/common/common.c index d3a1c9023..41b97da62 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -8112,6 +8112,60 @@ char *version_string(void) return s; } +//returns <=0 on error. +//this function is useful for auto updates. +int parse_revision_number(const char *s, qboolean strict) +{ + int rev; + char *e; + + //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. + if (!s || !strcmp(s, "-") || !*s) + return false; //no version info at all. + + if (!strncmp(s, "git-", 4)) + { //git gets messy and takes the form of one of the following... + //bad: git-XXXXXXXX[-dirty] + //git-tag-extracommits-hash[-dirty] + //if 'tag' is [R]VVVV then someone's tagging revisions to match svn revisions. + //if a fork wants to block updates, then they can either just disable engine updates or they can fiddle with this tagging stuff. + s+=4; + if (*s == 'r' || *s == 'R') + s++; //R prefix is optional. + + if (strict && strstr(s, "-dirty")) + return false; //boo hiss. + + rev = strtoul(s, &e, 10); + if (*e == '-') + { //we used --long so this should be a count of extra commits + if (strtoul(e+1, &e, 10) && strict) + return false; //doesn't exactly match the tag, and we're strict + if (*e != '-') + return false; //no hash info? something odd is happening... + //hash is uninteresting. + } + else //looks like there's no tag info there, just a commit hash. don't consider it a valid revision number. + return false; //--long didn't + } + else + { + //[lower-]upper[M] + rev = strtoul(s, &e, 10); + if (*e && strict) + return false; //something odd. + } + return rev; +} +int revision_number(qboolean strict) +{ +#ifdef SVNREVISION + return parse_revision_number(STRINGIFY(SVNREVISION), strict); +#else + return 0; +#endif +} + //C90 void COM_TimeOfDay(date_t *date) { diff --git a/engine/common/common.h b/engine/common/common.h index 69c7d86cf..6b7f2b110 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -939,6 +939,8 @@ unsigned int CalcHashInt(const hashfunc_t *hash, const unsigned char *data, size size_t CalcHash(const hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datasize); size_t CalcHMAC(const hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen); +int parse_revision_number(const char *revstr, qboolean strict); //returns our 'svn' revision numbers +int revision_number(qboolean strict); //returns our 'svn' revision numbers int version_number(void); char *version_string(void); diff --git a/engine/common/sys_linux_threads.c b/engine/common/sys_linux_threads.c index 6c2677da5..24d6ccadd 100644 --- a/engine/common/sys_linux_threads.c +++ b/engine/common/sys_linux_threads.c @@ -578,23 +578,13 @@ qboolean Sys_SetUpdatedBinary(const char *newbinary) qboolean Sys_EngineMayUpdate(void) { char enginebinary[MAX_OSPATH]; - char *e; int len; -#define SVNREVISIONSTR STRINGIFY(SVNREVISION) + //if we can't get a revision number from our cflags then don't allow updates (unless forced on). if (!COM_CheckParm("-allowupdate")) - { - //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. - if (!strcmp(SVNREVISIONSTR, "-")) + if (revision_number(true)<=0) return false; - //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified. - //either way, its bad and autoupdates when we don't know what we're updating from is a bad idea. - strtoul(SVNREVISIONSTR, &e, 10); - if (!*SVNREVISIONSTR || *e) - return false; - } - //update blocked via commandline if (COM_CheckParm("-noupdate") || COM_CheckParm("--noupdate") || COM_CheckParm("-noautoupdate") || COM_CheckParm("--noautoupdate")) return false;