git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Brad Roberts <braddr@puremagic.com>
To: git@vger.kernel.org, Petr Baudis <pasky@ucw.cz>
Cc: Juliusz Chroboczek <Juliusz.Chroboczek@pps.jussieu.fr>
Subject: Re: Darcs-git: a few notes for Git hackers
Date: Sun, 15 May 2005 02:11:41 -0700 (PDT)	[thread overview]
Message-ID: <Pine.LNX.4.44.0505150208020.2136-200000@bellevue.puremagic.com> (raw)
In-Reply-To: <Pine.LNX.4.44.0505141851340.2136-200000@bellevue.puremagic.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2652 bytes --]

Resending, I left off the mailing list on the to list last time.

> > I wasn't able to finish redoing these against linus tip, but I got most of
> > it done (patches 1-14 of the original 19):
> >
> >   http://gameboy2.puremagic.com:8090/
> >   rsync://gameboy2.puremagic.com/git/
> >
> > The second, third, and forth to last changes need a careful review,
> > they're direct applications of the original patches which were lightly
> > tested during the first round and nothing other than compile tested in
> > this round.
> >
> > I suspect the remaining parts of the original patch series will go in
> > fairly smoothly.  If no one gets to them before tonight I'll finish
> > it up after work.
> >
> > Later,
> > Brad
>
> I've completed the re-merge, and moved to tip of git-pb.git rather than
> tip of git.git.  Unfortunatly that merge was also somewhat intrusive and
> my individual diffs along the way are somewhat useless now.  The entire
> history is available about the above locations still.  Attached is the
> full diff vs git-pb @ 902b92e00e491a60d55c4b2bce122903b8347f34.
>
> The unit tests that are being added are a wonderful thing, thanks so much
> for doing them Junio.
>
> These changes feel rough to me still.  Some areas to discuss / think
> about:
>
> 1) The hunks that change the merge routines from pointer based to index
> based could have been left much less intruded upon by adding a
> get_cache_entry_array(cache) api.
>
> 2) Should the index changing areas be constructing a new index instead of
> shuffling bits within the current index?
>
> 3) The vocabulary and code is inconsistent between cache and index.
>
> 4) read-cache.c does much more than reading.
>
> 5) Like before, cleaning up memory for the cache is a rarity, preferring
> to let the end of the process garbage collect everything.
>
>  cache.h          |   52 ++++++-------
>  check-files.c    |   12 +--
>  checkout-cache.c |   26 +++---
>  diff-cache.c     |   60 ++++++++-------
>  diff-files.c     |   31 ++++---
>  diff-helper.c    |    6 -
>  diff-tree.c      |   50 ++++++------
>  diff.c           |   36 +++++----
>  diff.h           |   11 +-
>  fsck-cache.c     |    6 -
>  local-pull.c     |    2
>  ls-files.c       |   47 ++++++-----
>  merge-cache.c    |   29 +++----
>  read-cache.c     |  217 ++++++++++++++++++++++++++++++++++---------------------
>  read-tree.c      |   65 +++++++++-------
>  sha1_file.c      |    4 -
>  tree.c           |   15 ++-
>  update-cache.c   |   45 +++++------
>  write-tree.c     |   29 ++++---
>  19 files changed, 416 insertions(+), 327 deletions(-)
>
> Signed-off-by: Brad Roberts <braddr@puremagic.com>
>
>


[-- Attachment #2: diff-vs-git-pb --]
[-- Type: TEXT/PLAIN, Size: 63306 bytes --]

Index: cache.h
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/cache.h  (mode:100644)
+++ uncommitted/cache.h  (mode:100644)
@@ -40,19 +40,8 @@
 
 /*
  * Basic data structures for the directory cache
- *
- * NOTE NOTE NOTE! This is all in the native CPU byte format. It's
- * not even trying to be portable. It's trying to be efficient. It's
- * just a cache, after all.
  */
 
-#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
-struct cache_header {
-	unsigned int hdr_signature;
-	unsigned int hdr_version;
-	unsigned int hdr_entries;
-};
-
 /*
  * The "cache_time" is just the low 32 bits of the
  * time. It doesn't matter if it overflows - we only
@@ -89,6 +78,9 @@
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
 
+extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
+extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
+
 #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
 #define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags))
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
@@ -104,9 +96,6 @@
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
-extern struct cache_entry **active_cache;
-extern unsigned int active_nr, active_alloc, active_cache_changed;
-
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
@@ -120,17 +109,19 @@
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
-extern int read_cache(void);
-extern int write_cache(int newfd, struct cache_entry **cache, int entries);
-extern int cache_name_pos(const char *name, int namelen);
+extern struct cache *new_cache(void);
+extern struct cache *read_cache(void);
+extern int write_cache(struct cache *cache, int newfd);
+extern void free_cache(struct cache *cache);
+extern int cache_name_pos(struct cache *cache, const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
-extern int add_cache_entry(struct cache_entry *ce, int option);
-extern int remove_entry_at(int pos);
-extern int remove_file_from_cache(char *path);
-extern int same_name(struct cache_entry *a, struct cache_entry *b);
-extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
+extern int add_cache_entry(struct cache *cache, struct cache_entry *ce, int option);
+extern int remove_file_from_cache(struct cache *cache, char *path);
+extern int get_num_cache_entries(struct cache *cache);
+extern struct cache_entry *get_cache_entry(struct cache *cache, int pos);
+extern void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos);
+extern int remove_cache_entry_at(struct cache *cache, int pos);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
@@ -148,11 +139,12 @@
 extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
 extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
 extern int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *return_sha1);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
 
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
 /* Read a tree into the cache */
-extern int read_tree(void *buffer, unsigned long size, int stage);
+extern int read_tree(struct cache *cache, void *buffer, unsigned long size, int stage);
 
 extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
 
@@ -179,7 +171,7 @@
 void parse_date(char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
 
-static inline void *xmalloc(int size)
+static inline void *xmalloc(size_t size)
 {
 	void *ret = malloc(size);
 	if (!ret)
@@ -187,7 +179,7 @@
 	return ret;
 }
 
-static inline void *xrealloc(void *ptr, int size)
+static inline void *xrealloc(void *ptr, size_t size)
 {
 	void *ret = realloc(ptr, size);
 	if (!ret)
@@ -195,4 +187,12 @@
 	return ret;
 }
 
+static inline void *xcalloc(size_t nmemb, size_t size)
+{
+	void *ret = calloc(nmemb, size);
+	if (!ret)
+		die("Out of memory, calloc failed");
+	return ret;
+}
+
 #endif /* CACHE_H */
Index: check-files.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/check-files.c  (mode:100644)
+++ uncommitted/check-files.c  (mode:100644)
@@ -8,7 +8,7 @@
  */
 #include "cache.h"
 
-static void check_file(const char *path)
+static void check_file(struct cache *cache, const char *path)
 {
 	int fd = open(path, O_RDONLY);
 	struct cache_entry *ce;
@@ -23,15 +23,15 @@
 	}
 
 	/* Exists but is not in the cache is not fine */
-	pos = cache_name_pos(path, strlen(path));
+	pos = cache_name_pos(cache, path, strlen(path));
 	if (pos < 0)
 		die("preparing to update existing file '%s' not in cache", path);
-	ce = active_cache[pos];
+	ce = get_cache_entry(cache, pos);
 
 	if (lstat(path, &st) < 0)
 		die("lstat(%s): %s", path, strerror(errno));
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (changed)
 		die("preparing to update file '%s' not uptodate in cache", path);
 }
@@ -39,9 +39,9 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache = read_cache();
 
-	read_cache();
 	for (i = 1; i < argc ; i++)
-		check_file(argv[i]);
+		check_file(cache, argv[i]);
 	return 0;
 }
Index: checkout-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/checkout-cache.c  (mode:100644)
+++ uncommitted/checkout-cache.c  (mode:100644)
@@ -167,7 +167,7 @@
 	strcpy(path + len, ce->name);
 
 	if (!lstat(path, &st)) {
-		unsigned changed = cache_match_stat(ce, &st);
+		unsigned changed = ce_match_stat(ce, &st);
 		if (!changed)
 			return 0;
 		if (!force) {
@@ -188,30 +188,30 @@
 	return write_entry(ce, path);
 }
 
-static int checkout_file(const char *name, const char *base_dir)
+static int checkout_file(struct cache *cache, const char *name, const char *base_dir)
 {
-	int pos = cache_name_pos(name, strlen(name));
+	int pos = cache_name_pos(cache, name, strlen(name));
 	if (pos < 0) {
 		if (!quiet) {
 			pos = -pos - 1;
 			fprintf(stderr,
 				"checkout-cache: %s is %s.\n",
 				name,
-				(pos < active_nr &&
-				 !strcmp(active_cache[pos]->name, name)) ?
+				(pos < get_num_cache_entries(cache) &&
+				 !strcmp(get_cache_entry(cache, pos)->name, name)) ?
 				"unmerged" : "not in the cache");
 		}
 		return -1;
 	}
-	return checkout_entry(active_cache[pos], base_dir);
+	return checkout_entry(get_cache_entry(cache, pos), base_dir);
 }
 
-static int checkout_all(const char *base_dir)
+static int checkout_all(struct cache *cache, const char *base_dir)
 {
 	int i;
 
-	for (i = 0; i < active_nr ; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache) ; i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ce_stage(ce))
 			continue;
 		if (checkout_entry(ce, base_dir) < 0)
@@ -225,15 +225,15 @@
 	int i, force_filename = 0;
 	const char *base_dir = "";
 
-	if (read_cache() < 0) {
+	struct cache *cache = read_cache();
+	if (!cache) 
 		die("invalid cache");
-	}
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!force_filename) {
 			if (!strcmp(arg, "-a")) {
-				checkout_all(base_dir);
+				checkout_all(cache, base_dir);
 				continue;
 			}
 			if (!strcmp(arg, "--")) {
@@ -257,7 +257,7 @@
 				continue;
 			}
 		}
-		checkout_file(arg, base_dir);
+		checkout_file(cache, arg, base_dir);
 	}
 	return 0;
 }
Index: diff-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-cache.c  (mode:100644)
+++ uncommitted/diff-cache.c  (mode:100644)
@@ -7,10 +7,10 @@
 static int line_termination = '\n';
 
 /* A file entry went away or appeared */
-static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
+static void show_file(struct cache *cache, const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
 {
 	if (generate_patch)
-		diff_addremove(prefix[0], ntohl(mode), sha1, ce->name, NULL);
+		diff_addremove(cache, prefix[0], ntohl(mode), sha1, ce->name, NULL);
 	else
 		printf("%s%06o\tblob\t%s\t%s%c", prefix, ntohl(mode),
 		       sha1_to_hex(sha1), ce->name, line_termination);
@@ -33,7 +33,7 @@
 			}
 			return -1;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		if (changed) {
 			mode = create_ce_mode(st.st_mode);
 			sha1 = no_sha1;
@@ -45,7 +45,7 @@
 	return 0;
 }
 
-static void show_new_file(struct cache_entry *new)
+static void show_new_file(struct cache *cache, struct cache_entry *new)
 {
 	unsigned char *sha1;
 	unsigned int mode;
@@ -54,10 +54,11 @@
 	if (get_stat_data(new, &sha1, &mode) < 0)
 		return;
 
-	show_file("+", new, sha1, mode);
+	show_file(cache, "+", new, sha1, mode);
 }
 
-static int show_modified(struct cache_entry *old,
+static int show_modified(struct cache *cache,
+			 struct cache_entry *old,
 			 struct cache_entry *new,
 			 int report_missing)
 {
@@ -67,7 +68,7 @@
 
 	if (get_stat_data(new, &sha1, &mode) < 0) {
 		if (report_missing)
-			show_file("-", old, old->sha1, old->ce_mode);
+			show_file(cache, "-", old, old->sha1, old->ce_mode);
 		return -1;
 	}
 
@@ -79,7 +80,7 @@
 	oldmode = ntohl(oldmode);
 
 	if (generate_patch)
-		diff_change(oldmode, mode,
+		diff_change(cache, oldmode, mode,
 			    old->sha1, sha1, old->name, NULL);
 	else {
 		strcpy(old_sha1_hex, sha1_to_hex(old->sha1));
@@ -90,30 +91,34 @@
 	return 0;
 }
 
-static int diff_cache(struct cache_entry **ac, int entries)
+static int diff_cache(struct cache *cache)
 {
-	while (entries) {
-		struct cache_entry *ce = *ac;
-		int same = (entries > 1) && same_name(ce, ac[1]);
+	int pos = 0, num = get_num_cache_entries(cache);
+
+	while (pos < num) {
+		struct cache_entry *ce = get_cache_entry(cache, pos);
+		struct cache_entry *ce_next = ((pos+1) < num) ?
+			get_cache_entry(cache, pos+1) : NULL;
+		int same = ce_next && ce_same_name(ce, ce_next);
 
 		switch (ce_stage(ce)) {
 		case 0:
 			/* No stage 1 entry? That means it's a new file */
 			if (!same) {
-				show_new_file(ce);
+				show_new_file(cache, ce);
 				break;
 			}
 			/* Show difference between old and new */
-			show_modified(ac[1], ce, 1);
+			show_modified(cache, ce_next, ce, 1);
 			break;
 		case 1:
 			/* No stage 3 (merge) entry? That means it's been deleted */
 			if (!same) {
-				show_file("-", ce, ce->sha1, ce->ce_mode);
+				show_file(cache, "-", ce, ce->sha1, ce->ce_mode);
 				break;
 			}
 			/* We come here with ce pointing at stage 1
-			 * (original tree) and ac[1] pointing at stage
+			 * (original tree) and ce_next pointing at stage
 			 * 3 (unmerged).  show-modified with
 			 * report-mising set to false does not say the
 			 * file is deleted but reports true if work
@@ -122,12 +127,12 @@
 			 * Otherwise, we show the differences between
 			 * the original tree and the work tree.
 			 */
-			if (!cached_only && !show_modified(ce, ac[1], 0))
+			if (!cached_only && !show_modified(cache, ce, ce_next, 0))
 				break;
 			/* fallthru */
 		case 3:
 			if (generate_patch)
-				diff_unmerge(ce->name);
+				diff_unmerge(cache, ce->name);
 			else
 				printf("U %s%c", ce->name, line_termination);
 			break;
@@ -141,9 +146,8 @@
 		 * we've handled the relevant cases now.
 		 */
 		do {
-			ac++;
-			entries--;
-		} while (entries && same_name(ce, ac[0]));
+			pos++;
+		} while (pos < num && ce_same_name(ce, get_cache_entry(cache, pos)));
 	}
 	return 0;
 }
@@ -153,11 +157,11 @@
  * when we read in the new tree (into "stage 1"), we won't lose sight
  * of the fact that we had unmerged entries.
  */
-static void mark_merge_entries(void)
+static void mark_merge_entries(struct cache *cache)
 {
 	int i;
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (!ce_stage(ce))
 			continue;
 		ce->ce_flags |= htons(CE_STAGEMASK);
@@ -172,8 +176,8 @@
 	unsigned char tree_sha1[20];
 	void *tree;
 	unsigned long size;
+	struct cache * cache = read_cache();
 
-	read_cache();
 	while (argc > 2) {
 		char *arg = argv[1];
 		argv++;
@@ -204,13 +208,13 @@
 	if (argc != 2 || get_sha1(argv[1], tree_sha1))
 		usage(diff_cache_usage);
 
-	mark_merge_entries();
+	mark_merge_entries(cache);
 
 	tree = read_object_with_reference(tree_sha1, "tree", &size, 0);
 	if (!tree)
 		die("bad tree object %s", argv[1]);
-	if (read_tree(tree, size, 1))
+	if (read_tree(cache, tree, size, 1))
 		die("unable to read tree object %s", argv[1]);
 
-	return diff_cache(active_cache, active_nr);
+	return diff_cache(cache);
 }
Index: diff-files.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-files.c  (mode:100644)
+++ uncommitted/diff-files.c  (mode:100644)
@@ -28,18 +28,18 @@
 	return 0;
 }
 
-static void show_unmerge(const char *path)
+static void show_unmerge(struct cache *cache, const char *path)
 {
 	if (generate_patch)
-		diff_unmerge(path);
+		diff_unmerge(cache, path);
 	else
 		printf("U %s%c", path, line_termination);
 }
 
-static void show_file(int pfx, struct cache_entry *ce)
+static void show_file(struct cache *cache, int pfx, struct cache_entry *ce)
 {
 	if (generate_patch)
-		diff_addremove(pfx, ntohl(ce->ce_mode), ce->sha1,
+		diff_addremove(cache, pfx, ntohl(ce->ce_mode), ce->sha1,
 			       ce->name, NULL);
 	else
 		printf("%c%06o\t%s\t%s\t%s%c",
@@ -47,7 +47,7 @@
 		       sha1_to_hex(ce->sha1), ce->name, line_termination);
 }
 
-static void show_modified(int oldmode, int mode,
+static void show_modified(struct cache *cache, int oldmode, int mode,
 			  const char *old_sha1, const char *sha1,
 			  char *path)
 {
@@ -55,7 +55,7 @@
 	strcpy(old_sha1_hex, sha1_to_hex(old_sha1));
 
 	if (generate_patch)
-		diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
+		diff_change(cache, oldmode, mode, old_sha1, sha1, path, NULL);
 	else
 		printf("*%06o->%06o\tblob\t%s->%s\t%s%c",
 		       oldmode, mode, old_sha1_hex, sha1_to_hex(sha1), path,
@@ -65,7 +65,8 @@
 int main(int argc, char **argv)
 {
 	static const char null_sha1[20] = { 0, };
-	int entries = read_cache();
+	struct cache *cache = read_cache();
+	int entries;
 	int i;
 
 	while (1 < argc && argv[1][0] == '-') {
@@ -87,15 +88,17 @@
 	/* At this point, if argc == 1, then we are doing everything.
 	 * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
 	 */
-	if (entries < 0) {
+	if (!cache) {
 		perror("read_cache");
 		exit(1);
 	}
 
+	entries = get_num_cache_entries(cache);
+
 	for (i = 0; i < entries; i++) {
 		struct stat st;
 		unsigned int oldmode, mode;
-		struct cache_entry *ce = active_cache[i];
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		int changed;
 
 		if (1 < argc &&
@@ -103,9 +106,9 @@
 			continue;
 
 		if (ce_stage(ce)) {
-			show_unmerge(ce->name);
+			show_unmerge(cache, ce->name);
 			while (i < entries &&
-			       !strcmp(ce->name, active_cache[i]->name))
+			       !strcmp(ce->name, get_cache_entry(cache, i)->name))
 				i++;
 			i--; /* compensate for loop control increments */
 			continue;
@@ -118,10 +121,10 @@
 			}	
 			if (silent)
 				continue;
-			show_file('-', ce);
+			show_file(cache, '-', ce);
 			continue;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		if (!changed)
 			continue;
 
@@ -129,7 +132,7 @@
 		mode = (S_ISLNK(st.st_mode) ? S_IFLNK :
 			S_IFREG | ce_permissions(st.st_mode));
 
-		show_modified(oldmode, mode, ce->sha1, null_sha1,
+		show_modified(cache, oldmode, mode, ce->sha1, null_sha1,
 			      ce->name);
 	}
 	return 0;
Index: diff-helper.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-helper.c  (mode:100644)
+++ uncommitted/diff-helper.c  (mode:100644)
@@ -56,7 +56,7 @@
 	switch (*cp++) {
 	case 'U':
 		if (!cnt || matches_pathspec(cp + 1, spec, cnt))
-			diff_unmerge(cp + 1);
+			diff_unmerge(NULL, cp + 1);
 		return 0;
 	case '+':
 		old.file_valid = 0;
@@ -102,9 +102,9 @@
 	}
 	if (!cnt || matches_pathspec(path, spec, cnt)) {
 		if (reverse)
-			run_external_diff(path, &new, &old);
+			run_external_diff(NULL, path, &new, &old);
 		else
-			run_external_diff(path, &old, &new);
+			run_external_diff(NULL, path, &old, &new);
 	}
 	return 0;
 }
Index: diff-tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-tree.c  (mode:100644)
+++ uncommitted/diff-tree.c  (mode:100644)
@@ -17,7 +17,7 @@
 static char **paths = NULL;
 static int *pathlens = NULL;
 
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
+static int diff_tree_sha1(struct cache *cache, const unsigned char *old, const unsigned char *new, const char *base);
 
 static void update_tree_entry(void **bufp, unsigned long *sizep)
 {
@@ -53,19 +53,19 @@
 	return newbase;
 }
 
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base);
+static void show_file(struct cache *cache, const char *prefix, void *tree, unsigned long size, const char *base);
 
 /* A whole sub-tree went away or appeared */
-static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base)
+static void show_tree(struct cache *cache, const char *prefix, void *tree, unsigned long size, const char *base)
 {
 	while (size) {
-		show_file(prefix, tree, size, base);
+		show_file(cache, prefix, tree, size, base);
 		update_tree_entry(&tree, &size);
 	}
 }
 
 /* A file entry went away or appeared */
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base)
+static void show_file(struct cache *cache, const char *prefix, void *tree, unsigned long size, const char *base)
 {
 	unsigned mode;
 	const char *path;
@@ -89,7 +89,7 @@
 		if (!tree || strcmp(type, "tree"))
 			die("corrupt tree sha %s", sha1_to_hex(sha1));
 
-		show_tree(prefix, tree, size, newbase);
+		show_tree(cache, prefix, tree, size, newbase);
 		
 		free(tree);
 		free(newbase);
@@ -98,7 +98,7 @@
 
 	if (generate_patch) {
 		if (!S_ISDIR(mode))
-			diff_addremove(prefix[0], mode, sha1, base, path);
+			diff_addremove(cache, prefix[0], mode, sha1, base, path);
 	}
 	else
 		printf("%s%06o\t%s\t%s\t%s%s%c", prefix, mode,
@@ -107,7 +107,7 @@
 		       line_termination);
 }
 
-static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
+static int compare_tree_entry(struct cache *cache, void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
 {
 	unsigned mode1, mode2;
 	const char *path1, *path2;
@@ -122,11 +122,11 @@
 	pathlen2 = strlen(path2);
 	cmp = cache_name_compare(path1, pathlen1, path2, pathlen2);
 	if (cmp < 0) {
-		show_file("-", tree1, size1, base);
+		show_file(cache, "-", tree1, size1, base);
 		return -1;
 	}
 	if (cmp > 0) {
-		show_file("+", tree2, size2, base);
+		show_file(cache, "+", tree2, size2, base);
 		return 1;
 	}
 	if (!memcmp(sha1, sha2, 20) && mode1 == mode2)
@@ -137,15 +137,15 @@
 	 * file, we need to consider it a remove and an add.
 	 */
 	if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
-		show_file("-", tree1, size1, base);
-		show_file("+", tree2, size2, base);
+		show_file(cache, "-", tree1, size1, base);
+		show_file(cache, "+", tree2, size2, base);
 		return 0;
 	}
 
 	if (recursive && S_ISDIR(mode1)) {
 		int retval;
 		char *newbase = malloc_base(base, path1, pathlen1);
-		retval = diff_tree_sha1(sha1, sha2, newbase);
+		retval = diff_tree_sha1(cache, sha1, sha2, newbase);
 		free(newbase);
 		return retval;
 	}
@@ -159,7 +159,7 @@
 
 	if (generate_patch) {
 		if (!S_ISDIR(mode1))
-			diff_change(mode1, mode2, sha1, sha2, base, path1);
+			diff_change(cache, mode1, mode2, sha1, sha2, base, path1);
 	}
 	else {
 		strcpy(old_sha1_hex, sha1_to_hex(sha1));
@@ -217,7 +217,7 @@
 	return 0; /* No matches */
 }
 
-static int diff_tree(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
+static int diff_tree(struct cache *cache, void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
 {
 	while (size1 | size2) {
 		if (nr_paths && size1 && !interesting(tree1, size1, base)) {
@@ -229,16 +229,16 @@
 			continue;
 		}
 		if (!size1) {
-			show_file("+", tree2, size2, base);
+			show_file(cache, "+", tree2, size2, base);
 			update_tree_entry(&tree2, &size2);
 			continue;
 		}
 		if (!size2) {
-			show_file("-", tree1, size1, base);
+			show_file(cache, "-", tree1, size1, base);
 			update_tree_entry(&tree1, &size1);
 			continue;
 		}
-		switch (compare_tree_entry(tree1, size1, tree2, size2, base)) {
+		switch (compare_tree_entry(cache, tree1, size1, tree2, size2, base)) {
 		case -1:
 			update_tree_entry(&tree1, &size1);
 			continue;
@@ -254,7 +254,7 @@
 	return 0;
 }
 
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base)
+static int diff_tree_sha1(struct cache *cache, const unsigned char *old, const unsigned char *new, const char *base)
 {
 	void *tree1, *tree2;
 	unsigned long size1, size2;
@@ -266,7 +266,7 @@
 	tree2 = read_object_with_reference(new, "tree", &size2, 0);
 	if (!tree2)
 		die("unable to read destination tree (%s)", sha1_to_hex(new));
-	retval = diff_tree(tree1, size1, tree2, size2, base);
+	retval = diff_tree(cache, tree1, size1, tree2, size2, base);
 	free(tree1);
 	free(tree2);
 	return retval;
@@ -342,7 +342,7 @@
 	return this_header;
 }
 
-static int diff_tree_stdin(char *line)
+static int diff_tree_stdin(struct cache *cache, char *line)
 {
 	int len = strlen(line);
 	unsigned char commit[20], parent[20];
@@ -360,7 +360,7 @@
 		line[81] = 0;
 		sprintf(this_header, "%s (from %s)\n", line, line+41);
 		header = this_header;
-		return diff_tree_sha1(parent, commit, "");
+		return diff_tree_sha1(cache, parent, commit, "");
 	}
 	buf = read_object_with_reference(commit, "commit", &size, NULL);
 	if (!buf)
@@ -378,7 +378,7 @@
 		if (get_sha1_hex(buf + offset + 7, parent))
 			return -1;
 		header = generate_header(line, sha1_to_hex(parent), buf, size);
-		diff_tree_sha1(parent, commit, "");
+		diff_tree_sha1(cache, parent, commit, "");
 		if (!header && verbose_header)
 			header_prefix = "\ndiff-tree ";
 		offset += 48;
@@ -458,10 +458,10 @@
 	}
 
 	if (!read_stdin)
-		return diff_tree_sha1(old, new, "");
+		return diff_tree_sha1(NULL, old, new, "");
 
 	while (fgets(line, sizeof(line), stdin))
-		diff_tree_stdin(line);
+		diff_tree_stdin(NULL, line);
 
 	return 0;
 }
Index: diff.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff.c  (mode:100644)
+++ uncommitted/diff.c  (mode:100644)
@@ -147,7 +147,7 @@
  * the work tree has that object contents, return true, so that
  * prepare_temp_file() does not have to inflate and extract.
  */
-static int work_tree_matches(const char *name, const unsigned char *sha1)
+static int work_tree_matches(struct cache *cache, const char *name, const unsigned char *sha1)
 {
 	struct cache_entry *ce;
 	struct stat st;
@@ -165,17 +165,17 @@
 	 * by diff-cache --cached, which does read the cache before
 	 * calling us.
 	 */ 
-	if (!active_cache)
+	if (!get_num_cache_entries(cache))
 		return 0;
 
 	len = strlen(name);
-	pos = cache_name_pos(name, len);
+	pos = cache_name_pos(cache, name, len);
 	if (pos < 0)
 		return 0;
-	ce = active_cache[pos];
+	ce = get_cache_entry(cache, pos);
 	if ((lstat(name, &st) < 0) ||
 	    !S_ISREG(st.st_mode) ||
-	    cache_match_stat(ce, &st) ||
+	    ce_match_stat(ce, &st) ||
 	    memcmp(sha1, ce->sha1, 20))
 		return 0;
 	return 1;
@@ -202,7 +202,8 @@
 	sprintf(temp->mode, "%06o", mode);
 }
 
-static void prepare_temp_file(const char *name,
+static void prepare_temp_file(struct cache *cache,
+			      const char *name,
 			      struct diff_tempfile *temp,
 			      struct diff_spec *one)
 {
@@ -222,7 +223,7 @@
 
 	if (one->sha1_valid &&
 	    (!memcmp(one->blob_sha1, null_sha1, sizeof(null_sha1)) ||
-	     work_tree_matches(name, one->blob_sha1)))
+	     work_tree_matches(cache, name, one->blob_sha1)))
 		use_work_tree = 1;
 
 	if (!one->sha1_valid || use_work_tree) {
@@ -293,7 +294,8 @@
  *               infile2 infile2-sha1 infile2-mode.
  *
  */
-void run_external_diff(const char *name,
+void run_external_diff(struct cache *cache,
+		       const char *name,
 		       struct diff_spec *one,
 		       struct diff_spec *two)
 {
@@ -303,8 +305,8 @@
 	static int atexit_asked = 0;
 
 	if (one && two) {
-		prepare_temp_file(name, &temp[0], one);
-		prepare_temp_file(name, &temp[1], two);
+		prepare_temp_file(cache, name, &temp[0], one);
+		prepare_temp_file(cache, name, &temp[1], two);
 		if (! atexit_asked &&
 		    (temp[0].name == temp[0].tmp_path ||
 		     temp[1].name == temp[1].tmp_path)) {
@@ -357,7 +359,8 @@
 	remove_tempfile();
 }
 
-void diff_addremove(int addremove, unsigned mode,
+void diff_addremove(struct cache *cache,
+		    int addremove, unsigned mode,
 		    const unsigned char *sha1,
 		    const char *base, const char *path)
 {
@@ -379,10 +382,11 @@
 		strcpy(concatpath, base);
 		strcat(concatpath, path);
 	}
-	run_external_diff(path ? concatpath : base, one, two);
+	run_external_diff(cache, path ? concatpath : base, one, two);
 }
 
-void diff_change(unsigned old_mode, unsigned new_mode,
+void diff_change(struct cache *cache,
+		 unsigned old_mode, unsigned new_mode,
 		 const unsigned char *old_sha1,
 		 const unsigned char *new_sha1,
 		 const char *base, const char *path) {
@@ -400,10 +404,10 @@
 		strcpy(concatpath, base);
 		strcat(concatpath, path);
 	}
-	run_external_diff(path ? concatpath : base, &spec[0], &spec[1]);
+	run_external_diff(cache, path ? concatpath : base, &spec[0], &spec[1]);
 }
 
-void diff_unmerge(const char *path)
+void diff_unmerge(struct cache *cache, const char *path)
 {
-	run_external_diff(path, NULL, NULL);
+	run_external_diff(cache, path, NULL, NULL);
 }
Index: diff.h
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff.h  (mode:100644)
+++ uncommitted/diff.h  (mode:100644)
@@ -4,18 +4,20 @@
 #ifndef DIFF_H
 #define DIFF_H
 
-extern void diff_addremove(int addremove,
+extern void diff_addremove(struct cache *cache,
+			   int addremove,
 			   unsigned mode,
 			   const unsigned char *sha1,
 			   const char *base,
 			   const char *path);
 
-extern void diff_change(unsigned mode1, unsigned mode2,
+extern void diff_change(struct cache *cache,
+			     unsigned mode1, unsigned mode2,
 			     const unsigned char *sha1,
 			     const unsigned char *sha2,
 			     const char *base, const char *path);
 
-extern void diff_unmerge(const char *path);
+extern void diff_unmerge(struct cache *cache, const char *path);
 
 /* These are for diff-helper */
 
@@ -31,7 +33,8 @@
 	unsigned file_valid : 1; /* if false the file does not even exist */
 };
 
-extern void run_external_diff(const char *name,
+extern void run_external_diff(struct cache *cache,
+			      const char *name,
 			      struct diff_spec *, struct diff_spec *);
 
 #endif /* DIFF_H */
Index: fsck-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/fsck-cache.c  (mode:100644)
+++ uncommitted/fsck-cache.c  (mode:100644)
@@ -356,9 +356,9 @@
 
 	if (keep_cache_objects) {
 		int i;
-		read_cache();
-		for (i = 0; i < active_nr; i++) {
-			struct blob *blob = lookup_blob(active_cache[i]->sha1);
+		struct cache *cache = read_cache();
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct blob *blob = lookup_blob(get_cache_entry(cache, i)->sha1);
 			struct object *obj;
 			if (!blob)
 				continue;
Index: local-pull.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/local-pull.c  (mode:100644)
+++ uncommitted/local-pull.c  (mode:100644)
@@ -61,7 +61,7 @@
 		}
 		map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, ifd, 0);
 		close(ifd);
-		if (-1 == (int)(long)map) {
+		if (MAP_FAILED == map) {
 			fprintf(stderr, "cannot mmap %s\n", filename);
 			return -1;
 		}
Index: ls-files.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/ls-files.c  (mode:100644)
+++ uncommitted/ls-files.c  (mode:100644)
@@ -98,11 +98,11 @@
 static int nr_dir;
 static int dir_alloc;
 
-static void add_name(const char *pathname, int len)
+static void add_name(struct cache *cache, const char *pathname, int len)
 {
 	struct nond_on_fs *ent;
 
-	if (cache_name_pos(pathname, len) >= 0)
+	if (cache_name_pos(cache, pathname, len) >= 0)
 		return;
 
 	if (nr_dir == dir_alloc) {
@@ -124,7 +124,7 @@
  * Also, we currently ignore all names starting with a dot.
  * That likely will not change.
  */
-static void read_directory(const char *path, const char *base, int baselen)
+static void read_directory(struct cache *cache, const char *path, const char *base, int baselen)
 {
 	DIR *dir = opendir(path);
 
@@ -157,14 +157,14 @@
 				/* fallthrough */
 			case DT_DIR:
 				memcpy(fullname + baselen + len, "/", 2);
-				read_directory(fullname, fullname,
+				read_directory(cache, fullname, fullname,
 					       baselen + len + 1);
 				continue;
 			case DT_REG:
 			case DT_LNK:
 				break;
 			}
-			add_name(fullname, baselen + len);
+			add_name(cache, fullname, baselen + len);
 		}
 		closedir(dir);
 	}
@@ -179,7 +179,7 @@
 				  e2->name, e2->len);
 }
 
-static void show_killed_files()
+static void show_killed_files(struct cache *cache)
 {
 	int i;
 	for (i = 0; i < nr_dir; i++) {
@@ -193,28 +193,28 @@
 				/* If ent->name is prefix of an entry in the
 				 * cache, it will be killed.
 				 */
-				pos = cache_name_pos(ent->name, ent->len);
+				pos = cache_name_pos(cache, ent->name, ent->len);
 				if (0 <= pos)
 					die("bug in show-killed-files");
 				pos = -pos - 1;
-				while (pos < active_nr &&
-				       ce_stage(active_cache[pos]))
+				while (pos < get_num_cache_entries(cache) &&
+				       ce_stage(get_cache_entry(cache, pos)))
 					pos++; /* skip unmerged */
-				if (active_nr <= pos)
+				if (get_num_cache_entries(cache) <= pos)
 					break;
 				/* pos points at a name immediately after
 				 * ent->name in the cache.  Does it expect
 				 * ent->name to be a directory?
 				 */
-				len = ce_namelen(active_cache[pos]);
+				len = ce_namelen(get_cache_entry(cache, pos));
 				if ((ent->len < len) &&
-				    !strncmp(active_cache[pos]->name,
+				    !strncmp(get_cache_entry(cache, pos)->name,
 					     ent->name, ent->len) &&
-				    active_cache[pos]->name[ent->len] == '/')
+				    get_cache_entry(cache, pos)->name[ent->len] == '/')
 					killed = 1;
 				break;
 			}
-			if (0 <= cache_name_pos(ent->name, sp - ent->name)) {
+			if (0 <= cache_name_pos(cache, ent->name, sp - ent->name)) {
 				/* If any of the leading directories in
 				 * ent->name is registered in the cache,
 				 * ent->name will be killed.
@@ -230,13 +230,13 @@
 	}
 }
 
-static void show_files(void)
+static void show_files(struct cache *cache)
 {
 	int i;
 
 	/* For cached/deleted files we don't need to even do the readdir */
 	if (show_others || show_killed) {
-		read_directory(".", "", 0);
+		read_directory(cache, ".", "", 0);
 		qsort(dir, nr_dir, sizeof(struct nond_on_fs *), cmp_name);
 		if (show_others)
 			for (i = 0; i < nr_dir; i++)
@@ -244,11 +244,11 @@
 				       dir[i]->len, dir[i]->name,
 				       line_terminator);
 		if (show_killed)
-			show_killed_files();
+			show_killed_files(cache);
 	}
 	if (show_cached | show_stage) {
-		for (i = 0; i < active_nr; i++) {
-			struct cache_entry *ce = active_cache[i];
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			if (excluded(ce->name) != show_ignored)
 				continue;
 			if (show_unmerged && !ce_stage(ce))
@@ -269,8 +269,8 @@
 		}
 	}
 	if (show_deleted) {
-		for (i = 0; i < active_nr; i++) {
-			struct cache_entry *ce = active_cache[i];
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			struct stat st;
 			if (excluded(ce->name) != show_ignored)
 				continue;
@@ -289,6 +289,7 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache;
 
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
@@ -341,7 +342,7 @@
 	if (!(show_stage | show_deleted | show_others | show_unmerged | show_killed))
 		show_cached = 1;
 
-	read_cache();
-	show_files();
+	cache = read_cache();
+	show_files(cache);
 	return 0;
 }
Index: merge-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/merge-cache.c  (mode:100644)
+++ uncommitted/merge-cache.c  (mode:100644)
@@ -34,11 +34,11 @@
 	}
 }
 
-static int merge_entry(int pos, const char *path)
+static int merge_entry(struct cache *cache, int pos, const char *path)
 {
 	int found;
 	
-	if (pos >= active_nr)
+	if (pos >= get_num_cache_entries(cache))
 		die("merge-cache: %s not in the cache", path);
 	arguments[0] = pgm;
 	arguments[1] = "";
@@ -52,7 +52,7 @@
 	do {
 		static char hexbuf[4][60];
 		static char ownbuf[4][60];
-		struct cache_entry *ce = active_cache[pos];
+		struct cache_entry *ce = get_cache_entry(cache, pos);
 		int stage = ce_stage(ce);
 
 		if (strcmp(ce->name, path))
@@ -62,44 +62,45 @@
 		sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode) & (~S_IFMT));
 		arguments[stage] = hexbuf[stage];
 		arguments[stage + 4] = ownbuf[stage];
-	} while (++pos < active_nr);
+	} while (++pos < get_num_cache_entries(cache));
 	if (!found)
 		die("merge-cache: %s not in the cache", path);
 	run_program();
 	return found;
 }
 
-static void merge_file(const char *path)
+static void merge_file(struct cache *cache, const char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 
 	/*
 	 * If it already exists in the cache as stage0, it's
 	 * already merged and there is nothing to do.
 	 */
 	if (pos < 0)
-		merge_entry(-pos-1, path);
+		merge_entry(cache, -pos-1, path);
 }
 
-static void merge_all(void)
+static void merge_all(struct cache *cache)
 {
 	int i;
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (!ce_stage(ce))
 			continue;
-		i += merge_entry(i, ce->name)-1;
+		i += merge_entry(cache, i, ce->name)-1;
 	}
 }
 
 int main(int argc, char **argv)
 {
 	int i, force_file = 0;
+	struct cache *cache;
 
 	if (argc < 3)
 		usage("merge-cache [-o] <merge-program> (-a | <filename>*)");
 
-	read_cache();
+	cache = read_cache();
 
 	i = 1;
 	if (!strcmp(argv[1], "-o")) {
@@ -115,12 +116,12 @@
 				continue;
 			}
 			if (!strcmp(arg, "-a")) {
-				merge_all();
+				merge_all(cache);
 				continue;
 			}
 			die("merge-cache: unknown option %s", arg);
 		}
-		merge_file(arg);
+		merge_file(cache, arg);
 	}
 	if (err)
 		die("merge program failed");
Index: read-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/read-cache.c  (mode:100644)
+++ uncommitted/read-cache.c  (mode:100644)
@@ -6,10 +6,49 @@
 #include <stdarg.h>
 #include "cache.h"
 
-struct cache_entry **active_cache = NULL;
-unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
+/*
+ * Basic data structures for the directory cache
+ */
+
+#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
+struct cache_header {
+	unsigned int hdr_signature;
+	unsigned int hdr_version;
+	unsigned int hdr_entries;
+};
+
+struct mmap_holder {
+	void * ptr;
+	size_t size;
+};
+
+struct cache {
+	struct mmap_holder   map;
+	struct cache_header *header;
+	struct cache_entry **entries;
+	unsigned int num_entries;
+	unsigned int allocated_entries;
+	unsigned int active_cache_changed;
+};
+
+struct cache * new_cache()
+{
+	struct cache *cache = xcalloc(1, sizeof(struct cache));
+
+	cache->map.ptr = MAP_FAILED;
+
+	return cache;
+}
+
+void free_cache(struct cache *cache)
+{
+	if (cache->map.ptr != MAP_FAILED)
+		munmap(cache->map.ptr, cache->map.size);
+
+	free(cache);
+}
 
-int cache_match_stat(struct cache_entry *ce, struct stat *st)
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
 
@@ -75,15 +114,15 @@
 	return 0;
 }
 
-int cache_name_pos(const char *name, int namelen)
+int cache_name_pos(struct cache *cache, const char *name, int namelen)
 {
 	int first, last;
 
 	first = 0;
-	last = active_nr;
+	last = cache->num_entries;
 	while (last > first) {
 		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
+		struct cache_entry *ce = get_cache_entry(cache, next);
 		int cmp = cache_name_compare(name, namelen, ce->name, htons(ce->ce_flags));
 		if (!cmp)
 			return next;
@@ -97,27 +136,27 @@
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-int remove_entry_at(int pos)
+int remove_cache_entry_at(struct cache *cache, int pos)
 {
-	active_cache_changed = 1;
-	active_nr--;
-	if (pos >= active_nr)
+	cache->active_cache_changed = 1;
+	cache->num_entries--;
+	if (pos >= cache->num_entries)
 		return 0;
-	memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
+	memmove(cache->entries + pos, cache->entries + pos + 1, (cache->num_entries - pos) * sizeof(struct cache_entry *));
 	return 1;
 }
 
-int remove_file_from_cache(char *path)
+int remove_file_from_cache(struct cache *cache, char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 	if (pos < 0)
 		pos = -pos-1;
-	while (pos < active_nr && !strcmp(active_cache[pos]->name, path))
-		remove_entry_at(pos);
+	while (pos < get_num_cache_entries(cache) && !strcmp(get_cache_entry(cache, pos)->name, path))
+		remove_cache_entry_at(cache, pos);
 	return 0;
 }
 
-int same_name(struct cache_entry *a, struct cache_entry *b)
+int ce_same_name(struct cache_entry *a, struct cache_entry *b)
 {
 	int len = ce_namelen(a);
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
@@ -132,7 +171,8 @@
  * from the cache so the caller should recompute the insert position.
  * When this happens, we return non-zero.
  */
-static int check_file_directory_conflict(const struct cache_entry *ce,
+static int check_file_directory_conflict(struct cache *cache,
+					 const struct cache_entry *ce,
 					 int ok_to_replace)
 {
 	int pos, replaced = 0;
@@ -155,7 +195,7 @@
 		if (!ep)
 			break;
 		*ep = 0;    /* first cut it at slash */
-		pos = cache_name_pos(pathbuf,
+		pos = cache_name_pos(cache, pathbuf,
 				     htons(create_ce_flags(ep-cp, stage)));
 		if (0 <= pos) {
 			/* Our leading path component is registered as a file,
@@ -167,7 +207,7 @@
 				return -1;
 			}
 			fprintf(stderr, "removing file '%s' to replace it with a directory to create '%s'.\n", pathbuf, path);
-			remove_entry_at(pos);
+			remove_cache_entry_at(cache, pos);
 			replaced = 1;
 		}
 		*ep = '/';  /* then restore it and go downwards */
@@ -179,7 +219,7 @@
 	 * of it?  That is, are we creating a file where they already expect
 	 * a directory there?
 	 */
-	pos = cache_name_pos(path,
+	pos = cache_name_pos(cache, path,
 			     htons(create_ce_flags(namelen, stage)));
 
 	/* (0 <= pos) cannot happen because add_cache_entry()
@@ -206,8 +246,8 @@
 	 * path of an existing entry anymore.
 	 */
 
-	while (pos < active_nr) {
-		struct cache_entry *other = active_cache[pos];
+	while (pos < get_num_cache_entries(cache)) {
+		struct cache_entry *other = get_cache_entry(cache, pos);
 		if (strncmp(other->name, path, namelen))
 			break; /* it is not our "subdirectory" anymore */
 		if ((ce_stage(other) == stage) &&
@@ -215,7 +255,7 @@
 			if (!ok_to_replace)
 				return -1;
 			fprintf(stderr, "removing file '%s' under '%s' to be replaced with a file\n", other->name, path);
-			remove_entry_at(pos);
+			remove_cache_entry_at(cache, pos);
 			replaced = 1;
 			continue; /* cycle without updating pos */
 		}
@@ -224,17 +264,35 @@
 	return replaced;
 }
 
-int add_cache_entry(struct cache_entry *ce, int option)
+void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos)
+{
+	cache->active_cache_changed = 1;
+	cache->entries[pos] = ce;
+}
+
+int get_num_cache_entries(struct cache *cache)
+{
+	return cache->num_entries;
+}
+
+struct cache_entry *get_cache_entry(struct cache *cache, int pos)
+{
+ 	/* You can NOT just free cache->entries[pos] here, since it
+  	 * might not be necessarily malloc()ed but can also come
+  	 * from mmap(). */
+	return cache->entries[pos];
+}
+
+int add_cache_entry(struct cache *cache, struct cache_entry *ce, int option)
 {
 	int pos;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
-	pos = cache_name_pos(ce->name, htons(ce->ce_flags));
+	pos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
-		active_cache_changed = 1;
-		active_cache[pos] = ce;
+		set_cache_entry(cache, ce, pos);
 		return 0;
 	}
 	pos = -pos-1;
@@ -243,10 +301,10 @@
 	 * Inserting a merged entry ("stage 0") into the index
 	 * will always replace all non-merged entries..
 	 */
-	if (pos < active_nr && ce_stage(ce) == 0) {
-		while (same_name(active_cache[pos], ce)) {
+	if (pos < get_num_cache_entries(cache) && ce_stage(ce) == 0) {
+		while (ce_same_name(get_cache_entry(cache, pos), ce)) {
 			ok_to_add = 1;
-			if (!remove_entry_at(pos))
+			if (!remove_cache_entry_at(cache, pos))
 				break;
 		}
 	}
@@ -254,25 +312,24 @@
 	if (!ok_to_add)
 		return -1;
 
-	if (check_file_directory_conflict(ce, ok_to_replace)) {
+	if (check_file_directory_conflict(cache, ce, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
-		pos = cache_name_pos(ce->name, htons(ce->ce_flags));
+		pos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));
 		pos = -pos-1;
 	}
 
 	/* Make sure the array is big enough .. */
-	if (active_nr == active_alloc) {
-		active_alloc = alloc_nr(active_alloc);
-		active_cache = xrealloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+	if (cache->num_entries == cache->allocated_entries) {
+		cache->allocated_entries = alloc_nr(cache->allocated_entries);
+		cache->entries = xrealloc(cache->entries, cache->allocated_entries * sizeof(struct cache_entry *));
 	}
 
 	/* Add it in.. */
-	active_nr++;
-	if (active_nr > pos)
-		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
-	active_cache_changed = 1;
+	cache->num_entries++;
+	if (cache->num_entries > pos)
+		memmove(cache->entries + pos + 1, cache->entries + pos, (cache->num_entries - pos - 1) * sizeof(ce));
+	set_cache_entry(cache, ce, pos);
 	return 0;
 }
 
@@ -293,54 +350,56 @@
 	return 0;
 }
 
-int read_cache(void)
+struct cache *read_cache(void)
 {
 	int fd, i;
 	struct stat st;
-	unsigned long size, offset;
-	void *map;
-	struct cache_header *hdr;
-
-	errno = EBUSY;
-	if (active_cache)
-		return error("more than one cachefile");
+	unsigned long offset;
+	struct cache *cache = new_cache();
+
 	errno = ENOENT;
 	fd = open(get_index_file(), O_RDONLY);
-	if (fd < 0)
-		return (errno == ENOENT) ? 0 : error("open failed");
+	if (fd < 0) {
+		if (errno == ENOENT)
+			return cache;
+		else {
+			free_cache(cache);
+			return NULL;
+		}
+	}
 
-	size = 0; // avoid gcc warning
-	map = (void *)-1;
 	if (!fstat(fd, &st)) {
-		size = st.st_size;
+		cache->map.size = st.st_size;
 		errno = EINVAL;
-		if (size >= sizeof(struct cache_header) + 20)
-			map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+		if (cache->map.size >= sizeof(struct cache_header) + 20)
+			cache->map.ptr = mmap(NULL, cache->map.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
 	}
 	close(fd);
-	if (-1 == (int)(long)map)
-		return error("mmap failed");
+	if (MAP_FAILED == cache->map.ptr) {
+		error("mmap failed");
+		free_cache(cache);
+		return NULL;
+	}
 
-	hdr = map;
-	if (verify_hdr(hdr, size) < 0)
-		goto unmap;
-
-	active_nr = ntohl(hdr->hdr_entries);
-	active_alloc = alloc_nr(active_nr);
-	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
-
-	offset = sizeof(*hdr);
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = map + offset;
-		offset = offset + ce_size(ce);
-		active_cache[i] = ce;
+	cache->header = cache->map.ptr;
+	if (verify_hdr(cache->header, cache->map.size) < 0) {
+		free_cache(cache);
+		errno = EINVAL;
+		error("verify header failed");
+		return NULL;
 	}
-	return active_nr;
 
-unmap:
-	munmap(map, size);
-	errno = EINVAL;
-	return error("verify header failed");
+	cache->num_entries = ntohl(cache->header->hdr_entries);
+	cache->allocated_entries = alloc_nr(cache->num_entries);
+	cache->entries = xcalloc(cache->allocated_entries, sizeof(struct cache_entry *));
+
+	offset = sizeof(*cache->header);
+	for (i = 0; i < cache->num_entries; i++) {
+		struct cache_entry *ce = cache->map.ptr + offset;
+		offset = offset + ce_size(ce);
+		cache->entries[i] = ce;
+	}
+	return cache;
 }
 
 #define WRITE_BUFFER_SIZE 8192
@@ -386,7 +445,7 @@
 	return 0;
 }
 
-int write_cache(int newfd, struct cache_entry **cache, int entries)
+int write_cache(struct cache *cache, int newfd)
 {
 	SHA_CTX c;
 	struct cache_header hdr;
@@ -394,14 +453,14 @@
 
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(2);
-	hdr.hdr_entries = htonl(entries);
+	hdr.hdr_entries = htonl(get_num_cache_entries(cache));
 
 	SHA1_Init(&c);
 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
 			return -1;
 	}
Index: read-tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/read-tree.c  (mode:100644)
+++ uncommitted/read-tree.c  (mode:100644)
@@ -7,7 +7,7 @@
 
 static int stage = 0;
 
-static int unpack_tree(unsigned char *sha1)
+static int unpack_tree(struct cache *cache, unsigned char *sha1)
 {
 	void *buffer;
 	unsigned long size;
@@ -16,7 +16,7 @@
 	buffer = read_object_with_reference(sha1, "tree", &size, 0);
 	if (!buffer)
 		return -1;
-	ret = read_tree(buffer, size, stage);
+	ret = read_tree(cache, buffer, size, stage);
 	free(buffer);
 	return ret;
 }
@@ -93,26 +93,30 @@
 	return NULL;
 }
 
-static void trivially_merge_cache(struct cache_entry **src, int nr)
+/* rather than doing the 'right' thing of deleting entries as we merge,
+ * walk dst through the cache, overwriting entries as we go and at the
+ * end truncate the size of the cache */
+static void trivially_merge_cache(struct cache *cache)
 {
 	static struct cache_entry null_entry;
-	struct cache_entry **dst = src;
 	struct cache_entry *old = &null_entry;
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
-	while (nr) {
+	while (src < nr) {
 		struct cache_entry *ce, *result;
 
-		ce = src[0];
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
 			old = ce;
 			src++;
-			nr--;
-			active_nr--;
 			continue;
 		}
-		if (nr > 2 && (result = merge_entries(ce, src[1], src[2])) != NULL) {
+		if ((src < (nr - 2)) &&
+		    (result = merge_entries(ce,
+					    get_cache_entry(cache, src + 1),
+					    get_cache_entry(cache, src + 2))) != NULL) {
 			/*
 			 * See if we can re-use the old CE directly?
 			 * That way we get the uptodate stat info.
@@ -122,40 +126,46 @@
 			ce = result;
 			ce->ce_flags &= ~htons(CE_STAGEMASK);
 			src += 2;
-			nr -= 2;
-			active_nr -= 2;
 		}
-		*dst++ = ce;
+		set_cache_entry(cache, ce, dst);
+		dst++;
 		src++;
+	}
+	/* this could be replaced by a truncate api */
+	while (nr > dst) {
 		nr--;
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
-static void merge_stat_info(struct cache_entry **src, int nr)
+static void merge_stat_info(struct cache *cache)
 {
 	static struct cache_entry null_entry;
-	struct cache_entry **dst = src;
 	struct cache_entry *old = &null_entry;
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
-	while (nr) {
+	while (src < nr) {
 		struct cache_entry *ce;
 
-		ce = src[0];
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
 			old = ce;
 			src++;
-			nr--;
-			active_nr--;
 			continue;
 		}
 		if (path_matches(ce, old) && same(ce, old))
 			*ce = *old;
 		ce->ce_flags &= ~htons(CE_STAGEMASK);
-		*dst++ = ce;
+		set_cache_entry(cache, ce, dst);
+		dst++;
 		src++;
+	}
+	/* this could be replaced by a truncate api */
+	while (nr > dst) {
 		nr--;
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
@@ -167,6 +177,7 @@
 	unsigned char sha1[20];
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct cache *cache = NULL;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -185,9 +196,9 @@
 			int i;
 			if (stage)
 				die("-m needs to come first");
-			read_cache();
-			for (i = 0; i < active_nr; i++) {
-				if (ce_stage(active_cache[i]))
+			cache = read_cache();
+			for (i = 0; i < get_num_cache_entries(cache); i++) {
+				if (ce_stage(get_cache_entry(cache, i)))
 					die("you need to resolve your current index first");
 			}
 			stage = 1;
@@ -198,23 +209,25 @@
 			usage(read_tree_usage);
 		if (stage > 3)
 			usage(read_tree_usage);
-		if (unpack_tree(sha1) < 0)
+		if (!cache)
+			cache = new_cache();
+		if (unpack_tree(cache, sha1) < 0)
 			die("failed to unpack tree object %s", arg);
 		stage++;
 	}
 	if (merge) {
 		switch (stage) {
 		case 4:	/* Three-way merge */
-			trivially_merge_cache(active_cache, active_nr);
+			trivially_merge_cache(cache);
 			break;
 		case 2:	/* Just read a tree, merge with old cache contents */
-			merge_stat_info(active_cache, active_nr);
+			merge_stat_info(cache);
 			break;
 		default:
 			die("just how do you expect me to merge %d trees?", stage-1);
 		}
 	}
-	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
+	if (write_cache(cache, newfd) || rename(lockfile, indexfile))
 		die("unable to write new index file");
 	lockfile_name = NULL;
 	return 0;
Index: sha1_file.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/sha1_file.c  (mode:100644)
+++ uncommitted/sha1_file.c  (mode:100644)
@@ -302,7 +302,7 @@
 	}
 	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if (-1 == (int)(long)map)
+	if (MAP_FAILED == map)
 		return NULL;
 	*size = st.st_size;
 	return map;
@@ -587,7 +587,7 @@
 	if (size)
 		buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if ((int)(long)buf == -1)
+	if (buf == MAP_FAILED)
 		return -1;
 
 	ret = write_sha1_file(buf, size, "blob", sha1);
Index: tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/tree.c  (mode:100644)
+++ uncommitted/tree.c  (mode:100644)
@@ -5,7 +5,8 @@
 
 const char *tree_type = "tree";
 
-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int read_one_entry(struct cache *cache, unsigned char *sha1, const char *base,
+		          int baselen, const char *pathname, unsigned mode, int stage)
 {
 	int len = strlen(pathname);
 	unsigned int size = cache_entry_size(baselen + len);
@@ -18,10 +19,10 @@
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+	return add_cache_entry(cache, ce, ADD_CACHE_OK_TO_ADD);
 }
 
-static int read_tree_recursive(void *buffer, unsigned long size,
+static int read_tree_recursive(struct cache* cache, void *buffer, unsigned long size,
 			       const char *base, int baselen, int stage)
 {
 	while (size) {
@@ -53,7 +54,7 @@
 			memcpy(newbase, base, baselen);
 			memcpy(newbase + baselen, path, pathlen);
 			newbase[baselen + pathlen] = '/';
-			retval = read_tree_recursive(eltbuf, eltsize,
+			retval = read_tree_recursive(cache, eltbuf, eltsize,
 						     newbase,
 						     baselen + pathlen + 1, stage);
 			free(eltbuf);
@@ -62,15 +63,15 @@
 				return -1;
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
+		if (read_one_entry(cache, sha1, base, baselen, path, mode, stage) < 0)
 			return -1;
 	}
 	return 0;
 }
 
-int read_tree(void *buffer, unsigned long size, int stage)
+int read_tree(struct cache *cache, void *buffer, unsigned long size, int stage)
 {
-	return read_tree_recursive(buffer, size, "", 0, stage);
+	return read_tree_recursive(cache, buffer, size, "", 0, stage);
 }
 
 struct tree *lookup_tree(unsigned char *sha1)
Index: update-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/update-cache.c  (mode:100644)
+++ uncommitted/update-cache.c  (mode:100644)
@@ -51,7 +51,7 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(struct cache *cache, char *path)
 {
 	int size, namelen, option, status;
 	struct cache_entry *ce;
@@ -71,7 +71,7 @@
 		 */
 		if (status == 0 || (errno == ENOENT || errno == ENOTDIR)) {
 			if (allow_remove)
-				return remove_file_from_cache(path);
+				return remove_file_from_cache(cache, path);
 		}
 		return error("open(\"%s\"): %s", path, strerror(errno));
 	}
@@ -106,7 +106,7 @@
 	}
 	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
 	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
-	return add_cache_entry(ce, option);
+	return add_cache_entry(cache, ce, option);
 }
 
 static int match_data(int fd, void *buffer, unsigned long size)
@@ -191,7 +191,7 @@
 	if (lstat(ce->name, &st) < 0)
 		return ERR_PTR(-errno);
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (!changed)
 		return ce;
 
@@ -222,19 +222,19 @@
 	return updated;
 }
 
-static int refresh_cache(void)
+static int refresh_cache(struct cache *cache)
 {
 	int i;
 	int has_errors = 0;
 
-	for (i = 0; i < active_nr; i++) {
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
 		struct cache_entry *ce, *new;
-		ce = active_cache[i];
+		ce = get_cache_entry(cache, i);
 		if (ce_stage(ce)) {
 			printf("%s: needs merge\n", ce->name);
 			has_errors = 1;
-			while ((i < active_nr) &&
-			       ! strcmp(active_cache[i]->name, ce->name))
+			while ((i < get_num_cache_entries(cache)) &&
+			       ! strcmp(get_cache_entry(cache, i)->name, ce->name))
 				i++;
 			i--;
 			continue;
@@ -248,11 +248,7 @@
 			}
 			continue;
 		}
-		active_cache_changed = 1;
-		/* You can NOT just free active_cache[i] here, since it
-		 * might not be necessarily malloc()ed but can also come
-		 * from mmap(). */
-		active_cache[i] = new;
+		set_cache_entry(cache, new, i);
 	}
 	return has_errors;
 }
@@ -285,7 +281,7 @@
 	}
 }
 
-static int add_cacheinfo(char *arg1, char *arg2, char *arg3)
+static int add_cacheinfo(struct cache *cache, char *arg1, char *arg2, char *arg3)
 {
 	int size, len, option;
 	unsigned int mode;
@@ -310,7 +306,7 @@
 	ce->ce_mode = create_ce_mode(mode);
 	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
 	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
-	return add_cache_entry(ce, option);
+	return add_cache_entry(cache, ce, option);
 }
 
 static const char *lockfile_name = NULL;
@@ -328,10 +324,11 @@
 
 int main(int argc, char **argv)
 {
-	int i, newfd, entries, has_errors = 0;
+	int i, newfd, has_errors = 0;
 	int allow_options = 1;
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct cache *cache = NULL;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -343,8 +340,8 @@
 	atexit(remove_lock_file);
 	lockfile_name = lockfile;
 
-	entries = read_cache();
-	if (entries < 0)
+	cache = read_cache();
+	if (!cache)
 		die("cache corrupted");
 
 	for (i = 1 ; i < argc; i++) {
@@ -368,13 +365,13 @@
 				continue;
 			}
 			if (!strcmp(path, "--refresh")) {
-				has_errors |= refresh_cache();
+				has_errors |= refresh_cache(cache);
 				continue;
 			}
 			if (!strcmp(path, "--cacheinfo")) {
 				if (i+3 >= argc)
 					die("update-cache: --cacheinfo <mode> <sha1> <path>");
-				if (add_cacheinfo(argv[i+1], argv[i+2], argv[i+3]))
+				if (add_cacheinfo(cache, argv[i+1], argv[i+2], argv[i+3]))
 					die("update-cache: --cacheinfo cannot add %s", argv[i+3]);
 				i += 3;
 				continue;
@@ -382,7 +379,7 @@
 			if (!strcmp(path, "--force-remove")) {
 				if (argc <= i + 1)
 					die("update-cache: --force-remove <path>");
-				if (remove_file_from_cache(argv[i+1]))
+				if (remove_file_from_cache(cache, argv[i+1]))
 					die("update-cache: --force-remove cannot remove %s", argv[i+1]);
 				i++;
 				continue;
@@ -398,10 +395,10 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(cache, path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
+	if (write_cache(cache, newfd) || rename(lockfile, indexfile))
 		die("Unable to write new cachefile");
 
 	lockfile_name = NULL;
Index: write-tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/write-tree.c  (mode:100644)
+++ uncommitted/write-tree.c  (mode:100644)
@@ -17,7 +17,7 @@
 	return ret;
 }
 
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
+static int write_tree(struct cache *cache, int start_pos, const char *base, int baselen, unsigned char *returnsha1)
 {
 	unsigned char subdir_sha1[20];
 	unsigned long size, offset;
@@ -30,8 +30,8 @@
 	offset = 0;
 
 	nr = 0;
-	while (nr < maxentries) {
-		struct cache_entry *ce = cachep[nr];
+	while ((start_pos + nr) < get_num_cache_entries(cache)) {
+		struct cache_entry *ce = get_cache_entry(cache, start_pos + nr);
 		const char *pathname = ce->name, *filename, *dirname;
 		int pathlen = ce_namelen(ce), entrylen;
 		unsigned char *sha1;
@@ -41,16 +41,13 @@
 		if (baselen >= pathlen || memcmp(base, pathname, baselen))
 			break;
 
-		sha1 = ce->sha1;
-		mode = ntohl(ce->ce_mode);
-
 		/* Do we have _further_ subdirectories? */
 		filename = pathname + baselen;
 		dirname = strchr(filename, '/');
 		if (dirname) {
 			int subdir_written;
 
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
+			subdir_written = write_tree(cache, start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);
 			nr += subdir_written;
 
 			/* Now we need to write out the directory entry into this tree.. */
@@ -60,6 +57,9 @@
 			/* ..but the directory entry doesn't count towards the total count */
 			nr--;
 			sha1 = subdir_sha1;
+		} else {
+			sha1 = ce->sha1;
+			mode = ntohl(ce->ce_mode);
 		}
 
 		if (check_valid_sha1(sha1) < 0)
@@ -85,16 +85,19 @@
 int main(int argc, char **argv)
 {
 	int i, funny;
-	int entries = read_cache();
+	struct cache *cache = read_cache();
+	int entries;
 	unsigned char sha1[20];
 
-	if (entries < 0)
+	if (!cache)
 		die("write-tree: error reading cache");
 
+	entries = get_num_cache_entries(cache);
+
 	/* Verify that the tree is merged */
 	funny = 0;
 	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = active_cache[i];
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
 			if (10 < ++funny) {
 				fprintf(stderr, "...\n");
@@ -116,8 +119,8 @@
 		 * the cache is sorted.  Also path can appear only once,
 		 * which means conflicting one would immediately follow.
 		 */
-		const char *this_name = active_cache[i]->name;
-		const char *next_name = active_cache[i+1]->name;
+		const char *this_name = get_cache_entry(cache, i)->name;
+		const char *next_name = get_cache_entry(cache, i+1)->name;
 		int this_len = strlen(this_name);
 		if (this_len < strlen(next_name) &&
 		    strncmp(this_name, next_name, this_len) == 0 &&
@@ -134,7 +137,7 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+	if (write_tree(cache, 0, "", 0, sha1) != entries)
 		die("write-tree: internal error");
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;

  parent reply	other threads:[~2005-05-15  9:16 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-05-09 18:01 Darcs-git: a few notes for Git hackers Juliusz Chroboczek
2005-05-09 21:28 ` Petr Baudis
2005-05-09 22:08   ` Juliusz Chroboczek
2005-05-09 22:20     ` H. Peter Anvin
2005-05-09 22:46       ` Juliusz Chroboczek
2005-05-09 22:50         ` H. Peter Anvin
2005-05-09 23:08           ` Juliusz Chroboczek
2005-05-09 22:50   ` Brad Roberts
2005-05-09 23:02     ` Petr Baudis
2005-05-09 23:34     ` Junio C Hamano
2005-05-10 12:55     ` Brad Roberts
     [not found]       ` <Pine.LNX.4.44.0505141851340.2136-200000@bellevue.puremagic.com>
2005-05-15  9:11         ` Brad Roberts [this message]
2005-05-15 11:48         ` Petr Baudis
2005-05-15 19:06           ` Brad Roberts
2005-05-15 19:25             ` Junio C Hamano
2005-05-15 19:48               ` Petr Baudis
2005-05-15 20:10                 ` Brad Roberts
2005-05-15 20:36                   ` Junio C Hamano
2005-05-17 20:19                     ` Petr Baudis
2005-05-17 20:21             ` Petr Baudis
2005-05-10  0:07 ` Daniel Barkalow

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.44.0505150208020.2136-200000@bellevue.puremagic.com \
    --to=braddr@puremagic.com \
    --cc=Juliusz.Chroboczek@pps.jussieu.fr \
    --cc=git@vger.kernel.org \
    --cc=pasky@ucw.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).