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