commit - 76b4ead2785ecd941602fa1a0aca516777bffd47
commit + a04f49d2f64d471bc4bc42ad21287d7ce6501cba
blob - fd2f57f3b5b776e534fe7f966be03fb9632aed0d
blob + 6305af48b43066c909580a54469f78b77d10f6d4
--- lib/reference.c
+++ lib/reference.c
#include <sys/types.h>
#include <sys/queue.h>
+#include <dirent.h>
#include <sha1.h>
#include <stdio.h>
#include <stdlib.h>
static const struct got_error *
open_ref(struct got_reference **ref, const char *path_refs, const char *subdir,
- const char *refname)
+ const char *name)
{
const struct got_error *err = NULL;
- char *path_ref;
- char *normpath;
+ char *path = NULL;
+ char *normpath = NULL;
+ char *absname = NULL;
+ int ref_is_absolute = (strncmp(name, "refs/", 5) == 0);
+ int ref_is_well_known = is_well_known_ref(name);
- if (asprintf(&path_ref, "%s/%s/%s", path_refs, subdir, refname) == -1)
- return got_error_from_errno();
+ if (ref_is_absolute || ref_is_well_known) {
+ if (asprintf(&path, "%s/%s", path_refs, name) == -1)
+ return got_error_from_errno();
+ absname = (char *)name;
+ } else {
+ if (asprintf(&path, "%s/%s/%s", path_refs, subdir, name) == -1)
+ return got_error_from_errno();
- normpath = got_path_normalize(path_ref);
+ if (asprintf(&absname, "refs/%s/%s", subdir, name) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ }
+
+ normpath = got_path_normalize(path);
if (normpath == NULL) {
err = got_error_from_errno();
goto done;
}
- err = parse_ref_file(ref, refname, normpath);
+ err = parse_ref_file(ref, absname, normpath);
done:
- free(path_ref);
+ if (!ref_is_absolute && !ref_is_well_known)
+ free(absname);
+ free(path);
free(normpath);
return err;
}
return NULL;
}
+static const struct got_error *
+gather_refs(struct got_reflist_head *refs, const char *path_refs,
+ const char *subdir, struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ DIR *d = NULL;
+ char *path_subdir;
+
+ if (asprintf(&path_subdir, "%s/%s", path_refs, subdir) == -1)
+ return got_error_from_errno();
+
+ d = opendir(path_subdir);
+ if (d == NULL)
+ goto done;
+
+ while (1) {
+ struct dirent *dent;
+ struct got_reference *ref;
+ char *child;
+
+ dent = readdir(d);
+ if (dent == NULL)
+ break;
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ switch (dent->d_type) {
+ case DT_REG:
+ err = open_ref(&ref, path_refs, subdir, dent->d_name);
+ if (err && err->code != GOT_ERR_NOT_REF)
+ goto done;
+ if (ref) {
+ err = append_ref(refs, ref, repo);
+ if (err)
+ goto done;
+ }
+ break;
+ case DT_DIR:
+ if (asprintf(&child, "%s%s%s", subdir,
+ subdir[0] == '\0' ? "" : "/", dent->d_name) == -1) {
+ err = got_error_from_errno();
+ break;
+ }
+ err = gather_refs(refs, path_refs, child, repo);
+ free(child);
+ break;
+ default:
+ break;
+ }
+ }
+done:
+ if (d)
+ closedir(d);
+ free(path_subdir);
+ return err;
+}
+
const struct got_error *
got_ref_list(struct got_reflist_head *refs, struct got_repository *repo)
{
const struct got_error *err;
- char *packed_refs_path, *path_refs;
+ char *packed_refs_path, *path_refs = NULL;
FILE *f;
struct got_reference *ref;
goto done;
}
err = open_ref(&ref, path_refs, "", GOT_REF_HEAD);
- free(path_refs);
if (err)
goto done;
err = append_ref(refs, ref, repo);
if (err)
goto done;
+ free(path_refs);
+ path_refs = get_refs_dir_path(repo, "");
+ if (path_refs == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ err = gather_refs(refs, path_refs, "", repo);
done:
+ free(path_refs);
if (f)
fclose(f);
return err;