]>
git.proxmox.com Git - libgit2.git/blob - src/signature.c
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
27 #include "signature.h"
28 #include "repository.h"
29 #include "git2/common.h"
31 void git_signature_free(git_signature
*sig
)
41 git_signature
*git_signature_new(const char *name
, const char *email
, git_time_t time
, int offset
)
43 git_signature
*p
= NULL
;
45 if ((p
= git__malloc(sizeof(git_signature
))) == NULL
)
48 p
->name
= git__strdup(name
);
49 p
->email
= git__strdup(email
);
51 p
->when
.offset
= offset
;
53 if (p
->name
== NULL
|| p
->email
== NULL
)
59 git_signature_free(p
);
63 git_signature
*git_signature_dup(const git_signature
*sig
)
65 return git_signature_new(sig
->name
, sig
->email
, sig
->when
.time
, sig
->when
.offset
);
68 git_signature
*git_signature_now(const char *name
, const char *email
)
72 struct tm
*utc_tm
, *local_tm
;
75 struct tm _utc
, _local
;
81 * On Win32, `gmtime_r` doesn't exist but
82 * `gmtime` is threadsafe, so we can use that
85 utc_tm
= gmtime(&now
);
86 local_tm
= localtime(&now
);
88 utc_tm
= gmtime_r(&now
, &_utc
);
89 local_tm
= localtime_r(&now
, &_local
);
92 offset
= mktime(local_tm
) - mktime(utc_tm
);
95 /* mktime takes care of setting tm_isdst correctly */
96 if (local_tm
->tm_isdst
)
99 return git_signature_new(name
, email
, now
, (int)offset
);
102 static int parse_timezone_offset(const char *buffer
, long *offset_out
)
104 long offset
, dec_offset
;
107 const char *offset_start
;
108 const char *offset_end
;
110 offset_start
= buffer
+ 1;
112 if (*offset_start
== '\n') {
117 if (offset_start
[0] != '-' && offset_start
[0] != '+')
118 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse TZ offset. It doesn't start with '+' or '-'");
120 if (git__strtol32(&dec_offset
, offset_start
+ 1, &offset_end
, 10) < GIT_SUCCESS
)
121 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse TZ offset. It isn't a number");
123 if (offset_end
- offset_start
!= 5)
124 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse TZ offset. Invalid length");
126 hours
= dec_offset
/ 100;
127 mins
= dec_offset
% 100;
129 if (hours
> 14) // see http://www.worldtimezone.com/faq.html
130 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse TZ offset. Hour value too large");;
133 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse TZ offset. Minute value too large");
135 offset
= (hours
* 60) + mins
;
137 if (offset_start
[0] == '-')
140 *offset_out
= offset
;
146 int git_signature__parse(git_signature
*sig
, const char **buffer_out
,
147 const char *buffer_end
, const char *header
)
149 const size_t header_len
= strlen(header
);
151 int name_length
, email_length
;
152 const char *buffer
= *buffer_out
;
153 const char *line_end
, *name_end
, *email_end
;
154 long offset
= 0, time
;
156 memset(sig
, 0x0, sizeof(git_signature
));
158 line_end
= memchr(buffer
, '\n', buffer_end
- buffer
);
160 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. No newline found");;
162 if (buffer
+ (header_len
+ 1) > line_end
)
163 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Signature too short");
165 if (memcmp(buffer
, header
, header_len
) != 0)
166 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header
);
168 buffer
+= header_len
;
171 if ((name_end
= memchr(buffer
, '<', buffer_end
- buffer
)) == NULL
)
172 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Can't find e-mail start");
174 name_length
= name_end
- buffer
- 1;
175 sig
->name
= git__malloc(name_length
+ 1);
176 if (sig
->name
== NULL
)
179 memcpy(sig
->name
, buffer
, name_length
);
180 sig
->name
[name_length
] = 0;
181 buffer
= name_end
+ 1;
183 if (buffer
>= line_end
)
184 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Ended unexpectedly");
187 if ((email_end
= memchr(buffer
, '>', buffer_end
- buffer
)) == NULL
)
188 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Can't find e-mail end");
190 email_length
= email_end
- buffer
;
191 sig
->email
= git__malloc(email_length
+ 1);
192 if (sig
->name
== NULL
)
195 memcpy(sig
->email
, buffer
, email_length
);
196 sig
->email
[email_length
] = 0;
197 buffer
= email_end
+ 1;
199 if (buffer
>= line_end
)
200 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Ended unexpectedly");
202 if (git__strtol32(&time
, buffer
, &buffer
, 10) < GIT_SUCCESS
)
203 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Timestamp isn't a number");
205 sig
->when
.time
= (time_t)time
;
207 if (parse_timezone_offset(buffer
, &offset
) < GIT_SUCCESS
)
208 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse signature. Could not parse timezone offset");
210 sig
->when
.offset
= offset
;
212 *buffer_out
= (line_end
+ 1);
216 int git_signature__write(char **signature
, const char *header
, const git_signature
*sig
)
218 int offset
, hours
, mins
;
219 char sig_buffer
[2048];
223 offset
= sig
->when
.offset
;
224 sign
= (sig
->when
.offset
< 0) ? '-' : '+';
232 sig_buffer_len
= snprintf(sig_buffer
, sizeof(sig_buffer
),
233 "%s %s <%s> %u %c%02d%02d\n",
234 header
, sig
->name
, sig
->email
,
235 (unsigned)sig
->when
.time
, sign
, hours
, mins
);
237 if (sig_buffer_len
< 0 || (size_t)sig_buffer_len
> sizeof(sig_buffer
))
240 *signature
= git__strdup(sig_buffer
);
241 return sig_buffer_len
;