6 #include "object-store.h"
9 #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
10 #define MIDX_VERSION 1
11 #define MIDX_BYTE_FILE_VERSION 4
12 #define MIDX_BYTE_HASH_VERSION 5
13 #define MIDX_BYTE_NUM_CHUNKS 6
14 #define MIDX_BYTE_NUM_PACKS 8
15 #define MIDX_HASH_VERSION 1
16 #define MIDX_HEADER_SIZE 12
17 #define MIDX_HASH_LEN 20
18 #define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + MIDX_HASH_LEN)
20 static char *get_midx_filename(const char *object_dir
)
22 return xstrfmt("%s/pack/multi-pack-index", object_dir
);
25 struct multi_pack_index
*load_multi_pack_index(const char *object_dir
)
27 struct multi_pack_index
*m
= NULL
;
31 void *midx_map
= NULL
;
32 uint32_t hash_version
;
33 char *midx_name
= get_midx_filename(object_dir
);
35 fd
= git_open(midx_name
);
40 error_errno(_("failed to read %s"), midx_name
);
44 midx_size
= xsize_t(st
.st_size
);
46 if (midx_size
< MIDX_MIN_SIZE
) {
47 error(_("multi-pack-index file %s is too small"), midx_name
);
51 FREE_AND_NULL(midx_name
);
53 midx_map
= xmmap(NULL
, midx_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
55 FLEX_ALLOC_MEM(m
, object_dir
, object_dir
, strlen(object_dir
));
58 m
->data_len
= midx_size
;
60 m
->signature
= get_be32(m
->data
);
61 if (m
->signature
!= MIDX_SIGNATURE
) {
62 error(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"),
63 m
->signature
, MIDX_SIGNATURE
);
67 m
->version
= m
->data
[MIDX_BYTE_FILE_VERSION
];
68 if (m
->version
!= MIDX_VERSION
) {
69 error(_("multi-pack-index version %d not recognized"),
74 hash_version
= m
->data
[MIDX_BYTE_HASH_VERSION
];
75 if (hash_version
!= MIDX_HASH_VERSION
) {
76 error(_("hash version %u does not match"), hash_version
);
79 m
->hash_len
= MIDX_HASH_LEN
;
81 m
->num_chunks
= m
->data
[MIDX_BYTE_NUM_CHUNKS
];
83 m
->num_packs
= get_be32(m
->data
+ MIDX_BYTE_NUM_PACKS
);
91 munmap(midx_map
, midx_size
);
97 static size_t write_midx_header(struct hashfile
*f
,
98 unsigned char num_chunks
,
101 unsigned char byte_values
[4];
103 hashwrite_be32(f
, MIDX_SIGNATURE
);
104 byte_values
[0] = MIDX_VERSION
;
105 byte_values
[1] = MIDX_HASH_VERSION
;
106 byte_values
[2] = num_chunks
;
107 byte_values
[3] = 0; /* unused */
108 hashwrite(f
, byte_values
, sizeof(byte_values
));
109 hashwrite_be32(f
, num_packs
);
111 return MIDX_HEADER_SIZE
;
115 struct packed_git
**list
;
120 static void add_pack_to_midx(const char *full_path
, size_t full_path_len
,
121 const char *file_name
, void *data
)
123 struct pack_list
*packs
= (struct pack_list
*)data
;
125 if (ends_with(file_name
, ".idx")) {
126 ALLOC_GROW(packs
->list
, packs
->nr
+ 1, packs
->alloc_list
);
128 packs
->list
[packs
->nr
] = add_packed_git(full_path
,
131 if (!packs
->list
[packs
->nr
]) {
132 warning(_("failed to add packfile '%s'"),
141 int write_midx_file(const char *object_dir
)
143 unsigned char num_chunks
= 0;
146 struct hashfile
*f
= NULL
;
148 struct pack_list packs
;
150 midx_name
= get_midx_filename(object_dir
);
151 if (safe_create_leading_directories(midx_name
)) {
153 die_errno(_("unable to create leading directories of %s"),
158 packs
.alloc_list
= 16;
160 ALLOC_ARRAY(packs
.list
, packs
.alloc_list
);
162 for_each_file_in_pack_dir(object_dir
, add_pack_to_midx
, &packs
);
164 hold_lock_file_for_update(&lk
, midx_name
, LOCK_DIE_ON_ERROR
);
165 f
= hashfd(lk
.tempfile
->fd
, lk
.tempfile
->filename
.buf
);
166 FREE_AND_NULL(midx_name
);
168 write_midx_header(f
, num_chunks
, packs
.nr
);
170 finalize_hashfile(f
, NULL
, CSUM_FSYNC
| CSUM_HASH_IN_STREAM
);
171 commit_lock_file(&lk
);
173 for (i
= 0; i
< packs
.nr
; i
++) {
175 close_pack(packs
.list
[i
]);