commit 776d4d299ae7521a3f409a3b5dbbcc1a400f2b5c from: Stefan Sperling date: Sun Jun 17 10:34:17 2018 UTC add got_object_open_as_tree() and got_object_open_by_path() commit - f7d20e8910435defc9367c68c5af4418123d088e commit + 776d4d299ae7521a3f409a3b5dbbcc1a400f2b5c blob - ec5c5b134da4aac3b2260284f17374a481a813ca blob + 6687d7a01fd4ec3044033b802990e13135f72b4b --- include/got_object.h +++ include/got_object.h @@ -182,6 +182,13 @@ const struct got_error *got_object_blob_read_block(siz const struct got_error * got_object_open_as_commit(struct got_commit_object **, struct got_repository *, struct got_object_id *); +const struct got_error * +got_object_open_as_tree(struct got_tree_object **, + struct got_repository *, struct got_object_id *); +const struct got_error * +got_object_open_by_path(struct got_object **, struct got_repository *, + struct got_object_id *, const char *); + const struct got_error *got_object_commit_add_parent(struct got_commit_object *, const char *); blob - 1765ec7c9ff3743ac32416d1a8baa920602a89c6 blob + 7e037bbba1c2f2cf32211f9bc9ad9dd6a060568e --- lib/object.c +++ lib/object.c @@ -1121,7 +1121,28 @@ got_object_tree_open(struct got_tree_object **tree, return err; err = read_tree_object_privsep(tree, obj, fd); close(fd); + } + return err; +} + +const struct got_error * +got_object_open_as_tree(struct got_tree_object **tree, + struct got_repository *repo, struct got_object_id *id) +{ + const struct got_error *err; + struct got_object *obj; + + err = got_object_open(&obj, repo, id); + if (err) + return err; + if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) { + err = got_error(GOT_ERR_OBJ_TYPE); + goto done; } + + err = got_object_tree_open(tree, repo, obj); +done: + got_object_close(obj); return err; } @@ -1334,5 +1355,104 @@ got_object_blob_read_block(size_t *outlenp, struct got if (n == 0 && ferror(blob->f)) return got_ferror(blob->f, GOT_ERR_IO); *outlenp = n; + return NULL; +} + +static struct got_tree_entry * +find_entry_by_name(struct got_tree_object *tree, const char *name) +{ + struct got_tree_entry *te; + + SIMPLEQ_FOREACH(te, &tree->entries, entry) { + if (strcmp(te->name, name) == 0) + return te; + } return NULL; +} + +const struct got_error * +got_object_open_by_path(struct got_object **obj, struct got_repository *repo, + struct got_object_id *commit_id, const char *path) +{ + const struct got_error *err = NULL; + struct got_commit_object *commit = NULL; + struct got_tree_object *tree = NULL; + struct got_tree_entry *entry = NULL; + char *seg, *s = NULL; + + *obj = NULL; + + /* We are expecting an absolute in-repository path. */ + if (path[0] != '/') + return got_error(GOT_ERR_NOT_ABSPATH); + + err = got_object_open_as_commit(&commit, repo, commit_id); + if (err) + goto done; + + /* Handle opening of root of commit's tree. */ + if (path[1] == '\0') { + err = got_object_open(obj, repo, commit->tree_id); + if (err) + goto done; + return NULL; + } + + err = got_object_open_as_tree(&tree, repo, commit->tree_id); + if (err) + goto done; + + s = strdup(path); + if (s == NULL) { + err = got_error_from_errno(); + goto done; + } + err = got_canonpath(path, s, strlen(s) + 1); + if (err) + goto done; + + s++; /* skip leading '/' */ + seg = s; + while (*s) { + struct got_tree_object *next_tree; + + if (*s != '/') { + s++; + continue; + } + + /* end of path segment */ + *s = '\0'; + + entry = find_entry_by_name(tree, seg); + if (entry == NULL) { + err = got_error(GOT_ERR_NO_OBJ); + goto done; + } + + seg = s + 1; + s++; + + if (*s) { + err = got_object_open_as_tree(&next_tree, repo, + entry->id); + entry = NULL; + if (err) + goto done; + got_object_tree_close(tree); + tree = next_tree; + } + } + + if (entry) + err = got_object_open(obj, repo, entry->id); + else + err = got_error(GOT_ERR_NO_OBJ); +done: + free(s); + if (commit) + got_object_commit_close(commit); + if (tree) + got_object_tree_close(tree); + return err; }