deps/reftable: implement system compatibility code

While the reftable library is mostly decoupled from the Git codebase,
some specific functionality intentionally taps into Git subsystems. To
make porting of the reftable library easier all of these are contained
in "system.h" and "system.c".

Reimplement those compatibility shims so that they work for libgit2.
This commit is contained in:
Patrick Steinhardt
2026-04-02 08:20:40 +02:00
parent 623a3783bb
commit 9e3b00acfb
2 changed files with 184 additions and 75 deletions

View File

@@ -8,11 +8,26 @@
* header is expected to be changed by the individual project.
*/
#define MINGW_DONT_HANDLE_IN_USE_ERROR
#include "compat/posix.h"
#include "compat/zlib-compat.h"
#include "map.h"
#include "posix.h"
#include "util.h"
#include <zlib.h>
int reftable_fsync(int fd);
#define fsync(fd) reftable_fsync(fd)
/*
* We only need to redefine on Windows as we expect stat(3p) et al to be
* available on Unix platforms. Furthermore, we only need to redefine fstat(3p)
* because we already redefine stat(3p) "win32-compat.h".
*/
#ifdef GIT_WIN32
# define fstat(fd, st) p_fstat(fd, st)
#endif
#define fsync(fd) p_fsync(fd)
#define poll(fds, fds_len, timeout) p_poll(fds, fds_len, timeout)
#define REFTABLE_ALLOW_BANNED_ALLOCATORS
#define inline GIT_INLINE_KEYWORD
#endif

234
deps/reftable/system.c vendored
View File

@@ -1,38 +1,53 @@
#include "../git-compat-util.h"
#include "system.h"
#include "basics.h"
#include "rand.h"
#include "reftable-error.h"
#include "../lockfile.h"
#include "../trace.h"
#include "../tempfile.h"
#include "../write-or-die.h"
uint32_t reftable_rand(void)
{
return git_rand(CSPRNG_BYTES_INSECURE);
return (uint32_t) git_rand_next();
}
int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern)
{
struct tempfile *tempfile;
git_str path = GIT_STR_INIT;
unsigned tries = 32;
tempfile = mks_tempfile(pattern);
if (!tempfile)
return REFTABLE_IO_ERROR;
if (git__suffixcmp(pattern, ".XXXXXX"))
return REFTABLE_API_ERROR;
out->path = tempfile->filename.buf;
out->fd = tempfile->fd;
out->priv = tempfile;
while (tries--) {
uint64_t rand = git_rand_next();
int fd;
return 0;
git_str_sets(&path, pattern);
git_str_shorten(&path, 6);
git_str_encode_hexstr(&path, (void *)&rand, 6);
if (git_str_oom(&path))
return REFTABLE_OUT_OF_MEMORY_ERROR;
if ((fd = p_open(path.ptr, O_CREAT | O_RDWR | O_EXCL | O_CLOEXEC, 0666)) < 0)
continue;
out->path = git_str_detach(&path);
out->fd = fd;
return 0;
}
git_str_dispose(&path);
return REFTABLE_IO_ERROR;
}
int tmpfile_close(struct reftable_tmpfile *t)
{
struct tempfile *tempfile = t->priv;
int ret = close_tempfile_gently(tempfile);
int ret;
if (t->fd < 0)
return 0;
ret = close(t->fd);
t->fd = -1;
if (ret < 0)
return REFTABLE_IO_ERROR;
return 0;
@@ -40,126 +55,205 @@ int tmpfile_close(struct reftable_tmpfile *t)
int tmpfile_delete(struct reftable_tmpfile *t)
{
struct tempfile *tempfile = t->priv;
int ret = delete_tempfile(&tempfile);
*t = REFTABLE_TMPFILE_INIT;
if (ret < 0)
int ret;
if (!t->path)
return 0;
tmpfile_close(t);
if ((ret = unlink(t->path)) < 0)
return REFTABLE_IO_ERROR;
reftable_free((char *) t->path);
t->path = NULL;
return 0;
}
int tmpfile_rename(struct reftable_tmpfile *t, const char *path)
{
struct tempfile *tempfile = t->priv;
int ret = rename_tempfile(&tempfile, path);
*t = REFTABLE_TMPFILE_INIT;
if (ret < 0)
int ret;
if (!t->path)
return REFTABLE_API_ERROR;
tmpfile_close(t);
if ((ret = p_rename(t->path, path)) < 0)
return REFTABLE_IO_ERROR;
reftable_free((char *) t->path);
t->path = NULL;
return 0;
}
struct libgit2_flock {
char *lock_path;
char *target_path;
};
int flock_acquire(struct reftable_flock *l, const char *target_path,
long timeout_ms)
{
struct lock_file *lockfile;
int err;
struct libgit2_flock *flock;
unsigned multiplier = 1, n = 1;
size_t lock_path_len;
uint64_t deadline;
int fd = -1, error;
lockfile = reftable_malloc(sizeof(*lockfile));
if (!lockfile)
return REFTABLE_OUT_OF_MEMORY_ERROR;
err = hold_lock_file_for_update_timeout(lockfile, target_path, LOCK_NO_DEREF,
timeout_ms);
if (err < 0) {
reftable_free(lockfile);
if (errno == EEXIST)
return REFTABLE_LOCK_ERROR;
return REFTABLE_IO_ERROR;
lock_path_len = strlen(target_path) + strlen(".lock") + 1;
if ((flock = reftable_calloc(sizeof(*flock), 1)) == NULL ||
(flock->target_path = reftable_strdup(target_path)) == NULL ||
(flock->lock_path = reftable_malloc(lock_path_len)) == NULL) {
error = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
l->fd = get_lock_file_fd(lockfile);
l->path = get_lock_file_path(lockfile);
l->priv = lockfile;
snprintf(flock->lock_path, lock_path_len, "%s.lock", target_path);
return 0;
deadline = git_time_monotonic() + timeout_ms;
while (1) {
uint64_t now, wait_ms;
if ((fd = p_open(flock->lock_path, O_WRONLY | O_EXCL | O_CREAT, 0666)) >= 0)
break;
if (errno != EEXIST) {
error = REFTABLE_IO_ERROR;
goto out;
}
now = git_time_monotonic();
if (now > deadline) {
error = REFTABLE_LOCK_ERROR;
goto out;
}
wait_ms = (750 + rand() % 500) * multiplier / 1000;
multiplier += 2 * n + 1;
if (multiplier > 1000)
multiplier = 1000;
else
n++;
p_poll(NULL, 0, (int) wait_ms);
}
l->priv = flock;
l->path = flock->lock_path;
l->fd = fd;
error = 0;
out:
if (error) {
if (flock) {
reftable_free(flock->target_path);
reftable_free(flock->lock_path);
}
reftable_free(flock);
}
return error;
}
int flock_close(struct reftable_flock *l)
{
struct lock_file *lockfile = l->priv;
int ret;
if (!lockfile)
return REFTABLE_API_ERROR;
if (l->fd < 0)
return 0;
ret = close_lock_file_gently(lockfile);
ret = p_close(l->fd);
l->fd = -1;
if (ret < 0)
return REFTABLE_IO_ERROR;
return 0;
}
static void libgit2_flock_release(struct reftable_flock *l)
{
struct libgit2_flock *flock = l->priv;
reftable_free(flock->lock_path);
reftable_free(flock->target_path);
reftable_free(flock);
l->priv = NULL;
l->path = NULL;
}
int flock_release(struct reftable_flock *l)
{
struct lock_file *lockfile = l->priv;
struct libgit2_flock *flock = l->priv;
int ret;
if (!lockfile)
if (!flock)
return 0;
ret = rollback_lock_file(lockfile);
reftable_free(lockfile);
*l = REFTABLE_FLOCK_INIT;
flock_close(l);
if ((ret = p_unlink(flock->lock_path)) < 0)
goto out;
out:
libgit2_flock_release(l);
if (ret < 0)
return REFTABLE_IO_ERROR;
return 0;
}
int flock_commit(struct reftable_flock *l)
{
struct lock_file *lockfile = l->priv;
struct libgit2_flock *flock = l->priv;
int ret;
if (!lockfile)
flock_close(l);
if (!flock)
return REFTABLE_API_ERROR;
ret = commit_lock_file(lockfile);
reftable_free(lockfile);
*l = REFTABLE_FLOCK_INIT;
if ((ret = p_rename(flock->lock_path, flock->target_path)) < 0)
goto out;
out:
libgit2_flock_release(l);
if (ret < 0)
return REFTABLE_IO_ERROR;
return 0;
}
int reftable_fsync(int fd)
{
return fsync_component(FSYNC_COMPONENT_REFERENCE, fd);
}
uint64_t reftable_time_ms(void)
{
return getnanotime() / 1000000;
return git_time_monotonic();
}
int reftable_mmap(struct reftable_mmap *out, int fd, size_t len)
{
void *data = xmmap_gently(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
if (data == MAP_FAILED)
git_map *mmap;
mmap = git__malloc(sizeof(*mmap));
if (!mmap)
return REFTABLE_OUT_OF_MEMORY_ERROR;
if (p_mmap(mmap, len, GIT_PROT_READ, GIT_MAP_PRIVATE, fd, 0) < 0)
return REFTABLE_IO_ERROR;
out->data = data;
out->size = len;
out->priv = mmap;
out->data = mmap->data;
out->size = mmap->len;
return 0;
}
int reftable_munmap(struct reftable_mmap *mmap)
{
if (munmap(mmap->data, mmap->size) < 0)
git_map *map = mmap->priv;
if (p_munmap(map) < 0)
return REFTABLE_IO_ERROR;
git__free(map);
memset(mmap, 0, sizeof(*mmap));
return 0;
}