Commit 86194b24 by Vicent Marti

Split packed from unpacked references

These two reference types are now stored separately to eventually allow
the removal/renaming of loose references and rewriting of the refs
packfile.

Signed-off-by: Vicent Marti <tanoku@gmail.com>
parent 32054c24
......@@ -53,6 +53,5 @@ typedef SSIZE_T ssize_t;
#include "bswap.h"
#define GIT_PATH_MAX 4096
#define GIT_FILELOCK_EXTENSION ".lock\0"
#endif /* INCLUDE_common_h__ */
......@@ -28,9 +28,6 @@
#include "filebuf.h"
#include "fileops.h"
static const char *GIT_FILELOCK_EXTENSION = ".lock\0";
static const size_t GIT_FILELOCK_EXTLENGTH = 6;
static const size_t WRITE_BUFFER_SIZE = (4096 * 2);
static int lock_file(git_filebuf *file, int flags)
......
......@@ -12,6 +12,9 @@
#define GIT_FILEBUF_APPEND 0x2
#define GIT_FILEBUF_FORCE 0x4
#define GIT_FILELOCK_EXTENSION ".lock\0"
#define GIT_FILELOCK_EXTLENGTH 6
struct git_filebuf {
char *path_original;
char *path_lock;
......
......@@ -140,10 +140,11 @@ typedef struct git_reference git_reference;
/** Basic type of any Git reference. */
typedef enum {
GIT_REF_ANY = -2, /** Reference can be an object id reference or a symbolic reference */
GIT_REF_INVALID = -1, /** Invalid reference */
GIT_REF_INVALID = 0, /** Invalid reference */
GIT_REF_OID = 1, /** A reference which points at an object id */
GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */
GIT_REF_PACKED = 4,
GIT_REF_HAS_PEEL = 8,
} git_rtype;
/** @} */
......
......@@ -30,7 +30,20 @@
#define MAX_NESTING_LEVEL 5
typedef struct {
git_reference ref;
git_oid oid;
git_oid peel_target;
} reference_oid;
typedef struct {
git_reference ref;
char *target;
} reference_symbolic;
static int reference_write(git_reference *ref);
static int normalize_name(char *buffer_out, const char *name, int is_oid_ref);
static const int default_table_size = 32;
......@@ -54,30 +67,34 @@ static void reference_free(git_reference *reference)
free(reference->name);
if (reference->type == GIT_REF_SYMBOLIC)
free(reference->target.ref);
free(((reference_symbolic *)reference)->target);
free(reference);
}
static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type) {
char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
int error = GIT_SUCCESS;
int error = GIT_SUCCESS, size;
git_reference *reference = NULL;
assert(ref_out && repo && name);
if (type != GIT_REF_SYMBOLIC && type != GIT_REF_OID)
return GIT_EMISSINGOBJDATA;
if (type == GIT_REF_SYMBOLIC)
size = sizeof(reference_symbolic);
else if (type == GIT_REF_OID)
size = sizeof(reference_oid);
else
return GIT_EINVALIDREFSTATE;
reference = git__malloc(sizeof(git_reference));
reference = git__malloc(size);
if (reference == NULL)
return GIT_ENOMEM;
memset(reference, 0x0, sizeof(git_reference));
memset(reference, 0x0, size);
reference->owner = repo;
reference->type = type;
error = git_reference__normalize_name(normalized, name, type);
error = normalize_name(normalized, name, (type & GIT_REF_OID));
if (error < GIT_SUCCESS)
goto cleanup;
......@@ -107,7 +124,7 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo,
goto cleanup;
/* The target can aither be the name of an object id reference or the name of another symbolic reference */
error = git_reference__normalize_name(normalized, target, GIT_REF_ANY);
error = normalize_name(normalized, target, 0);
if (error < GIT_SUCCESS)
goto cleanup;
......@@ -116,6 +133,10 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo,
if (error < GIT_SUCCESS)
goto cleanup;
error = git_hashtable_insert(repo->references.loose_refs, ref->name, ref);
if (error < GIT_SUCCESS)
goto cleanup;
*ref_out = ref;
return error;
......@@ -139,6 +160,10 @@ int git_reference_create_oid(git_reference **ref_out, git_repository *repo, cons
if (error < GIT_SUCCESS)
goto cleanup;
error = git_hashtable_insert(repo->references.loose_refs, ref->name, ref);
if (error < GIT_SUCCESS)
goto cleanup;
*ref_out = ref;
return error;
......@@ -153,8 +178,10 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content)
const unsigned int header_len = strlen(GIT_SYMREF);
const char *refname_start;
char *eol;
reference_symbolic *ref_sym;
refname_start = (const char *)file_content->data;
ref_sym = (reference_symbolic *)ref;
if (file_content->len < (header_len + 1))
return GIT_EREFCORRUPTED;
......@@ -166,12 +193,12 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content)
refname_start += header_len;
ref->target.ref = git__strdup(refname_start);
if (ref->target.ref == NULL)
ref_sym->target = git__strdup(refname_start);
if (ref_sym->target == NULL)
return GIT_ENOMEM;
/* remove newline at the end of file */
eol = strchr(ref->target.ref, '\n');
eol = strchr(ref_sym->target, '\n');
if (eol == NULL)
return GIT_EREFCORRUPTED;
......@@ -184,19 +211,19 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content)
static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content)
{
reference_oid *ref_oid;
char *buffer;
git_oid id;
buffer = (char *)file_content->data;
ref_oid = (reference_oid *)ref;
/* File format: 40 chars (OID) + newline */
if (file_content->len < GIT_OID_HEXSZ + 1)
return GIT_EREFCORRUPTED;
if (git_oid_mkstr(&id, buffer) < GIT_SUCCESS)
if (git_oid_mkstr(&ref_oid->oid, buffer) < GIT_SUCCESS)
return GIT_EREFCORRUPTED;
git_oid_cpy(&ref->target.oid, &id);
buffer = buffer + GIT_OID_HEXSZ;
if (*buffer == '\r')
buffer++;
......@@ -261,7 +288,7 @@ static int lookup_loose_ref(
if (error < GIT_SUCCESS)
goto cleanup;
error = git_hashtable_insert(repo->references.cache, ref->name, ref);
error = git_hashtable_insert(repo->references.loose_refs, ref->name, ref);
if (error < GIT_SUCCESS)
goto cleanup;
......@@ -290,12 +317,10 @@ static int read_packed_refs(gitfo_buf *packfile, const char *repo_path)
}
static int parse_packed_line_peel(
git_reference **ref_out,
const git_reference *tag_ref,
reference_oid *tag_ref,
const char **buffer_out,
const char *buffer_end)
{
git_oid oid;
const char *buffer = *buffer_out + 1;
assert(buffer[-1] == '^');
......@@ -305,14 +330,14 @@ static int parse_packed_line_peel(
return GIT_EPACKEDREFSCORRUPTED;
/* Ensure reference is a tag */
if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0)
if (git__prefixcmp(tag_ref->ref.name, GIT_REFS_TAGS_DIR) != 0)
return GIT_EPACKEDREFSCORRUPTED;
if (buffer + GIT_OID_HEXSZ >= buffer_end)
return GIT_EPACKEDREFSCORRUPTED;
/* Is this a valid object id? */
if (git_oid_mkstr(&oid, buffer) < GIT_SUCCESS)
if (git_oid_mkstr(&tag_ref->peel_target, buffer) < GIT_SUCCESS)
return GIT_EPACKEDREFSCORRUPTED;
buffer = buffer + GIT_OID_HEXSZ;
......@@ -323,24 +348,18 @@ static int parse_packed_line_peel(
return GIT_EPACKEDREFSCORRUPTED;
*buffer_out = buffer + 1;
tag_ref->ref.type |= GIT_REF_HAS_PEEL;
/*
* TODO: do we need the packed line?
* Right now we don't, so we don't create a new
* reference.
*/
*ref_out = NULL;
return GIT_SUCCESS;
}
static int parse_packed_line(
git_reference **ref_out,
reference_oid **ref_out,
git_repository *repo,
const char **buffer_out,
const char *buffer_end)
{
git_reference *ref;
reference_oid *ref;
const char *buffer = *buffer_out;
const char *refname_begin, *refname_end;
......@@ -375,13 +394,12 @@ static int parse_packed_line(
if (refname[refname_len - 1] == '\r')
refname[refname_len - 1] = 0;
error = reference_create(&ref, repo, refname, GIT_REF_OID);
error = reference_create((git_reference **)&ref, repo, refname, GIT_REF_OID);
if (error < GIT_SUCCESS)
goto cleanup;
git_oid_cpy(&ref->target.oid, &id);
ref->packed = 1;
git_oid_cpy(&ref->oid, &id);
ref->ref.type |= GIT_REF_PACKED;
*ref_out = ref;
*buffer_out = refname_end + 1;
......@@ -389,11 +407,11 @@ static int parse_packed_line(
return GIT_SUCCESS;
cleanup:
reference_free(ref);
reference_free((git_reference *)ref);
return error;
}
static int parse_packed_refs(git_refcache *ref_cache, git_repository *repo)
static int load_packed_refs(git_refcache *ref_cache, git_repository *repo)
{
int error = GIT_SUCCESS;
gitfo_buf packfile = GITFO_BUF_INIT;
......@@ -425,34 +443,21 @@ static int parse_packed_refs(git_refcache *ref_cache, git_repository *repo)
while (buffer_start < buffer_end) {
git_reference *ref = NULL;
git_reference *ref_tag = NULL;
reference_oid *ref = NULL;
error = parse_packed_line(&ref, repo, &buffer_start, buffer_end);
if (error < GIT_SUCCESS)
goto cleanup;
if (buffer_start[0] == '^') {
error = parse_packed_line_peel(&ref_tag, ref, &buffer_start, buffer_end);
error = parse_packed_line_peel(ref, &buffer_start, buffer_end);
if (error < GIT_SUCCESS)
goto cleanup;
}
/*
* If a loose reference exists with the same name,
* we assume that the loose reference is more up-to-date.
* We don't need to cache this ref from the packfile.
*/
if (read_loose_ref(NULL, ref->name, repo->path_repository) == GIT_SUCCESS) {
reference_free(ref);
reference_free(ref_tag);
continue;
}
error = git_hashtable_insert(ref_cache->cache, ref->name, ref);
error = git_hashtable_insert(ref_cache->packed_refs, ref->ref.name, ref);
if (error < GIT_SUCCESS) {
reference_free(ref);
reference_free(ref_tag);
reference_free((git_reference *)ref);
goto cleanup;
}
}
......@@ -466,22 +471,32 @@ cleanup:
int git_reference_set_oid(git_reference *ref, const git_oid *id)
{
if (ref->type != GIT_REF_OID)
reference_oid *ref_oid;
if ((ref->type & GIT_REF_OID) == 0)
return GIT_EINVALIDREFSTATE;
git_oid_cpy(&ref->target.oid, id);
ref_oid = (reference_oid *)ref;
git_oid_cpy(&ref_oid->oid, id);
ref->type &= ~GIT_REF_HAS_PEEL;
/* TODO: set new peel target */
return reference_write(ref);
}
int git_reference_set_target(git_reference *ref, const char *target)
{
if (ref->type != GIT_REF_SYMBOLIC)
reference_symbolic *ref_sym;
if ((ref->type & GIT_REF_SYMBOLIC) == 0)
return GIT_EINVALIDREFSTATE;
free(ref->target.ref);
ref->target.ref = git__strdup(target);
if (ref->target.ref == NULL)
ref_sym = (reference_symbolic *)ref;
free(ref_sym->target);
ref_sym->target = git__strdup(target);
if (ref_sym->target == NULL)
return GIT_ENOMEM;
return reference_write(ref);
......@@ -491,26 +506,33 @@ const git_oid *git_reference_oid(git_reference *ref)
{
assert(ref);
if (ref->type != GIT_REF_OID)
if ((ref->type & GIT_REF_OID) == 0)
return NULL;
return &ref->target.oid;
return &((reference_oid *)ref)->oid;
}
const char *git_reference_target(git_reference *ref)
{
assert(ref);
if (ref->type != GIT_REF_SYMBOLIC)
if ((ref->type & GIT_REF_SYMBOLIC) == 0)
return NULL;
return ref->target.ref;
return ((reference_symbolic *)ref)->target;
}
git_rtype git_reference_type(git_reference *ref)
{
assert(ref);
return ref->type;
if (ref->type & GIT_REF_OID)
return GIT_REF_OID;
if (ref->type & GIT_REF_SYMBOLIC)
return GIT_REF_SYMBOLIC;
return GIT_REF_INVALID;
}
const char *git_reference_name(git_reference *ref)
......@@ -536,13 +558,15 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)
repo = ref->owner;
for (i = 0; i < MAX_NESTING_LEVEL; ++i) {
reference_symbolic *ref_sym;
if (ref->type == GIT_REF_OID) {
if (ref->type & GIT_REF_OID) {
*resolved_ref = ref;
return GIT_SUCCESS;
}
if ((error = git_repository_lookup_ref(&ref, repo, ref->target.ref)) < GIT_SUCCESS)
ref_sym = (reference_symbolic *)ref;
if ((error = git_repository_lookup_ref(&ref, repo, ref_sym->target)) < GIT_SUCCESS)
return error;
}
......@@ -556,14 +580,13 @@ static int reference_write(git_reference *ref)
int error, contents_size;
char *ref_contents = NULL;
assert(ref->type == GIT_REF_OID || ref->type == GIT_REF_SYMBOLIC);
git__joinpath(ref_path, ref->owner->path_repository, ref->name);
if ((error = git_filebuf_open(&file, ref_path, 0)) < GIT_SUCCESS)
goto error_cleanup;
return error;
if (ref->type == GIT_REF_OID) {
if (ref->type & GIT_REF_OID) {
reference_oid *ref_oid = (reference_oid *)ref;
contents_size = GIT_OID_HEXSZ + 1;
ref_contents = git__malloc(contents_size);
......@@ -572,11 +595,12 @@ static int reference_write(git_reference *ref)
goto unlock;
}
git_oid_fmt(ref_contents, &ref->target.oid);
git_oid_fmt(ref_contents, &ref_oid->oid);
} else { /* GIT_REF_SYMBOLIC */
} else if (ref->type & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */
reference_symbolic *ref_sym = (reference_symbolic *)ref;
contents_size = strlen(GIT_SYMREF) + strlen(ref->target.ref) + 1;
contents_size = strlen(GIT_SYMREF) + strlen(ref_sym->target) + 1;
ref_contents = git__malloc(contents_size);
if (ref_contents == NULL) {
error = GIT_ENOMEM;
......@@ -584,28 +608,25 @@ static int reference_write(git_reference *ref)
}
strcpy(ref_contents, GIT_SYMREF);
strcat(ref_contents, ref->target.ref);
strcat(ref_contents, ref_sym->target);
} else {
error = GIT_EINVALIDREFSTATE;
goto unlock;
}
/* TODO: win32 carriage return when writing references in Windows? */
ref_contents[contents_size - 1] = '\n';
if ((error = git_filebuf_write(&file, ref_contents, contents_size)) < GIT_SUCCESS)
goto error_cleanup;
error = git_filebuf_commit(&file);
if (error < GIT_SUCCESS)
goto unlock;
error = git_hashtable_insert(ref->owner->references.cache, ref->name, ref);
if (error < GIT_SUCCESS)
goto unlock;
error = git_filebuf_commit(&file);
free(ref_contents);
return GIT_SUCCESS;
return error;
unlock:
git_filebuf_cleanup(&lock);
git_filebuf_cleanup(&file);
free(ref_contents);
return error;
}
......@@ -619,7 +640,7 @@ int git_repository_lookup_ref(git_reference **ref_out, git_repository *repo, con
*ref_out = NULL;
error = git_reference__normalize_name(normalized_name, name, GIT_REF_ANY);
error = normalize_name(normalized_name, name, 0);
if (error < GIT_SUCCESS)
return error;
......@@ -627,7 +648,7 @@ int git_repository_lookup_ref(git_reference **ref_out, git_repository *repo, con
* First, check if the reference is on the local cache;
* references on the cache are assured to be up-to-date
*/
*ref_out = git_hashtable_lookup(repo->references.cache, normalized_name);
*ref_out = git_hashtable_lookup(repo->references.loose_refs, normalized_name);
if (*ref_out != NULL)
return GIT_SUCCESS;
......@@ -644,28 +665,17 @@ int git_repository_lookup_ref(git_reference **ref_out, git_repository *repo, con
if (error != GIT_ENOTFOUND)
return error;
/*
* Check if we have loaded the packed references.
* If the packed references have been loaded, they would be
* stored already on the cache: that means that the ref
* we are looking for doesn't exist.
*
* If they haven't been loaded yet, we load the packfile
* and check if our reference is inside of it.
*/
if (!repo->references.pack_loaded) {
/* load all the packed references */
error = parse_packed_refs(&repo->references, repo);
error = load_packed_refs(&repo->references, repo);
if (error < GIT_SUCCESS)
return error;
/* check the cache again -- hopefully the reference will be there */
*ref_out = git_hashtable_lookup(repo->references.cache, normalized_name);
if (*ref_out != NULL)
return GIT_SUCCESS;
}
*ref_out = git_hashtable_lookup(repo->references.packed_refs, normalized_name);
if (*ref_out != NULL)
return GIT_SUCCESS;
/* The reference doesn't exist anywhere */
return GIT_ENOTFOUND;
}
......@@ -674,26 +684,36 @@ int git_repository__refcache_init(git_refcache *refs)
{
assert(refs);
refs->cache = git_hashtable_alloc(
refs->loose_refs = git_hashtable_alloc(
default_table_size,
reftable_hash,
(git_hash_keyeq_ptr)strcmp);
refs->packed_refs = git_hashtable_alloc(
default_table_size,
reftable_hash,
(git_hash_keyeq_ptr)strcmp);
return refs->cache ? GIT_SUCCESS : GIT_ENOMEM;
return (refs->loose_refs && refs->packed_refs) ? GIT_SUCCESS : GIT_ENOMEM;
}
void git_repository__refcache_free(git_refcache *refs)
{
const char *ref_name;
git_reference *reference;
const void *_unused;
assert(refs);
GIT_HASHTABLE_FOREACH(refs->cache, ref_name, reference,
reference_free(reference)
GIT_HASHTABLE_FOREACH(refs->loose_refs, _unused, reference,
reference_free(reference);
);
GIT_HASHTABLE_FOREACH(refs->packed_refs, _unused, reference,
reference_free(reference);
);
git_hashtable_free(refs->cache);
git_hashtable_free(refs->loose_refs);
git_hashtable_free(refs->packed_refs);
}
static int check_valid_ref_char(char ch)
......@@ -717,7 +737,8 @@ static int check_valid_ref_char(char ch)
}
}
int git_reference__normalize_name(char *buffer_out, const char *name, git_rtype type)
static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
{
int error = GIT_SUCCESS;
const char *name_end, *buffer_out_start;
......@@ -730,9 +751,6 @@ int git_reference__normalize_name(char *buffer_out, const char *name, git_rtype
current = (char *)name;
name_end = name + strlen(name);
if (type == GIT_REF_INVALID)
return GIT_EINVALIDTYPE;
/* A refname can not be empty */
if (name_end == name)
return GIT_EINVALIDREFNAME;
......@@ -770,7 +788,7 @@ int git_reference__normalize_name(char *buffer_out, const char *name, git_rtype
}
/* Object id refname have to contain at least one slash */
if (type == GIT_REF_OID && !contains_a_slash)
if (is_oid_ref && !contains_a_slash)
return GIT_EINVALIDREFNAME;
/* A refname can not end with ".lock" */
......@@ -780,10 +798,21 @@ int git_reference__normalize_name(char *buffer_out, const char *name, git_rtype
*buffer_out = '\0';
/* For object id references, name has to start with refs/(heads|tags|remotes) */
if (type == GIT_REF_OID && !(!git__prefixcmp(buffer_out_start, GIT_REFS_HEADS_DIR) ||
if (is_oid_ref && !(!git__prefixcmp(buffer_out_start, GIT_REFS_HEADS_DIR) ||
!git__prefixcmp(buffer_out_start, GIT_REFS_TAGS_DIR) || !git__prefixcmp(buffer_out_start, GIT_REFS_REMOTES_DIR)))
return GIT_EINVALIDREFNAME;
return error;
}
int git_reference__normalize_name(char *buffer_out, const char *name)
{
return normalize_name(buffer_out, name, 0);
}
int git_reference__normalize_name_oid(char *buffer_out, const char *name)
{
return normalize_name(buffer_out, name, 1);
}
......@@ -18,25 +18,22 @@
struct git_reference {
git_repository *owner;
git_rtype type;
char *name;
unsigned packed:1;
union {
char *ref;
git_oid oid;
} target;
unsigned int type;
};
typedef struct {
git_hashtable *cache;
git_hashtable *packed_refs;
git_hashtable *loose_refs;
unsigned pack_loaded:1;
} git_refcache;
void git_repository__refcache_free(git_refcache *refs);
int git_repository__refcache_init(git_refcache *refs);
int git_reference__normalize_name(char *buffer_out, const char *name, git_rtype type);
int git_reference__normalize_name(char *buffer_out, const char *name);
int git_reference__normalize_name_oid(char *buffer_out, const char *name);
#endif
......@@ -35,18 +35,13 @@ static int resize_vector(git_vector *v)
void **new_contents;
v->_alloc_size = ((unsigned int)(v->_alloc_size * resize_factor)) + 1;
if (v->_alloc_size == 0)
if (v->_alloc_size < minimum_size)
v->_alloc_size = minimum_size;
new_contents = git__malloc(v->_alloc_size * sizeof(void *));
if (new_contents == NULL)
v->contents = realloc(v->contents, v->_alloc_size * sizeof(void *));
if (v->contents == NULL)
return GIT_ENOMEM;
memcpy(new_contents, v->contents, v->length * sizeof(void *));
free(v->contents);
v->contents = new_contents;
return GIT_SUCCESS;
}
......@@ -93,12 +88,6 @@ int git_vector_insert(git_vector *v, void *element)
return GIT_SUCCESS;
}
void *git_vector_get(git_vector *v, unsigned int position)
{
assert(v);
return (position < v->length) ? v->contents[position] : NULL;
}
void git_vector_sort(git_vector *v)
{
assert(v);
......
......@@ -24,7 +24,10 @@ void git_vector_clear(git_vector *v);
int git_vector_search(git_vector *v, const void *key);
void git_vector_sort(git_vector *v);
void *git_vector_get(git_vector *v, unsigned int position);
GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position)
{
return (position < v->length) ? v->contents[position] : NULL;
}
int git_vector_insert(git_vector *v, void *element);
int git_vector_remove(git_vector *v, unsigned int idx);
......
......@@ -38,8 +38,8 @@ BEGIN_TEST("readtag", loose_tag_reference_looking_up)
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
must_pass(git_repository_lookup_ref(&reference, repo, loose_tag_ref_name));
must_be_true(reference->type == GIT_REF_OID);
must_be_true(reference->packed == 0);
must_be_true(reference->type & GIT_REF_OID);
must_be_true((reference->type & GIT_REF_PACKED) == 0);
must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
must_pass(git_repository_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY));
......@@ -73,8 +73,8 @@ BEGIN_TEST("readsymref", symbolic_reference_looking_up)
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
must_pass(git_repository_lookup_ref(&reference, repo, head_ref_name));
must_be_true(reference->type == GIT_REF_SYMBOLIC);
must_be_true(reference->packed == 0);
must_be_true(reference->type & GIT_REF_SYMBOLIC);
must_be_true((reference->type & GIT_REF_PACKED) == 0);
must_be_true(strcmp(reference->name, head_ref_name) == 0);
must_pass(git_reference_resolve(&resolved_ref, reference));
......@@ -99,8 +99,8 @@ BEGIN_TEST("readsymref", nested_symbolic_reference_looking_up)
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
must_pass(git_repository_lookup_ref(&reference, repo, head_tracker_sym_ref_name));
must_be_true(reference->type == GIT_REF_SYMBOLIC);
must_be_true(reference->packed == 0);
must_be_true(reference->type & GIT_REF_SYMBOLIC);
must_be_true((reference->type & GIT_REF_PACKED) == 0);
must_be_true(strcmp(reference->name, head_tracker_sym_ref_name) == 0);
must_pass(git_reference_resolve(&resolved_ref, reference));
......@@ -163,8 +163,8 @@ BEGIN_TEST("readpackedref", packed_reference_looking_up)
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
must_pass(git_repository_lookup_ref(&reference, repo, packed_head_name));
must_be_true(reference->type == GIT_REF_OID);
must_be_true(reference->packed == 1);
must_be_true(reference->type & GIT_REF_OID);
must_be_true((reference->type & GIT_REF_PACKED) != 0);
must_be_true(strcmp(reference->name, packed_head_name) == 0);
must_pass(git_repository_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY));
......@@ -181,8 +181,8 @@ BEGIN_TEST("readpackedref", packed_exists_but_more_recent_loose_reference_is_ret
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
must_pass(git_repository_lookup_ref(&reference, repo, packed_head_name));
must_pass(git_repository_lookup_ref(&reference, repo, packed_test_head_name));
must_be_true(reference->type == GIT_REF_OID);
must_be_true(reference->packed == 0);
must_be_true(reference->type & GIT_REF_OID);
must_be_true((reference->type & GIT_REF_PACKED) == 0);
must_be_true(strcmp(reference->name, packed_test_head_name) == 0);
git_repository_free(repo);
......@@ -208,8 +208,8 @@ BEGIN_TEST("createref", create_new_symbolic_ref)
/* Ensure the reference can be looked-up... */
must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head_tracker));
must_be_true(looked_up_ref->type == GIT_REF_SYMBOLIC);
must_be_true(looked_up_ref->packed == 0);
must_be_true(looked_up_ref->type & GIT_REF_SYMBOLIC);
must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
must_be_true(strcmp(looked_up_ref->name, new_head_tracker) == 0);
/* ...peeled.. */
......@@ -276,8 +276,8 @@ BEGIN_TEST("createref", create_new_object_id_ref)
/* Ensure the reference can be looked-up... */
must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head));
must_be_true(looked_up_ref->type == GIT_REF_OID);
must_be_true(looked_up_ref->packed == 0);
must_be_true(looked_up_ref->type & GIT_REF_OID);
must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
must_be_true(strcmp(looked_up_ref->name, new_head) == 0);
/* ...and that it points to the current master tip */
......@@ -296,12 +296,16 @@ BEGIN_TEST("createref", create_new_object_id_ref)
must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */
END_TEST
static int ensure_refname_normalized(git_rtype ref_type, const char *input_refname, const char *expected_refname)
static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname)
{
int error = GIT_SUCCESS;
char buffer_out[GIT_PATH_MAX];
error = git_reference__normalize_name(buffer_out, input_refname, ref_type);
if (is_oid_ref)
error = git_reference__normalize_name_oid(buffer_out, input_refname);
else
error = git_reference__normalize_name(buffer_out, input_refname);
if (error < GIT_SUCCESS)
return error;
......@@ -314,73 +318,69 @@ static int ensure_refname_normalized(git_rtype ref_type, const char *input_refna
return error;
}
BEGIN_TEST("normalizeref", normalize_unknown_ref_type)
must_fail(ensure_refname_normalized(GIT_REF_INVALID, "a", NULL));
END_TEST
BEGIN_TEST("normalizeref", normalize_object_id_ref)
must_fail(ensure_refname_normalized(GIT_REF_OID, "a", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/a/", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/a.", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/a.lock", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/dummy/a", NULL));
must_pass(ensure_refname_normalized(GIT_REF_OID, "refs/tags/a", "refs/tags/a"));
must_pass(ensure_refname_normalized(GIT_REF_OID, "refs/heads/a/b", "refs/heads/a/b"));
must_pass(ensure_refname_normalized(GIT_REF_OID, "refs/heads/a./b", "refs/heads/a./b"));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/foo?bar", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads\foo", NULL));
must_pass(ensure_refname_normalized(GIT_REF_OID, "refs/heads/v@ation", "refs/heads/v@ation"));
must_pass(ensure_refname_normalized(GIT_REF_OID, "refs///heads///a", "refs/heads/a"));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/.a/b", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/foo/../bar", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/foo..bar", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/./foo", NULL));
must_fail(ensure_refname_normalized(GIT_REF_OID, "refs/heads/v@{ation", NULL));
must_fail(ensure_refname_normalized(1, "a", NULL));
must_fail(ensure_refname_normalized(1, "", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/a/", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/a.", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/a.lock", NULL));
must_fail(ensure_refname_normalized(1, "refs/dummy/a", NULL));
must_pass(ensure_refname_normalized(1, "refs/tags/a", "refs/tags/a"));
must_pass(ensure_refname_normalized(1, "refs/heads/a/b", "refs/heads/a/b"));
must_pass(ensure_refname_normalized(1, "refs/heads/a./b", "refs/heads/a./b"));
must_fail(ensure_refname_normalized(1, "refs/heads/foo?bar", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads\foo", NULL));
must_pass(ensure_refname_normalized(1, "refs/heads/v@ation", "refs/heads/v@ation"));
must_pass(ensure_refname_normalized(1, "refs///heads///a", "refs/heads/a"));
must_fail(ensure_refname_normalized(1, "refs/heads/.a/b", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/foo/../bar", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/foo..bar", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/./foo", NULL));
must_fail(ensure_refname_normalized(1, "refs/heads/v@{ation", NULL));
END_TEST
BEGIN_TEST("normalizeref", normalize_symbolic_ref)
must_pass(ensure_refname_normalized(GIT_REF_SYMBOLIC, "a", "a"));
must_pass(ensure_refname_normalized(GIT_REF_SYMBOLIC, "a/b", "a/b"));
must_fail(ensure_refname_normalized(GIT_REF_SYMBOLIC, "", NULL));
must_fail(ensure_refname_normalized(GIT_REF_SYMBOLIC, "heads\foo", NULL));
must_pass(ensure_refname_normalized(0, "a", "a"));
must_pass(ensure_refname_normalized(0, "a/b", "a/b"));
must_fail(ensure_refname_normalized(0, "", NULL));
must_fail(ensure_refname_normalized(0, "heads\foo", NULL));
END_TEST
BEGIN_TEST("normalizeref", normalize_any_ref) /* Slash related rules do not apply, neither do 'refs' prefix related rules */
must_pass(ensure_refname_normalized(GIT_REF_ANY, "a", "a"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "a/b", "a/b"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs///heads///a", "refs/heads/a"));
must_pass(ensure_refname_normalized(0, "a", "a"));
must_pass(ensure_refname_normalized(0, "a/b", "a/b"));
must_pass(ensure_refname_normalized(0, "refs///heads///a", "refs/heads/a"));
END_TEST
/* Ported from JGit, BSD licence. See https://github.com/spearce/JGit/commit/e4bf8f6957bbb29362575d641d1e77a02d906739 */
BEGIN_TEST("normalizeref", jgit_tests)
/* EmptyString */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "/", NULL));
must_fail(ensure_refname_normalized(0, "", NULL));
must_fail(ensure_refname_normalized(0, "/", NULL));
/* MustHaveTwoComponents */
must_fail(ensure_refname_normalized(GIT_REF_OID, "master", NULL));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "heads/master", "heads/master"));
must_fail(ensure_refname_normalized(1, "master", NULL));
must_pass(ensure_refname_normalized(0, "heads/master", "heads/master"));
/* ValidHead */
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master", "refs/heads/master"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/pu", "refs/heads/pu"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/z", "refs/heads/z"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/FoO", "refs/heads/FoO"));
must_pass(ensure_refname_normalized(0, "refs/heads/master", "refs/heads/master"));
must_pass(ensure_refname_normalized(0, "refs/heads/pu", "refs/heads/pu"));
must_pass(ensure_refname_normalized(0, "refs/heads/z", "refs/heads/z"));
must_pass(ensure_refname_normalized(0, "refs/heads/FoO", "refs/heads/FoO"));
/* ValidTag */
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/tags/v1.0", "refs/tags/v1.0"));
must_pass(ensure_refname_normalized(0, "refs/tags/v1.0", "refs/tags/v1.0"));
/* NoLockSuffix */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master.lock", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master.lock", NULL));
/* NoDirectorySuffix */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master/", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master/", NULL));
/* NoSpace */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/i haz space", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/i haz space", NULL));
/* NoAsciiControlCharacters */
{
......@@ -391,81 +391,81 @@ BEGIN_TEST("normalizeref", jgit_tests)
strncpy(buffer + 15, (const char *)&c, 1);
strncpy(buffer + 16, "er", 2);
buffer[18 - 1] = '\0';
must_fail(ensure_refname_normalized(GIT_REF_ANY, buffer, NULL));
must_fail(ensure_refname_normalized(0, buffer, NULL));
}
}
/* NoBareDot */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/.", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/..", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/./master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/../master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/.", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/..", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/./master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/../master", NULL));
/* NoLeadingOrTrailingDot */
must_fail(ensure_refname_normalized(GIT_REF_ANY, ".", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/.bar", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/..bar", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/bar.", NULL));
must_fail(ensure_refname_normalized(0, ".", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/.bar", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/..bar", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/bar.", NULL));
/* ContainsDot */
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r"));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master..pu", NULL));
must_pass(ensure_refname_normalized(0, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r"));
must_fail(ensure_refname_normalized(0, "refs/heads/master..pu", NULL));
/* NoMagicRefCharacters */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master^", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/^master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "^refs/heads/master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master^", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/^master", NULL));
must_fail(ensure_refname_normalized(0, "^refs/heads/master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master~", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/~master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "~refs/heads/master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master~", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/~master", NULL));
must_fail(ensure_refname_normalized(0, "~refs/heads/master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master:", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/:master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, ":refs/heads/master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master:", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/:master", NULL));
must_fail(ensure_refname_normalized(0, ":refs/heads/master", NULL));
/* ShellGlob */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master?", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/?master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "?refs/heads/master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master?", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/?master", NULL));
must_fail(ensure_refname_normalized(0, "?refs/heads/master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master[", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/[master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "[refs/heads/master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master[", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/[master", NULL));
must_fail(ensure_refname_normalized(0, "[refs/heads/master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master*", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/*master", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "*refs/heads/master", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master*", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/*master", NULL));
must_fail(ensure_refname_normalized(0, "*refs/heads/master", NULL));
/* ValidSpecialCharacters */
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/!", "refs/heads/!"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/\"", "refs/heads/\""));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/#", "refs/heads/#"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/$", "refs/heads/$"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/%", "refs/heads/%"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/&", "refs/heads/&"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/'", "refs/heads/'"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/(", "refs/heads/("));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/)", "refs/heads/)"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/+", "refs/heads/+"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/,", "refs/heads/,"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/-", "refs/heads/-"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/;", "refs/heads/;"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/<", "refs/heads/<"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/=", "refs/heads/="));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/>", "refs/heads/>"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/@", "refs/heads/@"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/]", "refs/heads/]"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/_", "refs/heads/_"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/`", "refs/heads/`"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/{", "refs/heads/{"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/|", "refs/heads/|"));
must_pass(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/}", "refs/heads/}"));
must_pass(ensure_refname_normalized(0, "refs/heads/!", "refs/heads/!"));
must_pass(ensure_refname_normalized(0, "refs/heads/\"", "refs/heads/\""));
must_pass(ensure_refname_normalized(0, "refs/heads/#", "refs/heads/#"));
must_pass(ensure_refname_normalized(0, "refs/heads/$", "refs/heads/$"));
must_pass(ensure_refname_normalized(0, "refs/heads/%", "refs/heads/%"));
must_pass(ensure_refname_normalized(0, "refs/heads/&", "refs/heads/&"));
must_pass(ensure_refname_normalized(0, "refs/heads/'", "refs/heads/'"));
must_pass(ensure_refname_normalized(0, "refs/heads/(", "refs/heads/("));
must_pass(ensure_refname_normalized(0, "refs/heads/)", "refs/heads/)"));
must_pass(ensure_refname_normalized(0, "refs/heads/+", "refs/heads/+"));
must_pass(ensure_refname_normalized(0, "refs/heads/,", "refs/heads/,"));
must_pass(ensure_refname_normalized(0, "refs/heads/-", "refs/heads/-"));
must_pass(ensure_refname_normalized(0, "refs/heads/;", "refs/heads/;"));
must_pass(ensure_refname_normalized(0, "refs/heads/<", "refs/heads/<"));
must_pass(ensure_refname_normalized(0, "refs/heads/=", "refs/heads/="));
must_pass(ensure_refname_normalized(0, "refs/heads/>", "refs/heads/>"));
must_pass(ensure_refname_normalized(0, "refs/heads/@", "refs/heads/@"));
must_pass(ensure_refname_normalized(0, "refs/heads/]", "refs/heads/]"));
must_pass(ensure_refname_normalized(0, "refs/heads/_", "refs/heads/_"));
must_pass(ensure_refname_normalized(0, "refs/heads/`", "refs/heads/`"));
must_pass(ensure_refname_normalized(0, "refs/heads/{", "refs/heads/{"));
must_pass(ensure_refname_normalized(0, "refs/heads/|", "refs/heads/|"));
must_pass(ensure_refname_normalized(0, "refs/heads/}", "refs/heads/}"));
// This is valid on UNIX, but not on Windows
// hence we make in invalid due to non-portability
//
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/\\", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/\\", NULL));
/* UnicodeNames */
/*
......@@ -474,8 +474,8 @@ BEGIN_TEST("normalizeref", jgit_tests)
*/
/* RefLogQueryIsValidRef */
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master@{1}", NULL));
must_fail(ensure_refname_normalized(GIT_REF_ANY, "refs/heads/master@{1.hour.ago}", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master@{1}", NULL));
must_fail(ensure_refname_normalized(0, "refs/heads/master@{1.hour.ago}", NULL));
END_TEST
git_testsuite *libgit2_suite_refs(void)
......@@ -493,7 +493,6 @@ git_testsuite *libgit2_suite_refs(void)
ADD_TEST(suite, "createref", create_new_symbolic_ref);
ADD_TEST(suite, "createref", create_deep_symbolic_ref);
ADD_TEST(suite, "createref", create_new_object_id_ref);
ADD_TEST(suite, "normalizeref", normalize_unknown_ref_type);
ADD_TEST(suite, "normalizeref", normalize_object_id_ref);
ADD_TEST(suite, "normalizeref", normalize_symbolic_ref);
ADD_TEST(suite, "normalizeref", normalize_any_ref);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment