Git fork
at reftables-rust 132 lines 3.0 kB view raw
1#include "git-compat-util.h" 2#include "gettext.h" 3#include "pack-mtimes.h" 4#include "odb.h" 5#include "packfile.h" 6#include "strbuf.h" 7 8static char *pack_mtimes_filename(struct packed_git *p) 9{ 10 size_t len; 11 if (!strip_suffix(p->pack_name, ".pack", &len)) 12 BUG("pack_name does not end in .pack"); 13 return xstrfmt("%.*s.mtimes", (int)len, p->pack_name); 14} 15 16#define MTIMES_HEADER_SIZE (12) 17 18struct mtimes_header { 19 uint32_t signature; 20 uint32_t version; 21 uint32_t hash_id; 22}; 23 24static int load_pack_mtimes_file(char *mtimes_file, 25 uint32_t num_objects, 26 const uint32_t **data_p, size_t *len_p) 27{ 28 int fd, ret = 0; 29 struct stat st; 30 uint32_t *data = NULL; 31 size_t mtimes_size, expected_size; 32 struct mtimes_header header; 33 34 fd = git_open(mtimes_file); 35 36 if (fd < 0) { 37 ret = -1; 38 goto cleanup; 39 } 40 if (fstat(fd, &st)) { 41 ret = error_errno(_("failed to read %s"), mtimes_file); 42 goto cleanup; 43 } 44 45 mtimes_size = xsize_t(st.st_size); 46 47 if (mtimes_size < MTIMES_HEADER_SIZE) { 48 ret = error(_("mtimes file %s is too small"), mtimes_file); 49 goto cleanup; 50 } 51 52 data = xmmap(NULL, mtimes_size, PROT_READ, MAP_PRIVATE, fd, 0); 53 54 header.signature = ntohl(data[0]); 55 header.version = ntohl(data[1]); 56 header.hash_id = ntohl(data[2]); 57 58 if (header.signature != MTIMES_SIGNATURE) { 59 ret = error(_("mtimes file %s has unknown signature"), mtimes_file); 60 goto cleanup; 61 } 62 63 if (header.version != 1) { 64 ret = error(_("mtimes file %s has unsupported version %"PRIu32), 65 mtimes_file, header.version); 66 goto cleanup; 67 } 68 69 if (!(header.hash_id == 1 || header.hash_id == 2)) { 70 ret = error(_("mtimes file %s has unsupported hash id %"PRIu32), 71 mtimes_file, header.hash_id); 72 goto cleanup; 73 } 74 75 76 expected_size = MTIMES_HEADER_SIZE; 77 expected_size = st_add(expected_size, st_mult(sizeof(uint32_t), num_objects)); 78 expected_size = st_add(expected_size, 2 * (header.hash_id == 1 ? GIT_SHA1_RAWSZ : GIT_SHA256_RAWSZ)); 79 80 if (mtimes_size != expected_size) { 81 ret = error(_("mtimes file %s is corrupt"), mtimes_file); 82 goto cleanup; 83 } 84 85cleanup: 86 if (ret) { 87 if (data) 88 munmap(data, mtimes_size); 89 } else { 90 *len_p = mtimes_size; 91 *data_p = data; 92 } 93 94 if (fd >= 0) 95 close(fd); 96 return ret; 97} 98 99int load_pack_mtimes(struct packed_git *p) 100{ 101 char *mtimes_name = NULL; 102 int ret = 0; 103 104 if (!p->is_cruft) 105 return ret; /* not a cruft pack */ 106 if (p->mtimes_map) 107 return ret; /* already loaded */ 108 109 ret = open_pack_index(p); 110 if (ret < 0) 111 goto cleanup; 112 113 mtimes_name = pack_mtimes_filename(p); 114 ret = load_pack_mtimes_file(mtimes_name, 115 p->num_objects, 116 &p->mtimes_map, 117 &p->mtimes_size); 118cleanup: 119 free(mtimes_name); 120 return ret; 121} 122 123uint32_t nth_packed_mtime(struct packed_git *p, uint32_t pos) 124{ 125 if (!p->mtimes_map) 126 BUG("pack .mtimes file not loaded for %s", p->pack_name); 127 if (p->num_objects <= pos) 128 BUG("pack .mtimes out-of-bounds (%"PRIu32" vs %"PRIu32")", 129 pos, p->num_objects); 130 131 return get_be32(p->mtimes_map + pos + 3); 132}