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