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