Coverage Report

Created: 2026-05-08 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libgit2/deps/reftable/system.c
Line
Count
Source
1
#include "system.h"
2
#include "basics.h"
3
#include "rand.h"
4
#include "reftable-error.h"
5
6
uint32_t reftable_rand(void)
7
0
{
8
0
  return (uint32_t) git_rand_next();
9
0
}
10
11
int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern)
12
0
{
13
0
  git_str path = GIT_STR_INIT;
14
0
  unsigned tries = 32;
15
16
0
  if (git__suffixcmp(pattern, ".XXXXXX"))
17
0
    return REFTABLE_API_ERROR;
18
19
0
  while (tries--) {
20
0
    uint64_t rand = git_rand_next();
21
0
    int fd;
22
23
0
    git_str_sets(&path, pattern);
24
0
    git_str_shorten(&path, 6);
25
0
    git_str_encode_hexstr(&path, (void *)&rand, 6);
26
27
0
    if (git_str_oom(&path))
28
0
      return REFTABLE_OUT_OF_MEMORY_ERROR;
29
30
0
    if ((fd = p_open(path.ptr, O_CREAT | O_RDWR | O_EXCL | O_CLOEXEC, 0666)) < 0)
31
0
      continue;
32
33
0
    out->path = git_str_detach(&path);
34
0
    out->fd = fd;
35
0
    return 0;
36
0
  }
37
38
0
  git_str_dispose(&path);
39
0
  return REFTABLE_IO_ERROR;
40
0
}
41
42
int tmpfile_close(struct reftable_tmpfile *t)
43
0
{
44
0
  int ret;
45
46
0
  if (t->fd < 0)
47
0
    return 0;
48
0
  ret = close(t->fd);
49
0
  t->fd = -1;
50
51
0
  if (ret < 0)
52
0
    return REFTABLE_IO_ERROR;
53
0
  return 0;
54
0
}
55
56
int tmpfile_delete(struct reftable_tmpfile *t)
57
0
{
58
0
  int ret;
59
60
0
  if (!t->path)
61
0
    return 0;
62
63
0
  tmpfile_close(t);
64
0
  if ((ret = unlink(t->path)) < 0)
65
0
    return REFTABLE_IO_ERROR;
66
67
0
  reftable_free((char *) t->path);
68
0
  t->path = NULL;
69
70
0
  return 0;
71
0
}
72
73
int tmpfile_rename(struct reftable_tmpfile *t, const char *path)
74
0
{
75
0
  int ret;
76
77
0
  if (!t->path)
78
0
    return REFTABLE_API_ERROR;
79
80
0
  tmpfile_close(t);
81
82
0
  if ((ret = p_rename(t->path, path)) < 0)
83
0
    return REFTABLE_IO_ERROR;
84
85
0
  reftable_free((char *) t->path);
86
0
  t->path = NULL;
87
88
0
  return 0;
89
0
}
90
91
struct libgit2_flock {
92
  char *lock_path;
93
  char *target_path;
94
};
95
96
int flock_acquire(struct reftable_flock *l, const char *target_path,
97
      long timeout_ms)
98
0
{
99
0
  struct libgit2_flock *flock;
100
0
  unsigned multiplier = 1, n = 1;
101
0
  size_t lock_path_len;
102
0
  uint64_t deadline;
103
0
  int fd = -1, error;
104
105
0
  lock_path_len = strlen(target_path) + strlen(".lock") + 1;
106
0
  if ((flock = reftable_calloc(sizeof(*flock), 1)) == NULL ||
107
0
      (flock->target_path = reftable_strdup(target_path)) == NULL ||
108
0
      (flock->lock_path = reftable_malloc(lock_path_len)) == NULL) {
109
0
    error = REFTABLE_OUT_OF_MEMORY_ERROR;
110
0
    goto out;
111
0
  }
112
113
0
  snprintf(flock->lock_path, lock_path_len, "%s.lock", target_path);
114
115
0
  deadline = git_time_monotonic() + timeout_ms;
116
117
0
  while (1) {
118
0
    uint64_t now, wait_ms;
119
120
0
    if ((fd = p_open(flock->lock_path, O_WRONLY | O_EXCL | O_CREAT, 0666)) >= 0)
121
0
      break;
122
0
    if (errno != EEXIST) {
123
0
      error = REFTABLE_IO_ERROR;
124
0
      goto out;
125
0
    }
126
127
0
    now = git_time_monotonic();
128
0
    if (now > deadline) {
129
0
      error = REFTABLE_LOCK_ERROR;
130
0
      goto out;
131
0
    }
132
133
0
    wait_ms = (750 + rand() % 500) * multiplier / 1000;
134
0
    multiplier += 2 * n + 1;
135
136
0
    if (multiplier > 1000)
137
0
      multiplier = 1000;
138
0
    else
139
0
      n++;
140
141
0
    p_poll(NULL, 0, (int) wait_ms);
142
0
  }
143
144
0
  l->priv = flock;
145
0
  l->path = flock->lock_path;
146
0
  l->fd = fd;
147
148
0
  error = 0;
149
150
0
out:
151
0
  if (error) {
152
0
    if (flock) {
153
0
      reftable_free(flock->target_path);
154
0
      reftable_free(flock->lock_path);
155
0
    }
156
0
    reftable_free(flock);
157
0
  }
158
159
0
  return error;
160
0
}
161
162
int flock_close(struct reftable_flock *l)
163
0
{
164
0
  int ret;
165
166
0
  if (l->fd < 0)
167
0
    return 0;
168
169
0
  ret = p_close(l->fd);
170
0
  l->fd = -1;
171
172
0
  if (ret < 0)
173
0
    return REFTABLE_IO_ERROR;
174
0
  return 0;
175
0
}
176
177
static void libgit2_flock_release(struct reftable_flock *l)
178
0
{
179
0
  struct libgit2_flock *flock = l->priv;
180
0
  reftable_free(flock->lock_path);
181
0
  reftable_free(flock->target_path);
182
0
  reftable_free(flock);
183
0
  l->priv = NULL;
184
0
  l->path = NULL;
185
0
}
186
187
int flock_release(struct reftable_flock *l)
188
0
{
189
0
  struct libgit2_flock *flock = l->priv;
190
0
  int ret;
191
192
0
  if (!flock)
193
0
    return 0;
194
195
0
  flock_close(l);
196
197
0
  if ((ret = p_unlink(flock->lock_path)) < 0)
198
0
    goto out;
199
200
0
out:
201
0
  libgit2_flock_release(l);
202
0
  if (ret < 0)
203
0
    return REFTABLE_IO_ERROR;
204
0
  return 0;
205
0
}
206
207
int flock_commit(struct reftable_flock *l)
208
0
{
209
0
  struct libgit2_flock *flock = l->priv;
210
0
  int ret;
211
212
0
  flock_close(l);
213
214
0
  if (!flock)
215
0
    return REFTABLE_API_ERROR;
216
217
0
  if ((ret = p_rename(flock->lock_path, flock->target_path)) < 0)
218
0
    goto out;
219
220
0
out:
221
0
  libgit2_flock_release(l);
222
0
  if (ret < 0)
223
0
    return REFTABLE_IO_ERROR;
224
0
  return 0;
225
0
}
226
227
uint64_t reftable_time_ms(void)
228
0
{
229
0
  return git_time_monotonic();
230
0
}
231
232
int reftable_mmap(struct reftable_mmap *out, int fd, size_t len)
233
0
{
234
0
  git_map *mmap;
235
236
0
  mmap = git__malloc(sizeof(*mmap));
237
0
  if (!mmap)
238
0
    return REFTABLE_OUT_OF_MEMORY_ERROR;
239
240
0
  if (p_mmap(mmap, len, GIT_PROT_READ, GIT_MAP_PRIVATE, fd, 0) < 0)
241
0
    return REFTABLE_IO_ERROR;
242
243
0
  out->priv = mmap;
244
0
  out->data = mmap->data;
245
0
  out->size = mmap->len;
246
247
0
  return 0;
248
0
}
249
250
int reftable_munmap(struct reftable_mmap *mmap)
251
0
{
252
0
  git_map *map = mmap->priv;
253
254
0
  if (p_munmap(map) < 0)
255
0
    return REFTABLE_IO_ERROR;
256
0
  git__free(map);
257
0
  memset(mmap, 0, sizeof(*mmap));
258
0
  return 0;
259
0
}