diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2007-04-10 08:14:26 +0400 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2007-04-11 00:44:16 +0400 |
commit | 0ebde32c87da2efac5985a808e6bd4130831b7a8 (patch) | |
tree | c94281955436c22a714a649e220a7e079842bb86 | |
parent | 5d5cea67af386cfd53428f1eb404841eca8e9062 (diff) |
Add 'resolve_gitlink_ref()' helper function
This new function resolves a ref in *another* git repository. It's
named for its intended use: to look up the git link to a subproject.
It's not actually wired up to anything yet, but we're getting closer to
having fundamental plumbing support for "links" from one git directory
to another, which is the basis of subproject support.
[jc: amended a FILE* leak]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r-- | refs.c | 80 | ||||
-rw-r--r-- | refs.h | 3 |
2 files changed, 83 insertions, 0 deletions
@@ -215,6 +215,86 @@ static struct ref_list *get_loose_refs(void) /* We allow "recursive" symbolic refs. Only within reason, though */ #define MAXDEPTH 5 +#define MAXREFLEN (1024) + +static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refname, unsigned char *result) +{ + FILE *f; + struct cached_refs refs; + struct ref_list *ref; + int retval; + + strcpy(name + pathlen, "packed-refs"); + f = fopen(name, "r"); + if (!f) + return -1; + read_packed_refs(f, &refs); + fclose(f); + ref = refs.packed; + retval = -1; + while (ref) { + if (!strcmp(ref->name, refname)) { + retval = 0; + memcpy(result, ref->sha1, 20); + break; + } + ref = ref->next; + } + free_ref_list(refs.packed); + return retval; +} + +static int resolve_gitlink_ref_recursive(char *name, int pathlen, const char *refname, unsigned char *result, int recursion) +{ + int fd, len = strlen(refname); + char buffer[128], *p; + + if (recursion > MAXDEPTH || len > MAXREFLEN) + return -1; + memcpy(name + pathlen, refname, len+1); + fd = open(name, O_RDONLY); + if (fd < 0) + return resolve_gitlink_packed_ref(name, pathlen, refname, result); + + len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + if (len < 0) + return -1; + while (len && isspace(buffer[len-1])) + len--; + buffer[len] = 0; + + /* Was it a detached head or an old-fashioned symlink? */ + if (!get_sha1_hex(buffer, result)) + return 0; + + /* Symref? */ + if (strncmp(buffer, "ref:", 4)) + return -1; + p = buffer + 4; + while (isspace(*p)) + p++; + + return resolve_gitlink_ref_recursive(name, pathlen, p, result, recursion+1); +} + +int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *result) +{ + int len = strlen(path), retval; + char *gitdir; + + while (len && path[len-1] == '/') + len--; + if (!len) + return -1; + gitdir = xmalloc(len + MAXREFLEN + 8); + memcpy(gitdir, path, len); + memcpy(gitdir + len, "/.git/", 7); + + retval = resolve_gitlink_ref_recursive(gitdir, len+6, refname, result, 0); + free(gitdir); + return retval; +} const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag) { @@ -60,4 +60,7 @@ extern int check_ref_format(const char *target); /** rename ref, return 0 on success **/ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg); +/** resolve ref in nested "gitlink" repository */ +extern int resolve_gitlink_ref(const char *name, const char *refname, unsigned char *result); + #endif /* REFS_H */ |