signature: distinguish +0000 and -0000 UTC offsets Git considers '-0000' a valid offset for signature lines. They need to be treated as _not_ equal to a '+0000' signature offset. Parsing a signature line stores the offset in a signed integer which does not distinguish between `+0` and `-0`. This patch adds an additional flag `sign` to the `git_time` in the `signature` object which is populated with the sign of the offset. In addition to exposing this information to the user, this information is also used to compare signatures. /cc @pks-t @ethomson
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
diff --git a/include/git2/types.h b/include/git2/types.h
index dfdaa29..8d9a947 100644
--- a/include/git2/types.h
+++ b/include/git2/types.h
@@ -159,6 +159,7 @@ typedef struct git_packbuilder git_packbuilder;
typedef struct git_time {
git_time_t time; /**< time in seconds from epoch */
int offset; /**< timezone offset, in minutes */
+ char sign; /**< indicator for questionable '-0000' offsets in signature */
} git_time;
/** An action signature (e.g. for committers, taggers, etc) */
diff --git a/src/signature.c b/src/signature.c
index bc3cf33..cd68523 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -90,6 +90,7 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema
p->when.time = time;
p->when.offset = offset;
+ p->when.sign = (offset < 0) ? '-' : '+';
*sig_out = p;
return 0;
@@ -113,6 +114,7 @@ int git_signature_dup(git_signature **dest, const git_signature *source)
signature->when.time = source->when.time;
signature->when.offset = source->when.offset;
+ signature->when.sign = source->when.sign;
*dest = signature;
@@ -137,6 +139,7 @@ int git_signature__pdup(git_signature **dest, const git_signature *source, git_p
signature->when.time = source->when.time;
signature->when.offset = source->when.offset;
+ signature->when.sign = source->when.sign;
*dest = signature;
@@ -257,6 +260,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
*/
if (hours <= 14 && mins <= 59) {
sig->when.offset = (hours * 60) + mins;
+ sig->when.sign = tz_start[0];
if (tz_start[0] == '-')
sig->when.offset = -sig->when.offset;
}
@@ -299,7 +303,7 @@ void git_signature__writebuf(git_buf *buf, const char *header, const git_signatu
assert(buf && sig);
offset = sig->when.offset;
- sign = (sig->when.offset < 0) ? '-' : '+';
+ sign = (sig->when.offset < 0 || sig->when.sign == '-') ? '-' : '+';
if (offset < 0)
offset = -offset;
@@ -320,6 +324,7 @@ bool git_signature__equal(const git_signature *one, const git_signature *two)
git__strcmp(one->name, two->name) == 0 &&
git__strcmp(one->email, two->email) == 0 &&
one->when.time == two->when.time &&
- one->when.offset == two->when.offset;
+ one->when.offset == two->when.offset &&
+ one->when.sign == two->when.sign;
}
diff --git a/tests/commit/signature.c b/tests/commit/signature.c
index 30bc929..286079f 100644
--- a/tests/commit/signature.c
+++ b/tests/commit/signature.c
@@ -1,4 +1,5 @@
#include "clar_libgit2.h"
+#include "signature.h"
static int try_build_signature(const char *name, const char *email, git_time_t time, int offset)
{
@@ -99,3 +100,29 @@ void test_commit_signature__from_buf(void)
git_signature_free(sign);
}
+void test_commit_signature__from_buf_with_neg_zero_offset(void)
+{
+ git_signature *sign;
+
+ cl_git_pass(git_signature_from_buffer(&sign, "Test User <test@test.tt> 1461698487 -0000"));
+ cl_assert_equal_s("Test User", sign->name);
+ cl_assert_equal_s("test@test.tt", sign->email);
+ cl_assert_equal_i(1461698487, sign->when.time);
+ cl_assert_equal_i(0, sign->when.offset);
+ cl_assert_equal_i('-', sign->when.sign);
+ git_signature_free(sign);
+}
+
+void test_commit_signature__pos_and_neg_zero_offsets_dont_match(void)
+{
+ git_signature *with_neg_zero;
+ git_signature *with_pos_zero;
+
+ cl_git_pass(git_signature_from_buffer(&with_neg_zero, "Test User <test@test.tt> 1461698487 -0000"));
+ cl_git_pass(git_signature_from_buffer(&with_pos_zero, "Test User <test@test.tt> 1461698487 +0000"));
+
+ cl_assert(!git_signature__equal(with_neg_zero, with_pos_zero));
+
+ git_signature_free((git_signature *)with_neg_zero);
+ git_signature_free((git_signature *)with_pos_zero);
+}