Coverage Report

Created: 2024-09-08 06:23

/src/git/loose.c
Line
Count
Source (jump to first uncovered line)
1
#define USE_THE_REPOSITORY_VARIABLE
2
3
#include "git-compat-util.h"
4
#include "hash.h"
5
#include "path.h"
6
#include "object-store.h"
7
#include "hex.h"
8
#include "wrapper.h"
9
#include "gettext.h"
10
#include "loose.h"
11
#include "lockfile.h"
12
#include "oidtree.h"
13
14
static const char *loose_object_header = "# loose-object-idx\n";
15
16
static inline int should_use_loose_object_map(struct repository *repo)
17
0
{
18
0
  return repo->compat_hash_algo && repo->gitdir;
19
0
}
20
21
void loose_object_map_init(struct loose_object_map **map)
22
0
{
23
0
  struct loose_object_map *m;
24
0
  m = xmalloc(sizeof(**map));
25
0
  m->to_compat = kh_init_oid_map();
26
0
  m->to_storage = kh_init_oid_map();
27
0
  *map = m;
28
0
}
29
30
static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const struct object_id *value)
31
0
{
32
0
  khiter_t pos;
33
0
  int ret;
34
0
  struct object_id *stored;
35
36
0
  pos = kh_put_oid_map(map, *key, &ret);
37
38
  /* This item already exists in the map. */
39
0
  if (ret == 0)
40
0
    return 0;
41
42
0
  stored = xmalloc(sizeof(*stored));
43
0
  oidcpy(stored, value);
44
0
  kh_value(map, pos) = stored;
45
0
  return 1;
46
0
}
47
48
static int insert_loose_map(struct object_directory *odb,
49
          const struct object_id *oid,
50
          const struct object_id *compat_oid)
51
0
{
52
0
  struct loose_object_map *map = odb->loose_map;
53
0
  int inserted = 0;
54
55
0
  inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
56
0
  inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
57
0
  if (inserted)
58
0
    oidtree_insert(odb->loose_objects_cache, compat_oid);
59
60
0
  return inserted;
61
0
}
62
63
static int load_one_loose_object_map(struct repository *repo, struct object_directory *dir)
64
0
{
65
0
  struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
66
0
  FILE *fp;
67
68
0
  if (!dir->loose_map)
69
0
    loose_object_map_init(&dir->loose_map);
70
0
  if (!dir->loose_objects_cache) {
71
0
    ALLOC_ARRAY(dir->loose_objects_cache, 1);
72
0
    oidtree_init(dir->loose_objects_cache);
73
0
  }
74
75
0
  insert_loose_map(dir, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
76
0
  insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
77
0
  insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
78
79
0
  strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
80
0
  fp = fopen(path.buf, "rb");
81
0
  if (!fp) {
82
0
    strbuf_release(&path);
83
0
    return 0;
84
0
  }
85
86
0
  errno = 0;
87
0
  if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header))
88
0
    goto err;
89
0
  while (!strbuf_getline_lf(&buf, fp)) {
90
0
    const char *p;
91
0
    struct object_id oid, compat_oid;
92
0
    if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) ||
93
0
        *p++ != ' ' ||
94
0
        parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) ||
95
0
        p != buf.buf + buf.len)
96
0
      goto err;
97
0
    insert_loose_map(dir, &oid, &compat_oid);
98
0
  }
99
100
0
  strbuf_release(&buf);
101
0
  strbuf_release(&path);
102
0
  return errno ? -1 : 0;
103
0
err:
104
0
  strbuf_release(&buf);
105
0
  strbuf_release(&path);
106
0
  return -1;
107
0
}
108
109
int repo_read_loose_object_map(struct repository *repo)
110
0
{
111
0
  struct object_directory *dir;
112
113
0
  if (!should_use_loose_object_map(repo))
114
0
    return 0;
115
116
0
  prepare_alt_odb(repo);
117
118
0
  for (dir = repo->objects->odb; dir; dir = dir->next) {
119
0
    if (load_one_loose_object_map(repo, dir) < 0) {
120
0
      return -1;
121
0
    }
122
0
  }
123
0
  return 0;
124
0
}
125
126
int repo_write_loose_object_map(struct repository *repo)
127
0
{
128
0
  kh_oid_map_t *map = repo->objects->odb->loose_map->to_compat;
129
0
  struct lock_file lock;
130
0
  int fd;
131
0
  khiter_t iter;
132
0
  struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
133
134
0
  if (!should_use_loose_object_map(repo))
135
0
    return 0;
136
137
0
  strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
138
0
  fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
139
0
  iter = kh_begin(map);
140
0
  if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
141
0
    goto errout;
142
143
0
  for (; iter != kh_end(map); iter++) {
144
0
    if (kh_exist(map, iter)) {
145
0
      if (oideq(&kh_key(map, iter), the_hash_algo->empty_tree) ||
146
0
          oideq(&kh_key(map, iter), the_hash_algo->empty_blob))
147
0
        continue;
148
0
      strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
149
0
      if (write_in_full(fd, buf.buf, buf.len) < 0)
150
0
        goto errout;
151
0
      strbuf_reset(&buf);
152
0
    }
153
0
  }
154
0
  strbuf_release(&buf);
155
0
  if (commit_lock_file(&lock) < 0) {
156
0
    error_errno(_("could not write loose object index %s"), path.buf);
157
0
    strbuf_release(&path);
158
0
    return -1;
159
0
  }
160
0
  strbuf_release(&path);
161
0
  return 0;
162
0
errout:
163
0
  rollback_lock_file(&lock);
164
0
  strbuf_release(&buf);
165
0
  error_errno(_("failed to write loose object index %s"), path.buf);
166
0
  strbuf_release(&path);
167
0
  return -1;
168
0
}
169
170
static int write_one_object(struct repository *repo, const struct object_id *oid,
171
          const struct object_id *compat_oid)
172
0
{
173
0
  struct lock_file lock;
174
0
  int fd;
175
0
  struct stat st;
176
0
  struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
177
178
0
  strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
179
0
  hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
180
181
0
  fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
182
0
  if (fd < 0)
183
0
    goto errout;
184
0
  if (fstat(fd, &st) < 0)
185
0
    goto errout;
186
0
  if (!st.st_size && write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
187
0
    goto errout;
188
189
0
  strbuf_addf(&buf, "%s %s\n", oid_to_hex(oid), oid_to_hex(compat_oid));
190
0
  if (write_in_full(fd, buf.buf, buf.len) < 0)
191
0
    goto errout;
192
0
  if (close(fd))
193
0
    goto errout;
194
0
  adjust_shared_perm(path.buf);
195
0
  rollback_lock_file(&lock);
196
0
  strbuf_release(&buf);
197
0
  strbuf_release(&path);
198
0
  return 0;
199
0
errout:
200
0
  error_errno(_("failed to write loose object index %s"), path.buf);
201
0
  close(fd);
202
0
  rollback_lock_file(&lock);
203
0
  strbuf_release(&buf);
204
0
  strbuf_release(&path);
205
0
  return -1;
206
0
}
207
208
int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
209
            const struct object_id *compat_oid)
210
0
{
211
0
  int inserted = 0;
212
213
0
  if (!should_use_loose_object_map(repo))
214
0
    return 0;
215
216
0
  inserted = insert_loose_map(repo->objects->odb, oid, compat_oid);
217
0
  if (inserted)
218
0
    return write_one_object(repo, oid, compat_oid);
219
0
  return 0;
220
0
}
221
222
int repo_loose_object_map_oid(struct repository *repo,
223
            const struct object_id *src,
224
            const struct git_hash_algo *to,
225
            struct object_id *dest)
226
0
{
227
0
  struct object_directory *dir;
228
0
  kh_oid_map_t *map;
229
0
  khiter_t pos;
230
231
0
  for (dir = repo->objects->odb; dir; dir = dir->next) {
232
0
    struct loose_object_map *loose_map = dir->loose_map;
233
0
    if (!loose_map)
234
0
      continue;
235
0
    map = (to == repo->compat_hash_algo) ?
236
0
      loose_map->to_compat :
237
0
      loose_map->to_storage;
238
0
    pos = kh_get_oid_map(map, *src);
239
0
    if (pos < kh_end(map)) {
240
0
      oidcpy(dest, kh_value(map, pos));
241
0
      return 0;
242
0
    }
243
0
  }
244
0
  return -1;
245
0
}
246
247
void loose_object_map_clear(struct loose_object_map **map)
248
0
{
249
0
  struct loose_object_map *m = *map;
250
0
  struct object_id *oid;
251
252
0
  if (!m)
253
0
    return;
254
255
0
  kh_foreach_value(m->to_compat, oid, free(oid));
256
0
  kh_foreach_value(m->to_storage, oid, free(oid));
257
0
  kh_destroy_oid_map(m->to_compat);
258
0
  kh_destroy_oid_map(m->to_storage);
259
0
  free(m);
260
0
  *map = NULL;
261
0
}