{"thread":{"id":"226","subject":"[PATCH 19/19] the end goal of the last dozen or so commits, there's no longer a global cache variable","startedAt":"2005-04-21T18:39:22Z","lastAt":"2005-04-21T18:39:22Z","messageCount":1,"participants":["Brad Roberts"],"isPatch":true,"patchVersion":1,"patchTotal":19},"messages":[{"id":"1175","messageId":"200504211839.j3LIdMKB027881@gameboy2.puremagic.com","threadId":"226","inReplyTo":null,"subject":"[PATCH 19/19] the end goal of the last dozen or so commits, there's no longer a global cache variable","fromName":"Brad Roberts","fromEmail":"braddr@gameboy2.puremagic.com","sentAt":"2005-04-21T18:39:22Z","receivedAt":"2005-04-21T18:39:22Z","isPatch":true,"sender":{"key":"braddr@gameboy2.puremagic.com","avatar":null},"body":"tree 38adb888a4c1adfe083f24d4ec51018e0b5a8335\nparent 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac\nauthor Brad Roberts <braddr@puremagic.com> 1114093024 -0700\ncommitter Brad Roberts <braddr@gameboy2.puremagic.com> 1114093024 -0700\n\n[PATCH] the end goal of the last dozen or so commits, there's no longer a global cache variable\n\nSigned-off-by: Brad Roberts <braddr@puremagic.com>\n---\n\n cache.h          |   21 +++++++-------\n check-files.c    |   10 +++---\n checkout-cache.c |   20 ++++++-------\n diff-cache.c     |   20 ++++++-------\n merge-cache.c    |   29 ++++++++++---------\n read-cache.c     |   82 ++++++++++++++++++++++++++++---------------------------\n read-tree.c      |   51 ++++++++++++++++++----------------\n show-diff.c      |    8 ++---\n show-files.c     |   27 +++++++++---------\n update-cache.c   |   35 ++++++++++++-----------\n write-tree.c     |   20 ++++++-------\n 11 files changed, 167 insertions(+), 156 deletions(-)\n\nIndex: cache.h\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/cache.h  (mode:100644 sha1:c64969602d80a0e9d7137b2716fb808c912b075c)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/cache.h  (mode:100644 sha1:d8ade9f4b9bd9b6045f97b4df5bef8356c767d46)\n@@ -72,16 +72,17 @@\n #define alloc_nr(x) (((x)+16)*3/2)\n \n /* Initialize and use the cache information */\n-extern int read_cache(void);\n-extern int write_cache(int newfd);\n-extern void free_cache();\n-extern int cache_name_pos(const char *name, int namelen);\n-extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);\n-extern int remove_file_from_cache(char *path);\n-extern int get_num_cache_entries();\n-extern struct cache_entry * get_cache_entry(int pos);\n-extern void set_cache_entry(struct cache_entry *ce, int pos);\n-extern int remove_cache_entry_at(int pos);\n+extern struct cache *new_cache(void);\n+extern struct cache *read_cache(void);\n+extern int write_cache(struct cache *cache, int newfd);\n+extern void free_cache(struct cache *cache);\n+extern int cache_name_pos(struct cache *cache, const char *name, int namelen);\n+extern int add_cache_entry(struct cache *cache, struct cache_entry *ce, int ok_to_add);\n+extern int remove_file_from_cache(struct cache *cache, char *path);\n+extern int get_num_cache_entries(struct cache *cache);\n+extern struct cache_entry * get_cache_entry(struct cache *cache, int pos);\n+extern void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos);\n+extern int remove_cache_entry_at(struct cache *cache, int pos);\n \n #define MTIME_CHANGED\t0x0001\n #define CTIME_CHANGED\t0x0002\nIndex: check-files.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/check-files.c  (mode:100644 sha1:0973e81fbbc0f9f98031fb249254bd89d8088889)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/check-files.c  (mode:100644 sha1:4de6d39e4997d29f13261c21eeb378f74b3f8a8f)\n@@ -8,7 +8,7 @@\n  */\n #include \"cache.h\"\n \n-static void check_file(const char *path)\n+static void check_file(struct cache *cache, const char *path)\n {\n \tint fd = open(path, O_RDONLY);\n \tstruct cache_entry *ce;\n@@ -23,10 +23,10 @@\n \t}\n \n \t/* Exists but is not in the cache is not fine */\n-\tpos = cache_name_pos(path, strlen(path));\n+\tpos = cache_name_pos(cache, path, strlen(path));\n \tif (pos < 0)\n \t\tdie(\"preparing to update existing file '%s' not in cache\", path);\n-\tce = get_cache_entry(pos);\n+\tce = get_cache_entry(cache, pos);\n \n \tif (fstat(fd, &st) < 0)\n \t\tdie(\"fstat(%s): %s\", path, strerror(errno));\n@@ -39,9 +39,9 @@\n int main(int argc, char **argv)\n {\n \tint i;\n+\tstruct cache *cache = read_cache();\n \n-\tread_cache();\n \tfor (i = 1; i < argc ; i++)\n-\t\tcheck_file(argv[i]);\n+\t\tcheck_file(cache, argv[i]);\n \treturn 0;\n }\nIndex: checkout-cache.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/checkout-cache.c  (mode:100644 sha1:27b559d5bcc5831eda441bcd1fd88d687f2567b8)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/checkout-cache.c  (mode:100644 sha1:2e8c61323a72f6052d8c9ef76a4eef05aa5ac0f9)\n@@ -120,23 +120,23 @@\n \treturn write_entry(ce);\n }\n \n-static int checkout_file(const char *name)\n+static int checkout_file(struct cache *cache, const char *name)\n {\n-\tint pos = cache_name_pos(name, strlen(name));\n+\tint pos = cache_name_pos(cache, name, strlen(name));\n \tif (pos < 0) {\n \t\tif (!quiet)\n \t\t\tfprintf(stderr, \"checkout-cache: %s is not in the cache\\n\", name);\n \t\treturn -1;\n \t}\n-\treturn checkout_entry(get_cache_entry(pos));\n+\treturn checkout_entry(get_cache_entry(cache, pos));\n }\n \n-static int checkout_all(void)\n+static int checkout_all(struct cache *cache)\n {\n \tint i;\n \n-\tfor (i = 0; i < get_num_cache_entries() ; i++) {\n-\t\tstruct cache_entry *ce = get_cache_entry(i);\n+\tfor (i = 0; i < get_num_cache_entries(cache) ; i++) {\n+\t\tstruct cache_entry *ce = get_cache_entry(cache, i);\n \t\tif (ce_stage(ce))\n \t\t\tcontinue;\n \t\tif (checkout_entry(ce) < 0)\n@@ -149,15 +149,15 @@\n {\n \tint i, force_filename = 0;\n \n-\tif (read_cache() < 0) {\n+\tstruct cache * cache = read_cache();\n+\tif (!cache)\n \t\tdie(\"invalid cache\");\n-\t}\n \n \tfor (i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n \t\tif (!force_filename) {\n \t\t\tif (!strcmp(arg, \"-a\")) {\n-\t\t\t\tcheckout_all();\n+\t\t\t\tcheckout_all(cache);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--\")) {\n@@ -173,7 +173,7 @@\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\tcheckout_file(arg);\n+\t\tcheckout_file(cache, arg);\n \t}\n \treturn 0;\n }\nIndex: diff-cache.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/diff-cache.c  (mode:100644 sha1:5ae6d5de5ed5ad34f72267904ff8eb6288855fc5)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/diff-cache.c  (mode:100644 sha1:1d39ca1f79d841e363a4be57871a5c1282d441e1)\n@@ -4,7 +4,7 @@\n static int recursive = 0;\n static int line_termination = '\\n';\n \n-static int diff_cache(void *tree, unsigned long size, int pos, const char *base);\n+static int diff_cache(void *tree, unsigned long size, struct cache *cache, int pos, const char *base);\n \n static void update_tree_entry(void **bufp, unsigned long *sizep)\n {\n@@ -82,10 +82,10 @@\n }\n \n static int compare_tree_entry(const char *path1, unsigned int mode1, const unsigned char *sha1,\n-\t\t\t      int *pos, const char *base)\n+\t\t\t      struct cache *cache, int *pos, const char *base)\n {\n \tint baselen = strlen(base);\n-\tstruct cache_entry *ce = get_cache_entry(*pos);\n+\tstruct cache_entry *ce = get_cache_entry(cache, *pos);\n \tconst char *path2 = ce->name + baselen;\n \tunsigned int mode2 = ntohl(ce->ce_mode);\n \tconst unsigned char *sha2 = ce->sha1;\n@@ -107,7 +107,7 @@\n \t\t\tmemcpy(newbase + baselen + pathlen1, \"/\", 2);\n \t\t\tif (!tree || strcmp(type, \"tree\"))\n \t\t\t\tdie(\"unable to read tree object %s\", sha1_to_hex(sha1));\n-\t\t\t*pos = diff_cache(tree, size, *pos, newbase);\n+\t\t\t*pos = diff_cache(tree, size, cache, *pos, newbase);\n \t\t\tfree(newbase);\n \t\t\tfree(tree);\n \t\t\treturn -1;\n@@ -158,7 +158,7 @@\n \treturn 0;\n }\n \n-static int diff_cache(void *tree, unsigned long size, int pos, const char *base)\n+static int diff_cache(void *tree, unsigned long size, struct cache *cache, int pos, const char *base)\n {\n \tint baselen = strlen(base);\n \n@@ -172,8 +172,8 @@\n \t\t * No entries in the cache (with this base)?\n \t\t * Output the tree contents.\n \t\t */\n-\t\tif ((pos == get_num_cache_entries()) ||\n-\t\t    ce_namelen(ce = get_cache_entry(pos)) < baselen ||\n+\t\tif ((pos == get_num_cache_entries(cache)) ||\n+\t\t    ce_namelen(ce = get_cache_entry(cache, pos)) < baselen ||\n \t\t    memcmp(ce->name, base, baselen)) {\n \t\t\tif (!size)\n \t\t\t\treturn pos;\n@@ -193,7 +193,7 @@\n \t\t}\n \n \t\tsha1 = extract(tree, size, &path, &mode);\n-\t\tswitch (compare_tree_entry(path, mode, sha1, &pos, base)) {\n+\t\tswitch (compare_tree_entry(path, mode, sha1, cache, &pos, base)) {\n \t\tcase -1:\n \t\t\tupdate_tree_entry(&tree, &size);\n \t\t\tcontinue;\n@@ -215,8 +215,8 @@\n \tvoid *tree;\n \tunsigned long size;\n \tchar type[20];\n+\tstruct cache *cache = read_cache();\n \n-\tread_cache();\n \twhile (argc > 2) {\n \t\tchar *arg = argv[1];\n \t\targv++;\n@@ -257,5 +257,5 @@\n \tif (strcmp(type, \"tree\"))\n \t\tdie(\"bad tree object %s (%s)\", sha1_to_hex(tree_sha1), type);\n \n-\treturn diff_cache(tree, size, 0, \"\");\n+\treturn diff_cache(tree, size, cache, 0, \"\");\n }\nIndex: merge-cache.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/merge-cache.c  (mode:100644 sha1:c2f96e7652a2aea9417c3790bfe9ab14ffcdb12f)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/merge-cache.c  (mode:100644 sha1:440d4d6e98d1387c5055ba5539b829e7557d9d4a)\n@@ -26,11 +26,11 @@\n \t\terr = 1;\n }\n \n-static int merge_entry(int pos, const char *path)\n+static int merge_entry(struct cache *cache, int pos, const char *path)\n {\n \tint found;\n \t\n-\tif (pos >= get_num_cache_entries())\n+\tif (pos >= get_num_cache_entries(cache))\n \t\tdie(\"merge-cache: %s not in the cache\", path);\n \targuments[0] = pgm;\n \targuments[1] = \"\";\n@@ -40,7 +40,7 @@\n \tfound = 0;\n \tdo {\n \t\tstatic char hexbuf[4][60];\n-\t\tstruct cache_entry *ce = get_cache_entry(pos);\n+\t\tstruct cache_entry *ce = get_cache_entry(cache, pos);\n \t\tint stage = ce_stage(ce);\n \n \t\tif (strcmp(ce->name, path))\n@@ -48,44 +48,45 @@\n \t\tfound++;\n \t\tstrcpy(hexbuf[stage], sha1_to_hex(ce->sha1));\n \t\targuments[stage] = hexbuf[stage];\n-\t} while (++pos < get_num_cache_entries());\n+\t} while (++pos < get_num_cache_entries(cache));\n \tif (!found)\n \t\tdie(\"merge-cache: %s not in the cache\", path);\n \trun_program();\n \treturn found;\n }\n \n-static void merge_file(const char *path)\n+static void merge_file(struct cache *cache, const char *path)\n {\n-\tint pos = cache_name_pos(path, strlen(path));\n+\tint pos = cache_name_pos(cache, path, strlen(path));\n \n \t/*\n \t * If it already exists in the cache as stage0, it's\n \t * already merged and there is nothing to do.\n \t */\n \tif (pos < 0)\n-\t\tmerge_entry(-pos-1, path);\n+\t\tmerge_entry(cache, -pos-1, path);\n }\n \n-static void merge_all(void)\n+static void merge_all(struct cache *cache)\n {\n \tint i;\n-\tfor (i = 0; i < get_num_cache_entries(); i++) {\n-\t\tstruct cache_entry *ce = get_cache_entry(i);\n+\tfor (i = 0; i < get_num_cache_entries(cache); i++) {\n+\t\tstruct cache_entry *ce = get_cache_entry(cache, i);\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n-\t\ti += merge_entry(i, ce->name)-1;\n+\t\ti += merge_entry(cache, i, ce->name)-1;\n \t}\n }\n \n int main(int argc, char **argv)\n {\n \tint i, force_file = 0;\n+\tstruct cache *cache;\n \n \tif (argc < 3)\n \t\tusage(\"merge-cache <merge-program> (-a | <filename>*)\");\n \n-\tread_cache();\n+\tcache = read_cache();\n \n \tpgm = argv[1];\n \tfor (i = 2; i < argc; i++) {\n@@ -96,12 +97,12 @@\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"-a\")) {\n-\t\t\t\tmerge_all();\n+\t\t\t\tmerge_all(cache);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tdie(\"merge-cache: unknown option %s\", arg);\n \t\t}\n-\t\tmerge_file(arg);\n+\t\tmerge_file(cache, arg);\n \t}\n \tif (err)\n \t\tdie(\"merge program failed\");\nIndex: read-cache.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/read-cache.c  (mode:100644 sha1:8837d27ab683bf07d38aee33c62a90f5a7221588)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/read-cache.c  (mode:100644 sha1:7084fcdf771ddc5bfac38b8778a5904d779de3a4)\n@@ -30,18 +30,15 @@\n \tunsigned int allocated_entries;\n };\n \n-static struct cache * cache = NULL;\n-\n struct cache * new_cache()\n {\n \treturn (struct cache*)calloc(1, sizeof(struct cache));\n }\n \n-void free_cache()\n+void free_cache(struct cache *cache)\n {\n \tmunmap(cache->map.ptr, cache->map.size);\n \tfree(cache);\n-\tcache = NULL;\n }\n \n int ce_match_stat(struct cache_entry *ce, struct stat *st)\n@@ -100,7 +97,7 @@\n \treturn 0;\n }\n \n-int cache_name_pos(const char *name, int namelen)\n+int cache_name_pos(struct cache *cache, const char *name, int namelen)\n {\n \tint first, last;\n \n@@ -122,7 +119,7 @@\n }\n \n /* Remove entry, return true if there are more entries to go.. */\n-int remove_cache_entry_at(int pos)\n+int remove_cache_entry_at(struct cache *cache, int pos)\n {\n \tcache->num_entries--;\n \tif (pos >= cache->num_entries)\n@@ -131,11 +128,11 @@\n \treturn 1;\n }\n \n-int remove_file_from_cache(char *path)\n+int remove_file_from_cache(struct cache *cache, char *path)\n {\n-\tint pos = cache_name_pos(path, strlen(path));\n+\tint pos = cache_name_pos(cache, path, strlen(path));\n \tif (pos >= 0)\n-\t\tremove_cache_entry_at(pos);\n+\t\tremove_cache_entry_at(cache, pos);\n \treturn 0;\n }\n \n@@ -145,17 +142,17 @@\n \treturn ce_namelen(b) == len && !memcmp(a->name, b->name, len);\n }\n \n-int get_num_cache_entries()\n+int get_num_cache_entries(struct cache *cache)\n {\n \treturn cache->num_entries;\n }\n \n-struct cache_entry * get_cache_entry(int pos)\n+struct cache_entry * get_cache_entry(struct cache *cache, int pos)\n {\n \treturn cache->entries[pos];\n }\n \n-void set_cache_entry(struct cache_entry *ce, int pos)\n+void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos)\n {\n \t/* You can NOT just free cache->entries[i] here, since it\n \t * might not be necessarily malloc()ed but can also come\n@@ -163,16 +160,11 @@\n \tcache->entries[pos] = ce;\n }\n \n-int add_cache_entry(struct cache_entry *ce, int ok_to_add)\n+int add_cache_entry(struct cache *cache, struct cache_entry *ce, int ok_to_add)\n {\n \tint pos;\n \n-\t/* temporary, read-tree.c expects the cache to always exist, even\n-\t * without a read_cache being called */\n-\tif (!cache)\n-\t\tcache = new_cache();\n-\n-\tpos = cache_name_pos(ce->name, htons(ce->ce_flags));\n+\tpos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));\n \n \t/* existing match? Just replace it */\n \tif (pos >= 0) {\n@@ -188,7 +180,7 @@\n \tif (pos < cache->num_entries && ce_stage(ce) == 0) {\n \t\twhile (same_name(cache->entries[pos], ce)) {\n \t\t\tok_to_add = 1;\n-\t\t\tif (!remove_cache_entry_at(pos))\n+\t\t\tif (!remove_cache_entry_at(cache, pos))\n \t\t\t\tbreak;\n \t\t}\n \t}\n@@ -227,29 +219,40 @@\n \treturn 0;\n }\n \n-int read_cache(void)\n+struct cache *read_cache(void)\n {\n \tint fd, i;\n \tstruct stat st;\n \tunsigned long offset;\n+\tstruct cache *cache;\n+\n+\tcache = new_cache();\n+\tif (!cache) {\n+\t\terrno = ENOMEM;\n+\t\terror(\"unable to allocate cache\");\n+\t\treturn NULL;\n+\t}\n \n-\terrno = EBUSY;\n-\tif (cache)\n-\t\treturn error(\"more than one cachefile\");\n \terrno = ENOENT;\n \tsha1_file_directory = getenv(DB_ENVIRONMENT);\n \tif (!sha1_file_directory)\n \t\tsha1_file_directory = DEFAULT_DB_ENVIRONMENT;\n-\tif (access(sha1_file_directory, X_OK) < 0)\n-\t\treturn error(\"no access to SHA1 file directory\");\n+\tif (access(sha1_file_directory, X_OK) < 0) {\n+\t\terror(\"no access to SHA1 file directory\");\n+\t\tfree(cache);\n+\t\treturn NULL;\n+\t}\n \tfd = open(\".git/index\", O_RDONLY);\n-\tif (fd < 0)\n-\t\treturn (errno == ENOENT) ? 0 : error(\"open failed\");\n-\n-\terrno = ENOMEM;\n-\tcache = new_cache();\n-\tif (!cache)\n-\t\treturn error(\"unable to allocate cache\");\n+\tif (fd < 0) {\n+\t\t/* TODO: Why special case this?  If we can't get to the data, what's the point? */\n+\t\tif (errno == ENOENT)\n+\t\t\treturn cache;\n+\t\telse {\n+\t\t\terror(\"open failed\");\n+\t\t\tfree(cache);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n \n \tcache->map.size = 0; /* avoid gcc warning */\n \tcache->map.ptr = (void *)-1;\n@@ -261,16 +264,17 @@\n \t}\n \tclose(fd);\n \tif (-1 == (int)(long)cache->map.ptr) {\n+\t\terror(\"mmap failed\");\n \t\tfree(cache);\n-\t\tcache = NULL;\n-\t\treturn error(\"mmap failed\");\n+\t\treturn NULL;\n \t}\n \n \tcache->header = cache->map.ptr;\n \tif (verify_hdr(cache->header, cache->map.size) < 0) {\n-\t\tfree_cache();\n+\t\tfree_cache(cache);\n \t\terrno = EINVAL;\n-\t\treturn error(\"verify header failed\");\n+\t\terror(\"verify header failed\");\n+\t\treturn NULL;\n \t}\n \n \tcache->num_entries = ntohl(cache->header->hdr_entries);\n@@ -283,7 +287,7 @@\n \t\toffset = offset + ce_size(ce);\n \t\tcache->entries[i] = ce;\n \t}\n-\treturn cache->num_entries;\n+\treturn cache;\n }\n \n #define WRITE_BUFFER_SIZE 8192\n@@ -329,7 +333,7 @@\n \treturn 0;\n }\n \n-int write_cache(int newfd)\n+int write_cache(struct cache *cache, int newfd)\n {\n \tSHA_CTX c;\n \tstruct cache_header hdr;\nIndex: read-tree.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/read-tree.c  (mode:100644 sha1:ad9128f26613a82361475516dd0f2b470f4ce4b3)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/read-tree.c  (mode:100644 sha1:a683b7f60e58514d36218a7b2c2ace2d3ec9f984)\n@@ -7,7 +7,7 @@\n \n static int stage = 0;\n \n-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)\n+static int read_one_entry(struct cache *cache, unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)\n {\n \tint len = strlen(pathname);\n \tunsigned int size = cache_entry_size(baselen + len);\n@@ -20,10 +20,10 @@\n \tmemcpy(ce->name, base, baselen);\n \tmemcpy(ce->name + baselen, pathname, len+1);\n \tmemcpy(ce->sha1, sha1, 20);\n-\treturn add_cache_entry(ce, 1);\n+\treturn add_cache_entry(cache, ce, 1);\n }\n \n-static int read_tree(unsigned char *sha1, const char *base, int baselen)\n+static int read_tree(struct cache *cache, unsigned char *sha1, const char *base, int baselen)\n {\n \tvoid *buffer, *bufptr;\n \tunsigned long size;\n@@ -57,7 +57,7 @@\n \t\t\tmemcpy(newbase, base, baselen);\n \t\t\tmemcpy(newbase + baselen, path, pathlen);\n \t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t\tretval = read_tree(sha1, newbase, baselen + pathlen + 1);\n+\t\t\tretval = read_tree(cache, sha1, newbase, baselen + pathlen + 1);\n \t\t\tfree(newbase);\n \t\t\tif (retval) {\n \t\t\t\tfree(buffer);\n@@ -65,7 +65,7 @@\n \t\t\t}\n \t\t\tcontinue;\n \t\t}\n-\t\tif (read_one_entry(sha1, base, baselen, path, mode) < 0) {\n+\t\tif (read_one_entry(cache, sha1, base, baselen, path, mode) < 0) {\n \t\t\tfree(buffer);\n \t\t\treturn -1;\n \t\t}\n@@ -149,16 +149,16 @@\n /* rather than doing the 'right' thing of deleting entries as we merge,\n  * walk dst through the cache, overwriting entries as we go and at the\n  * end truncate the size of the cache */\n-static void trivially_merge_cache()\n+static void trivially_merge_cache(struct cache *cache)\n {\n \tstatic struct cache_entry null_entry;\n \tstruct cache_entry *old = &null_entry;\n-\tint src = 0, dst = 0, nr = get_num_cache_entries();\n+\tint src = 0, dst = 0, nr = get_num_cache_entries(cache);\n \n \twhile (src < nr) {\n \t\tstruct cache_entry *ce, *result;\n \n-\t\tce = get_cache_entry(src);\n+\t\tce = get_cache_entry(cache, src);\n \n \t\t/* We throw away original cache entries except for the stat information */\n \t\tif (!ce_stage(ce)) {\n@@ -168,8 +168,8 @@\n \t\t}\n \t\tif ((src < (nr - 2)) &&\n \t\t    (result = merge_entries(ce,\n-\t\t\t\t\t    get_cache_entry(src + 1),\n-\t\t\t\t\t    get_cache_entry(src + 2))) != NULL) {\n+\t\t\t\t\t    get_cache_entry(cache, src + 1),\n+\t\t\t\t\t    get_cache_entry(cache, src + 2))) != NULL) {\n \t\t\t/*\n \t\t\t * See if we can re-use the old CE directly?\n \t\t\t * That way we get the uptodate stat info.\n@@ -180,27 +180,27 @@\n \t\t\tce->ce_flags &= ~htons(CE_STAGEMASK);\n \t\t\tsrc += 2;\n \t\t}\n-\t\tset_cache_entry(ce, dst);\n+\t\tset_cache_entry(cache, ce, dst);\n \t\tdst++;\n \t\tsrc++;\n \t}\n \t/* this could be replaced by a truncate api */\n \twhile (nr > dst) {\n \t\tnr--;\n-\t\tremove_cache_entry_at(nr);\n+\t\tremove_cache_entry_at(cache, nr);\n \t}\n }\n \n-static void merge_stat_info()\n+static void merge_stat_info(struct cache *cache)\n {\n \tstatic struct cache_entry null_entry;\n \tstruct cache_entry *old = &null_entry;\n-\tint src = 0, dst = 0, nr = get_num_cache_entries();\n+\tint src = 0, dst = 0, nr = get_num_cache_entries(cache);\n \n \twhile (src < nr) {\n \t\tstruct cache_entry *ce;\n \n-\t\tce = get_cache_entry(src);\n+\t\tce = get_cache_entry(cache, src);\n \n \t\t/* We throw away original cache entries except for the stat information */\n \t\tif (!ce_stage(ce)) {\n@@ -211,14 +211,14 @@\n \t\tif (path_matches(ce, old) && same(ce, old))\n \t\t\t*ce = *old;\n \t\tce->ce_flags &= ~htons(CE_STAGEMASK);\n-\t\tset_cache_entry(ce, dst);\n+\t\tset_cache_entry(cache, ce, dst);\n \t\tdst++;\n \t\tsrc++;\n \t}\n \t/* this could be replaced by a truncate api */\n \twhile (nr > dst) {\n \t\tnr--;\n-\t\tremove_cache_entry_at(nr);\n+\t\tremove_cache_entry_at(cache, nr);\n \t}\n }\n \n@@ -226,6 +226,7 @@\n {\n \tint i, newfd, merge;\n \tunsigned char sha1[20];\n+\tstruct cache *cache = NULL;\n \n \tnewfd = open(\".git/index.lock\", O_RDWR | O_CREAT | O_EXCL, 0600);\n \tif (newfd < 0)\n@@ -242,9 +243,9 @@\n \t\t\tint i;\n \t\t\tif (stage)\n \t\t\t\tusage(\"-m needs to come first\");\n-\t\t\tread_cache();\n-\t\t\tfor (i = 0; i < get_num_cache_entries(); i++) {\n-\t\t\t\tif (ce_stage(get_cache_entry(i)))\n+\t\t\tcache = read_cache();\n+\t\t\tfor (i = 0; i < get_num_cache_entries(cache); i++) {\n+\t\t\t\tif (ce_stage(get_cache_entry(cache, i)))\n \t\t\t\t\tusage(\"you need to resolve your current index first\");\n \t\t\t}\n \t\t\tstage = 1;\n@@ -255,23 +256,25 @@\n \t\t\tusage(\"read-tree [-m] <sha1>\");\n \t\tif (stage > 3)\n \t\t\tusage(\"can't merge more than two trees\");\n-\t\tif (read_tree(sha1, \"\", 0) < 0)\n+\t\tif (!cache)\n+\t\t\tcache = new_cache();\n+\t\tif (read_tree(cache, sha1, \"\", 0) < 0)\n \t\t\tdie(\"failed to unpack tree object %s\", arg);\n \t\tstage++;\n \t}\n \tif (merge) {\n \t\tswitch (stage) {\n \t\tcase 4:\t/* Three-way merge */\n-\t\t\ttrivially_merge_cache();\n+\t\t\ttrivially_merge_cache(cache);\n \t\t\tbreak;\n \t\tcase 2:\t/* Just read a tree, merge with old cache contents */\n-\t\t\tmerge_stat_info();\n+\t\t\tmerge_stat_info(cache);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tdie(\"just how do you expect me to merge %d trees?\", stage-1);\n \t\t}\n \t}\n-\tif (write_cache(newfd) ||\n+\tif (write_cache(cache, newfd) ||\n \t    rename(\".git/index.lock\", \".git/index\"))\n \t\tdie(\"unable to write new index file\");\n \tremove_lock = 0;\nIndex: show-diff.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/show-diff.c  (mode:100644 sha1:4a0902f50b3120b7791a4d4627a9a4f729afdcf7)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/show-diff.c  (mode:100644 sha1:d61bf6dea8106599c25ac5071743b351f6e000ce)\n@@ -129,9 +129,9 @@\n \tint entries;\n \tint matched = 0;\n \tint i;\n+\tstruct cache *cache = read_cache();\n \n-\tread_cache();\n-\tentries = get_num_cache_entries();\n+\tentries = get_num_cache_entries(cache);\n \tif (entries < 0) {\n \t\tperror(\"read_cache\");\n \t\texit(1);\n@@ -157,7 +157,7 @@\n \tprepare_diff_cmd();\n \tfor (i = 0; i < entries; i++) {\n \t\tstruct stat st;\n-\t\tstruct cache_entry *ce = get_cache_entry(i);\n+\t\tstruct cache_entry *ce = get_cache_entry(cache, i);\n \t\tint changed;\n \t\tunsigned long size;\n \t\tchar type[20];\n@@ -175,7 +175,7 @@\n \t\t\t\tprintf(\"%s: Unmerged\\n\",\n \t\t\t\t       ce->name);\n \t\t\twhile (i < entries &&\n-\t\t\t       !strcmp(ce->name, get_cache_entry(i)->name))\n+\t\t\t       !strcmp(ce->name, get_cache_entry(cache, i)->name))\n \t\t\t\ti++;\n \t\t\ti--; /* compensate for loop control increments */\n \t\t\tcontinue;\nIndex: show-files.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/show-files.c  (mode:100644 sha1:11fbbccef2df50d528105ceb48b15275f2a5693e)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/show-files.c  (mode:100644 sha1:c8dc21d0dd3f5db3f7016323859c58449968d800)\n@@ -27,11 +27,11 @@\n static int nr_dir;\n static int dir_alloc;\n \n-static void add_name(const char *pathname, int len)\n+static void add_name(struct cache *cache, const char *pathname, int len)\n {\n \tchar *name;\n \n-\tif (cache_name_pos(pathname, len) >= 0)\n+\tif (cache_name_pos(cache, pathname, len) >= 0)\n \t\treturn;\n \n \tif (nr_dir == dir_alloc) {\n@@ -51,7 +51,7 @@\n  * Also, we currently ignore all names starting with a dot.\n  * That likely will not change.\n  */\n-static void read_directory(const char *path, const char *base, int baselen)\n+static void read_directory(struct cache *cache, const char *path, const char *base, int baselen)\n {\n \tDIR *dir = opendir(path);\n \n@@ -82,12 +82,12 @@\n \t\t\t\t/* fallthrough */\n \t\t\tcase DT_DIR:\n \t\t\t\tmemcpy(fullname + baselen + len, \"/\", 2);\n-\t\t\t\tread_directory(fullname, fullname, baselen + len + 1);\n+\t\t\t\tread_directory(cache, fullname, fullname, baselen + len + 1);\n \t\t\t\tcontinue;\n \t\t\tcase DT_REG:\n \t\t\t\tbreak;\n \t\t\t}\n-\t\t\tadd_name(fullname, baselen + len);\n+\t\t\tadd_name(cache, fullname, baselen + len);\n \t\t}\n \t\tclosedir(dir);\n \t}\n@@ -102,13 +102,13 @@\n \treturn cache_name_compare(n1, l1, n2, l2);\n }\n \n-static void show_files(void)\n+static void show_files(struct cache *cache)\n {\n \tint i;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others | show_ignored) {\n-\t\tread_directory(\".\", \"\", 0);\n+\t\tread_directory(cache, \".\", \"\", 0);\n \t\tqsort(dir, nr_dir, sizeof(char *), cmp_name);\n \t}\n \tif (show_others) {\n@@ -116,8 +116,8 @@\n \t\t\tprintf(\"%s%s%c\", tag_other, dir[i], line_terminator);\n \t}\n \tif (show_cached | show_stage) {\n-\t\tfor (i = 0; i < get_num_cache_entries(); i++) {\n-\t\t\tstruct cache_entry *ce = get_cache_entry(i);\n+\t\tfor (i = 0; i < get_num_cache_entries(cache); i++) {\n+\t\t\tstruct cache_entry *ce = get_cache_entry(cache, i);\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (!show_stage)\n@@ -136,8 +136,8 @@\n \t\t}\n \t}\n \tif (show_deleted) {\n-\t\tfor (i = 0; i < get_num_cache_entries(); i++) {\n-\t\t\tstruct cache_entry *ce = get_cache_entry(i);\n+\t\tfor (i = 0; i < get_num_cache_entries(cache); i++) {\n+\t\t\tstruct cache_entry *ce = get_cache_entry(cache, i);\n \t\t\tstruct stat st;\n \t\t\tif (!stat(ce->name, &st))\n \t\t\t\tcontinue;\n@@ -152,6 +152,7 @@\n int main(int argc, char **argv)\n {\n \tint i;\n+\tstruct cache *cache;\n \n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n@@ -202,7 +203,7 @@\n \tif (!(show_stage | show_deleted | show_others | show_ignored | show_unmerged))\n \t\tshow_cached = 1;\n \n-\tread_cache();\n-\tshow_files();\n+\tcache = read_cache();\n+\tshow_files(cache);\n \treturn 0;\n }\nIndex: update-cache.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/update-cache.c  (mode:100644 sha1:3f251552283667c42797835088a4922ef865fe4a)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/update-cache.c  (mode:100644 sha1:565638acd2380023ea69e82316a7ab77d95d8ee7)\n@@ -85,7 +85,7 @@\n \tce->ce_size = htonl(st->st_size);\n }\n \n-static int add_file_to_cache(char *path)\n+static int add_file_to_cache(struct cache *cache, char *path)\n {\n \tint size, namelen;\n \tstruct cache_entry *ce;\n@@ -96,7 +96,7 @@\n \tif (fd < 0) {\n \t\tif (errno == ENOENT) {\n \t\t\tif (allow_remove)\n-\t\t\t\treturn remove_file_from_cache(path);\n+\t\t\t\treturn remove_file_from_cache(cache, path);\n \t\t}\n \t\treturn -1;\n \t}\n@@ -117,7 +117,7 @@\n \t\tfree(ce);\n \t\treturn -1;\n \t}\n-\tif (add_cache_entry(ce, allow_add)) {\n+\tif (add_cache_entry(cache, ce, allow_add)) {\n \t\tfree(ce);\n \t\treturn -1;\n \t}\n@@ -200,17 +200,17 @@\n \treturn updated;\n }\n \n-static void refresh_cache(void)\n+static void refresh_cache(struct cache *cache)\n {\n \tint i;\n \n-\tfor (i = 0; i < get_num_cache_entries(); i++) {\n+\tfor (i = 0; i < get_num_cache_entries(cache); i++) {\n \t\tstruct cache_entry *ce, *new;\n-\t\tce = get_cache_entry(i);\n+\t\tce = get_cache_entry(cache, i);\n \t\tif (ce_stage(ce)) {\n \t\t\tprintf(\"%s: needs merge\\n\", ce->name);\n-\t\t\twhile ((i < get_num_cache_entries()) &&\n-\t\t\t       ! strcmp(get_cache_entry(i)->name, ce->name))\n+\t\t\twhile ((i < get_num_cache_entries(cache)) &&\n+\t\t\t       ! strcmp(get_cache_entry(cache, i)->name, ce->name))\n \t\t\t\ti++;\n \t\t\ti--;\n \t\t\tcontinue;\n@@ -221,7 +221,7 @@\n \t\t\tprintf(\"%s: needs update\\n\", ce->name);\n \t\t\tcontinue;\n \t\t}\n-\t\tset_cache_entry(new, i);\n+\t\tset_cache_entry(cache, new, i);\n \t}\n }\n \n@@ -253,7 +253,7 @@\n \t}\n }\n \n-static int add_cacheinfo(char *arg1, char *arg2, char *arg3)\n+static int add_cacheinfo(struct cache *cache, char *arg1, char *arg2, char *arg3)\n {\n \tint size, len;\n \tunsigned int mode;\n@@ -276,7 +276,7 @@\n \tmemcpy(ce->name, arg3, len);\n \tce->ce_flags = htons(len);\n \tce->ce_mode = create_ce_mode(mode);\n-\treturn add_cache_entry(ce, allow_add);\n+\treturn add_cache_entry(cache, ce, allow_add);\n }\n \n static int remove_lock = 0;\n@@ -291,6 +291,7 @@\n {\n \tint i, newfd, entries;\n \tint allow_options = 1;\n+\tstruct cache *cache = NULL;\n \n \tnewfd = open(\".git/index.lock\", O_RDWR | O_CREAT | O_EXCL, 0600);\n \tif (newfd < 0)\n@@ -299,8 +300,8 @@\n \tatexit(remove_lock_file);\n \tremove_lock = 1;\n \n-\tread_cache();\n-\tentries = get_num_cache_entries();\n+\tcache = read_cache();\n+\tentries = get_num_cache_entries(cache);\n \tif (entries < 0)\n \t\tdie(\"cache corrupted\");\n \n@@ -321,11 +322,11 @@\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--refresh\")) {\n-\t\t\t\trefresh_cache();\n+\t\t\t\trefresh_cache(cache);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--cacheinfo\")) {\n-\t\t\t\tif (i+3 >= argc || add_cacheinfo(argv[i+1], argv[i+2], argv[i+3]))\n+\t\t\t\tif (i+3 >= argc || add_cacheinfo(cache, argv[i+1], argv[i+2], argv[i+3]))\n \t\t\t\t\tdie(\"update-cache: --cacheinfo <mode> <sha1> <path>\");\n \t\t\t\ti += 3;\n \t\t\t\tcontinue;\n@@ -336,10 +337,10 @@\n \t\t\tfprintf(stderr, \"Ignoring path %s\\n\", argv[i]);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (add_file_to_cache(path))\n+\t\tif (add_file_to_cache(cache, path))\n \t\t\tdie(\"Unable to add %s to database\", path);\n \t}\n-\tif (write_cache(newfd) ||\n+\tif (write_cache(cache, newfd) ||\n \t    rename(\".git/index.lock\", \".git/index\"))\n \t\tdie(\"Unable to write new cachefile\");\n \nIndex: write-tree.c\n===================================================================\n--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/write-tree.c  (mode:100644 sha1:92e707fd4780805da160ce6fa282e75111ea67b9)\n+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/write-tree.c  (mode:100644 sha1:ad148b422ffa85d7ecf515e55538c1afa13f17d6)\n@@ -29,7 +29,7 @@\n \n #define ORIG_OFFSET (40)\t/* Enough space to add the header of \"tree <size>\\0\" */\n \n-static int write_tree(int start_pos, const char *base, int baselen, unsigned char *returnsha1)\n+static int write_tree(struct cache *cache, int start_pos, const char *base, int baselen, unsigned char *returnsha1)\n {\n \tunsigned char subdir_sha1[20];\n \tunsigned long size, offset;\n@@ -43,7 +43,7 @@\n \n \tnr = 0;\n \tdo {\n-\t\tstruct cache_entry *ce = get_cache_entry(start_pos + nr);\n+\t\tstruct cache_entry *ce = get_cache_entry(cache, start_pos + nr);\n \t\tconst char *pathname = ce->name, *filename, *dirname;\n \t\tint pathlen = ce_namelen(ce), entrylen;\n \t\tunsigned char *sha1;\n@@ -59,7 +59,7 @@\n \t\tif (dirname) {\n \t\t\tint subdir_written;\n \n-\t\t\tsubdir_written = write_tree(start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);\n+\t\t\tsubdir_written = write_tree(cache, start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);\n \t\t\tnr += subdir_written;\n \n \t\t\t/* Now we need to write out the directory entry into this tree.. */\n@@ -87,7 +87,7 @@\n \t\tmemcpy(buffer + offset, sha1, 20);\n \t\toffset += 20;\n \t\tnr++;\n-\t} while ((start_pos + nr) < get_num_cache_entries());\n+\t} while ((start_pos + nr) < get_num_cache_entries(cache));\n \n \ti = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);\n \ti -= 5;\n@@ -101,18 +101,18 @@\n int main(int argc, char **argv)\n {\n \tint i, unmerged;\n-\tint entries;\n \tunsigned char sha1[20];\n+\tstruct cache *cache = read_cache();\n+\tint entries;\n \n-\tread_cache();\n-\tentries = get_num_cache_entries();\n-\tif (entries <= 0)\n+\tif (!cache)\n \t\tdie(\"write-tree: no cache contents to write\");\n+\tentries = get_num_cache_entries(cache);\n \n \t/* Verify that the tree is merged */\n \tunmerged = 0;\n \tfor (i = 0; i < entries; i++) {\n-\t\tstruct cache_entry *ce = get_cache_entry(i);\n+\t\tstruct cache_entry *ce = get_cache_entry(cache, i);\n \t\tif (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {\n \t\t\tif (++unmerged > 10) {\n \t\t\t\tfprintf(stderr, \"...\\n\");\n@@ -125,7 +125,7 @@\n \t\tdie(\"write-tree: not able to write tree\");\n \n \t/* Ok, write it out */\n-\tif (write_tree(0, \"\", 0, sha1) != entries)\n+\tif (write_tree(cache, 0, \"\", 0, sha1) != entries)\n \t\tdie(\"write-tree: internal error\");\n \tprintf(\"%s\\n\", sha1_to_hex(sha1));\n \treturn 0;\n\n"}]}