aboutsummaryrefslogtreecommitdiff
path: root/refs.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2007-04-21 17:21:10 -0700
committerJunio C Hamano <junkio@cox.net>2007-04-21 17:21:10 -0700
commitafb5b6a24bd333d298d10acac731f1c127bbb82d (patch)
tree9c403d4fa96f00d172e5b0a95602b68be839086f /refs.c
parent99ebd06c18fdb7f8274db6cca456a95942916bb6 (diff)
parent1c3e5c4ebc326c5c70350d3f4dc7f2b29e813480 (diff)
downloadgit-afb5b6a24bd333d298d10acac731f1c127bbb82d.tar.gz
git-afb5b6a24bd333d298d10acac731f1c127bbb82d.tar.xz
Merge branch 'lt/gitlink'
* lt/gitlink: Tests for core subproject support Expose subprojects as special files to "git diff" machinery Fix some "git ls-files -o" fallout from gitlinks Teach "git-read-tree -u" to check out submodules as a directory Teach git list-objects logic to not follow gitlinks Fix gitlink index entry filesystem matching Teach "git-read-tree -u" to check out submodules as a directory Teach git list-objects logic not to follow gitlinks Don't show gitlink directories when we want "other" files Teach git-update-index about gitlinks Teach directory traversal about subprojects Fix thinko in subproject entry sorting Teach core object handling functions about gitlinks Teach "fsck" not to follow subproject links Add "S_IFDIRLNK" file mode infrastructure for git links Add 'resolve_gitlink_ref()' helper function Avoid overflowing name buffer in deep directory structures diff-lib: use ce_mode_from_stat() rather than messing with modes manually
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/refs.c b/refs.c
index f9b880200..89876bff8 100644
--- a/refs.c
+++ b/refs.c
@@ -283,6 +283,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)
{