user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
d9c79cf9b138df9b716df9035001ffba943b5274 blob 3234 bytes (raw)

  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
 
/*
 * Copyright (C) 2020 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");
}

/* this requires an unabbreviated git OID */
#define CAPA(v) (sizeof(v) / sizeof((v)[0]))
void 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 {
		vec[0].iov_base = oidptr;
		vec[0].iov_len = oidlen;
		vec[1].iov_base = " missing";
		vec[1].iov_len = strlen(vec[1].iov_base);
	}
	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));
}
debug log:

solving d9c79cf9 ...
found d9c79cf9 in https://80x24.org/public-inbox.git

Code repositories for project(s) associated with this inbox:

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).