introduce got_object_tree_create()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
diff --git a/lib/got_lib_object_create.h b/lib/got_lib_object_create.h
index 79dd142..4d00479 100644
--- a/lib/got_lib_object_create.h
+++ b/lib/got_lib_object_create.h
@@ -16,3 +16,5 @@
const struct got_error *got_object_blob_create(struct got_object_id **,
const char *, struct got_repository *);
+const struct got_error *got_object_tree_create(struct got_object_id **,
+ struct got_tree_entries *, struct got_repository *);
diff --git a/lib/object_create.c b/lib/object_create.c
index e544db9..85d2c8c 100644
--- a/lib/object_create.c
+++ b/lib/object_create.c
@@ -199,3 +199,110 @@ done:
}
return err;
}
+
+static const struct got_error *
+mode2str(char *buf, size_t len, mode_t mode)
+{
+ int ret;
+ ret = snprintf(buf, len, "%o ", mode);
+ if (ret == -1 || ret >= len)
+ return got_error(GOT_ERR_NO_SPACE);
+ return NULL;
+}
+
+const struct got_error *
+got_object_tree_create(struct got_object_id **id,
+ struct got_tree_entries *entries, struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ char modebuf[sizeof("100644 ")];
+ SHA1_CTX sha1_ctx;
+ uint8_t digest[SHA1_DIGEST_LENGTH];
+ char *header = NULL;
+ size_t headerlen, len = 0, n;
+ FILE *treefile = NULL;
+ struct got_tree_entry *te;
+
+ *id = NULL;
+
+ SIMPLEQ_FOREACH(te, &entries->head, entry) {
+ err = mode2str(modebuf, sizeof(modebuf), te->mode);
+ if (err)
+ return err;
+ len += strlen(modebuf) + strlen(te->name) + 1 +
+ SHA1_DIGEST_LENGTH;
+ }
+
+ if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_TREE, len) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ headerlen = strlen(header) + 1;
+ SHA1Update(&sha1_ctx, header, headerlen);
+
+ treefile = got_opentemp();
+ if (treefile == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ n = fwrite(header, 1, headerlen, treefile);
+ if (n != headerlen) {
+ err = got_ferror(treefile, GOT_ERR_IO);
+ goto done;
+ }
+
+ SIMPLEQ_FOREACH(te, &entries->head, entry) {
+ err = mode2str(modebuf, sizeof(modebuf), te->mode);
+ if (err)
+ goto done;
+ len = strlen(modebuf);
+ n = fwrite(modebuf, 1, len, treefile);
+ if (n != len) {
+ err = got_ferror(treefile, GOT_ERR_IO);
+ goto done;
+ }
+ SHA1Update(&sha1_ctx, modebuf, len);
+
+ len = strlen(te->name) + 1; /* must include NUL */
+ n = fwrite(te->name, 1, len, treefile);
+ if (n != len) {
+ err = got_ferror(treefile, GOT_ERR_IO);
+ goto done;
+ }
+ SHA1Update(&sha1_ctx, te->name, len);
+
+ len = SHA1_DIGEST_LENGTH;
+ n = fwrite(te->id->sha1, 1, len, treefile);
+ if (n != len) {
+ err = got_ferror(treefile, GOT_ERR_IO);
+ goto done;
+ }
+ SHA1Update(&sha1_ctx, te->id->sha1, len);
+ }
+
+ SHA1Final(digest, &sha1_ctx);
+ *id = malloc(sizeof(**id));
+ if (*id == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ memcpy((*id)->sha1, digest, SHA1_DIGEST_LENGTH);
+
+ if (fflush(treefile) != 0) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ rewind(treefile);
+
+ err = create_loose_object(*id, treefile, repo);
+done:
+ free(header);
+ if (treefile && fclose(treefile) != 0 && err == NULL)
+ err = got_error_from_errno();
+ if (err) {
+ free(*id);
+ *id = NULL;
+ }
+ return err;
+}