diff options
author | Junio C Hamano <gitster@pobox.com> | 2017-08-26 22:55:09 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2017-08-26 22:55:09 -0700 |
commit | eabdcd4ab4b04af8f39e5ea3847b6d364acb874e (patch) | |
tree | 5f1a61054780d035391325b511e149e7397f6049 | |
parent | Merge branch 'mh/ref-lock-entry' (diff) | |
parent | pack: move for_each_packed_object() (diff) | |
download | tgif-eabdcd4ab4b04af8f39e5ea3847b6d364acb874e.tar.xz |
Merge branch 'jt/packmigrate'
Code movement to make it easier to hack later.
* jt/packmigrate: (23 commits)
pack: move for_each_packed_object()
pack: move has_pack_index()
pack: move has_sha1_pack()
pack: move find_pack_entry() and make it global
pack: move find_sha1_pack()
pack: move find_pack_entry_one(), is_pack_valid()
pack: move check_pack_index_ptr(), nth_packed_object_offset()
pack: move nth_packed_object_{sha1,oid}
pack: move clear_delta_base_cache(), packed_object_info(), unpack_entry()
pack: move unpack_object_header()
pack: move get_size_from_delta()
pack: move unpack_object_header_buffer()
pack: move {,re}prepare_packed_git and approximate_object_count
pack: move install_packed_git()
pack: move add_packed_git()
pack: move unuse_pack()
pack: move use_pack()
pack: move pack-closing functions
pack: move release_pack_memory()
pack: move open_pack_index(), parse_pack_index()
...
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | builtin/am.c | 1 | ||||
-rw-r--r-- | builtin/cat-file.c | 1 | ||||
-rw-r--r-- | builtin/clone.c | 1 | ||||
-rw-r--r-- | builtin/count-objects.c | 1 | ||||
-rw-r--r-- | builtin/fetch.c | 1 | ||||
-rw-r--r-- | builtin/fsck.c | 1 | ||||
-rw-r--r-- | builtin/gc.c | 1 | ||||
-rw-r--r-- | builtin/index-pack.c | 1 | ||||
-rw-r--r-- | builtin/merge.c | 1 | ||||
-rw-r--r-- | builtin/pack-objects.c | 1 | ||||
-rw-r--r-- | builtin/pack-redundant.c | 1 | ||||
-rw-r--r-- | builtin/prune-packed.c | 1 | ||||
-rw-r--r-- | builtin/receive-pack.c | 1 | ||||
-rw-r--r-- | bulk-checkin.c | 1 | ||||
-rw-r--r-- | cache.h | 122 | ||||
-rw-r--r-- | connected.c | 1 | ||||
-rw-r--r-- | diff.c | 1 | ||||
-rw-r--r-- | fast-import.c | 1 | ||||
-rw-r--r-- | fetch-pack.c | 1 | ||||
-rw-r--r-- | git-compat-util.h | 2 | ||||
-rw-r--r-- | http-backend.c | 1 | ||||
-rw-r--r-- | http-push.c | 1 | ||||
-rw-r--r-- | http-walker.c | 1 | ||||
-rw-r--r-- | http.c | 1 | ||||
-rw-r--r-- | outgoing/packfile.h | 0 | ||||
-rw-r--r-- | pack-bitmap.c | 1 | ||||
-rw-r--r-- | pack-check.c | 1 | ||||
-rw-r--r-- | packfile.c | 1896 | ||||
-rw-r--r-- | packfile.h | 138 | ||||
-rw-r--r-- | path.c | 1 | ||||
-rw-r--r-- | reachable.c | 1 | ||||
-rw-r--r-- | revision.c | 1 | ||||
-rw-r--r-- | server-info.c | 1 | ||||
-rw-r--r-- | sha1_file.c | 1906 | ||||
-rw-r--r-- | sha1_name.c | 1 | ||||
-rw-r--r-- | streaming.c | 1 |
37 files changed, 2081 insertions, 2014 deletions
@@ -817,6 +817,7 @@ LIB_OBJS += notes-merge.o LIB_OBJS += notes-utils.o LIB_OBJS += object.o LIB_OBJS += oidset.o +LIB_OBJS += packfile.o LIB_OBJS += pack-bitmap.o LIB_OBJS += pack-bitmap-write.o LIB_OBJS += pack-check.o diff --git a/builtin/am.c b/builtin/am.c index 81095dae02..c369dd1dce 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -31,6 +31,7 @@ #include "mailinfo.h" #include "apply.h" #include "string-list.h" +#include "packfile.h" /** * Returns 1 if the file is empty or does not exist, 0 otherwise. diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 62c8cf0ebf..4ccbfaac31 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -12,6 +12,7 @@ #include "streaming.h" #include "tree-walk.h" #include "sha1-array.h" +#include "packfile.h" struct batch_options { int enabled; diff --git a/builtin/clone.c b/builtin/clone.c index f7e17d2295..8d11b570a1 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -25,6 +25,7 @@ #include "remote.h" #include "run-command.h" #include "connected.h" +#include "packfile.h" /* * Overall FIXMEs: diff --git a/builtin/count-objects.c b/builtin/count-objects.c index 1d82e61f2a..33343818c8 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -10,6 +10,7 @@ #include "builtin.h" #include "parse-options.h" #include "quote.h" +#include "packfile.h" static unsigned long garbage; static off_t size_garbage; diff --git a/builtin/fetch.c b/builtin/fetch.c index 132e3224ed..225c734924 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -17,6 +17,7 @@ #include "connected.h" #include "argv-array.h" #include "utf8.h" +#include "packfile.h" static const char * const builtin_fetch_usage[] = { N_("git fetch [<options>] [<repository> [<refspec>...]]"), diff --git a/builtin/fsck.c b/builtin/fsck.c index 0ab13848a4..1e4c471b41 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -15,6 +15,7 @@ #include "progress.h" #include "streaming.h" #include "decorate.h" +#include "packfile.h" #define REACHABLE 0x0001 #define SEEN 0x0002 diff --git a/builtin/gc.c b/builtin/gc.c index e6b84475ae..3c78fcb9b1 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -19,6 +19,7 @@ #include "sigchain.h" #include "argv-array.h" #include "commit.h" +#include "packfile.h" #define FAILED_RUN "failed to run %s" diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 26828c1d82..f2be145e12 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -12,6 +12,7 @@ #include "exec_cmd.h" #include "streaming.h" #include "thread-utils.h" +#include "packfile.h" static const char index_pack_usage[] = "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])"; diff --git a/builtin/merge.c b/builtin/merge.c index cc57052993..7b7320dede 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -32,6 +32,7 @@ #include "gpg-interface.h" #include "sequencer.h" #include "string-list.h" +#include "packfile.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index c753e9237a..82ad6e0c81 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -25,6 +25,7 @@ #include "sha1-array.h" #include "argv-array.h" #include "mru.h" +#include "packfile.h" static const char *pack_usage[] = { N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"), diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index cb1df1c761..aaa8136322 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "builtin.h" +#include "packfile.h" #define BLKSIZE 512 diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c index 8f41f7c20e..419238171d 100644 --- a/builtin/prune-packed.c +++ b/builtin/prune-packed.c @@ -2,6 +2,7 @@ #include "cache.h" #include "progress.h" #include "parse-options.h" +#include "packfile.h" static const char * const prune_packed_usage[] = { N_("git prune-packed [-n | --dry-run] [-q | --quiet]"), diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 14b6e09b42..52c63ebfdc 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -23,6 +23,7 @@ #include "fsck.h" #include "tmp-objdir.h" #include "oidset.h" +#include "packfile.h" static const char * const receive_pack_usage[] = { N_("git receive-pack <git-dir>"), diff --git a/bulk-checkin.c b/bulk-checkin.c index 5be7ce5c73..9a1f6c49ab 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -6,6 +6,7 @@ #include "csum-file.h" #include "pack.h" #include "strbuf.h" +#include "packfile.h" static struct bulk_checkin_state { unsigned plugged:1; @@ -903,20 +903,6 @@ extern void check_repository_format(void); extern const char *sha1_file_name(const unsigned char *sha1); /* - * Return the name of the (local) packfile with the specified sha1 in - * its name. The return value is a pointer to memory that is - * overwritten each time this function is called. - */ -extern char *sha1_pack_name(const unsigned char *sha1); - -/* - * Return the name of the (local) pack index file with the specified - * sha1 in its name. The return value is a pointer to memory that is - * overwritten each time this function is called. - */ -extern char *sha1_pack_index_name(const unsigned char *sha1); - -/* * Return an abbreviated sha1 unique within this repository's object database. * The result will be at least `len` characters long, and will be NUL * terminated. @@ -1201,15 +1187,10 @@ extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size); extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz); extern int parse_sha1_header(const char *hdr, unsigned long *sizep); -/* global flag to enable extra checks when accessing packed objects */ -extern int do_check_packed_object_crc; - extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type); extern int finalize_object_file(const char *tmpfile, const char *filename); -extern int has_sha1_pack(const unsigned char *sha1); - /* * Open the loose object at path, check its sha1, and return the contents, * type, and size. If the object is a blob, then "contents" may return NULL, @@ -1245,8 +1226,6 @@ extern int has_object_file_with_flags(const struct object_id *oid, int flags); */ extern int has_loose_object_nonlocal(const unsigned char *sha1); -extern int has_pack_index(const unsigned char *sha1); - extern void assert_sha1_type(const unsigned char *sha1, enum object_type expect); /* Helper to check and "touch" a file */ @@ -1619,29 +1598,6 @@ struct pack_entry { struct packed_git *p; }; -extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path); - -/* A hook to report invalid files in pack directory */ -#define PACKDIR_FILE_PACK 1 -#define PACKDIR_FILE_IDX 2 -#define PACKDIR_FILE_GARBAGE 4 -extern void (*report_garbage)(unsigned seen_bits, const char *path); - -extern void prepare_packed_git(void); -extern void reprepare_packed_git(void); -extern void install_packed_git(struct packed_git *pack); - -/* - * Give a rough count of objects in the repository. This sacrifices accuracy - * for speed. - */ -unsigned long approximate_object_count(void); - -extern struct packed_git *find_sha1_pack(const unsigned char *sha1, - struct packed_git *packs); - -extern void pack_report(void); - /* * Create a temporary file rooted in the object database directory, or * die on failure. The filename is taken from "pattern", which should have the @@ -1651,15 +1607,6 @@ extern void pack_report(void); extern int odb_mkstemp(struct strbuf *template, const char *pattern); /* - * Generate the filename to be used for a pack file with checksum "sha1" and - * extension "ext". The result is written into the strbuf "buf", overwriting - * any existing contents. A pointer to buf->buf is returned as a convenience. - * - * Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx" - */ -extern char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext); - -/* * Create a pack .keep file named "name" (which should generally be the output * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on * error. @@ -1667,67 +1614,6 @@ extern char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const extern int odb_pack_keep(const char *name); /* - * mmap the index file for the specified packfile (if it is not - * already mmapped). Return 0 on success. - */ -extern int open_pack_index(struct packed_git *); - -/* - * munmap the index file for the specified packfile (if it is - * currently mmapped). - */ -extern void close_pack_index(struct packed_git *); - -extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *); -extern void close_pack_windows(struct packed_git *); -extern void close_all_packs(void); -extern void unuse_pack(struct pack_window **); -extern void clear_delta_base_cache(void); -extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local); - -/* - * Make sure that a pointer access into an mmap'd index file is within bounds, - * and can provide at least 8 bytes of data. - * - * Note that this is only necessary for variable-length segments of the file - * (like the 64-bit extended offset table), as we compare the size to the - * fixed-length parts when we open the file. - */ -extern void check_pack_index_ptr(const struct packed_git *p, const void *ptr); - -/* - * Return the SHA-1 of the nth object within the specified packfile. - * Open the index if it is not already open. The return value points - * at the SHA-1 within the mmapped index. Return NULL if there is an - * error. - */ -extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t n); -/* - * Like nth_packed_object_sha1, but write the data into the object specified by - * the the first argument. Returns the first argument on success, and NULL on - * error. - */ -extern const struct object_id *nth_packed_object_oid(struct object_id *, struct packed_git *, uint32_t n); - -/* - * Return the offset of the nth object within the specified packfile. - * The index must already be opened. - */ -extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t n); - -/* - * If the object named sha1 is present in the specified packfile, - * return its offset within the packfile; otherwise, return 0. - */ -extern off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *); - -extern int is_pack_valid(struct packed_git *); -extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *); -extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); -extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t); -extern int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *); - -/* * Iterate over the files in the loose-object parts of the object * directory "path", triggering the following callbacks: * @@ -1776,17 +1662,12 @@ int for_each_loose_file_in_objdir_buf(struct strbuf *path, void *data); /* - * Iterate over loose and packed objects in both the local + * Iterate over loose objects in both the local * repository and any alternates repositories (unless the * LOCAL_ONLY flag is set). */ #define FOR_EACH_OBJECT_LOCAL_ONLY 0x1 -typedef int each_packed_object_fn(const struct object_id *oid, - struct packed_git *pack, - uint32_t pos, - void *data); extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags); -extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags); struct object_info { /* Request */ @@ -1836,7 +1717,6 @@ struct object_info { /* Do not retry packed storage after checking packed and loose storage */ #define OBJECT_INFO_QUICK 8 extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags); -extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *); /* Dumb servers support */ extern int update_server_info(int); diff --git a/connected.c b/connected.c index 136c2ac168..f416b05051 100644 --- a/connected.c +++ b/connected.c @@ -3,6 +3,7 @@ #include "sigchain.h" #include "connected.h" #include "transport.h" +#include "packfile.h" /* * If we feed all the commits we want to verify to this command @@ -21,6 +21,7 @@ #include "string-list.h" #include "argv-array.h" #include "graph.h" +#include "packfile.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 diff --git a/fast-import.c b/fast-import.c index a959161b46..49516d60e6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -167,6 +167,7 @@ Format of STDIN stream: #include "quote.h" #include "dir.h" #include "run-command.h" +#include "packfile.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1) diff --git a/fetch-pack.c b/fetch-pack.c index fbbc99c888..105506e9aa 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -17,6 +17,7 @@ #include "prio-queue.h" #include "sha1-array.h" #include "oidset.h" +#include "packfile.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; diff --git a/git-compat-util.h b/git-compat-util.h index 7d2c0ca759..6678b488cc 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -749,8 +749,6 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t size); extern int git_atexit(void (*handler)(void)); #endif -extern void release_pack_memory(size_t); - typedef void (*try_to_free_t)(size_t); extern try_to_free_t set_try_to_free_routine(try_to_free_t); diff --git a/http-backend.c b/http-backend.c index 519025d2c3..8076b1d5e5 100644 --- a/http-backend.c +++ b/http-backend.c @@ -9,6 +9,7 @@ #include "string-list.h" #include "url.h" #include "argv-array.h" +#include "packfile.h" static const char content_type[] = "Content-Type"; static const char content_length[] = "Content-Length"; diff --git a/http-push.c b/http-push.c index c91f40a610..e4c9b065ce 100644 --- a/http-push.c +++ b/http-push.c @@ -11,6 +11,7 @@ #include "list-objects.h" #include "sigchain.h" #include "argv-array.h" +#include "packfile.h" #ifdef EXPAT_NEEDS_XMLPARSE_H #include <xmlparse.h> diff --git a/http-walker.c b/http-walker.c index ee049cb13d..1ae8363de2 100644 --- a/http-walker.c +++ b/http-walker.c @@ -4,6 +4,7 @@ #include "http.h" #include "list.h" #include "transport.h" +#include "packfile.h" struct alt_base { char *base; @@ -11,6 +11,7 @@ #include "pkt-line.h" #include "gettext.h" #include "transport.h" +#include "packfile.h" static struct trace_key trace_curl = TRACE_KEY_INIT(CURL); #if LIBCURL_VERSION_NUM >= 0x070a08 diff --git a/outgoing/packfile.h b/outgoing/packfile.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/outgoing/packfile.h diff --git a/pack-bitmap.c b/pack-bitmap.c index 327634cd71..cb3d14ba45 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -9,6 +9,7 @@ #include "pack-bitmap.h" #include "pack-revindex.h" #include "pack-objects.h" +#include "packfile.h" /* * An entry on the bitmap index, representing the bitmap for a given diff --git a/pack-check.c b/pack-check.c index e1fcb228fa..073c1fbd46 100644 --- a/pack-check.c +++ b/pack-check.c @@ -2,6 +2,7 @@ #include "pack.h" #include "pack-revindex.h" #include "progress.h" +#include "packfile.h" struct idx_entry { off_t offset; diff --git a/packfile.c b/packfile.c new file mode 100644 index 0000000000..f86fa051c9 --- /dev/null +++ b/packfile.c @@ -0,0 +1,1896 @@ +#include "cache.h" +#include "mru.h" +#include "pack.h" +#include "dir.h" +#include "mergesort.h" +#include "packfile.h" +#include "delta.h" +#include "list.h" +#include "streaming.h" +#include "sha1-lookup.h" + +char *odb_pack_name(struct strbuf *buf, + const unsigned char *sha1, + const char *ext) +{ + strbuf_reset(buf); + strbuf_addf(buf, "%s/pack/pack-%s.%s", get_object_directory(), + sha1_to_hex(sha1), ext); + return buf->buf; +} + +char *sha1_pack_name(const unsigned char *sha1) +{ + static struct strbuf buf = STRBUF_INIT; + return odb_pack_name(&buf, sha1, "pack"); +} + +char *sha1_pack_index_name(const unsigned char *sha1) +{ + static struct strbuf buf = STRBUF_INIT; + return odb_pack_name(&buf, sha1, "idx"); +} + +static unsigned int pack_used_ctr; +static unsigned int pack_mmap_calls; +static unsigned int peak_pack_open_windows; +static unsigned int pack_open_windows; +static unsigned int pack_open_fds; +static unsigned int pack_max_fds; +static size_t peak_pack_mapped; +static size_t pack_mapped; +struct packed_git *packed_git; + +static struct mru packed_git_mru_storage; +struct mru *packed_git_mru = &packed_git_mru_storage; + +#define SZ_FMT PRIuMAX +static inline uintmax_t sz_fmt(size_t s) { return s; } + +void pack_report(void) +{ + fprintf(stderr, + "pack_report: getpagesize() = %10" SZ_FMT "\n" + "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" + "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", + sz_fmt(getpagesize()), + sz_fmt(packed_git_window_size), + sz_fmt(packed_git_limit)); + fprintf(stderr, + "pack_report: pack_used_ctr = %10u\n" + "pack_report: pack_mmap_calls = %10u\n" + "pack_report: pack_open_windows = %10u / %10u\n" + "pack_report: pack_mapped = " + "%10" SZ_FMT " / %10" SZ_FMT "\n", + pack_used_ctr, + pack_mmap_calls, + pack_open_windows, peak_pack_open_windows, + sz_fmt(pack_mapped), sz_fmt(peak_pack_mapped)); +} + +/* + * Open and mmap the index file at path, perform a couple of + * consistency checks, then record its information to p. Return 0 on + * success. + */ +static int check_packed_git_idx(const char *path, struct packed_git *p) +{ + void *idx_map; + struct pack_idx_header *hdr; + size_t idx_size; + uint32_t version, nr, i, *index; + int fd = git_open(path); + struct stat st; + + if (fd < 0) + return -1; + if (fstat(fd, &st)) { + close(fd); + return -1; + } + idx_size = xsize_t(st.st_size); + if (idx_size < 4 * 256 + 20 + 20) { + close(fd); + return error("index file %s is too small", path); + } + idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + + hdr = idx_map; + if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) { + version = ntohl(hdr->idx_version); + if (version < 2 || version > 2) { + munmap(idx_map, idx_size); + return error("index file %s is version %"PRIu32 + " and is not supported by this binary" + " (try upgrading GIT to a newer version)", + path, version); + } + } else + version = 1; + + nr = 0; + index = idx_map; + if (version > 1) + index += 2; /* skip index header */ + for (i = 0; i < 256; i++) { + uint32_t n = ntohl(index[i]); + if (n < nr) { + munmap(idx_map, idx_size); + return error("non-monotonic index %s", path); + } + nr = n; + } + + if (version == 1) { + /* + * Total size: + * - 256 index entries 4 bytes each + * - 24-byte entries * nr (20-byte sha1 + 4-byte offset) + * - 20-byte SHA1 of the packfile + * - 20-byte SHA1 file checksum + */ + if (idx_size != 4*256 + nr * 24 + 20 + 20) { + munmap(idx_map, idx_size); + return error("wrong index v1 file size in %s", path); + } + } else if (version == 2) { + /* + * Minimum size: + * - 8 bytes of header + * - 256 index entries 4 bytes each + * - 20-byte sha1 entry * nr + * - 4-byte crc entry * nr + * - 4-byte offset entry * nr + * - 20-byte SHA1 of the packfile + * - 20-byte SHA1 file checksum + * And after the 4-byte offset table might be a + * variable sized table containing 8-byte entries + * for offsets larger than 2^31. + */ + unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20; + unsigned long max_size = min_size; + if (nr) + max_size += (nr - 1)*8; + if (idx_size < min_size || idx_size > max_size) { + munmap(idx_map, idx_size); + return error("wrong index v2 file size in %s", path); + } + if (idx_size != min_size && + /* + * make sure we can deal with large pack offsets. + * 31-bit signed offset won't be enough, neither + * 32-bit unsigned one will be. + */ + (sizeof(off_t) <= 4)) { + munmap(idx_map, idx_size); + return error("pack too large for current definition of off_t in %s", path); + } + } + + p->index_version = version; + p->index_data = idx_map; + p->index_size = idx_size; + p->num_objects = nr; + return 0; +} + +int open_pack_index(struct packed_git *p) +{ + char *idx_name; + size_t len; + int ret; + + if (p->index_data) + return 0; + + if (!strip_suffix(p->pack_name, ".pack", &len)) + die("BUG: pack_name does not end in .pack"); + idx_name = xstrfmt("%.*s.idx", (int)len, p->pack_name); + ret = check_packed_git_idx(idx_name, p); + free(idx_name); + return ret; +} + +static struct packed_git *alloc_packed_git(int extra) +{ + struct packed_git *p = xmalloc(st_add(sizeof(*p), extra)); + memset(p, 0, sizeof(*p)); + p->pack_fd = -1; + return p; +} + +struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path) +{ + const char *path = sha1_pack_name(sha1); + size_t alloc = st_add(strlen(path), 1); + struct packed_git *p = alloc_packed_git(alloc); + + memcpy(p->pack_name, path, alloc); /* includes NUL */ + hashcpy(p->sha1, sha1); + if (check_packed_git_idx(idx_path, p)) { + free(p); + return NULL; + } + + return p; +} + +static void scan_windows(struct packed_git *p, + struct packed_git **lru_p, + struct pack_window **lru_w, + struct pack_window **lru_l) +{ + struct pack_window *w, *w_l; + + for (w_l = NULL, w = p->windows; w; w = w->next) { + if (!w->inuse_cnt) { + if (!*lru_w || w->last_used < (*lru_w)->last_used) { + *lru_p = p; + *lru_w = w; + *lru_l = w_l; + } + } + w_l = w; + } +} + +static int unuse_one_window(struct packed_git *current) +{ + struct packed_git *p, *lru_p = NULL; + struct pack_window *lru_w = NULL, *lru_l = NULL; + + if (current) + scan_windows(current, &am |