commit fb79db15f5778760633c3283c43e4c9f1efc35d2 from: Stefan Sperling date: Fri Feb 01 20:01:58 2019 UTC add read support for packed refs commit - 62d20534cc5908ccf5efd1bb7460e1c29ab905ed commit + fb79db15f5778760633c3283c43e4c9f1efc35d2 blob - cf943eae02dc39d02f7f968083ca7b71d48cc286 blob + c026e9bdbd4e6a2294da9829b38751ccbf812f54 --- include/got_repository.h +++ include/got_repository.h @@ -36,6 +36,7 @@ const char *got_repo_get_path_git_dir(struct got_repos char *got_repo_get_path_objects(struct got_repository *); char *got_repo_get_path_objects_pack(struct got_repository *); char *got_repo_get_path_refs(struct got_repository *); +char *got_repo_get_path_packed_refs(struct got_repository *); struct got_reference; blob - 75e50d1e4ade6ef15160eadce5781d37a8291941 blob + 5730c82cd8e62233a17645c4661dc164d7a446d8 --- lib/reference.c +++ lib/reference.c @@ -36,6 +36,10 @@ #include "got_lib_inflate.h" #include "got_lib_object.h" +#ifndef nitems +#define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) +#endif + #define GOT_REF_HEADS "heads" #define GOT_REF_TAGS "tags" #define GOT_REF_REMOTES "remotes" @@ -159,6 +163,66 @@ get_refs_dir_path(struct got_repository *repo, const c } static const struct got_error * +parse_packed_ref_line(struct got_reference **ref, const char *abs_refname, + const char *line) +{ + uint8_t digest[SHA1_DIGEST_LENGTH]; + char *name; + + *ref = NULL; + + if (line[0] == '#') + return NULL; + + if (!got_parse_sha1_digest(digest, line)) + return got_error(GOT_ERR_NOT_REF); + + if (strcmp(line + SHA1_DIGEST_STRING_LENGTH, abs_refname) != 0) + return NULL; + + name = strdup(abs_refname); + if (name == NULL) + return got_error_from_errno(); + + *ref = calloc(1, sizeof(**ref)); + if (*ref == NULL) + return got_error_from_errno(); + (*ref)->ref.ref.name = name;; + memcpy(&(*ref)->ref.ref.sha1, digest, SHA1_DIGEST_LENGTH); + return NULL; +} + +static const struct got_error * +open_packed_ref(struct got_reference **ref, FILE *f, const char *subdir, + const char *refname) +{ + const struct got_error *err = NULL; + char *abs_refname; + char *line; + size_t len; + const char delim[3] = {'\0', '\0', '\0'}; + + if (asprintf(&abs_refname, "refs/%s/%s", subdir, refname) == -1) + return got_error_from_errno(); + + do { + line = fparseln(f, &len, NULL, delim, 0); + if (line == NULL) { + err = got_error(GOT_ERR_NOT_REF); + break; + } + + err = parse_packed_ref_line(ref, abs_refname, line); + free(line); + if (err) + break; + } while (*ref == NULL); + + free(abs_refname); + return err; +} + +static const struct got_error * open_ref(struct got_reference **ref, const char *path_refs, const char *subdir, const char *refname) { @@ -187,22 +251,37 @@ got_ref_open(struct got_reference **ref, struct got_re const char *refname) { const struct got_error *err = NULL; - char *path_refs = get_refs_dir_path(repo, refname); + char *path_refs; + const char *subdirs[] = { + GOT_REF_HEADS, GOT_REF_TAGS, GOT_REF_REMOTES + }; + char *packed_refs_path = got_repo_get_path_packed_refs(repo); + FILE *f = fopen(packed_refs_path, "rb"); + int i; + if (f) { + for (i = 0; i < nitems(subdirs); i++) { + err = open_packed_ref(ref, f, subdirs[i], refname); + if (err == NULL) + return NULL; + rewind(f); + } + fclose(f); + f = NULL; + } + + path_refs = get_refs_dir_path(repo, refname); if (path_refs == NULL) { err = got_error_from_errno(); goto done; } - /* XXX For now, this assumes that refs exist in the filesystem. */ - - err = open_ref(ref, path_refs, GOT_REF_HEADS, refname); - if (err != NULL) - err = open_ref(ref, path_refs, GOT_REF_TAGS, refname); - if (err != NULL) - err = open_ref(ref, path_refs, GOT_REF_REMOTES, refname); - if (err != NULL) - err = open_ref(ref, path_refs, "", refname); + for (i = 0; i < nitems(subdirs); i++) { + err = open_ref(ref, path_refs, subdirs[i], refname); + if (err == NULL) + goto done; + } + err = open_ref(ref, path_refs, "", refname); done: free(path_refs); return err; blob - d07b73f70b34559965294e584fc1a91bd324125e blob + 7c1144d171030372234ac834c818bd7f63628383 --- lib/repository.c +++ lib/repository.c @@ -65,6 +65,7 @@ #define GOT_FETCH_HEAD_FILE "FETCH_HEAD" #define GOT_ORIG_HEAD_FILE "ORIG_HEAD" #define GOT_OBJECTS_PACK_DIR "objects/pack" +#define GOT_PACKED_REFS_FILE "packed-refs" const char * got_repo_get_path(struct got_repository *repo) @@ -114,6 +115,12 @@ got_repo_get_path_refs(struct got_repository *repo) return get_path_git_child(repo, GOT_REFS_DIR); } +char * +got_repo_get_path_packed_refs(struct got_repository *repo) +{ + return get_path_git_child(repo, GOT_PACKED_REFS_FILE); +} + static char * get_path_head(struct got_repository *repo) {