Git fork
at reftables-rust 262 lines 6.9 kB view raw
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}