reftable/system: provide thin wrapper for tempfile subsystem

We use the tempfile subsystem to write temporary tables, but given that we're in the process of converting the reftable library to become standalone we cannot use this subsystem directly anymore. While we could in theory convert the code to use mkstemp(3p) instead, we'd lose access to our infrastructure that automatically prunes tempfiles via atexit(3p) or signal handlers. Provide a thin wrapper for the tempfile subsystem instead. Like this, the compatibility shim is fully self-contained in "reftable/system.c". Downstream users of the reftable library would have to implement their own tempfile shims by replacing "system.c" with a custom version. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 18, 2024 at 16:34 UTC 01e49941d6560dfebfac39a2ffe49d3d24b35069
4 files changed +114 -35
Makefile
+1
@@ -2722,6 +2722,7 @@ REFTABLE_OBJS += reftable/pq.o
2722 REFTABLE_OBJS += reftable/reader.o
2723 REFTABLE_OBJS += reftable/record.o
2724 REFTABLE_OBJS += reftable/stack.o
2725 +REFTABLE_OBJS += reftable/system.o
2726 REFTABLE_OBJS += reftable/tree.o
2727 REFTABLE_OBJS += reftable/writer.o
2728
reftable/stack.c
+23 -34
@@ -16,7 +16,6 @@ https://developers.google.com/open-source/licenses/bsd
16 #include "reftable-record.h"
17 #include "reftable-merged.h"
18 #include "writer.h"
19 -#include "tempfile.h"
19
20 static int stack_try_add(struct reftable_stack *st,
21 int (*write_table)(struct reftable_writer *wr,
@@ -867,7 +866,7 @@ int reftable_addition_add(struct reftable_addition *add,
866 struct reftable_buf tab_file_name = REFTABLE_BUF_INIT;
867 struct reftable_buf next_name = REFTABLE_BUF_INIT;
868 struct reftable_writer *wr = NULL;
870 - struct tempfile *tab_file = NULL;
869 + struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
870 struct fd_writer writer = {
871 .opts = &add->stack->opts,
872 };
@@ -887,20 +886,18 @@ int reftable_addition_add(struct reftable_addition *add,
886 if (err < 0)
887 goto done;
888
890 - tab_file = mks_tempfile(temp_tab_file_name.buf);
891 - if (!tab_file) {
892 - err = REFTABLE_IO_ERROR;
889 + err = tmpfile_from_pattern(&tab_file, temp_tab_file_name.buf);
890 + if (err < 0)
891 goto done;
894 - }
892 if (add->stack->opts.default_permissions) {
896 - if (chmod(get_tempfile_path(tab_file),
893 + if (chmod(tab_file.path,
894 add->stack->opts.default_permissions)) {
895 err = REFTABLE_IO_ERROR;
896 goto done;
897 }
898 }
899
903 - writer.fd = get_tempfile_fd(tab_file);
900 + writer.fd = tab_file.fd;
901 err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
902 &writer, &add->stack->opts);
903 if (err < 0)
@@ -918,11 +915,9 @@ int reftable_addition_add(struct reftable_addition *add,
915 if (err < 0)
916 goto done;
917
921 - err = close_tempfile_gently(tab_file);
922 - if (err < 0) {
923 - err = REFTABLE_IO_ERROR;
918 + err = tmpfile_close(&tab_file);
919 + if (err < 0)
920 goto done;
925 - }
921
922 if (wr->min_update_index < add->next_update_index) {
923 err = REFTABLE_API_ERROR;
@@ -945,11 +940,9 @@ int reftable_addition_add(struct reftable_addition *add,
940 On windows, this relies on rand() picking a unique destination name.
941 Maybe we should do retry loop as well?
942 */
948 - err = rename_tempfile(&tab_file, tab_file_name.buf);
949 - if (err < 0) {
950 - err = REFTABLE_IO_ERROR;
943 + err = tmpfile_rename(&tab_file, tab_file_name.buf);
944 + if (err < 0)
945 goto done;
952 - }
946
947 REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1,
948 add->new_tables_cap);
@@ -960,7 +953,7 @@ int reftable_addition_add(struct reftable_addition *add,
953 add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name);
954
955 done:
963 - delete_tempfile(&tab_file);
956 + tmpfile_delete(&tab_file);
957 reftable_buf_release(&temp_tab_file_name);
958 reftable_buf_release(&tab_file_name);
959 reftable_buf_release(&next_name);
@@ -980,7 +973,7 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
973 static int stack_compact_locked(struct reftable_stack *st,
974 size_t first, size_t last,
975 struct reftable_log_expiry_config *config,
983 - struct tempfile **tab_file_out)
976 + struct reftable_tmpfile *tab_file_out)
977 {
978 struct reftable_buf next_name = REFTABLE_BUF_INIT;
979 struct reftable_buf tab_file_path = REFTABLE_BUF_INIT;
@@ -988,7 +981,7 @@ static int stack_compact_locked(struct reftable_stack *st,
981 struct fd_writer writer= {
982 .opts = &st->opts,
983 };
991 - struct tempfile *tab_file;
984 + struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
985 int err = 0;
986
987 err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]),
@@ -1004,19 +997,17 @@ static int stack_compact_locked(struct reftable_stack *st,
997 if (err < 0)
998 goto done;
999
1007 - tab_file = mks_tempfile(tab_file_path.buf);
1008 - if (!tab_file) {
1009 - err = REFTABLE_IO_ERROR;
1000 + err = tmpfile_from_pattern(&tab_file, tab_file_path.buf);
1001 + if (err < 0)
1002 goto done;
1011 - }
1003
1004 if (st->opts.default_permissions &&
1014 - chmod(get_tempfile_path(tab_file), st->opts.default_permissions) < 0) {
1005 + chmod(tab_file.path, st->opts.default_permissions) < 0) {
1006 err = REFTABLE_IO_ERROR;
1007 goto done;
1008 }
1009
1019 - writer.fd = get_tempfile_fd(tab_file);
1010 + writer.fd = tab_file.fd;
1011 err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
1012 &writer, &st->opts);
1013 if (err < 0)
@@ -1030,15 +1021,15 @@ static int stack_compact_locked(struct reftable_stack *st,
1021 if (err < 0)
1022 goto done;
1023
1033 - err = close_tempfile_gently(tab_file);
1024 + err = tmpfile_close(&tab_file);
1025 if (err < 0)
1026 goto done;
1027
1028 *tab_file_out = tab_file;
1038 - tab_file = NULL;
1029 + tab_file = REFTABLE_TMPFILE_INIT;
1030
1031 done:
1041 - delete_tempfile(&tab_file);
1032 + tmpfile_delete(&tab_file);
1033 reftable_writer_free(wr);
1034 reftable_buf_release(&next_name);
1035 reftable_buf_release(&tab_file_path);
@@ -1171,7 +1162,7 @@ static int stack_compact_range(struct reftable_stack *st,
1162 struct reftable_buf table_name = REFTABLE_BUF_INIT;
1163 struct lock_file tables_list_lock = LOCK_INIT;
1164 struct lock_file *table_locks = NULL;
1174 - struct tempfile *new_table = NULL;
1165 + struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT;
1166 int is_empty_table = 0, err = 0;
1167 size_t first_to_replace, last_to_replace;
1168 size_t i, nlocks = 0;
@@ -1439,11 +1430,9 @@ static int stack_compact_range(struct reftable_stack *st,
1430 if (err < 0)
1431 goto done;
1432
1442 - err = rename_tempfile(&new_table, new_table_path.buf);
1443 - if (err < 0) {
1444 - err = REFTABLE_IO_ERROR;
1433 + err = tmpfile_rename(&new_table, new_table_path.buf);
1434 + if (err < 0)
1435 goto done;
1446 - }
1436 }
1437
1438 /*
@@ -1515,7 +1504,7 @@ done:
1504 rollback_lock_file(&table_locks[i]);
1505 reftable_free(table_locks);
1506
1518 - delete_tempfile(&new_table);
1507 + tmpfile_delete(&new_table);
1508 reftable_buf_release(&new_table_name);
1509 reftable_buf_release(&new_table_path);
1510 reftable_buf_release(&tables_list_buf);
reftable/system.c new
+49
@@ -0,0 +1,49 @@
1 +#include "system.h"
2 +#include "basics.h"
3 +#include "reftable-error.h"
4 +#include "../tempfile.h"
5 +
6 +int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern)
7 +{
8 + struct tempfile *tempfile;
9 +
10 + tempfile = mks_tempfile(pattern);
11 + if (!tempfile)
12 + return REFTABLE_IO_ERROR;
13 +
14 + out->path = tempfile->filename.buf;
15 + out->fd = tempfile->fd;
16 + out->priv = tempfile;
17 +
18 + return 0;
19 +}
20 +
21 +int tmpfile_close(struct reftable_tmpfile *t)
22 +{
23 + struct tempfile *tempfile = t->priv;
24 + int ret = close_tempfile_gently(tempfile);
25 + t->fd = -1;
26 + if (ret < 0)
27 + return REFTABLE_IO_ERROR;
28 + return 0;
29 +}
30 +
31 +int tmpfile_delete(struct reftable_tmpfile *t)
32 +{
33 + struct tempfile *tempfile = t->priv;
34 + int ret = delete_tempfile(&tempfile);
35 + *t = REFTABLE_TMPFILE_INIT;
36 + if (ret < 0)
37 + return REFTABLE_IO_ERROR;
38 + return 0;
39 +}
40 +
41 +int tmpfile_rename(struct reftable_tmpfile *t, const char *path)
42 +{
43 + struct tempfile *tempfile = t->priv;
44 + int ret = rename_tempfile(&tempfile, path);
45 + *t = REFTABLE_TMPFILE_INIT;
46 + if (ret < 0)
47 + return REFTABLE_IO_ERROR;
48 + return 0;
49 +}
reftable/system.h
+41 -1
@@ -13,6 +13,46 @@ https://developers.google.com/open-source/licenses/bsd
13
14 #include "git-compat-util.h"
15 #include "lockfile.h"
16 -#include "tempfile.h"
16 +
17 +/*
18 + * An implementation-specific temporary file. By making this specific to the
19 + * implementation it becomes possible to tie temporary files into any kind of
20 + * signal or atexit handlers for cleanup on abnormal situations.
21 + */
22 +struct reftable_tmpfile {
23 + const char *path;
24 + int fd;
25 + void *priv;
26 +};
27 +#define REFTABLE_TMPFILE_INIT ((struct reftable_tmpfile) { .fd = -1, })
28 +
29 +/*
30 + * Create a temporary file from a pattern similar to how mkstemp(3p) would.
31 + * The `pattern` shall not be modified. On success, the structure at `out` has
32 + * been initialized such that it is ready for use. Returns 0 on success, a
33 + * reftable error code on error.
34 + */
35 +int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern);
36 +
37 +/*
38 + * Close the temporary file's file descriptor without removing the file itself.
39 + * This is a no-op in case the file has already been closed beforehand. Returns
40 + * 0 on success, a reftable error code on error.
41 + */
42 +int tmpfile_close(struct reftable_tmpfile *t);
43 +
44 +/*
45 + * Close the temporary file and delete it. This is a no-op in case the file has
46 + * already been deleted or renamed beforehand. Returns 0 on success, a reftable
47 + * error code on error.
48 + */
49 +int tmpfile_delete(struct reftable_tmpfile *t);
50 +
51 +/*
52 + * Rename the temporary file to the provided path. The temporary file must be
53 + * active. Return 0 on success, a reftable error code on error. Deactivates the
54 + * temporary file.
55 + */
56 +int tmpfile_rename(struct reftable_tmpfile *t, const char *path);
57
58 #endif