Commit Diff


commit - 4684ea103757f25b8ac4aab872d9de45ae7d942e
commit + 0ffeb3c2d8dbe6ae565c5a4ae78d63c74897d102
blob - d993168dde3b77d1059065694c266b38c255c701
blob + d13b60b4636e8d6487f381e4411f9f4167864c19
--- include/got_object.h
+++ include/got_object.h
@@ -22,8 +22,16 @@ struct got_blob_object {
 	char *dummy;
 };
 
+struct got_tree_entry {
+	SIMPLEQ_ENTRY(got_tree_entry) entry;
+	mode_t mode;
+	char *name;
+	struct got_object_id id;
+};
+
 struct got_tree_object {
-	char *dummy;
+	int nentries;
+	SIMPLEQ_HEAD(, got_tree_entry) entries;
 };
 
 struct got_parent_id {
@@ -62,4 +70,6 @@ void got_object_close(struct got_object *);
 const struct got_error *got_object_commit_open(struct got_commit_object **,
     struct got_repository *, struct got_object *);
 void got_object_commit_close(struct got_commit_object *);
-
+const struct got_error *got_object_tree_open(struct got_tree_object **,
+    struct got_repository *, struct got_object *);
+void got_object_tree_close(struct got_tree_object *);
blob - f24b83d937d8f42d22bbce3b29d61394aca28678
blob + f4cdddb788293a815d8951ca973ba1e28f3dedfb
--- lib/object.c
+++ lib/object.c
@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <sys/stat.h>
 #include <sys/queue.h>
 
 #include <stdio.h>
@@ -413,10 +414,141 @@ parse_commit_object(struct got_commit_object **commit,
 done:
 	if (err)
 		got_object_commit_close(*commit);
+	return err;
+}
+
+static void
+tree_entry_close(struct got_tree_entry *te)
+{
+	free(te->name);
+	free(te);
+}
+
+static const char *
+mode_trailer(mode_t mode)
+{
+	if (S_ISDIR(mode))
+		return "/";
+
+	return "";
+}
+
+static const struct got_error *
+parse_tree_entry(struct got_tree_entry **te, size_t *elen, char *buf,
+    size_t maxlen)
+{
+	char *p = buf, *space;
+	const struct got_error *err = NULL;
+	char hex[SHA1_DIGEST_STRING_LENGTH];
+
+	*te = calloc(1, sizeof(**te));
+	if (*te == NULL)
+		return got_error(GOT_ERR_NO_MEM);
+
+	*elen = strlen(buf) + 1;
+	if (*elen > maxlen) {
+		free(*te);
+		return got_error(GOT_ERR_BAD_OBJ_DATA);
+	}
+
+	space = strchr(buf, ' ');
+	if (space == NULL) {
+		free(*te);
+		return got_error(GOT_ERR_BAD_OBJ_DATA);
+	}
+	while (*p != ' ') {
+		if (*p < '0' && *p > '7') {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		(*te)->mode <<= 3;
+		(*te)->mode |= *p - '0';
+		p++;
+	}
+
+	(*te)->name = strdup(space + 1);
+	if (*elen > maxlen || maxlen - *elen < SHA1_DIGEST_LENGTH) {
+		err = got_error(GOT_ERR_BAD_OBJ_DATA);
+		goto done;
+	}
+	buf += strlen(buf) + 1;
+	memcpy((*te)->id.sha1, buf, SHA1_DIGEST_LENGTH);
+	*elen += SHA1_DIGEST_LENGTH;
+
+	printf("%s %s%s\n", got_object_id_str(&(*te)->id, hex, sizeof(hex)),
+	    (*te)->name, mode_trailer((*te)->mode));
+done:
+	if (err)
+		tree_entry_close(*te);
 	return err;
 }
 
 static const struct got_error *
+open_tree_recursive(struct got_object_id *id, struct got_repository *repo)
+{
+	struct got_object *obj;
+	struct got_tree_object *tree;
+	const struct got_error *err;
+
+	err = got_object_open(&obj, repo, id);
+	if (err)
+		return err;
+	if (obj->type != GOT_OBJ_TYPE_TREE)
+		return got_error(GOT_ERR_OBJ_TYPE);
+
+	err = got_object_tree_open(&tree, repo, obj);
+	if (err) {
+		got_object_close(obj);
+		return err;
+	}
+
+	got_object_tree_close(tree);
+	got_object_close(obj);
+	return NULL;
+}
+
+static const struct got_error *
+parse_tree_object(struct got_tree_object **tree, struct got_repository *repo,
+    char *buf, size_t len)
+{
+	size_t remain = len;
+	int nentries;
+
+	*tree = calloc(1, sizeof(**tree));
+	if (*tree == NULL)
+		return got_error(GOT_ERR_NO_MEM);
+
+	SIMPLEQ_INIT(&(*tree)->entries);
+
+	while (remain > 0) {
+		struct got_tree_entry *te;
+		size_t elen;
+
+		parse_tree_entry(&te, &elen, buf, remain);
+		(*tree)->nentries++;
+		SIMPLEQ_INSERT_TAIL(&(*tree)->entries, te, entry);
+		if (S_ISDIR(te->mode)) {
+			const struct got_error *err;
+			err = open_tree_recursive(&te->id, repo);
+			if (err) {
+				got_object_tree_close(*tree);
+				return err;
+			}
+		}
+		buf += elen;
+		remain -= elen;
+	}
+	printf("\n");
+
+	if (remain != 0) {
+		got_object_tree_close(*tree);
+		return got_error(GOT_ERR_BAD_OBJ_DATA);
+	}
+
+	return NULL;
+}
+
+static const struct got_error *
 read_commit_object(struct got_commit_object **commit,
     struct got_repository *repo, struct got_object *obj, const char *path)
 {
@@ -492,3 +624,68 @@ got_object_commit_close(struct got_commit_object *comm
 	free(commit->logmsg);
 	free(commit);
 }
+
+static const struct got_error *
+read_tree_object(struct got_tree_object **tree,
+    struct got_repository *repo, struct got_object *obj, const char *path)
+{
+	const struct got_error *err = NULL;
+	FILE *f;
+	struct got_zstream_buf zb;
+	size_t len;
+	char *p;
+	int i, ret;
+
+	f = fopen(path, "rb");
+	if (f == NULL)
+		return got_error(GOT_ERR_BAD_PATH);
+
+	err = inflate_init(&zb, 8192);
+	if (err) {
+		fclose(f);
+		return err;
+	}
+
+	do {
+		err = inflate_read(&zb, f, &len);
+		if (err || len == 0)
+			break;
+	} while (len < obj->hdrlen + obj->size);
+
+	if (len < obj->hdrlen + obj->size) {
+		err = got_error(GOT_ERR_BAD_OBJ_DATA);
+		goto done;
+	}
+
+	/* Skip object header. */
+	len -= obj->hdrlen;
+	err = parse_tree_object(tree, repo, zb.outbuf + obj->hdrlen, len);
+done:
+	inflate_end(&zb);
+	fclose(f);
+	return err;
+}
+
+const struct got_error *
+got_object_tree_open(struct got_tree_object **tree,
+    struct got_repository *repo, struct got_object *obj)
+{
+	const struct got_error *err = NULL;
+	char *path = NULL;
+
+	if (obj->type != GOT_OBJ_TYPE_TREE)
+		return got_error(GOT_ERR_OBJ_TYPE);
+
+	err = object_path(&path, &obj->id, repo);
+	if (err)
+		return err;
+
+	err = read_tree_object(tree, repo, obj, path);
+	free(path);
+	return err;
+}
+
+void
+got_object_tree_close(struct got_tree_object *tree)
+{
+}
blob - 8c1fcd816103828141db98729cf464427feca200
blob + 2044938135e906df60393fc61d80b70c7c452e9a
--- regress/repository/repository_test.c
+++ regress/repository/repository_test.c
@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <sys/stat.h>
 #include <sys/queue.h>
 
 #include <stdio.h>
@@ -55,12 +56,27 @@ print_parent_commits(struct got_commit_object *commit,
 }
 
 static const struct got_error *
+print_tree_object(struct got_object *obj, struct got_repository *repo)
+{
+	struct got_tree_object *tree;
+	const struct got_error *err;
+
+	err = got_object_tree_open(&tree, repo, obj);
+	if (err != NULL)
+		return err;
+
+	got_object_tree_close(tree);
+	return NULL;
+}
+
+static const struct got_error *
 print_commit_object(struct got_object *obj, struct got_repository *repo)
 {
 	struct got_commit_object *commit;
 	struct got_parent_id *pid;
 	char buf[SHA1_DIGEST_STRING_LENGTH];
 	const struct got_error *err;
+	struct got_object* treeobj;
 
 	err = got_object_commit_open(&commit, repo, obj);
 	if (err != NULL)
@@ -77,6 +93,13 @@ print_commit_object(struct got_object *obj, struct got
 	printf("committer: %s\n", commit->committer);
 	printf("log: %s\n", commit->logmsg);
 
+	err = got_object_open(&treeobj, repo, &commit->tree_id);
+	if (err != NULL)
+		return err;
+	if (treeobj->type == GOT_OBJ_TYPE_TREE)
+		print_tree_object(treeobj, repo);
+	got_object_close(treeobj);
+
 	err = print_parent_commits(commit, repo);
 	got_object_commit_close(commit);