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