source src/refs.c
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 "refs.h" | ||
9 | - | |||
10 | - | #include "hash.h" | ||
11 | - | #include "repository.h" | ||
12 | - | #include "futils.h" | ||
13 | - | #include "filebuf.h" | ||
14 | - | #include "pack.h" | ||
15 | - | #include "reflog.h" | ||
16 | - | #include "refdb.h" | ||
17 | - | |||
18 | - | #include <git2/tag.h> | ||
19 | - | #include <git2/object.h> | ||
20 | - | #include <git2/oid.h> | ||
21 | - | #include <git2/branch.h> | ||
22 | - | #include <git2/refs.h> | ||
23 | - | #include <git2/refdb.h> | ||
24 | - | #include <git2/sys/refs.h> | ||
25 | - | #include <git2/signature.h> | ||
26 | - | #include <git2/commit.h> | ||
27 | - | |||
28 | - | bool git_reference__enable_symbolic_ref_target_validation = true; | ||
29 | - | |||
30 | - | #define DEFAULT_NESTING_LEVEL 5 | ||
31 | - | #define MAX_NESTING_LEVEL 10 | ||
32 | - | |||
33 | - | enum { | ||
34 | - | GIT_PACKREF_HAS_PEEL = 1, | ||
35 | - | GIT_PACKREF_WAS_LOOSE = 2 | ||
36 | - | }; | ||
37 | - | |||
38 | - | 2 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files)static git_reference *alloc_ref(const char *name) | |
39 | - | { | ||
40 | - | 2 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) git_reference *ref = NULL; | |
41 | - | 2 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) size_t namelen = strlen(name), reflen; | |
42 | - | |||
43 | - | 2-7,9,11-13 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && | |
44 | - | 8,10,14,15 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && | |
45 | - | 14 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) (ref = git__calloc(1, reflen)) != NULL) | |
46 | - | 16 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) memcpy(ref->name, name, namelen + 1); | |
47 | - | |||
48 | - | 17 | suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) return ref; | |
49 | - | } | ||
50 | - | |||
51 | 8844 | 2 | git_reference *git_reference__alloc_symbolic( | |
52 | - | const char *name, const char *target) | ||
53 | - | { | ||
54 | - | git_reference *ref; | ||
55 | - | |||
56 | 8844 | 2-4 | assert(name && target); | |
57 | - | |||
58 | 8844 | 5 | ref = alloc_ref(name); | |
59 | 8844 | 6 | if (!ref) | |
60 | ##### | 7 | return NULL; | |
61 | - | |||
62 | 8844 | 8 | ref->type = GIT_REFERENCE_SYMBOLIC; | |
63 | - | |||
64 | 8844 | 8,9 | if ((ref->target.symbolic = git__strdup(target)) == NULL) { | |
65 | ##### | 10 | git__free(ref); | |
66 | ##### | 11 | return NULL; | |
67 | - | } | ||
68 | - | |||
69 | 8844 | 12 | return ref; | |
70 | - | } | ||
71 | - | |||
72 | - | 2 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files)git_reference *git_reference__alloc( | |
73 | - | const char *name, | ||
74 | - | const git_oid *oid, | ||
75 | - | const git_oid *peel) | ||
76 | - | { | ||
77 | - | git_reference *ref; | ||
78 | - | |||
79 | - | 2-4 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) assert(name && oid); | |
80 | - | |||
81 | - | 5 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) ref = alloc_ref(name); | |
82 | - | 6 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) if (!ref) | |
83 | - | 7 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) return NULL; | |
84 | - | |||
85 | - | 8 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) ref->type = GIT_REFERENCE_DIRECT; | |
86 | - | 8 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) git_oid_cpy(&ref->target.oid, oid); | |
87 | - | |||
88 | - | 9 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) if (peel != NULL) | |
89 | - | 10 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) git_oid_cpy(&ref->peel, peel); | |
90 | - | |||
91 | - | 11 | suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) return ref; | |
92 | - | } | ||
93 | - | |||
94 | 38 | 2 | git_reference *git_reference__realloc( | |
95 | - | git_reference **ptr_to_ref, const char *name) | ||
96 | - | { | ||
97 | - | size_t namelen, reflen; | ||
98 | 38 | 2 | git_reference *rewrite = NULL; | |
99 | - | |||
100 | 38 | 2-4 | assert(ptr_to_ref && name); | |
101 | - | |||
102 | 38 | 5 | namelen = strlen(name); | |
103 | - | |||
104 | 38 | 5-10,12,14-16 | if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && | |
105 | 38 | 11,13,17,18 | !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && | |
106 | 38 | 17 | (rewrite = git__realloc(*ptr_to_ref, reflen)) != NULL) | |
107 | 38 | 19 | memcpy(rewrite->name, name, namelen + 1); | |
108 | - | |||
109 | 38 | 20 | *ptr_to_ref = NULL; | |
110 | - | |||
111 | 38 | 20 | return rewrite; | |
112 | - | } | ||
113 | - | |||
114 | 3 | 2 | int git_reference_dup(git_reference **dest, git_reference *source) | |
115 | - | { | ||
116 | 3 | 2 | if (source->type == GIT_REFERENCE_SYMBOLIC) | |
117 | 1 | 3,4 | *dest = git_reference__alloc_symbolic(source->name, source->target.symbolic); | |
118 | - | else | ||
119 | 2 | 5,6 | *dest = git_reference__alloc(source->name, &source->target.oid, &source->peel); | |
120 | - | |||
121 | 3 | 7,8 | GIT_ERROR_CHECK_ALLOC(*dest); | |
122 | - | |||
123 | 3 | 9 | (*dest)->db = source->db; | |
124 | 3 | 9 | GIT_REFCOUNT_INC((*dest)->db); | |
125 | - | |||
126 | 3 | 10 | return 0; | |
127 | - | } | ||
128 | - | |||
129 | 37388 | 2 | void git_reference_free(git_reference *reference) | |
130 | - | { | ||
131 | 37388 | 2 | if (reference == NULL) | |
132 | 37410 | 3,12 | return; | |
133 | - | |||
134 | 26941 | 4 | if (reference->type == GIT_REFERENCE_SYMBOLIC) | |
135 | 8844 | 5 | git__free(reference->target.symbolic); | |
136 | - | |||
137 | 26947 | 6 | if (reference->db) | |
138 | 25886 | 7-10 | GIT_REFCOUNT_DEC(reference->db, git_refdb__free); | |
139 | - | |||
140 | 26958 | 11 | git__free(reference); | |
141 | - | } | ||
142 | - | |||
143 | 88 | 2 | int git_reference_delete(git_reference *ref) | |
144 | - | { | ||
145 | 88 | 2 | const git_oid *old_id = NULL; | |
146 | 88 | 2 | const char *old_target = NULL; | |
147 | - | |||
148 | 88 | 2 | if (!strcmp(ref->name, "HEAD")) { | |
149 | 2 | 3 | git_error_set(GIT_ERROR_REFERENCE, "cannot delete HEAD"); | |
150 | 2 | 4 | return GIT_ERROR; | |
151 | - | } | ||
152 | - | |||
153 | 86 | 5 | if (ref->type == GIT_REFERENCE_DIRECT) | |
154 | 83 | 6 | old_id = &ref->target.oid; | |
155 | - | else | ||
156 | 3 | 7 | old_target = ref->target.symbolic; | |
157 | - | |||
158 | 86 | 8 | return git_refdb_delete(ref->db, ref->name, old_id, old_target); | |
159 | - | } | ||
160 | - | |||
161 | 27 | 2 | int git_reference_remove(git_repository *repo, const char *name) | |
162 | - | { | ||
163 | - | git_refdb *db; | ||
164 | - | int error; | ||
165 | - | |||
166 | 27 | 2,3 | if ((error = git_repository_refdb__weakptr(&db, repo)) < 0) | |
167 | ##### | 4 | return error; | |
168 | - | |||
169 | 27 | 5 | return git_refdb_delete(db, name, NULL, NULL); | |
170 | - | } | ||
171 | - | |||
172 | 13011 | 2 | int git_reference_lookup(git_reference **ref_out, | |
173 | - | git_repository *repo, const char *name) | ||
174 | - | { | ||
175 | 13011 | 2 | return git_reference_lookup_resolved(ref_out, repo, name, 0); | |
176 | - | } | ||
177 | - | |||
178 | 5749 | 2 | int git_reference_name_to_id( | |
179 | - | git_oid *out, git_repository *repo, const char *name) | ||
180 | - | { | ||
181 | - | int error; | ||
182 | - | git_reference *ref; | ||
183 | - | |||
184 | 5749 | 2,3 | if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0) | |
185 | 2958 | 4 | return error; | |
186 | - | |||
187 | 2791 | 5,6 | git_oid_cpy(out, git_reference_target(ref)); | |
188 | 2791 | 7 | git_reference_free(ref); | |
189 | 2791 | 8 | return 0; | |
190 | - | } | ||
191 | - | |||
192 | 33946 | 2 | static int reference_normalize_for_repo( | |
193 | - | git_refname_t out, | ||
194 | - | git_repository *repo, | ||
195 | - | const char *name, | ||
196 | - | bool validate) | ||
197 | - | { | ||
198 | - | int precompose; | ||
199 | 33946 | 2 | unsigned int flags = GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL; | |
200 | - | |||
201 | 33946 | 2-4 | if (!git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) && | |
202 | - | precompose) | ||
203 | 1025 | 5 | flags |= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE; | |
204 | - | |||
205 | 33946 | 6 | if (!validate) | |
206 | 1 | 7 | flags |= GIT_REFERENCE_FORMAT__VALIDATION_DISABLE; | |
207 | - | |||
208 | 33946 | 8 | return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags); | |
209 | - | } | ||
210 | - | |||
211 | 31378 | 2 | int git_reference_lookup_resolved( | |
212 | - | git_reference **ref_out, | ||
213 | - | git_repository *repo, | ||
214 | - | const char *name, | ||
215 | - | int max_nesting) | ||
216 | - | { | ||
217 | - | git_refname_t scan_name; | ||
218 | - | git_reference_t scan_type; | ||
219 | 31378 | 2 | int error = 0, nesting; | |
220 | 31378 | 2 | git_reference *ref = NULL; | |
221 | - | git_refdb *refdb; | ||
222 | - | |||
223 | 31378 | 2-5 | assert(ref_out && repo && name); | |
224 | - | |||
225 | 31378 | 6 | *ref_out = NULL; | |
226 | - | |||
227 | 31378 | 6 | if (max_nesting > MAX_NESTING_LEVEL) | |
228 | ##### | 7 | max_nesting = MAX_NESTING_LEVEL; | |
229 | 31378 | 8 | else if (max_nesting < 0) | |
230 | 18268 | 9 | max_nesting = DEFAULT_NESTING_LEVEL; | |
231 | - | |||
232 | 31378 | 10 | scan_type = GIT_REFERENCE_SYMBOLIC; | |
233 | - | |||
234 | 31378 | 10,11 | if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0) | |
235 | 12 | 12 | return error; | |
236 | - | |||
237 | 31365 | 13,14 | if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) | |
238 | ##### | 15 | return error; | |
239 | - | |||
240 | 52011 | 16,23 | for (nesting = max_nesting; | |
241 | 39711 | 24 | nesting >= 0 && scan_type == GIT_REFERENCE_SYMBOLIC; | |
242 | 20646 | 22 | nesting--) | |
243 | - | { | ||
244 | 32654 | 17 | if (nesting != max_nesting) { | |
245 | 1289 | 18 | strncpy(scan_name, ref->target.symbolic, sizeof(scan_name)); | |
246 | 1289 | 18 | git_reference_free(ref); | |
247 | - | } | ||
248 | - | |||
249 | 32655 | 19,20 | if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0) | |
250 | 12009 | 21 | return error; | |
251 | - | |||
252 | 20646 | 22 | scan_type = ref->type; | |
253 | - | } | ||
254 | - | |||
255 | 19357 | 25,26 | if (scan_type != GIT_REFERENCE_DIRECT && max_nesting != 0) { | |
256 | ##### | 27 | git_error_set(GIT_ERROR_REFERENCE, | |
257 | - | "cannot resolve reference (>%u levels deep)", max_nesting); | ||
258 | ##### | 28 | git_reference_free(ref); | |
259 | ##### | 29 | return -1; | |
260 | - | } | ||
261 | - | |||
262 | 19357 | 30 | *ref_out = ref; | |
263 | 19357 | 30 | return 0; | |
264 | - | } | ||
265 | - | |||
266 | 110 | 2 | int git_reference__read_head( | |
267 | - | git_reference **out, | ||
268 | - | git_repository *repo, | ||
269 | - | const char *path) | ||
270 | - | { | ||
271 | 110 | 2 | git_buf reference = GIT_BUF_INIT; | |
272 | 110 | 2 | char *name = NULL; | |
273 | - | int error; | ||
274 | - | |||
275 | 110 | 2,3 | if ((error = git_futils_readbuffer(&reference, path)) < 0) | |
276 | 2 | 4 | goto out; | |
277 | 108 | 5 | git_buf_rtrim(&reference); | |
278 | - | |||
279 | 108 | 6 | if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) { | |
280 | 106 | 7 | git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF)); | |
281 | - | |||
282 | 106 | 8 | name = git_path_basename(path); | |
283 | - | |||
284 | 106 | 9,10 | if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) { | |
285 | ##### | 11 | error = -1; | |
286 | ##### | 11 | goto out; | |
287 | - | } | ||
288 | - | } else { | ||
289 | 2 | 12,13 | if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0) | |
290 | 2 | 14 | goto out; | |
291 | - | } | ||
292 | - | |||
293 | - | out: | ||
294 | 110 | 15 | git__free(name); | |
295 | 110 | 16 | git_buf_dispose(&reference); | |
296 | - | |||
297 | 110 | 17 | return error; | |
298 | - | } | ||
299 | - | |||
300 | 1689 | 2 | int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname) | |
301 | - | { | ||
302 | 1689 | 2 | int error = 0, i; | |
303 | 1689 | 2 | bool fallbackmode = true, foundvalid = false; | |
304 | - | git_reference *ref; | ||
305 | 1689 | 2 | git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; | |
306 | - | |||
307 | - | static const char* formatters[] = { | ||
308 | - | "%s", | ||
309 | - | GIT_REFS_DIR "%s", | ||
310 | - | GIT_REFS_TAGS_DIR "%s", | ||
311 | - | GIT_REFS_HEADS_DIR "%s", | ||
312 | - | GIT_REFS_REMOTES_DIR "%s", | ||
313 | - | GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE, | ||
314 | - | NULL | ||
315 | - | }; | ||
316 | - | |||
317 | 1689 | 2 | if (*refname) | |
318 | 1682 | 3 | git_buf_puts(&name, refname); | |
319 | - | else { | ||
320 | 7 | 4 | git_buf_puts(&name, GIT_HEAD_FILE); | |
321 | 7 | 5 | fallbackmode = false; | |
322 | - | } | ||
323 | - | |||
324 | 10180 | 6,22-25 | for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) { | |
325 | - | |||
326 | 8819 | 7 | git_buf_clear(&refnamebuf); | |
327 | - | |||
328 | 8819 | 8-10 | if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0) | |
329 | ##### | 11 | goto cleanup; | |
330 | - | |||
331 | 8819 | 12-14 | if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) { | |
332 | 396 | 15 | error = GIT_EINVALIDSPEC; | |
333 | 396 | 15 | continue; | |
334 | - | } | ||
335 | 8423 | 16 | foundvalid = true; | |
336 | - | |||
337 | 8423 | 16,17 | error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1); | |
338 | - | |||
339 | 8423 | 18 | if (!error) { | |
340 | 328 | 19 | *out = ref; | |
341 | 328 | 19 | error = 0; | |
342 | 328 | 19 | goto cleanup; | |
343 | - | } | ||
344 | - | |||
345 | 8095 | 20 | if (error != GIT_ENOTFOUND) | |
346 | ##### | 21 | goto cleanup; | |
347 | - | } | ||
348 | - | |||
349 | - | cleanup: | ||
350 | 1689 | 26,27 | if (error && !foundvalid) { | |
351 | - | /* never found a valid reference name */ | ||
352 | 3 | 28,29 | git_error_set(GIT_ERROR_REFERENCE, | |
353 | - | "could not use '%s' as valid reference name", git_buf_cstr(&name)); | ||
354 | - | } | ||
355 | - | |||
356 | 1689 | 30 | if (error == GIT_ENOTFOUND) | |
357 | 1358 | 31 | git_error_set(GIT_ERROR_REFERENCE, "no reference found for shorthand '%s'", refname); | |
358 | - | |||
359 | 1689 | 32 | git_buf_dispose(&name); | |
360 | 1689 | 33 | git_buf_dispose(&refnamebuf); | |
361 | 1689 | 34 | return error; | |
362 | - | } | ||
363 | - | |||
364 | - | /** | ||
365 | - | * Getters | ||
366 | - | */ | ||
367 | 12254 | 2 | git_reference_t git_reference_type(const git_reference *ref) | |
368 | - | { | ||
369 | 12254 | 2,3 | assert(ref); | |
370 | 12254 | 4 | return ref->type; | |
371 | - | } | ||
372 | - | |||
373 | 2089 | 2 | const char *git_reference_name(const git_reference *ref) | |
374 | - | { | ||
375 | 2089 | 2,3 | assert(ref); | |
376 | 2089 | 4 | return ref->name; | |
377 | - | } | ||
378 | - | |||
379 | 4395 | 2 | git_repository *git_reference_owner(const git_reference *ref) | |
380 | - | { | ||
381 | 4395 | 2,3 | assert(ref); | |
382 | 4395 | 4 | return ref->db->repo; | |
383 | - | } | ||
384 | - | |||
385 | 6901 | 2 | const git_oid *git_reference_target(const git_reference *ref) | |
386 | - | { | ||
387 | 6901 | 2,3 | assert(ref); | |
388 | - | |||
389 | 6901 | 4 | if (ref->type != GIT_REFERENCE_DIRECT) | |
390 | 2 | 5 | return NULL; | |
391 | - | |||
392 | 6899 | 6 | return &ref->target.oid; | |
393 | - | } | ||
394 | - | |||
395 | ##### | 2 | const git_oid *git_reference_target_peel(const git_reference *ref) | |
396 | - | { | ||
397 | ##### | 2,3 | assert(ref); | |
398 | - | |||
399 | ##### | 4-6 | if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel)) | |
400 | ##### | 7 | return NULL; | |
401 | - | |||
402 | ##### | 8 | return &ref->peel; | |
403 | - | } | ||
404 | - | |||
405 | 6139 | 2 | const char *git_reference_symbolic_target(const git_reference *ref) | |
406 | - | { | ||
407 | 6139 | 2,3 | assert(ref); | |
408 | - | |||
409 | 6139 | 4 | if (ref->type != GIT_REFERENCE_SYMBOLIC) | |
410 | ##### | 5 | return NULL; | |
411 | - | |||
412 | 6139 | 6 | return ref->target.symbolic; | |
413 | - | } | ||
414 | - | |||
415 | 2246 | 2 | static int reference__create( | |
416 | - | git_reference **ref_out, | ||
417 | - | git_repository *repo, | ||
418 | - | const char *name, | ||
419 | - | const git_oid *oid, | ||
420 | - | const char *symbolic, | ||
421 | - | int force, | ||
422 | - | const git_signature *signature, | ||
423 | - | const char *log_message, | ||
424 | - | const git_oid *old_id, | ||
425 | - | const char *old_target) | ||
426 | - | { | ||
427 | - | git_refname_t normalized; | ||
428 | - | git_refdb *refdb; | ||
429 | 2246 | 2 | git_reference *ref = NULL; | |
430 | 2246 | 2 | int error = 0; | |
431 | - | |||
432 | 2246 | 2-4 | assert(repo && name); | |
433 | 2246 | 5-7 | assert(symbolic || signature); | |
434 | - | |||
435 | 2246 | 8 | if (ref_out) | |
436 | 2235 | 9 | *ref_out = NULL; | |
437 | - | |||
438 | 2246 | 10 | error = reference_normalize_for_repo(normalized, repo, name, true); | |
439 | 2246 | 11 | if (error < 0) | |
440 | 17 | 12 | return error; | |
441 | - | |||
442 | 2229 | 13 | error = git_repository_refdb__weakptr(&refdb, repo); | |
443 | 2229 | 14 | if (error < 0) | |
444 | ##### | 15 | return error; | |
445 | - | |||
446 | 2229 | 16 | if (oid != NULL) { | |
447 | 1952 | 17,18 | assert(symbolic == NULL); | |
448 | - | |||
449 | 1952 | 19,20 | if (!git_object__is_valid(repo, oid, GIT_OBJECT_ANY)) { | |
450 | 1 | 21 | git_error_set(GIT_ERROR_REFERENCE, | |
451 | - | "target OID for the reference doesn't exist on the repository"); | ||
452 | 1 | 22 | return -1; | |
453 | - | } | ||
454 | - | |||
455 | 1951 | 23 | ref = git_reference__alloc(normalized, oid, NULL); | |
456 | - | } else { | ||
457 | - | git_refname_t normalized_target; | ||
458 | - | |||
459 | 277 | 24 | error = reference_normalize_for_repo(normalized_target, repo, | |
460 | - | symbolic, git_reference__enable_symbolic_ref_target_validation); | ||
461 | - | |||
462 | 277 | 25 | if (error < 0) | |
463 | 2 | 26 | return error; | |
464 | - | |||
465 | 275 | 27,28 | ref = git_reference__alloc_symbolic(normalized, normalized_target); | |
466 | - | } | ||
467 | - | |||
468 | 2226 | 29,30 | GIT_ERROR_CHECK_ALLOC(ref); | |
469 | - | |||
470 | 2226 | 31,32 | if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) { | |
471 | 21 | 33 | git_reference_free(ref); | |
472 | 21 | 34 | return error; | |
473 | - | } | ||
474 | - | |||
475 | 2205 | 35 | if (ref_out == NULL) | |
476 | 9 | 36 | git_reference_free(ref); | |
477 | - | else | ||
478 | 2196 | 37 | *ref_out = ref; | |
479 | - | |||
480 | 2205 | 38 | return 0; | |
481 | - | } | ||
482 | - | |||
483 | 2175 | 2 | static int refs_configured_ident(git_signature **out, const git_repository *repo) | |
484 | - | { | ||
485 | 2175 | 2,3 | if (repo->ident_name && repo->ident_email) | |
486 | 89 | 4 | return git_signature_now(out, repo->ident_name, repo->ident_email); | |
487 | - | |||
488 | - | /* if not configured let us fall-through to the next method */ | ||
489 | 2086 | 5 | return -1; | |
490 | - | } | ||
491 | - | |||
492 | 2175 | 2 | int git_reference__log_signature(git_signature **out, git_repository *repo) | |
493 | - | { | ||
494 | - | int error; | ||
495 | - | git_signature *who; | ||
496 | - | |||
497 | 2175 | 2-5 | if(((error = refs_configured_ident(&who, repo)) < 0) && | |
498 | 2086 | 6,7 | ((error = git_signature_default(&who, repo)) < 0) && | |
499 | - | ((error = git_signature_now(&who, "unknown", "unknown")) < 0)) | ||
500 | ##### | 8 | return error; | |
501 | - | |||
502 | 2175 | 9 | *out = who; | |
503 | 2175 | 9 | return 0; | |
504 | - | } | ||
505 | - | |||
506 | 1645 | 2 | int git_reference_create_matching( | |
507 | - | git_reference **ref_out, | ||
508 | - | git_repository *repo, | ||
509 | - | const char *name, | ||
510 | - | const git_oid *id, | ||
511 | - | int force, | ||
512 | - | const git_oid *old_id, | ||
513 | - | const char *log_message) | ||
514 | - | |||
515 | - | { | ||
516 | - | int error; | ||
517 | 1645 | 2 | git_signature *who = NULL; | |
518 | - | |||
519 | 1645 | 2,3 | assert(id); | |
520 | - | |||
521 | 1645 | 4,5 | if ((error = git_reference__log_signature(&who, repo)) < 0) | |
522 | ##### | 6 | return error; | |
523 | - | |||
524 | 1645 | 7 | error = reference__create( | |
525 | - | ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL); | ||
526 | - | |||
527 | 1645 | 8 | git_signature_free(who); | |
528 | 1645 | 9 | return error; | |
529 | - | } | ||
530 | - | |||
531 | 1632 | 2 | int git_reference_create( | |
532 | - | git_reference **ref_out, | ||
533 | - | git_repository *repo, | ||
534 | - | const char *name, | ||
535 | - | const git_oid *id, | ||
536 | - | int force, | ||
537 | - | const char *log_message) | ||
538 | - | { | ||
539 | 1632 | 2 | return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message); | |
540 | - | } | ||
541 | - | |||
542 | 285 | 2 | int git_reference_symbolic_create_matching( | |
543 | - | git_reference **ref_out, | ||
544 | - | git_repository *repo, | ||
545 | - | const char *name, | ||
546 | - | const char *target, | ||
547 | - | int force, | ||
548 | - | const char *old_target, | ||
549 | - | const char *log_message) | ||
550 | - | { | ||
551 | - | int error; | ||
552 | 285 | 2 | git_signature *who = NULL; | |
553 | - | |||
554 | 285 | 2,3 | assert(target); | |
555 | - | |||
556 | 285 | 4,5 | if ((error = git_reference__log_signature(&who, repo)) < 0) | |
557 | ##### | 6 | return error; | |
558 | - | |||
559 | 285 | 7 | error = reference__create( | |
560 | - | ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target); | ||
561 | - | |||
562 | 285 | 8 | git_signature_free(who); | |
563 | 285 | 9 | return error; | |
564 | - | } | ||
565 | - | |||
566 | 274 | 2 | int git_reference_symbolic_create( | |
567 | - | git_reference **ref_out, | ||
568 | - | git_repository *repo, | ||
569 | - | const char *name, | ||
570 | - | const char *target, | ||
571 | - | int force, | ||
572 | - | const char *log_message) | ||
573 | - | { | ||
574 | 274 | 2 | return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message); | |
575 | - | } | ||
576 | - | |||
577 | 36 | 2 | static int ensure_is_an_updatable_direct_reference(git_reference *ref) | |
578 | - | { | ||
579 | 36 | 2 | if (ref->type == GIT_REFERENCE_DIRECT) | |
580 | 35 | 3 | return 0; | |
581 | - | |||
582 | 1 | 4 | git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference"); | |
583 | 1 | 5 | return -1; | |
584 | - | } | ||
585 | - | |||
586 | 5 | 2 | int git_reference_set_target( | |
587 | - | git_reference **out, | ||
588 | - | git_reference *ref, | ||
589 | - | const git_oid *id, | ||
590 | - | const char *log_message) | ||
591 | - | { | ||
592 | - | int error; | ||
593 | - | git_repository *repo; | ||
594 | - | |||
595 | 5 | 2-5 | assert(out && ref && id); | |
596 | - | |||
597 | 5 | 6 | repo = ref->db->repo; | |
598 | - | |||
599 | 5 | 6,7 | if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) | |
600 | 1 | 8 | return error; | |
601 | - | |||
602 | 4 | 9 | return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message); | |
603 | - | } | ||
604 | - | |||
605 | 9 | 2 | static int ensure_is_an_updatable_symbolic_reference(git_reference *ref) | |
606 | - | { | ||
607 | 9 | 2 | if (ref->type == GIT_REFERENCE_SYMBOLIC) | |
608 | 8 | 3 | return 0; | |
609 | - | |||
610 | 1 | 4 | git_error_set(GIT_ERROR_REFERENCE, "cannot set symbolic target on a direct reference"); | |
611 | 1 | 5 | return -1; | |
612 | - | } | ||
613 | - | |||
614 | 9 | 2 | int git_reference_symbolic_set_target( | |
615 | - | git_reference **out, | ||
616 | - | git_reference *ref, | ||
617 | - | const char *target, | ||
618 | - | const char *log_message) | ||
619 | - | { | ||
620 | - | int error; | ||
621 | - | |||
622 | 9 | 2-5 | assert(out && ref && target); | |
623 | - | |||
624 | 9 | 6,7 | if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0) | |
625 | 1 | 8 | return error; | |
626 | - | |||
627 | 8 | 9 | return git_reference_symbolic_create_matching( | |
628 | 8 | 9 | out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message); | |
629 | - | } | ||
630 | - | |||
631 | - | typedef struct { | ||
632 | - | const char *old_name; | ||
633 | - | git_refname_t new_name; | ||
634 | - | } rename_cb_data; | ||
635 | - | |||
636 | 40 | 2 | static int update_wt_heads(git_repository *repo, const char *path, void *payload) | |
637 | - | { | ||
638 | 40 | 2 | rename_cb_data *data = (rename_cb_data *) payload; | |
639 | 40 | 2 | git_reference *head = NULL; | |
640 | 40 | 2 | char *gitdir = NULL; | |
641 | - | int error; | ||
642 | - | |||
643 | 40 | 2,3 | if ((error = git_reference__read_head(&head, repo, path)) < 0) { | |
644 | ##### | 4 | git_error_set(GIT_ERROR_REFERENCE, "could not read HEAD when renaming references"); | |
645 | ##### | 5 | goto out; | |
646 | - | } | ||
647 | - | |||
648 | 40 | 6,7 | if ((gitdir = git_path_dirname(path)) == NULL) { | |
649 | ##### | 8 | error = -1; | |
650 | ##### | 8 | goto out; | |
651 | - | } | ||
652 | - | |||
653 | 40 | 9-11 | if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC || | |
654 | 40 | 11 | git__strcmp(head->target.symbolic, data->old_name) != 0) { | |
655 | 39 | 12 | error = 0; | |
656 | 39 | 12 | goto out; | |
657 | - | } | ||
658 | - | |||
659 | - | /* Update HEAD it was pointing to the reference being renamed */ | ||
660 | 1 | 13,14 | if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) { | |
661 | ##### | 15 | git_error_set(GIT_ERROR_REFERENCE, "failed to update HEAD after renaming reference"); | |
662 | ##### | 16 | goto out; | |
663 | - | } | ||
664 | - | |||
665 | - | out: | ||
666 | 40 | 17 | git_reference_free(head); | |
667 | 40 | 18 | git__free(gitdir); | |
668 | - | |||
669 | 40 | 19 | return error; | |
670 | - | } | ||
671 | - | |||
672 | 45 | 2 | static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force, | |
673 | - | const git_signature *signature, const char *message) | ||
674 | - | { | ||
675 | - | git_repository *repo; | ||
676 | - | git_refname_t normalized; | ||
677 | 45 | 2 | bool should_head_be_updated = false; | |
678 | 45 | 2 | int error = 0; | |
679 | - | |||
680 | 45 | 2-5 | assert(ref && new_name && signature); | |
681 | - | |||
682 | 45 | 6 | repo = git_reference_owner(ref); | |
683 | - | |||
684 | 45 | 7,8 | if ((error = reference_normalize_for_repo( | |
685 | - | normalized, repo, new_name, true)) < 0) | ||
686 | 3 | 9 | return error; | |
687 | - | |||
688 | - | /* Check if we have to update HEAD. */ | ||
689 | 42 | 10,11 | if ((error = git_branch_is_head(ref)) < 0) | |
690 | ##### | 12 | return error; | |
691 | - | |||
692 | 42 | 13 | should_head_be_updated = (error > 0); | |
693 | - | |||
694 | 42 | 13,14 | if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0) | |
695 | 5 | 15 | return error; | |
696 | - | |||
697 | - | /* Update HEAD if it was pointing to the reference being renamed */ | ||
698 | 37 | 16 | if (should_head_be_updated) { | |
699 | 6 | 17 | error = git_repository_set_head(ref->db->repo, normalized); | |
700 | - | } else { | ||
701 | - | rename_cb_data payload; | ||
702 | 31 | 18 | payload.old_name = ref->name; | |
703 | 31 | 18 | memcpy(&payload.new_name, &normalized, sizeof(normalized)); | |
704 | - | |||
705 | 31 | 18,19 | error = git_repository_foreach_head(repo, update_wt_heads, 0, &payload); | |
706 | - | } | ||
707 | - | |||
708 | 37 | 20 | return error; | |
709 | - | } | ||
710 | - | |||
711 | - | |||
712 | 45 | 2 | int git_reference_rename( | |
713 | - | git_reference **out, | ||
714 | - | git_reference *ref, | ||
715 | - | const char *new_name, | ||
716 | - | int force, | ||
717 | - | const char *log_message) | ||
718 | - | { | ||
719 | - | git_signature *who; | ||
720 | - | int error; | ||
721 | - | |||
722 | 45 | 2-4 | assert(out && ref); | |
723 | - | |||
724 | 45 | 5,6 | if ((error = git_reference__log_signature(&who, ref->db->repo)) < 0) | |
725 | ##### | 7 | return error; | |
726 | - | |||
727 | 45 | 8 | error = reference__rename(out, ref, new_name, force, who, log_message); | |
728 | 45 | 9 | git_signature_free(who); | |
729 | - | |||
730 | 45 | 10 | return error; | |
731 | - | } | ||
732 | - | |||
733 | 2051 | 2 | int git_reference_resolve(git_reference **ref_out, const git_reference *ref) | |
734 | - | { | ||
735 | 2051 | 2,3 | switch (git_reference_type(ref)) { | |
736 | - | case GIT_REFERENCE_DIRECT: | ||
737 | 1767 | 4 | return git_reference_lookup(ref_out, ref->db->repo, ref->name); | |
738 | - | |||
739 | - | case GIT_REFERENCE_SYMBOLIC: | ||
740 | 284 | 5 | return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); | |
741 | - | |||
742 | - | default: | ||
743 | ##### | 6 | git_error_set(GIT_ERROR_REFERENCE, "invalid reference"); | |
744 | ##### | 7 | return -1; | |
745 | - | } | ||
746 | - | } | ||
747 | - | |||
748 | 40 | 2 | int git_reference_foreach( | |
749 | - | git_repository *repo, | ||
750 | - | git_reference_foreach_cb callback, | ||
751 | - | void *payload) | ||
752 | - | { | ||
753 | - | git_reference_iterator *iter; | ||
754 | - | git_reference *ref; | ||
755 | - | int error; | ||
756 | - | |||
757 | 40 | 2,3 | if ((error = git_reference_iterator_new(&iter, repo)) < 0) | |
758 | ##### | 4 | return error; | |
759 | - | |||
760 | 115 | 5,10,11 | while (!(error = git_reference_next(&ref, iter))) { | |
761 | 76 | 6,7 | if ((error = callback(ref, payload)) != 0) { | |
762 | 1 | 8 | git_error_set_after_callback(error); | |
763 | 1 | 9 | break; | |
764 | - | } | ||
765 | - | } | ||
766 | - | |||
767 | 40 | 12 | if (error == GIT_ITEROVER) | |
768 | 39 | 13 | error = 0; | |
769 | - | |||
770 | 40 | 14 | git_reference_iterator_free(iter); | |
771 | 40 | 15 | return error; | |
772 | - | } | ||
773 | - | |||
774 | 341 | 2 | int git_reference_foreach_name( | |
775 | - | git_repository *repo, | ||
776 | - | git_reference_foreach_name_cb callback, | ||
777 | - | void *payload) | ||
778 | - | { | ||
779 | - | git_reference_iterator *iter; | ||
780 | - | const char *refname; | ||
781 | - | int error; | ||
782 | - | |||
783 | 341 | 2,3 | if ((error = git_reference_iterator_new(&iter, repo)) < 0) | |
784 | ##### | 4 | return error; | |
785 | - | |||
786 | 4211 | 5,10,11 | while (!(error = git_reference_next_name(&refname, iter))) { | |
787 | 3873 | 6,7 | if ((error = callback(refname, payload)) != 0) { | |
788 | 3 | 8 | git_error_set_after_callback(error); | |
789 | 3 | 9 | break; | |
790 | - | } | ||
791 | - | } | ||
792 | - | |||
793 | 341 | 12 | if (error == GIT_ITEROVER) | |
794 | 338 | 13 | error = 0; | |
795 | - | |||
796 | 341 | 14 | git_reference_iterator_free(iter); | |
797 | 341 | 15 | return error; | |
798 | - | } | ||
799 | - | |||
800 | 6 | 2 | int git_reference_foreach_glob( | |
801 | - | git_repository *repo, | ||
802 | - | const char *glob, | ||
803 | - | git_reference_foreach_name_cb callback, | ||
804 | - | void *payload) | ||
805 | - | { | ||
806 | - | git_reference_iterator *iter; | ||
807 | - | const char *refname; | ||
808 | - | int error; | ||
809 | - | |||
810 | 6 | 2,3 | if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0) | |
811 | ##### | 4 | return error; | |
812 | - | |||
813 | 57 | 5,10,11 | while (!(error = git_reference_next_name(&refname, iter))) { | |
814 | 52 | 6,7 | if ((error = callback(refname, payload)) != 0) { | |
815 | 1 | 8 | git_error_set_after_callback(error); | |
816 | 1 | 9 | break; | |
817 | - | } | ||
818 | - | } | ||
819 | - | |||
820 | 6 | 12 | if (error == GIT_ITEROVER) | |
821 | 5 | 13 | error = 0; | |
822 | - | |||
823 | 6 | 14 | git_reference_iterator_free(iter); | |
824 | 6 | 15 | return error; | |
825 | - | } | ||
826 | - | |||
827 | 427 | 2 | int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo) | |
828 | - | { | ||
829 | - | git_refdb *refdb; | ||
830 | - | |||
831 | 427 | 2,3 | if (git_repository_refdb__weakptr(&refdb, repo) < 0) | |
832 | ##### | 4 | return -1; | |
833 | - | |||
834 | 427 | 5 | return git_refdb_iterator(out, refdb, NULL); | |
835 | - | } | ||
836 | - | |||
837 | 61 | 2 | int git_reference_iterator_glob_new( | |
838 | - | git_reference_iterator **out, git_repository *repo, const char *glob) | ||
839 | - | { | ||
840 | - | git_refdb *refdb; | ||
841 | - | |||
842 | 61 | 2,3 | if (git_repository_refdb__weakptr(&refdb, repo) < 0) | |
843 | ##### | 4 | return -1; | |
844 | - | |||
845 | 61 | 5 | return git_refdb_iterator(out, refdb, glob); | |
846 | - | } | ||
847 | - | |||
848 | 3097 | 2 | int git_reference_next(git_reference **out, git_reference_iterator *iter) | |
849 | - | { | ||
850 | 3097 | 2 | return git_refdb_iterator_next(out, iter); | |
851 | - | } | ||
852 | - | |||
853 | 4400 | 2 | int git_reference_next_name(const char **out, git_reference_iterator *iter) | |
854 | - | { | ||
855 | 4400 | 2 | return git_refdb_iterator_next_name(out, iter); | |
856 | - | } | ||
857 | - | |||
858 | 488 | 2 | void git_reference_iterator_free(git_reference_iterator *iter) | |
859 | - | { | ||
860 | 488 | 2 | if (iter == NULL) | |
861 | 488 | 3,5 | return; | |
862 | - | |||
863 | 488 | 4 | git_refdb_iterator_free(iter); | |
864 | - | } | ||
865 | - | |||
866 | 2331 | 2 | static int cb__reflist_add(const char *ref, void *data) | |
867 | - | { | ||
868 | 2331 | 2 | char *name = git__strdup(ref); | |
869 | 2331 | 3,4 | GIT_ERROR_CHECK_ALLOC(name); | |
870 | 2331 | 5 | return git_vector_insert((git_vector *)data, name); | |
871 | - | } | ||
872 | - | |||
873 | 136 | 2 | int git_reference_list( | |
874 | - | git_strarray *array, | ||
875 | - | git_repository *repo) | ||
876 | - | { | ||
877 | - | git_vector ref_list; | ||
878 | - | |||
879 | 136 | 2-4 | assert(array && repo); | |
880 | - | |||
881 | 136 | 5 | array->strings = NULL; | |
882 | 136 | 5 | array->count = 0; | |
883 | - | |||
884 | 136 | 5,6 | if (git_vector_init(&ref_list, 8, NULL) < 0) | |
885 | ##### | 7 | return -1; | |
886 | - | |||
887 | 136 | 8,9 | if (git_reference_foreach_name( | |
888 | - | repo, &cb__reflist_add, (void *)&ref_list) < 0) { | ||
889 | ##### | 10 | git_vector_free(&ref_list); | |
890 | ##### | 11 | return -1; | |
891 | - | } | ||
892 | - | |||
893 | 136 | 12 | array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list); | |
894 | - | |||
895 | 136 | 13 | return 0; | |
896 | - | } | ||
897 | - | |||
898 | 880764 | 2 | static int is_valid_ref_char(char ch) | |
899 | - | { | ||
900 | 880764 | 2 | if ((unsigned) ch <= ' ') | |
901 | 66 | 3 | return 0; | |
902 | - | |||
903 | 880698 | 4 | switch (ch) { | |
904 | - | case '~': | ||
905 | - | case '^': | ||
906 | - | case ':': | ||
907 | - | case '\\': | ||
908 | - | case '?': | ||
909 | - | case '[': | ||
910 | 1107 | 5 | return 0; | |
911 | - | default: | ||
912 | 879591 | 6 | return 1; | |
913 | - | } | ||
914 | - | } | ||
915 | - | |||
916 | 162063 | 2 | static int ensure_segment_validity(const char *name, char may_contain_glob) | |
917 | - | { | ||
918 | 162063 | 2 | const char *current = name; | |
919 | 162063 | 2 | char prev = '\0'; | |
920 | 162063 | 2 | const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION); | |
921 | - | int segment_len; | ||
922 | - | |||
923 | 162063 | 2 | if (*current == '.') | |
924 | 13 | 3 | return -1; /* Refname starts with "." */ | |
925 | - | |||
926 | 879555 | 4,20 | for (current = name; ; current++) { | |
927 | 1041605 | 5,6 | if (*current == '\0' || *current == '/') | |
928 | - | break; | ||
929 | - | |||
930 | 880764 | 7,8 | if (!is_valid_ref_char(*current)) | |
931 | 1173 | 9 | return -1; /* Illegal character in refname */ | |
932 | - | |||
933 | 879590 | 10,11 | if (prev == '.' && *current == '.') | |
934 | 2 | 12 | return -1; /* Refname contains ".." */ | |
935 | - | |||
936 | 879588 | 13,14 | if (prev == '@' && *current == '{') | |
937 | 19 | 15 | return -1; /* Refname contains "@{" */ | |
938 | - | |||
939 | 879569 | 16 | if (*current == '*') { | |
940 | 1952 | 17 | if (!may_contain_glob) | |
941 | 14 | 18 | return -1; | |
942 | 1938 | 19 | may_contain_glob = 0; | |
943 | - | } | ||
944 | - | |||
945 | 879555 | 20 | prev = *current; | |
946 | 879555 | 20 | } | |
947 | - | |||
948 | 160841 | 21 | segment_len = (int)(current - name); | |
949 | - | |||
950 | - | /* A refname component can not end with ".lock" */ | ||
951 | 160841 | 21,22 | if (segment_len >= lock_len && | |
952 | 70476 | 22 | !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len)) | |
953 | 6 | 23 | return -1; | |
954 | - | |||
955 | 160835 | 24 | return segment_len; | |
956 | - | } | ||
957 | - | |||
958 | 51183 | 2 | static bool is_all_caps_and_underscore(const char *name, size_t len) | |
959 | - | { | ||
960 | - | size_t i; | ||
961 | - | char c; | ||
962 | - | |||
963 | 51183 | 2-4 | assert(name && len > 0); | |
964 | - | |||
965 | 89857 | 5,10,11 | for (i = 0; i < len; i++) | |
966 | - | { | ||
967 | 80246 | 6 | c = name[i]; | |
968 | 80246 | 6-8 | if ((c < 'A' || c > 'Z') && c != '_') | |
969 | 41572 | 9 | return false; | |
970 | - | } | ||
971 | - | |||
972 | 9611 | 12,13 | if (*name == '_' || name[len - 1] == '_') | |
973 | 2 | 14 | return false; | |
974 | - | |||
975 | 9609 | 15 | return true; | |
976 | - | } | ||
977 | - | |||
978 | - | /* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */ | ||
979 | 52523 | 2 | int git_reference__normalize_name( | |
980 | - | git_buf *buf, | ||
981 | - | const char *name, | ||
982 | - | unsigned int flags) | ||
983 | - | { | ||
984 | - | const char *current; | ||
985 | 52523 | 2 | int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; | |
986 | - | unsigned int process_flags; | ||
987 | 52523 | 2 | bool normalize = (buf != NULL); | |
988 | 52523 | 2 | bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0; | |
989 | - | |||
990 | - | #ifdef GIT_USE_ICONV | ||
991 | - | git_path_iconv_t ic = GIT_PATH_ICONV_INIT; | ||
992 | - | #endif | ||
993 | - | |||
994 | 52523 | 2,3 | assert(name); | |
995 | - | |||
996 | 52523 | 4 | process_flags = flags; | |
997 | 52523 | 4 | current = (char *)name; | |
998 | - | |||
999 | 52523 | 4,5 | if (validate && *current == '/') | |
1000 | 10 | 6 | goto cleanup; | |
1001 | - | |||
1002 | 52513 | 7 | if (normalize) | |
1003 | 34129 | 8 | git_buf_clear(buf); | |
1004 | - | |||
1005 | - | #ifdef GIT_USE_ICONV | ||
1006 | - | if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) { | ||
1007 | - | size_t namelen = strlen(current); | ||
1008 | - | if ((error = git_path_iconv_init_precompose(&ic)) < 0 || | ||
1009 | - | (error = git_path_iconv(&ic, ¤t, &namelen)) < 0) | ||
1010 | - | goto cleanup; | ||
1011 | - | error = GIT_EINVALIDSPEC; | ||
1012 | - | } | ||
1013 | - | #endif | ||
1014 | - | |||
1015 | 52513 | 9 | if (!validate) { | |
1016 | 1 | 10 | git_buf_sets(buf, current); | |
1017 | - | |||
1018 | 1 | 11-14 | error = git_buf_oom(buf) ? -1 : 0; | |
1019 | 1 | 15 | goto cleanup; | |
1020 | - | } | ||
1021 | - | |||
1022 | - | while (true) { | ||
1023 | 162064 | 16 | char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; | |
1024 | - | |||
1025 | 162064 | 16 | segment_len = ensure_segment_validity(current, may_contain_glob); | |
1026 | 162066 | 17 | if (segment_len < 0) | |
1027 | 1227 | 18 | goto cleanup; | |
1028 | - | |||
1029 | 160839 | 19 | if (segment_len > 0) { | |
1030 | - | /* | ||
1031 | - | * There may only be one glob in a pattern, thus we reset | ||
1032 | - | * the pattern-flag in case the current segment has one. | ||
1033 | - | */ | ||
1034 | 160795 | 20 | if (memchr(current, '*', segment_len)) | |
1035 | 1936 | 21 | process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; | |
1036 | - | |||
1037 | 160795 | 22 | if (normalize) { | |
1038 | 96875 | 23 | size_t cur_len = git_buf_len(buf); | |
1039 | - | |||
1040 | 96875 | 24,25 | git_buf_joinpath(buf, git_buf_cstr(buf), current); | |
1041 | 96876 | 26-29 | git_buf_truncate(buf, | |
1042 | 96876 | 26 | cur_len + segment_len + (segments_count ? 1 : 0)); | |
1043 | - | |||
1044 | 96873 | 30,31 | if (git_buf_oom(buf)) { | |
1045 | ##### | 32 | error = -1; | |
1046 | ##### | 32 | goto cleanup; | |
1047 | - | } | ||
1048 | - | } | ||
1049 | - | |||
1050 | 160793 | 33 | segments_count++; | |
1051 | - | } | ||
1052 | - | |||
1053 | - | /* No empty segment is allowed when not normalizing */ | ||
1054 | 160837 | 34,35 | if (segment_len == 0 && !normalize) | |
1055 | 12 | 36 | goto cleanup; | |
1056 | - | |||
1057 | 160825 | 37 | if (current[segment_len] == '\0') | |
1058 | 51273 | 38 | break; | |
1059 | - | |||
1060 | 109552 | 39 | current += segment_len + 1; | |
1061 | 109552 | 39 | } | |
1062 | - | |||
1063 | - | /* A refname can not be empty */ | ||
1064 | 51273 | 40,41 | if (segment_len == 0 && segments_count == 0) | |
1065 | 3 | 42 | goto cleanup; | |
1066 | - | |||
1067 | - | /* A refname can not end with "." */ | ||
1068 | 51270 | 43 | if (current[segment_len - 1] == '.') | |
1069 | 4 | 44 | goto cleanup; | |
1070 | - | |||
1071 | - | /* A refname can not end with "/" */ | ||
1072 | 51266 | 45 | if (current[segment_len - 1] == '/') | |
1073 | 3 | 46 | goto cleanup; | |
1074 | - | |||
1075 | 51263 | 47,48 | if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL)) | |
1076 | 4 | 49 | goto cleanup; | |
1077 | - | |||
1078 | 51259 | 50,51 | if ((segments_count == 1 ) && | |
1079 | 10069 | 51,53 | !(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) && | |
1080 | 9993 | 52,54 | !(is_all_caps_and_underscore(name, (size_t)segment_len) || | |
1081 | 386 | 54,55 | ((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) | |
1082 | - | goto cleanup; | ||
1083 | - | |||
1084 | 50874 | 56 | if ((segments_count > 1) | |
1085 | 41190 | 57,58 | && (is_all_caps_and_underscore(name, strchr(name, '/') - name))) | |
1086 | 2 | 59 | goto cleanup; | |
1087 | - | |||
1088 | 50871 | 60 | error = 0; | |
1089 | - | |||
1090 | - | cleanup: | ||
1091 | 52522 | 61 | if (error == GIT_EINVALIDSPEC) | |
1092 | 1650 | 62 | git_error_set( | |
1093 | - | GIT_ERROR_REFERENCE, | ||
1094 | - | "the given reference name '%s' is not valid", name); | ||
1095 | - | |||
1096 | 52522 | 63,64 | if (error && normalize) | |
1097 | 129 | 65 | git_buf_dispose(buf); | |
1098 | - | |||
1099 | - | #ifdef GIT_USE_ICONV | ||
1100 | - | git_path_iconv_clear(&ic); | ||
1101 | - | #endif | ||
1102 | - | |||
1103 | 52522 | 66 | return error; | |
1104 | - | } | ||
1105 | - | |||
1106 | 34098 | 2 | int git_reference_normalize_name( | |
1107 | - | char *buffer_out, | ||
1108 | - | size_t buffer_size, | ||
1109 | - | const char *name, | ||
1110 | - | unsigned int flags) | ||
1111 | - | { | ||
1112 | 34098 | 2 | git_buf buf = GIT_BUF_INIT; | |
1113 | - | int error; | ||
1114 | - | |||
1115 | 34098 | 2,3 | if ((error = git_reference__normalize_name(&buf, name, flags)) < 0) | |
1116 | 128 | 4 | goto cleanup; | |
1117 | - | |||
1118 | 33969 | 5,6 | if (git_buf_len(&buf) > buffer_size - 1) { | |
1119 | 1 | 7 | git_error_set( | |
1120 | - | GIT_ERROR_REFERENCE, | ||
1121 | - | "the provided buffer is too short to hold the normalization of '%s'", name); | ||
1122 | 1 | 8 | error = GIT_EBUFS; | |
1123 | 1 | 8 | goto cleanup; | |
1124 | - | } | ||
1125 | - | |||
1126 | 33968 | 9 | git_buf_copy_cstr(buffer_out, buffer_size, &buf); | |
1127 | - | |||
1128 | 33968 | 10 | error = 0; | |
1129 | - | |||
1130 | - | cleanup: | ||
1131 | 34097 | 11 | git_buf_dispose(&buf); | |
1132 | 34096 | 12 | return error; | |
1133 | - | } | ||
1134 | - | |||
1135 | - | #define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC) | ||
1136 | - | |||
1137 | 7 | 2 | int git_reference_cmp( | |
1138 | - | const git_reference *ref1, | ||
1139 | - | const git_reference *ref2) | ||
1140 | - | { | ||
1141 | - | git_reference_t type1, type2; | ||
1142 | 7 | 2-4 | assert(ref1 && ref2); | |
1143 | - | |||
1144 | 7 | 5 | type1 = git_reference_type(ref1); | |
1145 | 7 | 6 | type2 = git_reference_type(ref2); | |
1146 | - | |||
1147 | - | /* let's put symbolic refs before OIDs */ | ||
1148 | 7 | 7 | if (type1 != type2) | |
1149 | 1 | 8-11 | return (type1 == GIT_REFERENCE_SYMBOLIC) ? -1 : 1; | |
1150 | - | |||
1151 | 6 | 12 | if (type1 == GIT_REFERENCE_SYMBOLIC) | |
1152 | 1 | 13 | return strcmp(ref1->target.symbolic, ref2->target.symbolic); | |
1153 | - | |||
1154 | 5 | 14 | return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); | |
1155 | - | } | ||
1156 | - | |||
1157 | - | /** | ||
1158 | - | * Get the end of a chain of references. If the final one is not | ||
1159 | - | * found, we return the reference just before that. | ||
1160 | - | */ | ||
1161 | 531 | 2 | static int get_terminal(git_reference **out, git_repository *repo, const char *ref_name, int nesting) | |
1162 | - | { | ||
1163 | - | git_reference *ref; | ||
1164 | 531 | 2 | int error = 0; | |
1165 | - | |||
1166 | 531 | 2 | if (nesting > MAX_NESTING_LEVEL) { | |
1167 | ##### | 3 | git_error_set(GIT_ERROR_REFERENCE, "reference chain too deep (%d)", nesting); | |
1168 | ##### | 4 | return GIT_ENOTFOUND; | |
1169 | - | } | ||
1170 | - | |||
1171 | - | /* set to NULL to let the caller know that they're at the end of the chain */ | ||
1172 | 531 | 5,6 | if ((error = git_reference_lookup(&ref, repo, ref_name)) < 0) { | |
1173 | 64 | 7 | *out = NULL; | |
1174 | 64 | 7 | return error; | |
1175 | - | } | ||
1176 | - | |||
1177 | 467 | 8,9 | if (git_reference_type(ref) == GIT_REFERENCE_DIRECT) { | |
1178 | 221 | 10 | *out = ref; | |
1179 | 221 | 10 | error = 0; | |
1180 | - | } else { | ||
1181 | 246 | 11,12 | error = get_terminal(out, repo, git_reference_symbolic_target(ref), nesting + 1); | |
1182 | 246 | 13,14 | if (error == GIT_ENOTFOUND && !*out) | |
1183 | 62 | 15 | *out = ref; | |
1184 | - | else | ||
1185 | 184 | 16 | git_reference_free(ref); | |
1186 | - | } | ||
1187 | - | |||
1188 | 467 | 17 | return error; | |
1189 | - | } | ||
1190 | - | |||
1191 | - | /* | ||
1192 | - | * Starting with the reference given by `ref_name`, follows symbolic | ||
1193 | - | * references until a direct reference is found and updated the OID | ||
1194 | - | * on that direct reference to `oid`. | ||
1195 | - | */ | ||
1196 | 285 | 2 | int git_reference__update_terminal( | |
1197 | - | git_repository *repo, | ||
1198 | - | const char *ref_name, | ||
1199 | - | const git_oid *oid, | ||
1200 | - | const git_signature *sig, | ||
1201 | - | const char *log_message) | ||
1202 | - | { | ||
1203 | 285 | 2 | git_reference *ref = NULL, *ref2 = NULL; | |
1204 | 285 | 2 | git_signature *who = NULL; | |
1205 | - | const git_signature *to_use; | ||
1206 | 285 | 2 | int error = 0; | |
1207 | - | |||
1208 | 285 | 2-4 | if (!sig && (error = git_reference__log_signature(&who, repo)) < 0) | |
1209 | ##### | 5 | return error; | |
1210 | - | |||
1211 | 285 | 6-8 | to_use = sig ? sig : who; | |
1212 | 285 | 9 | error = get_terminal(&ref, repo, ref_name, 0); | |
1213 | - | |||
1214 | - | /* found a dangling symref */ | ||
1215 | 285 | 10,11 | if (error == GIT_ENOTFOUND && ref) { | |
1216 | 62 | 12-14 | assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC); | |
1217 | 62 | 15 | git_error_clear(); | |
1218 | 62 | 16 | error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use, | |
1219 | - | log_message, NULL, NULL); | ||
1220 | 223 | 17 | } else if (error == GIT_ENOTFOUND) { | |
1221 | 2 | 18 | git_error_clear(); | |
1222 | 2 | 19 | error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use, | |
1223 | - | log_message, NULL, NULL); | ||
1224 | 221 | 20 | } else if (error == 0) { | |
1225 | 221 | 21-23 | assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT); | |
1226 | 221 | 24 | error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use, | |
1227 | 221 | 24 | log_message, &ref->target.oid, NULL); | |
1228 | - | } | ||
1229 | - | |||
1230 | 285 | 25 | git_reference_free(ref2); | |
1231 | 285 | 26 | git_reference_free(ref); | |
1232 | 285 | 27 | git_signature_free(who); | |
1233 | 285 | 28 | return error; | |
1234 | - | } | ||
1235 | - | |||
1236 | 126 | 2 | static const char *commit_type(const git_commit *commit) | |
1237 | - | { | ||
1238 | 126 | 2 | unsigned int count = git_commit_parentcount(commit); | |
1239 | - | |||
1240 | 126 | 3 | if (count >= 2) | |
1241 | 1 | 4 | return " (merge)"; | |
1242 | 125 | 5 | else if (count == 0) | |
1243 | 63 | 6 | return " (initial)"; | |
1244 | - | else | ||
1245 | 62 | 7 | return ""; | |
1246 | - | } | ||
1247 | - | |||
1248 | 126 | 2 | int git_reference__update_for_commit( | |
1249 | - | git_repository *repo, | ||
1250 | - | git_reference *ref, | ||
1251 | - | const char *ref_name, | ||
1252 | - | const git_oid *id, | ||
1253 | - | const char *operation) | ||
1254 | - | { | ||
1255 | 126 | 2 | git_reference *ref_new = NULL; | |
1256 | 126 | 2 | git_commit *commit = NULL; | |
1257 | 126 | 2 | git_buf reflog_msg = GIT_BUF_INIT; | |
1258 | - | const git_signature *who; | ||
1259 | - | int error; | ||
1260 | - | |||
1261 | 126 | 2,3,9,10 | if ((error = git_commit_lookup(&commit, repo, id)) < 0 || | |
1262 | 126 | 4-8 | (error = git_buf_printf(&reflog_msg, "%s%s: %s", | |
1263 | - | operation ? operation : "commit", | ||
1264 | - | commit_type(commit), | ||
1265 | - | git_commit_summary(commit))) < 0) | ||
1266 | - | goto done; | ||
1267 | - | |||
1268 | 126 | 11 | who = git_commit_committer(commit); | |
1269 | - | |||
1270 | 126 | 12 | if (ref) { | |
1271 | 31 | 13,14 | if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) | |
1272 | ##### | 15 | return error; | |
1273 | - | |||
1274 | 31 | 16,17 | error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who, | |
1275 | 31 | 16 | git_buf_cstr(&reflog_msg), &ref->target.oid, NULL); | |
1276 | - | } | ||
1277 | - | else | ||
1278 | 95 | 18,19 | error = git_reference__update_terminal( | |
1279 | - | repo, ref_name, id, who, git_buf_cstr(&reflog_msg)); | ||
1280 | - | |||
1281 | - | done: | ||
1282 | 126 | 20 | git_reference_free(ref_new); | |
1283 | 126 | 21 | git_buf_dispose(&reflog_msg); | |
1284 | 126 | 22 | git_commit_free(commit); | |
1285 | 126 | 23 | return error; | |
1286 | - | } | ||
1287 | - | |||
1288 | 8 | 2 | int git_reference_has_log(git_repository *repo, const char *refname) | |
1289 | - | { | ||
1290 | - | int error; | ||
1291 | - | git_refdb *refdb; | ||
1292 | - | |||
1293 | 8 | 2-4 | assert(repo && refname); | |
1294 | - | |||
1295 | 8 | 5,6 | if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) | |
1296 | ##### | 7 | return error; | |
1297 | - | |||
1298 | 8 | 8 | return git_refdb_has_log(refdb, refname); | |
1299 | - | } | ||
1300 | - | |||
1301 | 61 | 2 | int git_reference_ensure_log(git_repository *repo, const char *refname) | |
1302 | - | { | ||
1303 | - | int error; | ||
1304 | - | git_refdb *refdb; | ||
1305 | - | |||
1306 | 61 | 2-4 | assert(repo && refname); | |
1307 | - | |||
1308 | 61 | 5,6 | if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) | |
1309 | ##### | 7 | return error; | |
1310 | - | |||
1311 | 61 | 8 | return git_refdb_ensure_log(refdb, refname); | |
1312 | - | } | ||
1313 | - | |||
1314 | 731 | 2 | int git_reference__is_branch(const char *ref_name) | |
1315 | - | { | ||
1316 | 731 | 2 | return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0; | |
1317 | - | } | ||
1318 | - | |||
1319 | 394 | 2 | int git_reference_is_branch(const git_reference *ref) | |
1320 | - | { | ||
1321 | 394 | 2,3 | assert(ref); | |
1322 | 394 | 4 | return git_reference__is_branch(ref->name); | |
1323 | - | } | ||
1324 | - | |||
1325 | 82 | 2 | int git_reference__is_remote(const char *ref_name) | |
1326 | - | { | ||
1327 | 82 | 2 | return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0; | |
1328 | - | } | ||
1329 | - | |||
1330 | 7 | 2 | int git_reference_is_remote(const git_reference *ref) | |
1331 | - | { | ||
1332 | 7 | 2,3 | assert(ref); | |
1333 | 7 | 4 | return git_reference__is_remote(ref->name); | |
1334 | - | } | ||
1335 | - | |||
1336 | 73 | 2 | int git_reference__is_tag(const char *ref_name) | |
1337 | - | { | ||
1338 | 73 | 2 | return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0; | |
1339 | - | } | ||
1340 | - | |||
1341 | 11 | 2 | int git_reference_is_tag(const git_reference *ref) | |
1342 | - | { | ||
1343 | 11 | 2,3 | assert(ref); | |
1344 | 11 | 4 | return git_reference__is_tag(ref->name); | |
1345 | - | } | ||
1346 | - | |||
1347 | 3 | 2 | int git_reference__is_note(const char *ref_name) | |
1348 | - | { | ||
1349 | 3 | 2 | return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0; | |
1350 | - | } | ||
1351 | - | |||
1352 | 3 | 2 | int git_reference_is_note(const git_reference *ref) | |
1353 | - | { | ||
1354 | 3 | 2,3 | assert(ref); | |
1355 | 3 | 4 | return git_reference__is_note(ref->name); | |
1356 | - | } | ||
1357 | - | |||
1358 | ##### | 2 | static int peel_error(int error, const git_reference *ref, const char* msg) | |
1359 | - | { | ||
1360 | ##### | 2,3 | git_error_set( | |
1361 | - | GIT_ERROR_INVALID, | ||
1362 | - | "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg); | ||
1363 | ##### | 4 | return error; | |
1364 | - | } | ||
1365 | - | |||
1366 | 4105 | 2 | int git_reference_peel( | |
1367 | - | git_object **peeled, | ||
1368 | - | const git_reference *ref, | ||
1369 | - | git_object_t target_type) | ||
1370 | - | { | ||
1371 | 4105 | 2 | const git_reference *resolved = NULL; | |
1372 | 4105 | 2 | git_reference *allocated = NULL; | |
1373 | 4105 | 2 | git_object *target = NULL; | |
1374 | - | int error; | ||
1375 | - | |||
1376 | 4105 | 2,3 | assert(ref); | |
1377 | - | |||
1378 | 4105 | 4 | if (ref->type == GIT_REFERENCE_DIRECT) { | |
1379 | 3969 | 5 | resolved = ref; | |
1380 | - | } else { | ||
1381 | 136 | 6,7 | if ((error = git_reference_resolve(&allocated, ref)) < 0) | |
1382 | ##### | 8 | return peel_error(error, ref, "Cannot resolve reference"); | |
1383 | - | |||
1384 | 136 | 9 | resolved = allocated; | |
1385 | - | } | ||
1386 | - | |||
1387 | - | /* | ||
1388 | - | * If we try to peel an object to a tag, we cannot use | ||
1389 | - | * the fully peeled object, as that will always resolve | ||
1390 | - | * to a commit. So we only want to use the peeled value | ||
1391 | - | * if it is not zero and the target is not a tag. | ||
1392 | - | */ | ||
1393 | 4105 | 10-12 | if (target_type != GIT_OBJECT_TAG && !git_oid_is_zero(&resolved->peel)) { | |
1394 | 2 | 13,14 | error = git_object_lookup(&target, | |
1395 | - | git_reference_owner(ref), &resolved->peel, GIT_OBJECT_ANY); | ||
1396 | - | } else { | ||
1397 | 4103 | 15,16 | error = git_object_lookup(&target, | |
1398 | - | git_reference_owner(ref), &resolved->target.oid, GIT_OBJECT_ANY); | ||
1399 | - | } | ||
1400 | - | |||
1401 | 4105 | 17 | if (error < 0) { | |
1402 | ##### | 18 | peel_error(error, ref, "Cannot retrieve reference target"); | |
1403 | ##### | 19 | goto cleanup; | |
1404 | - | } | ||
1405 | - | |||
1406 | 4105 | 20-22 | if (target_type == GIT_OBJECT_ANY && git_object_type(target) != GIT_OBJECT_TAG) | |
1407 | 56 | 23 | error = git_object_dup(peeled, target); | |
1408 | - | else | ||
1409 | 4049 | 24 | error = git_object_peel(peeled, target, target_type); | |
1410 | - | |||
1411 | - | cleanup: | ||
1412 | 4105 | 25 | git_object_free(target); | |
1413 | 4105 | 26 | git_reference_free(allocated); | |
1414 | - | |||
1415 | 4105 | 27 | return error; | |
1416 | - | } | ||
1417 | - | |||
1418 | 18387 | 2 | int git_reference__is_valid_name(const char *refname, unsigned int flags) | |
1419 | - | { | ||
1420 | 18387 | 2,3 | if (git_reference__normalize_name(NULL, refname, flags) < 0) { | |
1421 | 1521 | 4 | git_error_clear(); | |
1422 | 1521 | 5 | return false; | |
1423 | - | } | ||
1424 | - | |||
1425 | 16866 | 6 | return true; | |
1426 | - | } | ||
1427 | - | |||
1428 | 14532 | 2 | int git_reference_is_valid_name(const char *refname) | |
1429 | - | { | ||
1430 | 14532 | 2 | return git_reference__is_valid_name(refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL); | |
1431 | - | } | ||
1432 | - | |||
1433 | 270 | 2 | const char *git_reference__shorthand(const char *name) | |
1434 | - | { | ||
1435 | 270 | 2,3 | if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) | |
1436 | 241 | 4 | return name + strlen(GIT_REFS_HEADS_DIR); | |
1437 | 29 | 5,6 | else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR)) | |
1438 | 7 | 7 | return name + strlen(GIT_REFS_TAGS_DIR); | |
1439 | 22 | 8,9 | else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR)) | |
1440 | 21 | 10 | return name + strlen(GIT_REFS_REMOTES_DIR); | |
1441 | 1 | 11,12 | else if (!git__prefixcmp(name, GIT_REFS_DIR)) | |
1442 | 1 | 13 | return name + strlen(GIT_REFS_DIR); | |
1443 | - | |||
1444 | - | /* No shorthands are avaiable, so just return the name */ | ||
1445 | ##### | 14 | return name; | |
1446 | - | } | ||
1447 | - | |||
1448 | 26 | 2 | const char *git_reference_shorthand(const git_reference *ref) | |
1449 | - | { | ||
1450 | 26 | 2 | return git_reference__shorthand(ref->name); | |
1451 | - | } | ||
1452 | - | |||
1453 | 18 | 2 | int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_repository *repo) | |
1454 | - | { | ||
1455 | - | int error; | ||
1456 | - | git_reference *tmp_ref; | ||
1457 | 18 | 2-5 | assert(unborn && ref && repo); | |
1458 | - | |||
1459 | 18 | 6 | if (ref->type == GIT_REFERENCE_DIRECT) { | |
1460 | 4 | 7 | *unborn = 0; | |
1461 | 4 | 7 | return 0; | |
1462 | - | } | ||
1463 | - | |||
1464 | 14 | 8 | error = git_reference_lookup_resolved(&tmp_ref, repo, ref->name, -1); | |
1465 | 14 | 9 | git_reference_free(tmp_ref); | |
1466 | - | |||
1467 | 14 | 10,11 | if (error != 0 && error != GIT_ENOTFOUND) | |
1468 | ##### | 12 | return error; | |
1469 | 14 | 13,14 | else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_FILE) == 0) | |
1470 | 2 | 15 | *unborn = true; | |
1471 | - | else | ||
1472 | 12 | 16 | *unborn = false; | |
1473 | - | |||
1474 | 14 | 17 | return 0; | |
1475 | - | } |