]>
git.proxmox.com Git - libgit2.git/blob - src/refs.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.
28 #include "repository.h"
32 #include <git2/object.h>
34 #define MAX_NESTING_LEVEL 5
47 static const int default_table_size
= 32;
49 static uint32_t reftable_hash(const void *key
, int hash_id
)
51 static uint32_t hash_seeds
[GIT_HASHTABLE_HASHES
] = {
57 return git__hash(key
, strlen((const char *)key
), hash_seeds
[hash_id
]);
60 static void reference_free(git_reference
*reference
);
61 static int reference_create(git_reference
**ref_out
, git_repository
*repo
, const char *name
, git_rtype type
);
62 static int reference_read(git_fbuffer
*file_content
, time_t *mtime
, const char *repo_path
, const char *ref_name
, int *updated
);
65 static int loose_parse_symbolic(git_reference
*ref
, git_fbuffer
*file_content
);
66 static int loose_parse_oid(git_reference
*ref
, git_fbuffer
*file_content
);
67 static int loose_lookup(git_reference
**ref_out
, git_repository
*repo
, const char *name
, int skip_symbolic
);
68 static int loose_write(git_reference
*ref
);
69 static int loose_update(git_reference
*ref
);
72 static int packed_parse_peel(reference_oid
*tag_ref
, const char **buffer_out
, const char *buffer_end
);
73 static int packed_parse_oid(reference_oid
**ref_out
, git_repository
*repo
, const char **buffer_out
, const char *buffer_end
);
74 static int packed_load(git_repository
*repo
);
75 static int packed_loadloose(git_repository
*repository
);
76 static int packed_write_ref(reference_oid
*ref
, git_filebuf
*file
);
77 static int packed_find_peel(reference_oid
*ref
);
78 static int packed_remove_loose(git_repository
*repo
, git_vector
*packing_list
);
79 static int packed_sort(const void *a
, const void *b
);
80 static int packed_write(git_repository
*repo
);
82 /* internal helpers */
83 static int reference_available(git_repository
*repo
, const char *ref
, const char *old_ref
);
85 /* name normalization */
86 static int check_valid_ref_char(char ch
);
87 static int normalize_name(char *buffer_out
, size_t out_size
, const char *name
, int is_oid_ref
);
89 /*****************************************
90 * Internal methods - Constructor/destructor
91 *****************************************/
92 static void reference_free(git_reference
*reference
)
94 if (reference
== NULL
)
98 free(reference
->name
);
100 if (reference
->type
== GIT_REF_SYMBOLIC
)
101 free(((reference_symbolic
*)reference
)->target
);
106 static int reference_create(
107 git_reference
**ref_out
,
108 git_repository
*repo
,
112 char normalized
[GIT_REFNAME_MAX
];
113 int error
= GIT_SUCCESS
, size
;
114 git_reference
*reference
= NULL
;
116 assert(ref_out
&& repo
&& name
);
118 if (type
== GIT_REF_SYMBOLIC
)
119 size
= sizeof(reference_symbolic
);
120 else if (type
== GIT_REF_OID
)
121 size
= sizeof(reference_oid
);
123 return git__throw(GIT_EINVALIDARGS
,
124 "Invalid reference type. Use either GIT_REF_OID or GIT_REF_SYMBOLIC as type specifier");
126 reference
= git__malloc(size
);
127 if (reference
== NULL
)
130 memset(reference
, 0x0, size
);
131 reference
->owner
= repo
;
132 reference
->type
= type
;
134 error
= normalize_name(normalized
, sizeof(normalized
), name
, (type
& GIT_REF_OID
));
135 if (error
< GIT_SUCCESS
)
138 reference
->name
= git__strdup(normalized
);
139 if (reference
->name
== NULL
) {
144 *ref_out
= reference
;
146 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to create reference");
149 reference_free(reference
);
150 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to create reference");
153 static int reference_read(git_fbuffer
*file_content
, time_t *mtime
, const char *repo_path
, const char *ref_name
, int *updated
)
155 char path
[GIT_PATH_MAX
];
157 assert(file_content
&& repo_path
&& ref_name
);
159 /* Determine the full path of the file */
160 git_path_join(path
, repo_path
, ref_name
);
162 return git_futils_readbuffer_updated(file_content
, path
, mtime
, updated
);
168 /*****************************************
169 * Internal methods - Loose references
170 *****************************************/
171 static int loose_update(git_reference
*ref
)
174 git_fbuffer ref_file
= GIT_FBUFFER_INIT
;
176 if (ref
->type
& GIT_REF_PACKED
)
177 return packed_load(ref
->owner
);
179 /* error = reference_read(NULL, &ref_time, ref->owner->path_repository, ref->name);
180 if (error < GIT_SUCCESS)
183 if (ref_time == ref->mtime)
186 error
= reference_read(&ref_file
, &ref
->mtime
, ref
->owner
->path_repository
, ref
->name
, &updated
);
187 if (error
< GIT_SUCCESS
)
193 if (ref
->type
== GIT_REF_SYMBOLIC
)
194 error
= loose_parse_symbolic(ref
, &ref_file
);
195 else if (ref
->type
== GIT_REF_OID
)
196 error
= loose_parse_oid(ref
, &ref_file
);
198 error
= git__throw(GIT_EOBJCORRUPTED
,
199 "Invalid reference type (%d) for loose reference", ref
->type
);
203 git_futils_freebuffer(&ref_file
);
204 if (error
!= GIT_SUCCESS
) {
206 git_hashtable_remove(ref
->owner
->references
.loose_cache
, ref
->name
);
209 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to update loose reference");
212 static int loose_parse_symbolic(git_reference
*ref
, git_fbuffer
*file_content
)
214 const unsigned int header_len
= strlen(GIT_SYMREF
);
215 const char *refname_start
;
217 reference_symbolic
*ref_sym
;
219 refname_start
= (const char *)file_content
->data
;
220 ref_sym
= (reference_symbolic
*)ref
;
222 if (file_content
->len
< (header_len
+ 1))
223 return git__throw(GIT_EOBJCORRUPTED
,
224 "Failed to parse loose reference. Object too short");
227 * Assume we have already checked for the header
228 * before calling this function
231 refname_start
+= header_len
;
233 free(ref_sym
->target
);
234 ref_sym
->target
= git__strdup(refname_start
);
235 if (ref_sym
->target
== NULL
)
238 /* remove newline at the end of file */
239 eol
= strchr(ref_sym
->target
, '\n');
241 return git__throw(GIT_EOBJCORRUPTED
,
242 "Failed to parse loose reference. Missing EOL");
251 static int loose_parse_oid(git_reference
*ref
, git_fbuffer
*file_content
)
254 reference_oid
*ref_oid
;
257 buffer
= (char *)file_content
->data
;
258 ref_oid
= (reference_oid
*)ref
;
260 /* File format: 40 chars (OID) + newline */
261 if (file_content
->len
< GIT_OID_HEXSZ
+ 1)
262 return git__throw(GIT_EOBJCORRUPTED
,
263 "Failed to parse loose reference. Reference too short");
265 if ((error
= git_oid_fromstr(&ref_oid
->oid
, buffer
)) < GIT_SUCCESS
)
266 return git__rethrow(GIT_EOBJCORRUPTED
, "Failed to parse loose reference.");
268 buffer
= buffer
+ GIT_OID_HEXSZ
;
273 return git__throw(GIT_EOBJCORRUPTED
,
274 "Failed to parse loose reference. Missing EOL");
280 static git_rtype
loose_guess_rtype(const char *full_path
)
282 git_fbuffer ref_file
= GIT_FBUFFER_INIT
;
285 type
= GIT_REF_INVALID
;
287 if (git_futils_readbuffer(&ref_file
, full_path
) == GIT_SUCCESS
) {
288 if (git__prefixcmp((const char *)(ref_file
.data
), GIT_SYMREF
) == 0)
289 type
= GIT_REF_SYMBOLIC
;
294 git_futils_freebuffer(&ref_file
);
298 static int loose_lookup(
299 git_reference
**ref_out
,
300 git_repository
*repo
,
304 int error
= GIT_SUCCESS
;
305 git_fbuffer ref_file
= GIT_FBUFFER_INIT
;
306 git_reference
*ref
= NULL
;
311 error
= reference_read(&ref_file
, &ref_time
, repo
->path_repository
, name
, NULL
);
312 if (error
< GIT_SUCCESS
)
315 if (git__prefixcmp((const char *)(ref_file
.data
), GIT_SYMREF
) == 0) {
319 error
= reference_create(&ref
, repo
, name
, GIT_REF_SYMBOLIC
);
320 if (error
< GIT_SUCCESS
)
323 error
= loose_parse_symbolic(ref
, &ref_file
);
325 error
= reference_create(&ref
, repo
, name
, GIT_REF_OID
);
326 if (error
< GIT_SUCCESS
)
329 error
= loose_parse_oid(ref
, &ref_file
);
332 if (error
< GIT_SUCCESS
)
335 ref
->mtime
= ref_time
;
337 git_futils_freebuffer(&ref_file
);
341 git_futils_freebuffer(&ref_file
);
343 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to lookup loose reference");
346 static int loose_write(git_reference
*ref
)
349 char ref_path
[GIT_PATH_MAX
];
353 git_path_join(ref_path
, ref
->owner
->path_repository
, ref
->name
);
355 if ((error
= git_filebuf_open(&file
, ref_path
, GIT_FILEBUF_FORCE
)) < GIT_SUCCESS
)
356 return git__rethrow(error
, "Failed to write loose reference");
358 if (ref
->type
& GIT_REF_OID
) {
359 reference_oid
*ref_oid
= (reference_oid
*)ref
;
360 char oid
[GIT_OID_HEXSZ
+ 1];
362 memset(oid
, 0x0, sizeof(oid
));
364 git_oid_fmt(oid
, &ref_oid
->oid
);
365 error
= git_filebuf_printf(&file
, "%s\n", oid
);
366 if (error
< GIT_SUCCESS
)
369 } else if (ref
->type
& GIT_REF_SYMBOLIC
) { /* GIT_REF_SYMBOLIC */
370 reference_symbolic
*ref_sym
= (reference_symbolic
*)ref
;
372 error
= git_filebuf_printf(&file
, GIT_SYMREF
"%s\n", ref_sym
->target
);
374 error
= git__throw(GIT_EOBJCORRUPTED
, "Failed to write reference. Invalid reference type");
378 error
= git_filebuf_commit(&file
);
380 if (p_stat(ref_path
, &st
) == GIT_SUCCESS
)
381 ref
->mtime
= st
.st_mtime
;
383 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write loose reference");
386 git_filebuf_cleanup(&file
);
387 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write loose reference");
395 /*****************************************
396 * Internal methods - Packed references
397 *****************************************/
399 static int packed_parse_peel(
400 reference_oid
*tag_ref
,
401 const char **buffer_out
,
402 const char *buffer_end
)
404 const char *buffer
= *buffer_out
+ 1;
406 assert(buffer
[-1] == '^');
408 /* Ensure it's not the first entry of the file */
410 return git__throw(GIT_EPACKEDREFSCORRUPTED
, "Failed to parse packed reference. Reference is the first entry of the file");
412 /* Ensure reference is a tag */
413 if (git__prefixcmp(tag_ref
->ref
.name
, GIT_REFS_TAGS_DIR
) != 0)
414 return git__throw(GIT_EPACKEDREFSCORRUPTED
, "Failed to parse packed reference. Reference is not a tag");
416 if (buffer
+ GIT_OID_HEXSZ
>= buffer_end
)
417 return git__throw(GIT_EPACKEDREFSCORRUPTED
, "Failed to parse packed reference. Buffer too small");
419 /* Is this a valid object id? */
420 if (git_oid_fromstr(&tag_ref
->peel_target
, buffer
) < GIT_SUCCESS
)
421 return git__throw(GIT_EPACKEDREFSCORRUPTED
, "Failed to parse packed reference. Not a valid object ID");
423 buffer
= buffer
+ GIT_OID_HEXSZ
;
428 return git__throw(GIT_EPACKEDREFSCORRUPTED
, "Failed to parse packed reference. Buffer not terminated correctly");
430 *buffer_out
= buffer
+ 1;
431 tag_ref
->ref
.type
|= GIT_REF_HAS_PEEL
;
436 static int packed_parse_oid(
437 reference_oid
**ref_out
,
438 git_repository
*repo
,
439 const char **buffer_out
,
440 const char *buffer_end
)
442 reference_oid
*ref
= NULL
;
444 const char *buffer
= *buffer_out
;
445 const char *refname_begin
, *refname_end
;
447 int error
= GIT_SUCCESS
;
449 char refname
[GIT_REFNAME_MAX
];
452 refname_begin
= (buffer
+ GIT_OID_HEXSZ
+ 1);
453 if (refname_begin
>= buffer_end
||
454 refname_begin
[-1] != ' ') {
455 error
= GIT_EPACKEDREFSCORRUPTED
;
459 /* Is this a valid object id? */
460 if ((error
= git_oid_fromstr(&id
, buffer
)) < GIT_SUCCESS
)
463 refname_end
= memchr(refname_begin
, '\n', buffer_end
- refname_begin
);
464 if (refname_end
== NULL
) {
465 error
= GIT_EPACKEDREFSCORRUPTED
;
469 refname_len
= refname_end
- refname_begin
;
471 memcpy(refname
, refname_begin
, refname_len
);
472 refname
[refname_len
] = 0;
474 if (refname
[refname_len
- 1] == '\r')
475 refname
[refname_len
- 1] = 0;
477 error
= reference_create((git_reference
**)&ref
, repo
, refname
, GIT_REF_OID
);
478 if (error
< GIT_SUCCESS
)
481 git_oid_cpy(&ref
->oid
, &id
);
482 ref
->ref
.type
|= GIT_REF_PACKED
;
485 *buffer_out
= refname_end
+ 1;
490 reference_free((git_reference
*)ref
);
491 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to parse OID of packed reference");
494 static int packed_load(git_repository
*repo
)
496 int error
= GIT_SUCCESS
, updated
;
497 git_fbuffer packfile
= GIT_FBUFFER_INIT
;
498 const char *buffer_start
, *buffer_end
;
499 git_refcache
*ref_cache
= &repo
->references
;
501 /* First we make sure we have allocated the hash table */
502 if (ref_cache
->packfile
== NULL
) {
503 ref_cache
->packfile
= git_hashtable_alloc(
506 (git_hash_keyeq_ptr
)(&git__strcmp_cb
));
508 if (ref_cache
->packfile
== NULL
) {
514 error
= reference_read(&packfile
, &ref_cache
->packfile_time
,
515 repo
->path_repository
, GIT_PACKEDREFS_FILE
, &updated
);
518 * If we couldn't find the file, we need to clear the table and
519 * return. On any other error, we return that error. If everything
520 * went fine and the file wasn't updated, then there's nothing new
521 * for us here, so just return. Anything else means we need to
522 * refresh the packed refs.
524 if (error
== GIT_ENOTFOUND
) {
525 git_hashtable_clear(ref_cache
->packfile
);
527 } else if (error
< GIT_SUCCESS
) {
528 return git__rethrow(error
, "Failed to read packed refs");
529 } else if (!updated
) {
534 * At this point, we want to refresh the packed refs. We already
535 * have the contents in our buffer.
538 git_hashtable_clear(ref_cache
->packfile
);
540 buffer_start
= (const char *)packfile
.data
;
541 buffer_end
= (const char *)(buffer_start
) + packfile
.len
;
543 while (buffer_start
< buffer_end
&& buffer_start
[0] == '#') {
544 buffer_start
= strchr(buffer_start
, '\n');
545 if (buffer_start
== NULL
) {
546 error
= GIT_EPACKEDREFSCORRUPTED
;
552 while (buffer_start
< buffer_end
) {
553 reference_oid
*ref
= NULL
;
555 error
= packed_parse_oid(&ref
, repo
, &buffer_start
, buffer_end
);
556 if (error
< GIT_SUCCESS
)
559 if (buffer_start
[0] == '^') {
560 error
= packed_parse_peel(ref
, &buffer_start
, buffer_end
);
561 if (error
< GIT_SUCCESS
)
565 error
= git_hashtable_insert(ref_cache
->packfile
, ref
->ref
.name
, ref
);
566 if (error
< GIT_SUCCESS
) {
567 reference_free((git_reference
*)ref
);
572 git_futils_freebuffer(&packfile
);
576 git_hashtable_free(ref_cache
->packfile
);
577 ref_cache
->packfile
= NULL
;
578 git_futils_freebuffer(&packfile
);
579 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to load packed references");
585 struct dirent_list_data
{
586 git_repository
*repo
;
587 size_t repo_path_len
;
588 unsigned int list_flags
;
590 int (*callback
)(const char *, void *);
591 void *callback_payload
;
594 static int _dirent_loose_listall(void *_data
, char *full_path
)
596 struct dirent_list_data
*data
= (struct dirent_list_data
*)_data
;
597 char *file_path
= full_path
+ data
->repo_path_len
;
599 if (git_futils_isdir(full_path
) == GIT_SUCCESS
)
600 return git_futils_direach(full_path
, GIT_PATH_MAX
, _dirent_loose_listall
, _data
);
602 /* do not add twice a reference that exists already in the packfile */
603 if ((data
->list_flags
& GIT_REF_PACKED
) != 0 &&
604 git_hashtable_lookup(data
->repo
->references
.packfile
, file_path
) != NULL
)
607 if (data
->list_flags
!= GIT_REF_LISTALL
) {
608 if ((data
->list_flags
& loose_guess_rtype(full_path
)) == 0)
609 return GIT_SUCCESS
; /* we are filtering out this reference */
612 return data
->callback(file_path
, data
->callback_payload
);
615 static int _dirent_loose_load(void *data
, char *full_path
)
617 git_repository
*repository
= (git_repository
*)data
;
618 git_reference
*reference
, *old_ref
;
622 if (git_futils_isdir(full_path
) == GIT_SUCCESS
)
623 return git_futils_direach(full_path
, GIT_PATH_MAX
, _dirent_loose_load
, repository
);
625 file_path
= full_path
+ strlen(repository
->path_repository
);
626 error
= loose_lookup(&reference
, repository
, file_path
, 1);
627 if (error
== GIT_SUCCESS
&& reference
!= NULL
) {
628 reference
->type
|= GIT_REF_PACKED
;
630 if (git_hashtable_insert2(repository
->references
.packfile
, reference
->name
, reference
, (void **)&old_ref
) < GIT_SUCCESS
) {
631 reference_free(reference
);
636 reference_free(old_ref
);
639 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to load loose dirent");
643 * Load all the loose references from the repository
644 * into the in-memory Packfile, and build a vector with
645 * all the references so it can be written back to
648 static int packed_loadloose(git_repository
*repository
)
650 char refs_path
[GIT_PATH_MAX
];
652 /* the packfile must have been previously loaded! */
653 assert(repository
->references
.packfile
);
655 git_path_join(refs_path
, repository
->path_repository
, GIT_REFS_DIR
);
657 /* Remove any loose references from the cache */
659 const void *GIT_UNUSED(_unused
);
660 git_reference
*reference
;
662 GIT_HASHTABLE_FOREACH(repository
->references
.loose_cache
, _unused
, reference
,
663 reference_free(reference
);
667 git_hashtable_clear(repository
->references
.loose_cache
);
670 * Load all the loose files from disk into the Packfile table.
671 * This will overwrite any old packed entries with their
672 * updated loose versions
674 return git_futils_direach(refs_path
, GIT_PATH_MAX
, _dirent_loose_load
, repository
);
678 * Write a single reference into a packfile
680 static int packed_write_ref(reference_oid
*ref
, git_filebuf
*file
)
683 char oid
[GIT_OID_HEXSZ
+ 1];
685 git_oid_fmt(oid
, &ref
->oid
);
686 oid
[GIT_OID_HEXSZ
] = 0;
689 * For references that peel to an object in the repo, we must
690 * write the resulting peel on a separate line, e.g.
692 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
693 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
695 * This obviously only applies to tags.
696 * The required peels have already been loaded into `ref->peel_target`.
698 if (ref
->ref
.type
& GIT_REF_HAS_PEEL
) {
699 char peel
[GIT_OID_HEXSZ
+ 1];
700 git_oid_fmt(peel
, &ref
->peel_target
);
701 peel
[GIT_OID_HEXSZ
] = 0;
703 error
= git_filebuf_printf(file
, "%s %s\n^%s\n", oid
, ref
->ref
.name
, peel
);
705 error
= git_filebuf_printf(file
, "%s %s\n", oid
, ref
->ref
.name
);
708 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write packed reference");
712 * Find out what object this reference resolves to.
714 * For references that point to a 'big' tag (e.g. an
715 * actual tag object on the repository), we need to
716 * cache on the packfile the OID of the object to
717 * which that 'big tag' is pointing to.
719 static int packed_find_peel(reference_oid
*ref
)
724 if (ref
->ref
.type
& GIT_REF_HAS_PEEL
)
728 * Only applies to tags, i.e. references
729 * in the /refs/tags folder
731 if (git__prefixcmp(ref
->ref
.name
, GIT_REFS_TAGS_DIR
) != 0)
735 * Find the tagged object in the repository
737 error
= git_object_lookup(&object
, ref
->ref
.owner
, &ref
->oid
, GIT_OBJ_ANY
);
738 if (error
< GIT_SUCCESS
)
739 return git__throw(GIT_EOBJCORRUPTED
, "Failed to find packed reference");
742 * If the tagged object is a Tag object, we need to resolve it;
743 * if the ref is actually a 'weak' ref, we don't need to resolve
746 if (git_object_type(object
) == GIT_OBJ_TAG
) {
747 git_tag
*tag
= (git_tag
*)object
;
750 * Find the object pointed at by this tag
752 git_oid_cpy(&ref
->peel_target
, git_tag_target_oid(tag
));
753 ref
->ref
.type
|= GIT_REF_HAS_PEEL
;
756 * The reference has now cached the resolved OID, and is
757 * marked at such. When written to the packfile, it'll be
758 * accompanied by this resolved oid
762 git_object_close(object
);
768 * Remove all loose references
770 * Once we have successfully written a packfile,
771 * all the loose references that were packed must be
774 * This is a dangerous method; make sure the packfile
775 * is well-written, because we are destructing references
778 static int packed_remove_loose(git_repository
*repo
, git_vector
*packing_list
)
781 char full_path
[GIT_PATH_MAX
];
782 int error
= GIT_SUCCESS
;
783 git_reference
*reference
;
785 for (i
= 0; i
< packing_list
->length
; ++i
) {
786 git_reference
*ref
= git_vector_get(packing_list
, i
);
788 /* Ensure the packed reference doesn't exist
789 * in a (more up-to-date?) state as a loose reference
791 reference
= git_hashtable_lookup(ref
->owner
->references
.loose_cache
, ref
->name
);
792 if (reference
!= NULL
)
795 git_path_join(full_path
, repo
->path_repository
, ref
->name
);
797 if (git_futils_exists(full_path
) == GIT_SUCCESS
&&
798 p_unlink(full_path
) < GIT_SUCCESS
)
802 * if we fail to remove a single file, this is *not* good,
803 * but we should keep going and remove as many as possible.
804 * After we've removed as many files as possible, we return
805 * the error code anyway.
807 * TODO: mark this with a very special error code?
812 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to remove loose packed reference");
815 static int packed_sort(const void *a
, const void *b
)
817 const git_reference
*ref_a
= (const git_reference
*)a
;
818 const git_reference
*ref_b
= (const git_reference
*)b
;
820 return strcmp(ref_a
->name
, ref_b
->name
);
824 * Write all the contents in the in-memory packfile to disk.
826 static int packed_write(git_repository
*repo
)
828 git_filebuf pack_file
;
831 char pack_file_path
[GIT_PATH_MAX
];
833 git_vector packing_list
;
836 assert(repo
&& repo
->references
.packfile
);
838 total_refs
= repo
->references
.packfile
->key_count
;
839 if ((error
= git_vector_init(&packing_list
, total_refs
, packed_sort
)) < GIT_SUCCESS
)
840 return git__rethrow(error
, "Failed to write packed reference");
842 /* Load all the packfile into a vector */
844 git_reference
*reference
;
845 const void *GIT_UNUSED(_unused
);
847 GIT_HASHTABLE_FOREACH(repo
->references
.packfile
, _unused
, reference
,
848 git_vector_insert(&packing_list
, reference
); /* cannot fail: vector already has the right size */
852 /* sort the vector so the entries appear sorted on the packfile */
853 git_vector_sort(&packing_list
);
855 /* Now we can open the file! */
856 git_path_join(pack_file_path
, repo
->path_repository
, GIT_PACKEDREFS_FILE
);
857 if ((error
= git_filebuf_open(&pack_file
, pack_file_path
, 0)) < GIT_SUCCESS
)
858 return git__rethrow(error
, "Failed to write packed reference");
860 /* Packfiles have a header... apparently
861 * This is in fact not required, but we might as well print it
863 if ((error
= git_filebuf_printf(&pack_file
, "%s\n", GIT_PACKEDREFS_HEADER
)) < GIT_SUCCESS
)
864 return git__rethrow(error
, "Failed to write packed reference");
866 for (i
= 0; i
< packing_list
.length
; ++i
) {
867 reference_oid
*ref
= (reference_oid
*)git_vector_get(&packing_list
, i
);
869 /* only direct references go to the packfile; otherwise
870 * this is a disaster */
871 assert(ref
->ref
.type
& GIT_REF_OID
);
873 if ((error
= packed_find_peel(ref
)) < GIT_SUCCESS
) {
874 error
= git__throw(GIT_EOBJCORRUPTED
, "A reference cannot be peeled");
879 if ((error
= packed_write_ref(ref
, &pack_file
)) < GIT_SUCCESS
)
884 /* if we've written all the references properly, we can commit
885 * the packfile to make the changes effective */
886 if (error
== GIT_SUCCESS
) {
887 error
= git_filebuf_commit(&pack_file
);
889 /* when and only when the packfile has been properly written,
890 * we can go ahead and remove the loose refs */
891 if (error
== GIT_SUCCESS
) {
894 error
= packed_remove_loose(repo
, &packing_list
);
896 if (p_stat(pack_file_path
, &st
) == GIT_SUCCESS
)
897 repo
->references
.packfile_time
= st
.st_mtime
;
900 else git_filebuf_cleanup(&pack_file
);
902 git_vector_free(&packing_list
);
904 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write packed reference");
907 static int _reference_available_cb(const char *ref
, void *data
)
909 const char *new, *old
;
914 refs
= (git_vector
*)data
;
916 new = (const char *)git_vector_get(refs
, 0);
917 old
= (const char *)git_vector_get(refs
, 1);
919 if (!old
|| strcmp(old
, ref
)) {
920 int reflen
= strlen(ref
);
921 int newlen
= strlen(new);
922 int cmplen
= reflen
< newlen
? reflen
: newlen
;
923 const char *lead
= reflen
< newlen
? new : ref
;
925 if (!strncmp(new, ref
, cmplen
) &&
933 static int reference_available(git_repository
*repo
, const char *ref
, const char* old_ref
)
938 if (git_vector_init(&refs
, 2, NULL
) < GIT_SUCCESS
)
941 git_vector_insert(&refs
, (void *)ref
);
942 git_vector_insert(&refs
, (void *)old_ref
);
944 error
= git_reference_foreach(repo
, GIT_REF_LISTALL
, _reference_available_cb
, (void *)&refs
);
946 git_vector_free(&refs
);
948 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__throw(GIT_EEXISTS
, "Reference name `%s` conflicts with existing reference", ref
);
951 /*****************************************
952 * External Library API
953 *****************************************/
958 int git_reference_lookup(git_reference
**ref_out
, git_repository
*repo
, const char *name
)
961 char normalized_name
[GIT_REFNAME_MAX
];
963 assert(ref_out
&& repo
&& name
);
967 error
= normalize_name(normalized_name
, sizeof(normalized_name
), name
, 0);
968 if (error
< GIT_SUCCESS
)
969 return git__rethrow(error
, "Failed to lookup reference");
971 /* First, check has been previously loaded and cached */
972 *ref_out
= git_hashtable_lookup(repo
->references
.loose_cache
, normalized_name
);
973 if (*ref_out
!= NULL
)
974 return loose_update(*ref_out
);
976 /* Then check if there is a loose file for that reference.*/
977 error
= loose_lookup(ref_out
, repo
, normalized_name
, 0);
979 /* If the file exists, we store it on the cache */
980 if (error
== GIT_SUCCESS
)
981 return git_hashtable_insert(repo
->references
.loose_cache
, (*ref_out
)->name
, (*ref_out
));
983 /* The loose lookup has failed, but not because the reference wasn't found;
984 * probably the loose reference is corrupted. this is bad. */
985 if (error
!= GIT_ENOTFOUND
)
986 return git__rethrow(error
, "Failed to lookup reference");
989 * If we cannot find a loose reference, we look into the packfile
990 * Load the packfile first if it hasn't been loaded
992 /* load all the packed references */
993 error
= packed_load(repo
);
994 if (error
< GIT_SUCCESS
)
995 return git__rethrow(error
, "Failed to lookup reference");
997 /* Look up on the packfile */
998 *ref_out
= git_hashtable_lookup(repo
->references
.packfile
, normalized_name
);
999 if (*ref_out
!= NULL
)
1002 /* The reference doesn't exist anywhere */
1003 return git__throw(GIT_ENOTFOUND
, "Failed to lookup reference. Reference doesn't exist");
1009 git_rtype
git_reference_type(git_reference
*ref
)
1013 if (ref
->type
& GIT_REF_OID
)
1016 if (ref
->type
& GIT_REF_SYMBOLIC
)
1017 return GIT_REF_SYMBOLIC
;
1019 return GIT_REF_INVALID
;
1022 const char *git_reference_name(git_reference
*ref
)
1028 git_repository
*git_reference_owner(git_reference
*ref
)
1034 const git_oid
*git_reference_oid(git_reference
*ref
)
1038 if ((ref
->type
& GIT_REF_OID
) == 0)
1041 if (loose_update(ref
) < GIT_SUCCESS
)
1044 return &((reference_oid
*)ref
)->oid
;
1047 const char *git_reference_target(git_reference
*ref
)
1051 if ((ref
->type
& GIT_REF_SYMBOLIC
) == 0)
1054 if (loose_update(ref
) < GIT_SUCCESS
)
1057 return ((reference_symbolic
*)ref
)->target
;
1060 int git_reference_create_symbolic(git_reference
**ref_out
, git_repository
*repo
, const char *name
, const char *target
, int force
)
1062 char normalized
[GIT_REFNAME_MAX
];
1063 int error
= GIT_SUCCESS
, updated
= 0;
1064 git_reference
*ref
= NULL
, *old_ref
= NULL
;
1066 if (git_reference_lookup(&ref
, repo
, name
) == GIT_SUCCESS
&& !force
)
1067 return git__throw(GIT_EEXISTS
, "Failed to create symbolic reference. Reference already exists");
1070 * If they old ref was of the same type, then we can just update
1071 * it (once we've checked that the target is valid). Otherwise we
1072 * need a new reference because we can't make a symbolic ref out
1074 * If if didn't exist, then we need to create a new one anyway.
1076 if (ref
&& ref
->type
& GIT_REF_SYMBOLIC
){
1080 error
= reference_create(&ref
, repo
, name
, GIT_REF_SYMBOLIC
);
1081 if (error
< GIT_SUCCESS
)
1085 /* The target can aither be the name of an object id reference or the name of another symbolic reference */
1086 error
= normalize_name(normalized
, sizeof(normalized
), target
, 0);
1087 if (error
< GIT_SUCCESS
)
1090 /* set the target; this will write the reference on disk */
1091 error
= git_reference_set_target(ref
, normalized
);
1092 if (error
< GIT_SUCCESS
)
1096 * If we didn't update the ref, then we need to insert or replace
1097 * it in the loose cache. If we replaced a ref, free it.
1100 error
= git_hashtable_insert2(repo
->references
.loose_cache
, ref
->name
, ref
, (void **) &old_ref
);
1101 if (error
< GIT_SUCCESS
)
1105 reference_free(old_ref
);
1110 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to create symbolic reference");
1113 reference_free(ref
);
1114 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to create symbolic reference");
1117 int git_reference_create_oid(git_reference
**ref_out
, git_repository
*repo
, const char *name
, const git_oid
*id
, int force
)
1119 int error
= GIT_SUCCESS
, updated
= 0;
1120 git_reference
*ref
= NULL
, *old_ref
= NULL
;
1122 if(git_reference_lookup(&ref
, repo
, name
) == GIT_SUCCESS
&& !force
)
1123 return git__throw(GIT_EEXISTS
, "Failed to create reference OID. Reference already exists");
1125 if ((error
= reference_available(repo
, name
, NULL
)) < GIT_SUCCESS
)
1126 return git__rethrow(error
, "Failed to create reference");
1129 * If they old ref was of the same type, then we can just update
1130 * it (once we've checked that the target is valid). Otherwise we
1131 * need a new reference because we can't make a symbolic ref out
1133 * If if didn't exist, then we need to create a new one anyway.
1135 if (ref
&& ref
-> type
& GIT_REF_OID
){
1139 error
= reference_create(&ref
, repo
, name
, GIT_REF_OID
);
1140 if (error
< GIT_SUCCESS
)
1144 /* set the oid; this will write the reference on disk */
1145 error
= git_reference_set_oid(ref
, id
);
1146 if (error
< GIT_SUCCESS
)
1150 error
= git_hashtable_insert2(repo
->references
.loose_cache
, ref
->name
, ref
, (void **) &old_ref
);
1151 if (error
< GIT_SUCCESS
)
1155 reference_free(old_ref
);
1160 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to create reference OID");
1163 reference_free(ref
);
1164 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to create reference OID");
1172 * Change the OID target of a reference.
1174 * For loose references, just change the oid in memory
1175 * and overwrite the file in disk.
1177 * For packed files, this is not pretty:
1178 * For performance reasons, we write the new reference
1179 * loose on disk (it replaces the old on the packfile),
1180 * but we cannot invalidate the pointer to the reference,
1181 * and most importantly, the `packfile` object must stay
1182 * consistent with the representation of the packfile
1183 * on disk. This is what we need to:
1185 * 1. Copy the reference
1186 * 2. Change the oid on the original
1187 * 3. Write the original to disk
1188 * 4. Write the original to the loose cache
1189 * 5. Replace the original with the copy (old reference) in the packfile cache
1191 int git_reference_set_oid(git_reference
*ref
, const git_oid
*id
)
1193 reference_oid
*ref_oid
;
1194 reference_oid
*ref_old
= NULL
;
1195 int error
= GIT_SUCCESS
;
1197 if ((ref
->type
& GIT_REF_OID
) == 0)
1198 return git__throw(GIT_EINVALIDREFSTATE
, "Failed to set OID target of reference. Not an OID reference");
1200 ref_oid
= (reference_oid
*)ref
;
1204 /* Don't let the user create references to OIDs that
1205 * don't exist in the ODB */
1206 if (!git_odb_exists(git_repository_database(ref
->owner
), id
))
1207 return git__throw(GIT_ENOTFOUND
, "Failed to set OID target of reference. OID doesn't exist in ODB");
1209 /* duplicate the reference;
1210 * this copy will stay on the packfile cache */
1211 if (ref
->type
& GIT_REF_PACKED
) {
1212 ref_old
= git__malloc(sizeof(reference_oid
));
1213 if (ref_old
== NULL
)
1216 ref_old
->ref
.name
= git__strdup(ref
->name
);
1217 if (ref_old
->ref
.name
== NULL
) {
1223 git_oid_cpy(&ref_oid
->oid
, id
);
1224 ref
->type
&= ~GIT_REF_HAS_PEEL
;
1226 error
= loose_write(ref
);
1227 if (error
< GIT_SUCCESS
)
1230 if (ref
->type
& GIT_REF_PACKED
) {
1231 /* insert the original on the loose cache */
1232 error
= git_hashtable_insert(ref
->owner
->references
.loose_cache
, ref
->name
, ref
);
1233 if (error
< GIT_SUCCESS
)
1236 ref
->type
&= ~GIT_REF_PACKED
;
1238 /* replace the original in the packfile with the copy */
1239 error
= git_hashtable_insert(ref
->owner
->references
.packfile
, ref_old
->ref
.name
, ref_old
);
1240 if (error
< GIT_SUCCESS
)
1247 reference_free((git_reference
*)ref_old
);
1248 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to set OID target of reference");
1252 * Change the target of a symbolic reference.
1254 * This is easy because symrefs cannot be inside
1255 * a pack. We just change the target in memory
1256 * and overwrite the file on disk.
1258 int git_reference_set_target(git_reference
*ref
, const char *target
)
1260 reference_symbolic
*ref_sym
;
1262 if ((ref
->type
& GIT_REF_SYMBOLIC
) == 0)
1263 return git__throw(GIT_EINVALIDREFSTATE
, "Failed to set reference target. Not a symbolic reference");
1265 ref_sym
= (reference_symbolic
*)ref
;
1267 free(ref_sym
->target
);
1268 ref_sym
->target
= git__strdup(target
);
1269 if (ref_sym
->target
== NULL
)
1272 return loose_write(ref
);
1279 int git_reference_rename(git_reference
*ref
, const char *new_name
, int force
)
1282 char *old_name
= NULL
;
1284 char aux_path
[GIT_PATH_MAX
];
1285 char normalized
[GIT_REFNAME_MAX
];
1287 const char *target_ref
= NULL
;
1288 const char *head_target
= NULL
;
1289 const git_oid
*target_oid
= NULL
;
1290 git_reference
*new_ref
= NULL
, *old_ref
= NULL
, *head
= NULL
;
1294 error
= normalize_name(normalized
, sizeof(normalized
), new_name
, ref
->type
& GIT_REF_OID
);
1295 if (error
< GIT_SUCCESS
)
1296 return git__rethrow(error
, "Failed to rename reference. Invalid name");
1298 new_name
= normalized
;
1300 error
= git_reference_lookup(&new_ref
, ref
->owner
, new_name
);
1301 if (error
== GIT_SUCCESS
) {
1303 return git__throw(GIT_EEXISTS
, "Failed to rename reference. Reference already exists");
1305 error
= git_reference_delete(new_ref
);
1308 if (error
< GIT_SUCCESS
&& error
!= GIT_ENOTFOUND
)
1311 if ((error
= reference_available(ref
->owner
, new_name
, ref
->name
)) < GIT_SUCCESS
)
1312 return git__rethrow(error
, "Failed to rename reference. Reference already exists");
1315 * First, we backup the reference targets. Just keeping the old
1316 * reference won't work, since we may have to remove it to create
1317 * the new reference, e.g. when renaming foo/bar -> foo.
1320 old_name
= git__strdup(ref
->name
);
1322 if (ref
->type
& GIT_REF_SYMBOLIC
) {
1323 if ((target_ref
= git_reference_target(ref
)) == NULL
)
1326 if ((target_oid
= git_reference_oid(ref
)) == NULL
)
1331 * Now delete the old ref and remove an possibly existing directory
1335 if (ref
->type
& GIT_REF_PACKED
) {
1336 ref
->type
&= ~GIT_REF_PACKED
;
1338 git_hashtable_remove(ref
->owner
->references
.packfile
, old_name
);
1339 if ((error
= packed_write(ref
->owner
)) < GIT_SUCCESS
)
1342 git_path_join(aux_path
, ref
->owner
->path_repository
, old_name
);
1343 if ((error
= p_unlink(aux_path
)) < GIT_SUCCESS
)
1346 git_hashtable_remove(ref
->owner
->references
.loose_cache
, old_name
);
1349 /* build new path */
1350 git_path_join(aux_path
, ref
->owner
->path_repository
, new_name
);
1352 if (git_futils_exists(aux_path
) == GIT_SUCCESS
) {
1353 if (git_futils_isdir(aux_path
) == GIT_SUCCESS
) {
1354 if ((error
= git_futils_rmdir_r(aux_path
, 0)) < GIT_SUCCESS
)
1356 } else goto rollback
;
1360 * Crude hack: delete any logs till we support proper reflogs.
1361 * Otherwise git.git will possibly fail and leave a mess. git.git
1362 * writes reflogs by default in any repo with a working directory:
1364 * "We only enable reflogs in repositories that have a working directory
1365 * associated with them, as shared/bare repositories do not have
1366 * an easy means to prune away old log entries, or may fail logging
1367 * entirely if the user's gecos information is not valid during a push.
1368 * This heuristic was suggested on the mailing list by Junio."
1370 * Shawn O. Pearce - 0bee59186976b1d9e6b2dd77332480c9480131d5
1376 git_path_join_n(aux_path
, 3, ref
->owner
->path_repository
, "logs", old_name
);
1377 if (git_futils_isfile(aux_path
) == GIT_SUCCESS
) {
1378 if ((error
= p_unlink(aux_path
)) < GIT_SUCCESS
)
1383 * Finally we can create the new reference.
1385 if (ref
->type
& GIT_REF_SYMBOLIC
) {
1386 if ((error
= git_reference_create_symbolic(&new_ref
, ref
->owner
, new_name
, target_ref
, 0)) < GIT_SUCCESS
)
1389 if ((error
= git_reference_create_oid(&new_ref
, ref
->owner
, new_name
, target_oid
, 0)) < GIT_SUCCESS
)
1394 ref
->name
= new_ref
->name
;
1397 * No need in new_ref anymore. We created it to fix the change on disk.
1398 * TODO: Refactoring required.
1400 new_ref
->name
= NULL
;
1401 reference_free(new_ref
);
1403 if ((error
= git_hashtable_insert2(ref
->owner
->references
.loose_cache
, ref
->name
, ref
, (void **)&old_ref
)) < GIT_SUCCESS
)
1407 * Check if we have to update HEAD.
1410 if ((error
= git_reference_lookup(&head
, ref
->owner
, GIT_HEAD_FILE
)) < GIT_SUCCESS
)
1413 head_target
= git_reference_target(head
);
1415 if (head_target
&& !strcmp(head_target
, old_name
))
1416 if ((error
= git_reference_create_symbolic(&head
, ref
->owner
, "HEAD", ref
->name
, 1)) < GIT_SUCCESS
)
1421 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to rename reference");
1425 * Try to create the old reference again.
1427 if (ref
->type
& GIT_REF_SYMBOLIC
)
1428 error
= git_reference_create_symbolic(&new_ref
, ref
->owner
, old_name
, target_ref
, 0);
1430 error
= git_reference_create_oid(&new_ref
, ref
->owner
, old_name
, target_oid
, 0);
1432 ref
->name
= old_name
;
1434 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to rename reference. Failed to rollback");
1438 * Delete a reference.
1440 * If the reference is packed, this is an expensive
1441 * operation. We need to remove the reference from
1442 * the memory cache and then rewrite the whole pack
1444 * If the reference is loose, we remove it on
1445 * the filesystem and update the in-memory cache
1446 * accordingly. We also make sure that an older version
1447 * of it doesn't exist as a packed reference. If this
1448 * is the case, this packed reference is removed as well.
1450 * This obviously invalidates the `ref` pointer.
1452 int git_reference_delete(git_reference
*ref
)
1455 git_reference
*reference
;
1459 if (ref
->type
& GIT_REF_PACKED
) {
1460 /* load the existing packfile */
1461 if ((error
= packed_load(ref
->owner
)) < GIT_SUCCESS
)
1462 return git__rethrow(error
, "Failed to delete reference");
1464 if (git_hashtable_remove(ref
->owner
->references
.packfile
, ref
->name
) < GIT_SUCCESS
)
1465 return git__throw(GIT_ENOTFOUND
, "Reference not found");
1467 error
= packed_write(ref
->owner
);
1469 char full_path
[GIT_PATH_MAX
];
1470 git_path_join(full_path
, ref
->owner
->path_repository
, ref
->name
);
1471 git_hashtable_remove(ref
->owner
->references
.loose_cache
, ref
->name
);
1472 error
= p_unlink(full_path
);
1473 if (error
< GIT_SUCCESS
)
1476 /* When deleting a loose reference, we have to ensure that an older
1477 * packed version of it doesn't exist
1479 if (!git_reference_lookup(&reference
, ref
->owner
, ref
->name
)) {
1480 assert((reference
->type
& GIT_REF_PACKED
) != 0);
1481 error
= git_reference_delete(reference
);
1486 reference_free(ref
);
1487 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to delete reference");
1490 int git_reference_resolve(git_reference
**resolved_ref
, git_reference
*ref
)
1492 git_repository
*repo
;
1495 assert(resolved_ref
&& ref
);
1496 *resolved_ref
= NULL
;
1498 if ((error
= loose_update(ref
)) < GIT_SUCCESS
)
1499 return git__rethrow(error
, "Failed to resolve reference");
1503 for (i
= 0; i
< MAX_NESTING_LEVEL
; ++i
) {
1504 reference_symbolic
*ref_sym
;
1506 *resolved_ref
= ref
;
1508 if (ref
->type
& GIT_REF_OID
)
1511 ref_sym
= (reference_symbolic
*)ref
;
1512 if ((error
= git_reference_lookup(&ref
, repo
, ref_sym
->target
)) < GIT_SUCCESS
)
1516 return git__throw(GIT_ENOMEM
, "Failed to resolve reference. Reference is too nested");
1519 int git_reference_packall(git_repository
*repo
)
1523 /* load the existing packfile */
1524 if ((error
= packed_load(repo
)) < GIT_SUCCESS
)
1525 return git__rethrow(error
, "Failed to pack references");
1527 /* update it in-memory with all the loose references */
1528 if ((error
= packed_loadloose(repo
)) < GIT_SUCCESS
)
1529 return git__rethrow(error
, "Failed to pack references");
1531 /* write it back to disk */
1532 return packed_write(repo
);
1535 int git_reference_foreach(git_repository
*repo
, unsigned int list_flags
, int (*callback
)(const char *, void *), void *payload
)
1538 struct dirent_list_data data
;
1539 char refs_path
[GIT_PATH_MAX
];
1541 /* list all the packed references first */
1542 if (list_flags
& GIT_REF_PACKED
) {
1543 const char *ref_name
;
1544 void *GIT_UNUSED(_unused
);
1546 if ((error
= packed_load(repo
)) < GIT_SUCCESS
)
1547 return git__rethrow(error
, "Failed to list references");
1549 GIT_HASHTABLE_FOREACH(repo
->references
.packfile
, ref_name
, _unused
,
1550 if ((error
= callback(ref_name
, payload
)) < GIT_SUCCESS
)
1551 return git__throw(error
, "Failed to list references. User callback failed");
1555 /* now list the loose references, trying not to
1556 * duplicate the ref names already in the packed-refs file */
1558 data
.repo_path_len
= strlen(repo
->path_repository
);
1559 data
.list_flags
= list_flags
;
1561 data
.callback
= callback
;
1562 data
.callback_payload
= payload
;
1565 git_path_join(refs_path
, repo
->path_repository
, GIT_REFS_DIR
);
1566 return git_futils_direach(refs_path
, GIT_PATH_MAX
, _dirent_loose_listall
, &data
);
1569 int cb__reflist_add(const char *ref
, void *data
)
1571 return git_vector_insert((git_vector
*)data
, git__strdup(ref
));
1574 int git_reference_listall(git_strarray
*array
, git_repository
*repo
, unsigned int list_flags
)
1577 git_vector ref_list
;
1579 assert(array
&& repo
);
1581 array
->strings
= NULL
;
1584 if (git_vector_init(&ref_list
, 8, NULL
) < GIT_SUCCESS
)
1587 error
= git_reference_foreach(repo
, list_flags
, &cb__reflist_add
, (void *)&ref_list
);
1589 if (error
< GIT_SUCCESS
) {
1590 git_vector_free(&ref_list
);
1594 array
->strings
= (char **)ref_list
.contents
;
1595 array
->count
= ref_list
.length
;
1602 /*****************************************
1603 * Init/free (repository API)
1604 *****************************************/
1605 int git_repository__refcache_init(git_refcache
*refs
)
1609 refs
->loose_cache
= git_hashtable_alloc(
1612 (git_hash_keyeq_ptr
)(&git__strcmp_cb
));
1614 /* packfile loaded lazily */
1615 refs
->packfile
= NULL
;
1616 refs
->packfile_time
= 0;
1618 return (refs
->loose_cache
) ? GIT_SUCCESS
: GIT_ENOMEM
;
1621 void git_repository__refcache_free(git_refcache
*refs
)
1623 git_reference
*reference
;
1624 const void *GIT_UNUSED(_unused
);
1628 GIT_HASHTABLE_FOREACH(refs
->loose_cache
, _unused
, reference
,
1629 reference_free(reference
);
1632 git_hashtable_free(refs
->loose_cache
);
1634 if (refs
->packfile
) {
1635 GIT_HASHTABLE_FOREACH(refs
->packfile
, _unused
, reference
,
1636 reference_free(reference
);
1639 git_hashtable_free(refs
->packfile
);
1645 /*****************************************
1646 * Name normalization
1647 *****************************************/
1648 static int check_valid_ref_char(char ch
)
1669 static int normalize_name(char *buffer_out
, size_t out_size
, const char *name
, int is_oid_ref
)
1671 const char *name_end
, *buffer_out_start
;
1672 const char *current
;
1673 int contains_a_slash
= 0;
1675 assert(name
&& buffer_out
);
1677 buffer_out_start
= buffer_out
;
1679 name_end
= name
+ strlen(name
);
1681 /* Terminating null byte */
1684 /* A refname can not be empty */
1685 if (name_end
== name
)
1686 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name is empty");
1688 /* A refname can not end with a dot or a slash */
1689 if (*(name_end
- 1) == '.' || *(name_end
- 1) == '/')
1690 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name ends with dot or slash");
1692 while (current
< name_end
&& out_size
) {
1693 if (check_valid_ref_char(*current
))
1694 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name contains invalid characters");
1696 if (buffer_out
> buffer_out_start
) {
1697 char prev
= *(buffer_out
- 1);
1699 /* A refname can not start with a dot nor contain a double dot */
1700 if (*current
== '.' && ((prev
== '.') || (prev
== '/')))
1701 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name starts with a dot or contains a double dot");
1703 /* '@{' is forbidden within a refname */
1704 if (*current
== '{' && prev
== '@')
1705 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name contains '@{'");
1707 /* Prevent multiple slashes from being added to the output */
1708 if (*current
== '/' && prev
== '/') {
1714 if (*current
== '/')
1715 contains_a_slash
= 1;
1717 *buffer_out
++ = *current
++;
1722 return git__throw(GIT_EINVALIDREFNAME
, "Reference name is too long");
1724 /* Object id refname have to contain at least one slash, except
1725 * for HEAD in a detached state or MERGE_HEAD if we're in the
1726 * middle of a merge */
1727 if (is_oid_ref
&& !contains_a_slash
&& (strcmp(name
, GIT_HEAD_FILE
) && strcmp(name
, GIT_MERGE_HEAD_FILE
)))
1728 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name contains no slashes");
1730 /* A refname can not end with ".lock" */
1731 if (!git__suffixcmp(name
, GIT_FILELOCK_EXTENSION
))
1732 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name ends with '.lock'");
1737 * For object id references, name has to start with refs/. Again,
1738 * we need to allow HEAD to be in a detached state.
1740 if (is_oid_ref
&& !(git__prefixcmp(buffer_out_start
, GIT_REFS_DIR
) ||
1741 strcmp(buffer_out_start
, GIT_HEAD_FILE
)))
1742 return git__throw(GIT_EINVALIDREFNAME
, "Failed to normalize name. Reference name does not start with 'refs/'");
1747 int git_reference__normalize_name(char *buffer_out
, size_t out_size
, const char *name
)
1749 return normalize_name(buffer_out
, out_size
, name
, 0);
1752 int git_reference__normalize_name_oid(char *buffer_out
, size_t out_size
, const char *name
)
1754 return normalize_name(buffer_out
, out_size
, name
, 1);