Merge branch 'js/lsfix'

* js/lsfix:
  Initialize lock_file struct to all zero.
  Make git-update-ref a builtin
  Make git-update-index a builtin
  Make git-stripspace a builtin
  Make git-mailinfo a builtin
  Make git-mailsplit a builtin
  Make git-write-tree a builtin
diff --git a/Makefile b/Makefile
index 69b5500..a5b6784 100644
--- a/Makefile
+++ b/Makefile
@@ -144,34 +144,33 @@
 
 # The ones that do not have to link with lcrypto, lz nor xdiff.
 SIMPLE_PROGRAMS = \
-	git-mailsplit$X \
-	git-stripspace$X git-daemon$X
+	git-daemon$X
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
 	git-checkout-index$X \
 	git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
 	git-hash-object$X git-index-pack$X git-local-fetch$X \
-	git-mailinfo$X git-merge-base$X \
+	git-merge-base$X \
 	git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
 	git-peek-remote$X git-prune-packed$X git-receive-pack$X \
 	git-send-pack$X git-shell$X \
 	git-show-index$X git-ssh-fetch$X \
 	git-ssh-upload$X git-unpack-file$X \
-	git-unpack-objects$X git-update-index$X git-update-server-info$X \
-	git-upload-pack$X git-verify-pack$X git-write-tree$X \
-	git-update-ref$X git-symbolic-ref$X \
+	git-unpack-objects$X git-update-server-info$X \
+	git-upload-pack$X git-verify-pack$X \
+	git-symbolic-ref$X \
 	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
 	git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
 
-BUILT_INS = git-log$X git-whatchanged$X git-show$X \
-	git-count-objects$X git-diff$X git-push$X \
-	git-grep$X git-add$X git-rm$X git-rev-list$X \
-	git-check-ref-format$X git-rev-parse$X \
+BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
+	git-count-objects$X git-diff$X git-push$X git-mailsplit$X \
+	git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \
+	git-check-ref-format$X git-rev-parse$X git-mailinfo$X \
 	git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
 	git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
-	git-read-tree$X git-commit-tree$X \
-	git-apply$X git-show-branch$X git-diff-files$X \
+	git-read-tree$X git-commit-tree$X git-write-tree$X \
+	git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
 	git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -222,12 +221,13 @@
 	builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
 	builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
 	builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
-	builtin-tar-tree.o builtin-upload-tar.o \
-	builtin-ls-files.o builtin-ls-tree.o \
-	builtin-read-tree.o builtin-commit-tree.o \
+	builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
+	builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
+	builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
 	builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
 	builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
-	builtin-cat-file.o
+	builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
+	builtin-update-ref.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
@@ -380,9 +380,7 @@
 	else
 		ICONV_LINK =
 	endif
-	LIB_4_ICONV = $(ICONV_LINK) -liconv
-else
-	LIB_4_ICONV =
+	LIBS += $(ICONV_LINK) -liconv
 endif
 ifdef NEEDS_SOCKET
 	LIBS += -lsocket
@@ -566,10 +564,6 @@
 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIB_FILE) $(SIMPLE_LIB)
 
-git-mailinfo$X: mailinfo.o $(LIB_FILE)
-	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-		$(LIB_FILE) $(SIMPLE_LIB) $(LIB_4_ICONV)
-
 git-local-fetch$X: fetch.o
 git-ssh-fetch$X: rsh.o fetch.o
 git-ssh-upload$X: rsh.o
diff --git a/mailinfo.c b/builtin-mailinfo.c
similarity index 94%
rename from mailinfo.c
rename to builtin-mailinfo.c
index d9b74f3..821642a 100644
--- a/mailinfo.c
+++ b/builtin-mailinfo.c
@@ -12,11 +12,12 @@
 #endif
 #include "git-compat-util.h"
 #include "cache.h"
+#include "builtin.h"
 
-static FILE *cmitmsg, *patchfile;
+static FILE *cmitmsg, *patchfile, *fin, *fout;
 
 static int keep_subject = 0;
-static char *metainfo_charset = NULL;
+static const char *metainfo_charset = NULL;
 static char line[1000];
 static char date[1000];
 static char name[1000];
@@ -49,7 +50,7 @@
 
 	/* This is fallback, so do not bother if we already have an
 	 * e-mail address.
-	 */ 
+	 */
 	if (*email)
 		return 0;
 
@@ -322,13 +323,13 @@
 			if (remove <= len *2) {
 				subject = p+1;
 				continue;
-			}	
+			}
 			break;
 		}
 		eatspace(subject);
 		return subject;
 	}
-}			
+}
 
 static void cleanup_space(char *buf)
 {
@@ -648,7 +649,7 @@
 	cleanup_space(email);
 	cleanup_space(sub);
 
-	printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
+	fprintf(fout, "Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
 	       name, email, sub, date);
 }
 
@@ -685,7 +686,7 @@
 			continue;
 
 		fputs(line, cmitmsg);
-	} while (fgets(line, sizeof(line), stdin) != NULL);
+	} while (fgets(line, sizeof(line), fin) != NULL);
 	fclose(cmitmsg);
 	cmitmsg = NULL;
 	return 0;
@@ -706,7 +707,7 @@
 		decode_transfer_encoding(line);
 		fputs(line, patchfile);
 		patch_lines++;
-	} while (fgets(line, sizeof(line), stdin) != NULL);
+	} while (fgets(line, sizeof(line), fin) != NULL);
 }
 
 /* multipart boundary and transfer encoding are set up for us, and we
@@ -719,7 +720,7 @@
 {
 	int n = 0;
 
-	while (fgets(line, sizeof(line), stdin) != NULL) {
+	while (fgets(line, sizeof(line), fin) != NULL) {
 	again:
 		n++;
 		if (is_multipart_boundary(line))
@@ -740,7 +741,7 @@
 	int part_num = 0;
 
 	/* Skip up to the first boundary */
-	while (fgets(line, sizeof(line), stdin) != NULL)
+	while (fgets(line, sizeof(line), fin) != NULL)
 		if (is_multipart_boundary(line)) {
 			part_num = 1;
 			break;
@@ -749,7 +750,7 @@
 		return;
 	/* We are on boundary line.  Start slurping the subhead. */
 	while (1) {
-		int hdr = read_one_header_line(line, sizeof(line), stdin);
+		int hdr = read_one_header_line(line, sizeof(line), fin);
 		if (!hdr) {
 			if (handle_multipart_one_part(&seen) < 0)
 				return;
@@ -781,10 +782,45 @@
 	}
 }
 
+int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
+	     const char *msg, const char *patch)
+{
+	keep_subject = ks;
+	metainfo_charset = encoding;
+	fin = in;
+	fout = out;
+
+	cmitmsg = fopen(msg, "w");
+	if (!cmitmsg) {
+		perror(msg);
+		return -1;
+	}
+	patchfile = fopen(patch, "w");
+	if (!patchfile) {
+		perror(patch);
+		fclose(cmitmsg);
+		return -1;
+	}
+	while (1) {
+		int hdr = read_one_header_line(line, sizeof(line), fin);
+		if (!hdr) {
+			if (multipart_boundary[0])
+				handle_multipart_body();
+			else
+				handle_body();
+			handle_info();
+			break;
+		}
+		check_header_line(line);
+	}
+
+	return 0;
+}
+
 static const char mailinfo_usage[] =
 	"git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
 
-int main(int argc, char **argv)
+int cmd_mailinfo(int argc, const char **argv, char **envp)
 {
 	/* NEEDSWORK: might want to do the optional .git/ directory
 	 * discovery
@@ -805,27 +841,6 @@
 
 	if (argc != 3)
 		usage(mailinfo_usage);
-	cmitmsg = fopen(argv[1], "w");
-	if (!cmitmsg) {
-		perror(argv[1]);
-		exit(1);
-	}
-	patchfile = fopen(argv[2], "w");
-	if (!patchfile) {
-		perror(argv[2]);
-		exit(1);
-	}
-	while (1) {
-		int hdr = read_one_header_line(line, sizeof(line), stdin);
-		if (!hdr) {
-			if (multipart_boundary[0])
-				handle_multipart_body();
-			else
-				handle_body();
-			handle_info();
-			break;
-		}
-		check_header_line(line);
-	}
-	return 0;
+
+	return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]);
 }
diff --git a/mailsplit.c b/builtin-mailsplit.c
similarity index 84%
rename from mailsplit.c
rename to builtin-mailsplit.c
index 70a569c..e2a0058 100644
--- a/mailsplit.c
+++ b/builtin-mailsplit.c
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <stdio.h>
 #include "cache.h"
+#include "builtin.h"
 
 static const char git_mailsplit_usage[] =
 "git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
@@ -102,14 +103,48 @@
 	exit(1);
 }
 
-int main(int argc, const char **argv)
+int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
 {
-	int nr = 0, nr_prec = 4;
+	char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+	int ret = -1;
+
+	while (*mbox) {
+		const char *file = *mbox++;
+		FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+		int file_done = 0;
+
+		if ( !f ) {
+			error("cannot open mbox %s", file);
+			goto out;
+		}
+
+		if (fgets(buf, sizeof(buf), f) == NULL) {
+			if (f == stdin)
+				break; /* empty stdin is OK */
+			error("cannot read mbox %s", file);
+			goto out;
+		}
+
+		while (!file_done) {
+			sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+			file_done = split_one(f, name, allow_bare);
+		}
+
+		if (f != stdin)
+			fclose(f);
+	}
+	ret = skip;
+out:
+	free(name);
+	return ret;
+}
+int cmd_mailsplit(int argc, const char **argv, char **envp)
+{
+	int nr = 0, nr_prec = 4, ret;
 	int allow_bare = 0;
 	const char *dir = NULL;
 	const char **argp;
 	static const char *stdin_only[] = { "-", NULL };
-	char *name;
 
 	for (argp = argv+1; *argp; argp++) {
 		const char *arg = *argp;
@@ -158,31 +193,9 @@
 			argp = stdin_only;
 	}
 
-	name = xmalloc(strlen(dir) + 2 + 3 * sizeof(nr));
+	ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
+	if (ret != -1)
+		printf("%d\n", ret);
 
-	while (*argp) {
-		const char *file = *argp++;
-		FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
-		int file_done = 0;
-
-		if ( !f )
-			die ("cannot open mbox %s", file);
-
-		if (fgets(buf, sizeof(buf), f) == NULL) {
-			if (f == stdin)
-				break; /* empty stdin is OK */
-			die("cannot read mbox %s", file);
-		}
-
-		while (!file_done) {
-			sprintf(name, "%s/%0*d", dir, nr_prec, ++nr);
-			file_done = split_one(f, name, allow_bare);
-		}
-
-		if (f != stdin)
-			fclose(f);
-	}
-
-	printf("%d\n", nr);
-	return 0;
+	return ret == -1;
 }
diff --git a/stripspace.c b/builtin-stripspace.c
similarity index 75%
rename from stripspace.c
rename to builtin-stripspace.c
index 65a6346..2ce1264 100644
--- a/stripspace.c
+++ b/builtin-stripspace.c
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include "builtin.h"
 
 /*
  * Remove empty lines from the beginning and end.
@@ -28,21 +29,21 @@
 	return 1;
 }
 
-int main(int argc, char **argv)
+void stripspace(FILE *in, FILE *out)
 {
 	int empties = -1;
 	int incomplete = 0;
 	char line[1024];
 
-	while (fgets(line, sizeof(line), stdin)) {
+	while (fgets(line, sizeof(line), in)) {
 		incomplete = cleanup(line);
 
 		/* Not just an empty line? */
 		if (line[0] != '\n') {
 			if (empties > 0)
-				putchar('\n');
+				fputc('\n', out);
 			empties = 0;
-			fputs(line, stdout);
+			fputs(line, out);
 			continue;
 		}
 		if (empties < 0)
@@ -50,6 +51,11 @@
 		empties++;
 	}
 	if (incomplete)
-		putchar('\n');
+		fputc('\n', out);
+}
+
+int cmd_stripspace(int argc, const char **argv, char **envp)
+{
+	stripspace(stdin, stdout);
 	return 0;
 }
diff --git a/update-index.c b/builtin-update-index.c
similarity index 97%
rename from update-index.c
rename to builtin-update-index.c
index fbccc4a..ef50243 100644
--- a/update-index.c
+++ b/builtin-update-index.c
@@ -8,6 +8,7 @@
 #include "quote.h"
 #include "cache-tree.h"
 #include "tree-walk.h"
+#include "builtin.h"
 
 /*
  * Default to not allowing changes to the list of files. The
@@ -186,8 +187,6 @@
 	die("git-update-index: cannot chmod %cx '%s'", flip, path);
 }
 
-static struct lock_file lock_file;
-
 static void update_one(const char *path, const char *prefix, int prefix_length)
 {
 	const char *p = prefix_path(prefix, prefix_length, path);
@@ -238,7 +237,7 @@
 		 * (2) mode SP type SP sha1          TAB path
 		 * The second format is to stuff git-ls-tree output
 		 * into the index file.
-		 * 
+		 *
 		 * (3) mode         SP sha1 SP stage TAB path
 		 * This format is to put higher order stages into the
 		 * index file and matches git-ls-files --stage output.
@@ -477,7 +476,7 @@
 	return 0;
 }
 
-int main(int argc, const char **argv)
+int cmd_update_index(int argc, const char **argv, char **envp)
 {
 	int i, newfd, entries, has_errors = 0, line_termination = '\n';
 	int allow_options = 1;
@@ -486,12 +485,16 @@
 	int prefix_length = prefix ? strlen(prefix) : 0;
 	char set_executable_bit = 0;
 	unsigned int refresh_flags = 0;
+	struct lock_file *lock_file;
 
 	git_config(git_default_config);
 
-	newfd = hold_lock_file_for_update(&lock_file, get_index_file());
+	/* We can't free this memory, it becomes part of a linked list parsed atexit() */
+	lock_file = xcalloc(1, sizeof(struct lock_file));
+
+	newfd = hold_lock_file_for_update(lock_file, get_index_file());
 	if (newfd < 0)
-		die("unable to create new index file");
+		die("unable to create new cachefile");
 
 	entries = read_cache();
 	if (entries < 0)
@@ -645,9 +648,11 @@
  finish:
 	if (active_cache_changed) {
 		if (write_cache(newfd, active_cache, active_nr) ||
-		    commit_lock_file(&lock_file))
+		    commit_lock_file(lock_file))
 			die("Unable to write new index file");
 	}
 
+	rollback_lock_file(lock_file);
+
 	return has_errors ? 1 : 0;
 }
diff --git a/update-ref.c b/builtin-update-ref.c
similarity index 88%
rename from update-ref.c
rename to builtin-update-ref.c
index a1e6bb9..00333c7 100644
--- a/update-ref.c
+++ b/builtin-update-ref.c
@@ -1,10 +1,11 @@
 #include "cache.h"
 #include "refs.h"
+#include "builtin.h"
 
 static const char git_update_ref_usage[] =
 "git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
 
-int main(int argc, char **argv)
+int cmd_update_ref(int argc, const char **argv, char **envp)
 {
 	const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
 	struct ref_lock *lock;
@@ -52,5 +53,7 @@
 		return 1;
 	if (write_ref_sha1(lock, sha1, msg) < 0)
 		return 1;
+
+	/* write_ref_sha1 always unlocks the ref, no need to do it explicitly */
 	return 0;
 }
diff --git a/write-tree.c b/builtin-write-tree.c
similarity index 66%
rename from write-tree.c
rename to builtin-write-tree.c
index bd07da6..70e9b6f 100644
--- a/write-tree.c
+++ b/builtin-write-tree.c
@@ -3,29 +3,72 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#include "builtin.h"
 #include "cache.h"
 #include "tree.h"
 #include "cache-tree.h"
 
-static int missing_ok = 0;
-static char *prefix = NULL;
-
 static const char write_tree_usage[] =
 "git-write-tree [--missing-ok] [--prefix=<prefix>/]";
 
-static struct lock_file lock_file;
-
-int main(int argc, char **argv)
+int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
 {
 	int entries, was_valid, newfd;
 
+	/* We can't free this memory, it becomes part of a linked list parsed atexit() */
+	struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+	newfd = hold_lock_file_for_update(lock_file, get_index_file());
+
+	entries = read_cache();
+	if (entries < 0)
+		die("git-write-tree: error reading cache");
+
+	if (!active_cache_tree)
+		active_cache_tree = cache_tree();
+
+	was_valid = cache_tree_fully_valid(active_cache_tree);
+
+	if (!was_valid) {
+		if (cache_tree_update(active_cache_tree,
+				      active_cache, active_nr,
+				      missing_ok, 0) < 0)
+			die("git-write-tree: error building trees");
+		if (0 <= newfd) {
+			if (!write_cache(newfd, active_cache, active_nr))
+				commit_lock_file(lock_file);
+		}
+		/* Not being able to write is fine -- we are only interested
+		 * in updating the cache-tree part, and if the next caller
+		 * ends up using the old index with unupdated cache-tree part
+		 * it misses the work we did here, but that is just a
+		 * performance penalty and not a big deal.
+		 */
+	}
+
+	if (prefix) {
+		struct cache_tree *subtree =
+			cache_tree_find(active_cache_tree, prefix);
+		memcpy(sha1, subtree->sha1, 20);
+	}
+	else
+		memcpy(sha1, active_cache_tree->sha1, 20);
+
+	rollback_lock_file(lock_file);
+
+	return 0;
+}
+
+int cmd_write_tree(int argc, const char **argv, char **envp)
+{
+	int missing_ok = 0, ret;
+	const char *prefix = NULL;
+	unsigned char sha1[20];
+
 	setup_git_directory();
 
-	newfd = hold_lock_file_for_update(&lock_file, get_index_file());
-	entries = read_cache();
-
 	while (1 < argc) {
-		char *arg = argv[1];
+		const char *arg = argv[1];
 		if (!strcmp(arg, "--missing-ok"))
 			missing_ok = 1;
 		else if (!strncmp(arg, "--prefix=", 9))
@@ -38,35 +81,8 @@
 	if (argc > 2)
 		die("too many options");
 
-	if (entries < 0)
-		die("git-write-tree: error reading cache");
+	ret = write_tree(sha1, missing_ok, prefix);
+	printf("%s\n", sha1_to_hex(sha1));
 
-	if (!active_cache_tree)
-		active_cache_tree = cache_tree();
-
-	was_valid = cache_tree_fully_valid(active_cache_tree);
-	if (!was_valid) {
-		if (cache_tree_update(active_cache_tree,
-				      active_cache, active_nr,
-				      missing_ok, 0) < 0)
-			die("git-write-tree: error building trees");
-		if (0 <= newfd) {
-			if (!write_cache(newfd, active_cache, active_nr))
-				commit_lock_file(&lock_file);
-		}
-		/* Not being able to write is fine -- we are only interested
-		 * in updating the cache-tree part, and if the next caller
-		 * ends up using the old index with unupdated cache-tree part
-		 * it misses the work we did here, but that is just a
-		 * performance penalty and not a big deal.
-		 */
-	}
-	if (prefix) {
-		struct cache_tree *subtree =
-			cache_tree_find(active_cache_tree, prefix);
-		printf("%s\n", sha1_to_hex(subtree->sha1));
-	}
-	else
-		printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
-	return 0;
+	return ret;
 }
diff --git a/builtin.h b/builtin.h
index b9f36be..f12d5e6 100644
--- a/builtin.h
+++ b/builtin.h
@@ -1,6 +1,8 @@
 #ifndef BUILTIN_H
 #define BUILTIN_H
 
+#include <stdio.h>
+
 #ifndef PATH_MAX
 # define PATH_MAX 4096
 #endif
@@ -45,5 +47,18 @@
 extern int cmd_diff_tree(int argc, const char **argv, char **envp);
 extern int cmd_cat_file(int argc, const char **argv, char **envp);
 extern int cmd_rev_parse(int argc, const char **argv, char **envp);
+extern int cmd_update_index(int argc, const char **argv, char **envp);
+extern int cmd_update_ref(int argc, const char **argv, char **envp);
 
+extern int cmd_write_tree(int argc, const char **argv, char **envp);
+extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
+
+extern int cmd_mailsplit(int argc, const char **argv, char **envp);
+extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
+
+extern int cmd_mailinfo(int argc, const char **argv, char **envp);
+extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
+
+extern int cmd_stripspace(int argc, const char **argv, char **envp);
+extern void stripspace(FILE *in, FILE *out);
 #endif
diff --git a/git.c b/git.c
index 329ebec..94e9a4a 100644
--- a/git.c
+++ b/git.c
@@ -178,7 +178,13 @@
 		{ "diff-stages", cmd_diff_stages },
 		{ "diff-tree", cmd_diff_tree },
 		{ "cat-file", cmd_cat_file },
-		{ "rev-parse", cmd_rev_parse }
+		{ "rev-parse", cmd_rev_parse },
+		{ "write-tree", cmd_write_tree },
+		{ "mailsplit", cmd_mailsplit },
+		{ "mailinfo", cmd_mailinfo },
+		{ "stripspace", cmd_stripspace },
+		{ "update-index", cmd_update_index },
+		{ "update-ref", cmd_update_ref }
 	};
 	int i;