Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "signature.h"
9 -
10 - #include "repository.h"
11 - #include "git2/common.h"
12 - #include "posix.h"
13 -
14 26782 2 void git_signature_free(git_signature *sig)
15 - {
16 26782 2 if (sig == NULL)
17 26782 3,7 return;
18 -
19 22769 4 git__free(sig->name);
20 22769 5 sig->name = NULL;
21 22769 5 git__free(sig->email);
22 22769 6 sig->email = NULL;
23 22769 6 git__free(sig);
24 - }
25 -
26 26 2 static int signature_error(const char *msg)
27 - {
28 26 2 git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg);
29 26 3 return -1;
30 - }
31 -
32 5131 2 static bool contains_angle_brackets(const char *input)
33 - {
34 5131 2 return strchr(input, '<') != NULL || strchr(input, '>') != NULL;
35 - }
36 -
37 129379 2 static bool is_crud(unsigned char c)
38 - {
39 104987 3 return c <= 32 ||
40 104986 4 c == '.' ||
41 104986 5 c == ',' ||
42 104986 6 c == ':' ||
43 104986 7 c == ';' ||
44 104816 8 c == '<' ||
45 104646 9 c == '>' ||
46 104642 10 c == '"' ||
47 129379 2,11-13 c == '\\' ||
48 - c == '\'';
49 - }
50 -
51 52350 2 static char *extract_trimmed(const char *ptr, size_t len)
52 - {
53 53299 2,4-6 while (len && is_crud((unsigned char)ptr[0])) {
54 949 3 ptr++; len--;
55 - }
56 -
57 76138 7,9-11 while (len && is_crud((unsigned char)ptr[len - 1])) {
58 23788 8 len--;
59 - }
60 -
61 52350 12 return git__substrdup(ptr, len);
62 - }
63 -
64 2567 2 int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset)
65 - {
66 2567 2 git_signature *p = NULL;
67 -
68 2567 2-4 assert(name && email);
69 -
70 2567 5 *sig_out = NULL;
71 -
72 2567 5,6,8 if (contains_angle_brackets(name) ||
73 2564 7 contains_angle_brackets(email)) {
74 6 9 return signature_error(
75 - "Neither `name` nor `email` should contain angle brackets chars.");
76 - }
77 -
78 2561 10 p = git__calloc(1, sizeof(git_signature));
79 2561 11,12 GIT_ERROR_CHECK_ALLOC(p);
80 -
81 2561 13 p->name = extract_trimmed(name, strlen(name));
82 2561 14,15 GIT_ERROR_CHECK_ALLOC(p->name);
83 2561 16 p->email = extract_trimmed(email, strlen(email));
84 2561 17,18 GIT_ERROR_CHECK_ALLOC(p->email);
85 -
86 2561 19,20 if (p->name[0] == '\0' || p->email[0] == '\0') {
87 5 21 git_signature_free(p);
88 5 22 return signature_error("Signature cannot have an empty name or email");
89 - }
90 -
91 2556 23 p->when.time = time;
92 2556 23 p->when.offset = offset;
93 2556 23-25 p->when.sign = (offset < 0) ? '-' : '+';
94 -
95 2556 26 *sig_out = p;
96 2556 26 return 0;
97 - }
98 -
99 299 2 int git_signature_dup(git_signature **dest, const git_signature *source)
100 - {
101 - git_signature *signature;
102 -
103 299 2 if (source == NULL)
104 ##### 3 return 0;
105 -
106 299 4 signature = git__calloc(1, sizeof(git_signature));
107 299 5,6 GIT_ERROR_CHECK_ALLOC(signature);
108 -
109 299 7 signature->name = git__strdup(source->name);
110 299 8,9 GIT_ERROR_CHECK_ALLOC(signature->name);
111 -
112 299 10 signature->email = git__strdup(source->email);
113 299 11,12 GIT_ERROR_CHECK_ALLOC(signature->email);
114 -
115 299 13 signature->when.time = source->when.time;
116 299 13 signature->when.offset = source->when.offset;
117 299 13 signature->when.sign = source->when.sign;
118 -
119 299 13 *dest = signature;
120 -
121 299 13 return 0;
122 - }
123 -
124 23 2 int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool)
125 - {
126 - git_signature *signature;
127 -
128 23 2 if (source == NULL)
129 ##### 3 return 0;
130 -
131 23 4 signature = git_pool_mallocz(pool, sizeof(git_signature));
132 23 5,6 GIT_ERROR_CHECK_ALLOC(signature);
133 -
134 23 7 signature->name = git_pool_strdup(pool, source->name);
135 23 8,9 GIT_ERROR_CHECK_ALLOC(signature->name);
136 -
137 23 10 signature->email = git_pool_strdup(pool, source->email);
138 23 11,12 GIT_ERROR_CHECK_ALLOC(signature->email);
139 -
140 23 13 signature->when.time = source->when.time;
141 23 13 signature->when.offset = source->when.offset;
142 23 13 signature->when.sign = source->when.sign;
143 -
144 23 13 *dest = signature;
145 -
146 23 13 return 0;
147 - }
148 -
149 2241 2 int git_signature_now(git_signature **sig_out, const char *name, const char *email)
150 - {
151 - time_t now;
152 - time_t offset;
153 - struct tm *utc_tm;
154 - git_signature *sig;
155 - struct tm _utc;
156 -
157 2241 2 *sig_out = NULL;
158 -
159 - /*
160 - * Get the current time as seconds since the epoch and
161 - * transform that into a tm struct containing the time at
162 - * UTC. Give that to mktime which considers it a local time
163 - * (tm_isdst = -1 asks it to take DST into account) and gives
164 - * us that time as seconds since the epoch. The difference
165 - * between its return value and 'now' is our offset to UTC.
166 - */
167 2241 2 time(&now);
168 2241 3 utc_tm = p_gmtime_r(&now, &_utc);
169 2241 4 utc_tm->tm_isdst = -1;
170 2241 4,5 offset = (time_t)difftime(now, mktime(utc_tm));
171 2241 6 offset /= 60;
172 -
173 2241 6,7 if (git_signature_new(&sig, name, email, now, (int)offset) < 0)
174 ##### 8 return -1;
175 -
176 2241 9 *sig_out = sig;
177 -
178 2241 9 return 0;
179 - }
180 -
181 2088 2 int git_signature_default(git_signature **out, git_repository *repo)
182 - {
183 - int error;
184 - git_config *cfg;
185 - const char *user_name, *user_email;
186 -
187 2088 2,3 if ((error = git_repository_config_snapshot(&cfg, repo)) < 0)
188 ##### 4 return error;
189 -
190 2088 5-8 if (!(error = git_config_get_string(&user_name, cfg, "user.name")) &&
191 2 7 !(error = git_config_get_string(&user_email, cfg, "user.email")))
192 2 9 error = git_signature_now(out, user_name, user_email);
193 -
194 2088 10 git_config_free(cfg);
195 2088 11 return error;
196 - }
197 -
198 23629 2 int git_signature__parse(git_signature *sig, const char **buffer_out,
199 - const char *buffer_end, const char *header, char ender)
200 - {
201 23629 2 const char *buffer = *buffer_out;
202 - const char *email_start, *email_end;
203 -
204 23629 2 memset(sig, 0, sizeof(git_signature));
205 -
206 23629 2,3 if (ender &&
207 22862 3 (buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
208 5 4 return signature_error("no newline given");
209 -
210 23624 5 if (header) {
211 22857 6 const size_t header_len = strlen(header);
212 -
213 22857 6,7 if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0)
214 4 8 return signature_error("expected prefix doesn't match actual");
215 -
216 22853 9 buffer += header_len;
217 - }
218 -
219 23620 10 email_start = git__memrchr(buffer, '<', buffer_end - buffer);
220 23620 11 email_end = git__memrchr(buffer, '>', buffer_end - buffer);
221 -
222 23620 12-14 if (!email_start || !email_end || email_end <= email_start)
223 6 15 return signature_error("malformed e-mail");
224 -
225 23614 16 email_start += 1;
226 23614 16 sig->name = extract_trimmed(buffer, email_start - buffer - 1);
227 23614 17 sig->email = extract_trimmed(email_start, email_end - email_start);
228 -
229 - /* Do we even have a time at the end of the signature? */
230 23614 18 if (email_end + 2 < buffer_end) {
231 23573 19 const char *time_start = email_end + 2;
232 - const char *time_end;
233 -
234 23573 19,20 if (git__strntol64(&sig->when.time, time_start,
235 23573 19 buffer_end - time_start, &time_end, 10) < 0) {
236 ##### 21 git__free(sig->name);
237 ##### 22 git__free(sig->email);
238 ##### 23 sig->name = sig->email = NULL;
239 ##### 23,24 return signature_error("invalid Unix timestamp");
240 - }
241 -
242 - /* do we have a timezone? */
243 23573 25 if (time_end + 1 < buffer_end) {
244 - int offset, hours, mins;
245 - const char *tz_start, *tz_end;
246 -
247 23562 26 tz_start = time_end + 1;
248 -
249 23562 26,27,29 if ((tz_start[0] != '-' && tz_start[0] != '+') ||
250 23562 28 git__strntol32(&offset, tz_start + 1,
251 23562 28 buffer_end - tz_start - 1, &tz_end, 10) < 0) {
252 - /* malformed timezone, just assume it's zero */
253 ##### 30 offset = 0;
254 - }
255 -
256 23562 31 hours = offset / 100;
257 23562 31 mins = offset % 100;
258 -
259 - /*
260 - * only store timezone if it's not overflowing;
261 - * see http://www.worldtimezone.com/faq.html
262 - */
263 23562 31,32 if (hours <= 14 && mins <= 59) {
264 23560 33 sig->when.offset = (hours * 60) + mins;
265 23560 33 sig->when.sign = tz_start[0];
266 23560 33 if (tz_start[0] == '-')
267 23573 34-36 sig->when.offset = -sig->when.offset;
268 - }
269 - }
270 - }
271 -
272 23614 37 *buffer_out = buffer_end + 1;
273 23614 37 return 0;
274 - }
275 -
276 21 2 int git_signature_from_buffer(git_signature **out, const char *buf)
277 - {
278 - git_signature *sig;
279 - const char *buf_end;
280 - int error;
281 -
282 21 2-4 assert(out && buf);
283 -
284 21 5 *out = NULL;
285 -
286 21 5 sig = git__calloc(1, sizeof(git_signature));
287 21 6,7 GIT_ERROR_CHECK_ALLOC(sig);
288 -
289 21 8 buf_end = buf + strlen(buf);
290 21 8 error = git_signature__parse(sig, &buf, buf_end, NULL, '\0');
291 -
292 21 9 if (error)
293 ##### 10 git__free(sig);
294 - else
295 21 11 *out = sig;
296 -
297 21 12 return error;
298 - }
299 -
300 2389 2 void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig)
301 - {
302 - int offset, hours, mins;
303 - char sign;
304 -
305 2389 2-4 assert(buf && sig);
306 -
307 2389 5 offset = sig->when.offset;
308 2389 5-8 sign = (sig->when.offset < 0 || sig->when.sign == '-') ? '-' : '+';
309 -
310 2389 9 if (offset < 0)
311 1653 10 offset = -offset;
312 -
313 2389 11 hours = offset / 60;
314 2389 11 mins = offset % 60;
315 -
316 2389 11,11-14 git_buf_printf(buf, "%s%s <%s> %u %c%02d%02d\n",
317 - header ? header : "", sig->name, sig->email,
318 2389 11 (unsigned)sig->when.time, sign, hours, mins);
319 2389 15 }
320 -
321 12 2 bool git_signature__equal(const git_signature *one, const git_signature *two)
322 - {
323 12 2-4 assert(one && two);
324 -
325 12 12 return
326 12 5,6 git__strcmp(one->name, two->name) == 0 &&
327 12 6,7 git__strcmp(one->email, two->email) == 0 &&
328 12 7,8 one->when.time == two->when.time &&
329 12 5,8-11 one->when.offset == two->when.offset &&
330 12 9 one->when.sign == two->when.sign;
331 - }
332 -