2 * Copyright (C) 2020 all contributors <meta@public-inbox.org>
3 * License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
5 * libgit2 for Inline::C
6 * Avoiding Git::Raw since it doesn't guarantee a stable API,
7 * while libgit2 itself seems reasonably stable.
14 static void croak_if_err(int rc, const char *msg)
17 const git_error *e = giterr_last();
19 croak("%d %s (%s)", rc, msg, e ? e->message : "unknown");
27 int rc = git_odb_new(&odb);
28 croak_if_err(rc, "git_odb_new");
30 ref = newSViv((IV)odb);
31 self = newRV_noinc(ref);
32 sv_bless(self, gv_stashpv("PublicInbox::Gcf2", GV_ADD));
38 static git_odb *odb_ptr(SV *self)
40 return (git_odb *)SvIV(SvRV(self));
43 void DESTROY(SV *self)
45 git_odb_free(odb_ptr(self));
48 /* needs "$GIT_DIR/objects", not $GIT_DIR */
49 void add_alternate(SV *self, const char *objects_path)
51 int rc = git_odb_add_disk_alternate(odb_ptr(self), objects_path);
52 croak_if_err(rc, "git_odb_add_disk_alternate");
55 /* this requires an unabbreviated git OID */
56 #define CAPA(v) (sizeof(v) / sizeof((v)[0]))
57 void cat_oid(SV *self, int fd, SV *oidsv)
60 * adjust when libgit2 gets SHA-256 support, we return the
61 * same header as git-cat-file --batch "$OID $TYPE $SIZE\n"
63 char hdr[GIT_OID_HEXSZ + sizeof(" commit 18446744073709551615")];
65 size_t nvec = CAPA(vec);
67 git_odb_object *object = NULL;
70 char *oidptr = SvPV(oidsv, oidlen);
72 /* same trailer as git-cat-file --batch */
74 vec[2].iov_base = "\n";
76 rc = git_oid_fromstrn(&oid, oidptr, oidlen);
78 rc = git_odb_read(&object, odb_ptr(self), &oid);
80 vec[0].iov_base = hdr;
81 vec[1].iov_base = (void *)git_odb_object_data(object);
82 vec[1].iov_len = git_odb_object_size(object);
84 git_oid_nfmt(hdr, GIT_OID_HEXSZ, git_odb_object_id(object));
85 vec[0].iov_len = GIT_OID_HEXSZ +
86 snprintf(hdr + GIT_OID_HEXSZ,
87 sizeof(hdr) - GIT_OID_HEXSZ,
89 git_object_type2string(
90 git_odb_object_type(object)),
93 vec[0].iov_base = oidptr;
94 vec[0].iov_len = oidlen;
95 vec[1].iov_base = " missing";
96 vec[1].iov_len = strlen(vec[1].iov_base);
98 while (nvec && !err) {
99 ssize_t w = writev(fd, vec + CAPA(vec) - nvec, nvec);
105 for (i = CAPA(vec) - nvec; i < CAPA(vec); i++) {
106 if (w >= vec[i].iov_len) {
107 /* fully written vec */
110 } else { /* partially written vec */
111 char *p = vec[i].iov_base;
112 vec[i].iov_base = p + w;
123 pfd.events = POLLOUT;
131 } else { /* w == 0 */
136 git_odb_object_free(object);
138 croak("writev error: %s", strerror(err));