@ -5,14 +5,18 @@
@@ -5,14 +5,18 @@
#include <errno.h>
/* ISSYMREF=01 and ISPACKED=02 are public interfaces */
#define REF_KNOWS_PEELED 04
struct ref_list {
struct ref_list *next;
unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */
unsigned char flag; /* ISSYMREF? ISPACKED? */
unsigned char sha1[20];
unsigned char peeled[20];
char name[FLEX_ARRAY];
};
static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
static const char *parse_ref_line(char *line, unsigned char *sha1)
{
/*
* 42: the answer to everything.
@ -23,7 +27,6 @@ static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
@@ -23,7 +27,6 @@ static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
* +1 (newline at the end of the line)
*/
int len = strlen(line) - 42;
int peeled = 0;
if (len <= 0)
return NULL;
@ -32,29 +35,18 @@ static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
@@ -32,29 +35,18 @@ static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
if (!isspace(line[40]))
return NULL;
line += 41;
if (isspace(*line)) {
/* "SHA-1 SP SP refs/tags/tagname^{} LF"? */
line++;
len--;
peeled = 1;
}
if (isspace(*line))
return NULL;
if (line[len] != '\n')
return NULL;
line[len] = 0;
if (peeled && (len < 3 || strcmp(line + len - 3, "^{}")))
return NULL;
if (!peeled)
*flag &= ~REF_ISPEELED;
else
*flag |= REF_ISPEELED;
return line;
}
static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
int flag, struct ref_list *list)
int flag, struct ref_list *list,
struct ref_list **new_entry)
{
int len;
struct ref_list **p = &list, *entry;
@ -66,8 +58,11 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
@@ -66,8 +58,11 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
break;
/* Same as existing entry? */
if (!cmp)
if (!cmp) {
if (new_entry)
*new_entry = entry;
return list;
}
p = &entry->next;
}
@ -75,10 +70,13 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
@@ -75,10 +70,13 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
len = strlen(name) + 1;
entry = xmalloc(sizeof(struct ref_list) + len);
hashcpy(entry->sha1, sha1);
hashclr(entry->peeled);
memcpy(entry->name, name, len);
entry->flag = flag;
entry->next = *p;
*p = entry;
if (new_entry)
*new_entry = entry;
return list;
}
@ -114,27 +112,50 @@ static void invalidate_cached_refs(void)
@@ -114,27 +112,50 @@ static void invalidate_cached_refs(void)
ca->did_loose = ca->did_packed = 0;
}
static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
{
struct ref_list *list = NULL;
struct ref_list *last = NULL;
char refline[PATH_MAX];
int flag = REF_ISPACKED;
while (fgets(refline, sizeof(refline), f)) {
unsigned char sha1[20];
const char *name;
static const char header[] = "# pack-refs with:";
if (!strncmp(refline, header, sizeof(header)-1)) {
const char *traits = refline + sizeof(header) - 1;
if (strstr(traits, " peeled "))
flag |= REF_KNOWS_PEELED;
/* perhaps other traits later as well */
continue;
}
name = parse_ref_line(refline, sha1);
if (name) {
list = add_ref(name, sha1, flag, list, &last);
continue;
}
if (last &&
refline[0] == '^' &&
strlen(refline) == 42 &&
refline[41] == '\n' &&
!get_sha1_hex(refline + 1, sha1))
hashcpy(last->peeled, sha1);
}
cached_refs->packed = list;
}
static struct ref_list *get_packed_refs(void)
{
if (!cached_refs.did_packed) {
struct ref_list *refs = NULL;
FILE *f = fopen(git_path("packed-refs"), "r");
cached_refs.packed = NULL;
if (f) {
struct ref_list *list = NULL;
char refline[PATH_MAX];
while (fgets(refline, sizeof(refline), f)) {
unsigned char sha1[20];
int flag = REF_ISPACKED;
const char *name =
parse_ref_line(refline, sha1, &flag);
if (!name)
continue;
list = add_ref(name, sha1, flag, list);
}
read_packed_refs(f, &cached_refs);
fclose(f);
refs = list;
}
cached_refs.packed = refs;
cached_refs.did_packed = 1;
}
return cached_refs.packed;
@ -177,7 +198,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
@@ -177,7 +198,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
error("%s points nowhere!", ref);
continue;
}
list = add_ref(ref, sha1, flag, list);
list = add_ref(ref, sha1, flag, list, NULL);
}
free(ref);
closedir(dir);
@ -225,8 +246,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
@@ -225,8 +246,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
if (lstat(path, &st) < 0) {
struct ref_list *list = get_packed_refs();
while (list) {
if (!(list->flag & REF_ISPEELED) &&
!strcmp(ref, list->name)) {
if (!strcmp(ref, list->name)) {
hashcpy(sha1, list->sha1);
if (flag)
*flag |= REF_ISPACKED;
@ -348,8 +368,6 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
@@ -348,8 +368,6 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
return 0;
if (is_null_sha1(entry->sha1))
return 0;
if (entry->flag & REF_ISPEELED)
return 0;
if (!has_sha1_file(entry->sha1)) {
error("%s does not point to a valid object!", entry->name);
return 0;
@ -368,22 +386,21 @@ int peel_ref(const char *ref, unsigned char *sha1)
@@ -368,22 +386,21 @@ int peel_ref(const char *ref, unsigned char *sha1)
if ((flag & REF_ISPACKED)) {
struct ref_list *list = get_packed_refs();
int len = strlen(ref);
while (list) {
if ((list->flag & REF_ISPEELED) &&
!strncmp(list->name, ref, len) &&
strlen(list->name) == len + 3 &&
!strcmp(list->name + len, "^{}")) {
hashcpy(sha1, list->sha1);
return 0;
if (!strcmp(list->name, ref)) {
if (list->flag & REF_KNOWS_PEELED) {
hashcpy(sha1, list->peeled);
return 0;
}
/* older pack-refs did not leave peeled ones */
break;
}
list = list->next;
}
/* older pack-refs did not leave peeled ones in */
}
/* otherwise ... */
/* fallback - callers should not call this for unpacked refs */
o = parse_object(base);
if (o->type == OBJ_TAG) {
o = deref_tag(o, ref, 0);