summaryrefslogtreecommitdiff
path: root/packfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'packfile.c')
-rw-r--r--packfile.c145
1 files changed, 85 insertions, 60 deletions
diff --git a/packfile.c b/packfile.c
index 89402cf..d4df7fd 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "list.h"
#include "pack.h"
#include "repository.h"
@@ -6,16 +9,18 @@
#include "mergesort.h"
#include "packfile.h"
#include "delta.h"
-#include "streaming.h"
#include "hash-lookup.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
+#include "trace.h"
#include "tree-walk.h"
#include "tree.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "midx.h"
#include "commit-graph.h"
+#include "pack-revindex.h"
#include "promisor-remote.h"
char *odb_pack_name(struct strbuf *buf,
@@ -116,7 +121,7 @@ int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
if (idx_size < 4 * 256 + hashsz + hashsz)
return error("index file %s is too small", path);
- if (idx_map == NULL)
+ if (!idx_map)
return error("empty data");
if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
@@ -178,7 +183,7 @@ int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
*/
(sizeof(off_t) <= 4))
return error("pack too large for current definition of off_t in %s", path);
- p->crc_offset = 8 + 4 * 256 + nr * hashsz;
+ p->crc_offset = st_add(8 + 4 * 256, st_mult(nr, hashsz));
}
p->index_version = version;
@@ -324,7 +329,8 @@ void close_pack_index(struct packed_git *p)
}
}
-void close_pack_revindex(struct packed_git *p) {
+static void close_pack_revindex(struct packed_git *p)
+{
if (!p->revindex_map)
return;
@@ -333,12 +339,22 @@ void close_pack_revindex(struct packed_git *p) {
p->revindex_data = NULL;
}
+static void close_pack_mtimes(struct packed_git *p)
+{
+ if (!p->mtimes_map)
+ return;
+
+ munmap((void *)p->mtimes_map, p->mtimes_size);
+ p->mtimes_map = NULL;
+}
+
void close_pack(struct packed_git *p)
{
close_pack_windows(p);
close_pack_fd(p);
close_pack_index(p);
close_pack_revindex(p);
+ close_pack_mtimes(p);
oidset_clear(&p->bad_objects);
}
@@ -362,7 +378,7 @@ void close_object_store(struct raw_object_store *o)
void unlink_pack_path(const char *pack_name, int force_delete)
{
- static const char *exts[] = {".pack", ".idx", ".rev", ".keep", ".bitmap", ".promisor"};
+ static const char *exts[] = {".idx", ".pack", ".rev", ".keep", ".bitmap", ".promisor", ".mtimes"};
int i;
struct strbuf buf = STRBUF_INIT;
size_t plen;
@@ -717,6 +733,10 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
if (!access(p->pack_name, F_OK))
p->pack_promisor = 1;
+ xsnprintf(p->pack_name + path_len, alloc - path_len, ".mtimes");
+ if (!access(p->pack_name, F_OK))
+ p->is_cruft = 1;
+
xsnprintf(p->pack_name + path_len, alloc - path_len, ".pack");
if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
free(p);
@@ -730,7 +750,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
p->pack_local = local;
p->mtime = st.st_mtime;
if (path_len < the_hash_algo->hexsz ||
- get_sha1_hex(path + path_len - the_hash_algo->hexsz, p->hash))
+ get_hash_hex(path + path_len - the_hash_algo->hexsz, p->hash))
hashclr(p->hash);
return p;
}
@@ -868,7 +888,8 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
ends_with(file_name, ".pack") ||
ends_with(file_name, ".bitmap") ||
ends_with(file_name, ".keep") ||
- ends_with(file_name, ".promisor"))
+ ends_with(file_name, ".promisor") ||
+ ends_with(file_name, ".mtimes"))
string_list_append(data->garbage, full_name);
else
report_garbage(PACKDIR_FILE_GARBAGE, full_name);
@@ -925,20 +946,10 @@ unsigned long repo_approximate_object_count(struct repository *r)
return r->objects->approximate_object_count;
}
-static void *get_next_packed_git(const void *p)
-{
- return ((const struct packed_git *)p)->next;
-}
-
-static void set_next_packed_git(void *p, void *next)
-{
- ((struct packed_git *)p)->next = next;
-}
+DEFINE_LIST_SORT(static, sort_packs, struct packed_git, next);
-static int sort_pack(const void *a_, const void *b_)
+static int sort_pack(const struct packed_git *a, const struct packed_git *b)
{
- const struct packed_git *a = a_;
- const struct packed_git *b = b_;
int st;
/*
@@ -965,9 +976,7 @@ static int sort_pack(const void *a_, const void *b_)
static void rearrange_packed_git(struct repository *r)
{
- r->objects->packed_git = llist_mergesort(
- r->objects->packed_git, get_next_packed_git,
- set_next_packed_git, sort_pack);
+ sort_packs(&r->objects->packed_git, sort_pack);
}
static void prepare_packed_git_mru(struct repository *r)
@@ -1004,6 +1013,16 @@ void reprepare_packed_git(struct repository *r)
struct object_directory *odb;
obj_read_lock();
+
+ /*
+ * Reprepare alt odbs, in case the alternates file was modified
+ * during the course of this process. This only _adds_ odbs to
+ * the linked list, so existing odbs will continue to exist for
+ * the lifetime of the process.
+ */
+ r->objects->loaded_alternates = 0;
+ prepare_alt_odb(r);
+
for (odb = r->objects->odb; odb; odb = odb->next)
odb_clear_loose_cache(odb);
@@ -1060,7 +1079,7 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
unsigned long len, enum object_type *type, unsigned long *sizep)
{
unsigned shift;
- unsigned long size, c;
+ size_t size, c;
unsigned long used = 0;
c = buf[used++];
@@ -1068,16 +1087,16 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
size = c & 15;
shift = 4;
while (c & 0x80) {
- if (len <= used || bitsizeof(long) <= shift) {
+ if (len <= used || (bitsizeof(long) - 7) < shift) {
error("bad object header");
size = used = 0;
break;
}
c = buf[used++];
- size += (c & 0x7f) << shift;
+ size = st_add(size, st_left_shift(c & 0x7f, shift));
shift += 7;
}
- *sizep = size;
+ *sizep = cast_size_t_to_ulong(size);
return used;
}
@@ -1388,7 +1407,7 @@ static int delta_base_cache_key_eq(const struct delta_base_cache_key *a,
return a->p == b->p && a->base_offset == b->base_offset;
}
-static int delta_base_cache_hash_cmp(const void *unused_cmp_data,
+static int delta_base_cache_hash_cmp(const void *cmp_data UNUSED,
const struct hashmap_entry *va,
const struct hashmap_entry *vb,
const void *vkey)
@@ -1646,22 +1665,6 @@ struct unpack_entry_stack_ent {
unsigned long size;
};
-static void *read_object(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size)
-{
- struct object_info oi = OBJECT_INFO_INIT;
- void *content;
- oi.typep = type;
- oi.sizep = size;
- oi.contentp = &content;
-
- if (oid_object_info_extended(r, oid, &oi, 0) < 0)
- return NULL;
- return content;
-}
-
void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
enum object_type *final_type, unsigned long *final_size)
{
@@ -1794,6 +1797,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
uint32_t pos;
struct object_id base_oid;
if (!(offset_to_pack_pos(p, obj_offset, &pos))) {
+ struct object_info oi = OBJECT_INFO_INIT;
+
nth_packed_object_id(&base_oid, p,
pack_pos_to_index(p, pos));
error("failed to read delta base object %s"
@@ -1801,7 +1806,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
oid_to_hex(&base_oid), (uintmax_t)obj_offset,
p->pack_name);
mark_bad_packed_object(p, &base_oid);
- base = read_object(r, &base_oid, &type, &base_size);
+
+ oi.typep = &type;
+ oi.sizep = &base_size;
+ oi.contentp = &base;
+ if (oid_object_info_extended(r, &base_oid, &oi, 0) < 0)
+ base = NULL;
+
external_base = base;
}
}
@@ -1906,10 +1917,10 @@ int nth_packed_object_id(struct object_id *oid,
return -1;
index += 4 * 256;
if (p->index_version == 1) {
- oidread(oid, index + (hashsz + 4) * n + 4);
+ oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4));
} else {
index += 8;
- oidread(oid, index + hashsz * n);
+ oidread(oid, index + st_mult(hashsz, n));
}
return 0;
}
@@ -1934,14 +1945,15 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
const unsigned int hashsz = the_hash_algo->rawsz;
index += 4 * 256;
if (p->index_version == 1) {
- return ntohl(*((uint32_t *)(index + (hashsz + 4) * (size_t)n)));
+ return ntohl(*((uint32_t *)(index + st_mult(hashsz + 4, n))));
} else {
uint32_t off;
- index += 8 + (size_t)p->num_objects * (hashsz + 4);
- off = ntohl(*((uint32_t *)(index + 4 * n)));
+ index += st_add(8, st_mult(p->num_objects, hashsz + 4));
+ off = ntohl(*((uint32_t *)(index + st_mult(4, n))));
if (!(off & 0x80000000))
return off;
- index += (size_t)p->num_objects * 4 + (off & 0x7fffffff) * 8;
+ index += st_add(st_mult(p->num_objects, 4),
+ st_mult(off & 0x7fffffff, 8));
check_pack_index_ptr(p, index);
return get_be64(index);
}
@@ -2140,7 +2152,7 @@ int for_each_object_in_pack(struct packed_git *p,
int r = 0;
if (flags & FOR_EACH_OBJECT_PACK_ORDER) {
- if (load_pack_revindex(p))
+ if (load_pack_revindex(the_repository, p))
return -1;
}
@@ -2208,12 +2220,22 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
}
static int add_promisor_object(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
void *set_)
{
struct oidset *set = set_;
- struct object *obj = parse_object(the_repository, oid);
+ struct object *obj;
+ int we_parsed_object;
+
+ obj = lookup_object(the_repository, oid);
+ if (obj && obj->parsed) {
+ we_parsed_object = 0;
+ } else {
+ we_parsed_object = 1;
+ obj = parse_object(the_repository, oid);
+ }
+
if (!obj)
return 1;
@@ -2227,7 +2249,8 @@ static int add_promisor_object(const struct object_id *oid,
struct tree *tree = (struct tree *)obj;
struct tree_desc desc;
struct name_entry entry;
- if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
+ if (init_tree_desc_gently(&desc, &tree->object.oid,
+ tree->buffer, tree->size, 0))
/*
* Error messages are given when packs are
* verified, so do not print any here.
@@ -2235,7 +2258,8 @@ static int add_promisor_object(const struct object_id *oid,
return 0;
while (tree_entry_gently(&desc, &entry))
oidset_insert(set, &entry.oid);
- free_tree_buffer(tree);
+ if (we_parsed_object)
+ free_tree_buffer(tree);
} else if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
struct commit_list *parents = commit->parents;
@@ -2256,10 +2280,11 @@ int is_promisor_object(const struct object_id *oid)
static int promisor_objects_prepared;
if (!promisor_objects_prepared) {
- if (has_promisor_remote()) {
+ if (repo_has_promisor_remote(the_repository)) {
for_each_packed_object(add_promisor_object,
&promisor_objects,
- FOR_EACH_OBJECT_PROMISOR_ONLY);
+ FOR_EACH_OBJECT_PROMISOR_ONLY |
+ FOR_EACH_OBJECT_PACK_ORDER);
}
promisor_objects_prepared = 1;
}