From fc62721b06e3ac231b570741e21dba03b5cadaca Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 5 Nov 2014 13:28:29 -0500 Subject: [PATCH] Fix version number parsing to allow 2- and 3-part versions. Fixes bug 13661; bugfix on 0.0.8pre1. --- changes/bug13661 | 6 +++++ src/or/routerparse.c | 58 ++++++++++++++++++++++++++------------------ src/test/test_dir.c | 36 +++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 changes/bug13661 diff --git a/changes/bug13661 b/changes/bug13661 new file mode 100644 index 0000000000..7f0cb5e706 --- /dev/null +++ b/changes/bug13661 @@ -0,0 +1,6 @@ + o Minor bugfixes: + + - Support two-number and three-number version numbers correctly, in + case we change the Tor versioning system in the future. Fixes bug + 13661; bugfix on 0.0.8pre1. + diff --git a/src/or/routerparse.c b/src/or/routerparse.c index f990cebd82..68dbc707a8 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -4207,40 +4207,50 @@ tor_version_parse(const char *s, tor_version_t *out) char *eos=NULL; const char *cp=NULL; /* Format is: - * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ] + * "Tor " ? NUM dot NUM [ dot NUM [ ( pre | rc | dot ) NUM ] ] [ - tag ] */ tor_assert(s); tor_assert(out); memset(out, 0, sizeof(tor_version_t)); - + out->status = VER_RELEASE; if (!strcasecmpstart(s, "Tor ")) s += 4; - /* Get major. */ - out->major = (int)strtol(s,&eos,10); - if (!eos || eos==s || *eos != '.') return -1; - cp = eos+1; + cp = s; - /* Get minor */ - out->minor = (int) strtol(cp,&eos,10); - if (!eos || eos==cp || *eos != '.') return -1; - cp = eos+1; +#define NUMBER(m) \ + do { \ + out->m = (int)strtol(cp, &eos, 10); \ + if (!eos || eos == cp) \ + return -1; \ + cp = eos; \ + } while (0) - /* Get micro */ - out->micro = (int) strtol(cp,&eos,10); - if (!eos || eos==cp) return -1; - if (!*eos) { - out->status = VER_RELEASE; - out->patchlevel = 0; +#define DOT() \ + do { \ + if (*cp != '.') \ + return -1; \ + ++cp; \ + } while (0) + + NUMBER(major); + DOT(); + NUMBER(minor); + if (*cp == 0) return 0; - } - cp = eos; + else if (*cp == '-') + goto status_tag; + DOT(); + NUMBER(micro); /* Get status */ - if (*cp == '.') { - out->status = VER_RELEASE; + if (*cp == 0) { + return 0; + } else if (*cp == '.') { ++cp; + } else if (*cp == '-') { + goto status_tag; } else if (0==strncmp(cp, "pre", 3)) { out->status = VER_PRE; cp += 3; @@ -4251,11 +4261,9 @@ tor_version_parse(const char *s, tor_version_t *out) return -1; } - /* Get patchlevel */ - out->patchlevel = (int) strtol(cp,&eos,10); - if (!eos || eos==cp) return -1; - cp = eos; + NUMBER(patchlevel); + status_tag: /* Get status tag. */ if (*cp == '-' || *cp == '.') ++cp; @@ -4291,6 +4299,8 @@ tor_version_parse(const char *s, tor_version_t *out) } return 0; +#undef NUMBER +#undef DOT } /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a > diff --git a/src/test/test_dir.c b/src/test/test_dir.c index c03b63be27..61484f5fe1 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -337,6 +337,42 @@ test_dir_versions(void) test_eq(VER_RELEASE, ver1.status); test_streq("", ver1.status_tag); + test_eq(0, tor_version_parse("10.1", &ver1)); + test_eq(10, ver1.major); + test_eq(1, ver1.minor); + test_eq(0, ver1.micro); + test_eq(0, ver1.patchlevel); + test_eq(VER_RELEASE, ver1.status); + test_streq("", ver1.status_tag); + test_eq(0, tor_version_parse("5.99.999", &ver1)); + test_eq(5, ver1.major); + test_eq(99, ver1.minor); + test_eq(999, ver1.micro); + test_eq(0, ver1.patchlevel); + test_eq(VER_RELEASE, ver1.status); + test_streq("", ver1.status_tag); + test_eq(0, tor_version_parse("10.1-alpha", &ver1)); + test_eq(10, ver1.major); + test_eq(1, ver1.minor); + test_eq(0, ver1.micro); + test_eq(0, ver1.patchlevel); + test_eq(VER_RELEASE, ver1.status); + test_streq("alpha", ver1.status_tag); + test_eq(0, tor_version_parse("2.1.700-alpha", &ver1)); + test_eq(2, ver1.major); + test_eq(1, ver1.minor); + test_eq(700, ver1.micro); + test_eq(0, ver1.patchlevel); + test_eq(VER_RELEASE, ver1.status); + test_streq("alpha", ver1.status_tag); + test_eq(0, tor_version_parse("1.6.8-alpha-dev", &ver1)); + test_eq(1, ver1.major); + test_eq(6, ver1.minor); + test_eq(8, ver1.micro); + test_eq(0, ver1.patchlevel); + test_eq(VER_RELEASE, ver1.status); + test_streq("alpha-dev", ver1.status_tag); + #define tt_versionstatus_op(vs1, op, vs2) \ tt_assert_test_type(vs1,vs2,#vs1" "#op" "#vs2,version_status_t, \ (val1_ op val2_),"%d",TT_EXIT_TEST_FUNCTION)