public-inbox.git  about / heads / tags
an "archives first" approach to mailing lists
blob e1f0ef39a68623baf45c30c285324b8dfbc502ef 3213 bytes (raw)
$ git show HEAD:lib/PublicInbox/gcf2_libgit2.h	# shows this blob on the CLI

  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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
 
/*
 * Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
 * License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 *
 * libgit2 for Inline::C
 * Avoiding Git::Raw since it doesn't guarantee a stable API,
 * while libgit2 itself seems reasonably stable.
 */
#include <git2.h>
#include <sys/uio.h>
#include <errno.h>
#include <poll.h>

static void croak_if_err(int rc, const char *msg)
{
	if (rc != GIT_OK) {
		const git_error *e = giterr_last();

		croak("%d %s (%s)", rc, msg, e ? e->message : "unknown");
	}
}

SV *new()
{
	git_odb *odb;
	SV *ref, *self;
	int rc = git_odb_new(&odb);
	croak_if_err(rc, "git_odb_new");

	ref = newSViv((IV)odb);
	self = newRV_noinc(ref);
	sv_bless(self, gv_stashpv("PublicInbox::Gcf2", GV_ADD));
	SvREADONLY_on(ref);

	return self;
}

static git_odb *odb_ptr(SV *self)
{
	return (git_odb *)SvIV(SvRV(self));
}

void DESTROY(SV *self)
{
	git_odb_free(odb_ptr(self));
}

/* needs "$GIT_DIR/objects", not $GIT_DIR */
void add_alternate(SV *self, const char *objects_path)
{
	int rc = git_odb_add_disk_alternate(odb_ptr(self), objects_path);
	croak_if_err(rc, "git_odb_add_disk_alternate");
}

#define CAPA(v) (sizeof(v) / sizeof((v)[0]))

/*
 * returns true on success, false on failure
 * this requires an unabbreviated git OID
 */
int cat_oid(SV *self, int fd, SV *oidsv)
{
	/*
	 * adjust when libgit2 gets SHA-256 support, we return the
	 * same header as git-cat-file --batch "$OID $TYPE $SIZE\n"
	 */
	char hdr[GIT_OID_HEXSZ + sizeof(" commit 18446744073709551615")];
	struct iovec vec[3];
	size_t nvec = CAPA(vec);
	git_oid oid;
	git_odb_object *object = NULL;
	int rc, err = 0;
	STRLEN oidlen;
	char *oidptr = SvPV(oidsv, oidlen);

	/* same trailer as git-cat-file --batch */
	vec[2].iov_len = 1;
	vec[2].iov_base = "\n";

	rc = git_oid_fromstrn(&oid, oidptr, oidlen);
	if (rc == GIT_OK)
		rc = git_odb_read(&object, odb_ptr(self), &oid);
	if (rc == GIT_OK) {
		vec[0].iov_base = hdr;
		vec[1].iov_base = (void *)git_odb_object_data(object);
		vec[1].iov_len = git_odb_object_size(object);

		git_oid_nfmt(hdr, GIT_OID_HEXSZ, git_odb_object_id(object));
		vec[0].iov_len = GIT_OID_HEXSZ +
				snprintf(hdr + GIT_OID_HEXSZ,
					sizeof(hdr) - GIT_OID_HEXSZ,
					" %s %zu\n",
					git_object_type2string(
						git_odb_object_type(object)),
					vec[1].iov_len);
	} else { /* caller retries */
		nvec = 0;
	}
	while (nvec && !err) {
		ssize_t w = writev(fd, vec + CAPA(vec) - nvec, nvec);

		if (w > 0) {
			size_t done = 0;
			size_t i;

			for (i = CAPA(vec) - nvec; i < CAPA(vec); i++) {
				if (w >= vec[i].iov_len) {
					/* fully written vec */
					w -= vec[i].iov_len;
					done++;
				} else { /* partially written vec */
					char *p = vec[i].iov_base;
					vec[i].iov_base = p + w;
					vec[i].iov_len -= w;
					break;
				}
			}
			nvec -= done;
		} else if (w < 0) {
			err = errno;
			switch (err) {
			case EAGAIN: {
				struct pollfd pfd;
				pfd.events = POLLOUT;
				pfd.fd = fd;
				poll(&pfd, 1, -1);
			}
				/* fall-through */
			case EINTR:
				err = 0;
			}
		} else { /* w == 0 */
			err = ENOSPC;
		}
	}
	if (object)
		git_odb_object_free(object);
	if (err)
		croak("writev error: %s", strerror(err));

	return rc == GIT_OK;
}

git clone https://public-inbox.org/public-inbox.git
git clone http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git