builtin/cat-file: mark 'git cat-file' sparse-index compatible
[git/gitster.git] / loose.c
bloba8bf772172da01d3cc31f76f4aec859d8295c730
1 #define USE_THE_REPOSITORY_VARIABLE
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"
14 static const char *loose_object_header = "# loose-object-idx\n";
16 static inline int should_use_loose_object_map(struct repository *repo)
18 return repo->compat_hash_algo && repo->gitdir;
21 void loose_object_map_init(struct loose_object_map **map)
23 struct loose_object_map *m;
24 m = xmalloc(sizeof(**map));
25 m->to_compat = kh_init_oid_map();
26 m->to_storage = kh_init_oid_map();
27 *map = m;
30 static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const struct object_id *value)
32 khiter_t pos;
33 int ret;
34 struct object_id *stored;
36 pos = kh_put_oid_map(map, *key, &ret);
38 /* This item already exists in the map. */
39 if (ret == 0)
40 return 0;
42 stored = xmalloc(sizeof(*stored));
43 oidcpy(stored, value);
44 kh_value(map, pos) = stored;
45 return 1;
48 static int insert_loose_map(struct object_directory *odb,
49 const struct object_id *oid,
50 const struct object_id *compat_oid)
52 struct loose_object_map *map = odb->loose_map;
53 int inserted = 0;
55 inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
56 inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
57 if (inserted)
58 oidtree_insert(odb->loose_objects_cache, compat_oid);
60 return inserted;
63 static int load_one_loose_object_map(struct repository *repo, struct object_directory *dir)
65 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
66 FILE *fp;
68 if (!dir->loose_map)
69 loose_object_map_init(&dir->loose_map);
70 if (!dir->loose_objects_cache) {
71 ALLOC_ARRAY(dir->loose_objects_cache, 1);
72 oidtree_init(dir->loose_objects_cache);
75 insert_loose_map(dir, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
76 insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
77 insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
79 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
80 fp = fopen(path.buf, "rb");
81 if (!fp) {
82 strbuf_release(&path);
83 return 0;
86 errno = 0;
87 if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header))
88 goto err;
89 while (!strbuf_getline_lf(&buf, fp)) {
90 const char *p;
91 struct object_id oid, compat_oid;
92 if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) ||
93 *p++ != ' ' ||
94 parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) ||
95 p != buf.buf + buf.len)
96 goto err;
97 insert_loose_map(dir, &oid, &compat_oid);
100 strbuf_release(&buf);
101 strbuf_release(&path);
102 return errno ? -1 : 0;
103 err:
104 strbuf_release(&buf);
105 strbuf_release(&path);
106 return -1;
109 int repo_read_loose_object_map(struct repository *repo)
111 struct object_directory *dir;
113 if (!should_use_loose_object_map(repo))
114 return 0;
116 prepare_alt_odb(repo);
118 for (dir = repo->objects->odb; dir; dir = dir->next) {
119 if (load_one_loose_object_map(repo, dir) < 0) {
120 return -1;
123 return 0;
126 int repo_write_loose_object_map(struct repository *repo)
128 kh_oid_map_t *map = repo->objects->odb->loose_map->to_compat;
129 struct lock_file lock;
130 int fd;
131 khiter_t iter;
132 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
134 if (!should_use_loose_object_map(repo))
135 return 0;
137 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
138 fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
139 iter = kh_begin(map);
140 if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
141 goto errout;
143 for (; iter != kh_end(map); iter++) {
144 if (kh_exist(map, iter)) {
145 if (oideq(&kh_key(map, iter), the_hash_algo->empty_tree) ||
146 oideq(&kh_key(map, iter), the_hash_algo->empty_blob))
147 continue;
148 strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
149 if (write_in_full(fd, buf.buf, buf.len) < 0)
150 goto errout;
151 strbuf_reset(&buf);
154 strbuf_release(&buf);
155 if (commit_lock_file(&lock) < 0) {
156 error_errno(_("could not write loose object index %s"), path.buf);
157 strbuf_release(&path);
158 return -1;
160 strbuf_release(&path);
161 return 0;
162 errout:
163 rollback_lock_file(&lock);
164 strbuf_release(&buf);
165 error_errno(_("failed to write loose object index %s\n"), path.buf);
166 strbuf_release(&path);
167 return -1;
170 static int write_one_object(struct repository *repo, const struct object_id *oid,
171 const struct object_id *compat_oid)
173 struct lock_file lock;
174 int fd;
175 struct stat st;
176 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
178 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
179 hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
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;
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(path.buf);
195 rollback_lock_file(&lock);
196 strbuf_release(&buf);
197 strbuf_release(&path);
198 return 0;
199 errout:
200 error_errno(_("failed to write loose object index %s\n"), path.buf);
201 close(fd);
202 rollback_lock_file(&lock);
203 strbuf_release(&buf);
204 strbuf_release(&path);
205 return -1;
208 int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
209 const struct object_id *compat_oid)
211 int inserted = 0;
213 if (!should_use_loose_object_map(repo))
214 return 0;
216 inserted = insert_loose_map(repo->objects->odb, oid, compat_oid);
217 if (inserted)
218 return write_one_object(repo, oid, compat_oid);
219 return 0;
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)
227 struct object_directory *dir;
228 kh_oid_map_t *map;
229 khiter_t pos;
231 for (dir = repo->objects->odb; dir; dir = dir->next) {
232 struct loose_object_map *loose_map = dir->loose_map;
233 if (!loose_map)
234 continue;
235 map = (to == repo->compat_hash_algo) ?
236 loose_map->to_compat :
237 loose_map->to_storage;
238 pos = kh_get_oid_map(map, *src);
239 if (pos < kh_end(map)) {
240 oidcpy(dest, kh_value(map, pos));
241 return 0;
244 return -1;
247 void loose_object_map_clear(struct loose_object_map **map)
249 struct loose_object_map *m = *map;
250 struct object_id *oid;
252 if (!m)
253 return;
255 kh_foreach_value(m->to_compat, oid, free(oid));
256 kh_foreach_value(m->to_storage, oid, free(oid));
257 kh_destroy_oid_map(m->to_compat);
258 kh_destroy_oid_map(m->to_storage);
259 free(m);
260 *map = NULL;