[RFC 4/8] UTF file names.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 builtin-add.c            |    5 +-
 builtin-checkout-index.c |   46 ++++++---
 builtin-ls-files.c       |   26 +++++-
 builtin-ls-tree.c        |   16 +++-
 builtin-rev-parse.c      |    7 +-
 builtin-update-index.c   |   18 +++-
 builtin-write-tree.c     |    5 +-
 diff.c                   |   97 ++++++++++++++------
 git-commit.sh            |    5 +
 git-compat-util.h        |   42 +++++++++
 merge-index.c            |   25 ++++--
 read-cache.c             |    8 +-
 setup.c                  |   28 +++++-
 t/t-utf-filenames.sh     |   95 +++++++++++++++++++
 utf.c                    |  230 ++++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 580 insertions(+), 73 deletions(-)
 create mode 100755 t/t-utf-filenames.sh

diff --git a/builtin-add.c b/builtin-add.c
index febb75e..62ea692 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -131,9 +131,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		return 0;
 	}
 
-	for (i = 0; i < dir.nr; i++)
+	for (i = 0; i < dir.nr; i++) {
+	  P(("Adding '%s'\n", dir.entries[i]->name));
 		add_file_to_index(dir.entries[i]->name, verbose);
-
+	}
 	if (active_cache_changed) {
 		if (write_cache(newfd, active_cache, active_nr) ||
 		    close(newfd) || commit_lock_file(&lock_file))
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index b097c88..745bf9a 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -57,16 +57,22 @@ static void write_tempfile_record(const char *name, int prefix_length)
 		for (i = 1; i < 4; i++) {
 			if (i > 1)
 				putchar(' ');
-			if (topath[i][0])
-				fputs(topath[i], stdout);
-			else
+			if (topath[i][0]) {
+				char localbuf[MAXPATHLEN];
+				localcpy(localbuf, topath[i], strlen(topath[i])+1);
+				fputs(localbuf, stdout);
+			} else
 				putchar('.');
 		}
-	} else
-		fputs(topath[checkout_stage], stdout);
-
+	} else {
+		char localbuf[MAXPATHLEN];
+		localcpy(localbuf, topath[checkout_stage], strlen(topath[checkout_stage])+1);
+		fputs(localbuf, stdout);
+	}
 	putchar('\t');
-	write_name_quoted("", 0, name + prefix_length,
+	char localbuf[MAXPATHLEN];
+	localcpy(localbuf, name + prefix_length, strlen(name + prefix_length) + 1);
+	write_name_quoted("", 0, localbuf, 
 		line_termination, stdout);
 	putchar(line_termination);
 
@@ -77,8 +83,11 @@ static void write_tempfile_record(const char *name, int prefix_length)
 
 static int checkout_file(const char *name, int prefix_length)
 {
+	char utfname[MAXPATHLEN];
 	int namelen = strlen(name);
-	int pos = cache_name_pos(name, namelen);
+	utfcpy(utfname, name, namelen + 1);
+	int utfnamelen = strlen(utfname);
+	int pos = cache_name_pos(utfname, utfnamelen);
 	int has_same_name = 0;
 	int did_checkout = 0;
 	int errs = 0;
@@ -88,8 +97,8 @@ static int checkout_file(const char *name, int prefix_length)
 
 	while (pos < active_nr) {
 		struct cache_entry *ce = active_cache[pos];
-		if (ce_namelen(ce) != namelen ||
-		    memcmp(ce->name, name, namelen))
+		if (ce_namelen(ce) != utfnamelen ||
+		    memcmp(ce->name, utfname, utfnamelen))
 			break;
 		has_same_name = 1;
 		pos++;
@@ -224,7 +233,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 			continue;
 		}
 		if (!strncmp(arg, "--prefix=", 9)) {
-			state.base_dir = arg+9;
+			static char utfbasedir[MAXPATHLEN];
+			utfcpy(utfbasedir, arg+9, strlen(arg+9)+1);
+			state.base_dir = utfbasedir;
 			state.base_dir_len = strlen(state.base_dir);
 			continue;
 		}
@@ -262,13 +273,16 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 		const char *arg = argv[i];
 		const char *p;
 
+		char utfarg[MAXPATHLEN];
+		utfcpy(utfarg, arg, strlen(arg)+1);
+
 		if (all)
 			die("git-checkout-index: don't mix '--all' and explicit filenames");
 		if (read_from_stdin)
 			die("git-checkout-index: don't mix '--stdin' and explicit filenames");
-		p = prefix_path(prefix, prefix_length, arg);
+		p = prefix_path(prefix, prefix_length, utfarg);
 		checkout_file(p, prefix_length);
-		if (p < arg || p > arg + strlen(arg))
+		if (p < arg || p > arg + strlen(utfarg))
 			free((char*)p);
 	}
 
@@ -288,9 +302,11 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 				path_name = unquote_c_style(buf.buf, NULL);
 			else
 				path_name = buf.buf;
-			p = prefix_path(prefix, prefix_length, path_name);
+			char utfpath_name[MAXPATHLEN];
+			utfcpy(utfpath_name, path_name, strlen(path_name)+1);
+			p = prefix_path(prefix, prefix_length, utfpath_name);
 			checkout_file(p, prefix_length);
-			if (p < path_name || p > path_name + strlen(path_name))
+			if (p < utfpath_name || p > utfpath_name + strlen(utfpath_name))
 				free((char *)p);
 			if (path_name != buf.buf)
 				free(path_name);
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index ad8c41e..babac34 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -65,6 +65,7 @@ static int match(const char **spec, char *ps_matched,
 			ps_matched++;
 		continue;
 	matched:
+		P(("matched(%s,%s)\n",m+len, filename+len));
 		if (ps_matched)
 			*ps_matched = 1;
 		return 1;
@@ -76,6 +77,9 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
 {
 	int len = prefix_len;
 	int offset = prefix_offset;
+	char localpath[MAXPATHLEN];
+
+	P(("show_dir_entry(\"%s\",\"%s\"\n",tag,ent->name));
 
 	if (len >= ent->len)
 		die("git-ls-files: internal error - directory entry not superset of prefix");
@@ -84,7 +88,8 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
 		return;
 
 	fputs(tag, stdout);
-	write_name_quoted("", 0, ent->name + offset, line_terminator, stdout);
+	localcpy(localpath, ent->name + offset, strlen(ent->name + offset) + 1);
+	write_name_quoted("", 0, localpath, line_terminator, stdout);
 	putchar(line_terminator);
 }
 
@@ -165,6 +170,8 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
 	int len = prefix_len;
 	int offset = prefix_offset;
 
+	P(("show_ce_entry(\"%s\",\"%s\"\n",tag,ce->name));
+
 	if (len >= ce_namelen(ce))
 		die("git-ls-files: internal error - cache entry not superset of prefix");
 
@@ -189,19 +196,23 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
 	}
 
 	if (!show_stage) {
+		char localpath[MAXPATHLEN];
 		fputs(tag, stdout);
-		write_name_quoted("", 0, ce->name + offset,
+		localcpy(localpath, ce->name + offset, strlen(ce->name + offset) + 1);
+		write_name_quoted("", 0, localpath,
 				  line_terminator, stdout);
 		putchar(line_terminator);
 	}
 	else {
+		char localpath[MAXPATHLEN];
 		printf("%s%06o %s %d\t",
 		       tag,
 		       ntohl(ce->ce_mode),
 		       abbrev ? find_unique_abbrev(ce->sha1,abbrev)
 				: sha1_to_hex(ce->sha1),
 		       ce_stage(ce));
-		write_name_quoted("", 0, ce->name + offset,
+		localcpy(localpath, ce->name + offset, strlen(ce->name + offset) + 1);
+		write_name_quoted("", 0, localpath,
 				  line_terminator, stdout);
 		putchar(line_terminator);
 	}
@@ -451,6 +462,12 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 
 	pathspec = get_pathspec(prefix, argv + i);
 
+#ifdef DEBUG
+ 	if (pathspec) {
+		P(("pathspec[0]=%s\n",pathspec[0]));
+		P(("pathspec[1]=%s\n",pathspec[1]));
+	}
+#endif
 	/* Verify that the pathspec matches the prefix */
 	if (pathspec)
 		prefix = verify_pathspec(prefix);
@@ -461,6 +478,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 		for (num = 0; pathspec[num]; num++)
 			;
 		ps_matched = xcalloc(1, num);
+		P(("allocated ps_matched, %d entries\n",num));
 	}
 
 	if (dir.show_ignored && !exc_given) {
@@ -485,12 +503,14 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 		 */
 		int num, errors = 0;
 		for (num = 0; pathspec[num]; num++) {
+		  	P(("ps_matched[%d]=%d\n",num,ps_matched[num]));
 			if (ps_matched[num])
 				continue;
 			error("pathspec '%s' did not match any.",
 			      pathspec[num] + prefix_offset);
 			errors++;
 		}
+		P(("return errors ? 1 : 0; => %d\n",errors ? 1 : 0));
 		return errors ? 1 : 0;
 	}
 
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index 201defd..4f53b0d 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -78,8 +78,14 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
 		printf("%06o %s %s\t", mode, type,
 				abbrev ? find_unique_abbrev(sha1,abbrev)
 					: sha1_to_hex(sha1));
-	write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
-			  pathname,
+	char localprefix[MAXPATHLEN];
+	int localprefixlen = locallen(base + chomp_prefix, baselen - chomp_prefix);
+	localcpy(localprefix, base + chomp_prefix, baselen - chomp_prefix);
+	
+	char localpathname[MAXPATHLEN];
+	localcpy(localpathname, pathname, strlen(pathname)+1);
+	write_name_quoted(localprefix, localprefixlen,
+			  localpathname,
 			  line_termination, stdout);
 	putchar(line_termination);
 	return retval;
@@ -147,6 +153,12 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 		die("Not a valid object name %s", argv[1]);
 
 	pathspec = get_pathspec(prefix, argv + 2);
+#ifdef DEBUG
+	if (pathspec) {
+	  P(("pathspec[0]=%s\n",pathspec[0]));
+	  P(("pathspec[1]=%s\n",pathspec[1]));
+	}
+#endif
 	tree = parse_tree_indirect(sha1);
 	if (!tree)
 		die("not a tree object");
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index fd3ccc8..da03906 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -315,8 +315,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				continue;
 			}
 			if (!strcmp(arg, "--show-prefix")) {
-				if (prefix)
-					puts(prefix);
+				if (prefix) {
+					char localprefix[MAXPATHLEN];
+					localcpy(localprefix, prefix, strlen(prefix)+1);
+					puts(localprefix);
+				}
 				continue;
 			}
 			if (!strcmp(arg, "--show-cdup")) {
diff --git a/builtin-update-index.c b/builtin-update-index.c
index a3c0a45..cfea4cd 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -274,7 +274,9 @@ static void read_index_info(int line_termination)
 		else
 			path_name = ptr;
 
-		if (!verify_path(path_name)) {
+		char utfpath_name[MAXPATHLEN];
+		utfcpy(utfpath_name, path_name, strlen(path_name) + 1);
+		if (!verify_path(utfpath_name)) {
 			fprintf(stderr, "Ignoring path %s\n", path_name);
 			if (path_name != ptr)
 				free(path_name);
@@ -284,7 +286,7 @@ static void read_index_info(int line_termination)
 
 		if (!mode) {
 			/* mode == 0 means there is no such path -- remove */
-			if (remove_file_from_cache(path_name))
+			if (remove_file_from_cache(utfpath_name))
 				die("git-update-index: unable to remove %s",
 				    ptr);
 		}
@@ -294,7 +296,7 @@ static void read_index_info(int line_termination)
 			 * ptr[-41] is at the beginning of sha1
 			 */
 			ptr[-42] = ptr[-1] = 0;
-			if (add_cacheinfo(mode, sha1, path_name, stage))
+			if (add_cacheinfo(mode, sha1, utfpath_name, stage))
 				die("git-update-index: unable to update %s",
 				    path_name);
 		}
@@ -616,7 +618,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 				usage(update_index_usage);
 			die("unknown option %s", path);
 		}
-		update_one(path, prefix, prefix_length);
+		char utfpath[MAXPATHLEN];
+		utfcpy(utfpath, path, strlen(path) + 1);
+		update_one(utfpath, prefix, prefix_length);
 		if (set_executable_bit)
 			chmod_path(set_executable_bit, path);
 	}
@@ -633,11 +637,13 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 				path_name = unquote_c_style(buf.buf, NULL);
 			else
 				path_name = buf.buf;
-			p = prefix_path(prefix, prefix_length, path_name);
+			char utfpath_name[MAXPATHLEN];
+			utfcpy(utfpath_name, path_name, strlen(path_name) + 1);
+			p = prefix_path(prefix, prefix_length, utfpath_name);
 			update_one(p, NULL, 0);
 			if (set_executable_bit)
 				chmod_path(set_executable_bit, p);
-			if (p < path_name || p > path_name + strlen(path_name))
+			if (p < utfpath_name || p > utfpath_name + strlen(utfpath_name))
 				free((char*) p);
 			if (path_name != buf.buf)
 				free(path_name);
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index 50670dc..84c370f 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -80,7 +80,10 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
 	if (argc > 2)
 		die("too many options");
 
-	ret = write_tree(sha1, missing_ok, prefix);
+	char utfprefix[MAXPATHLEN];
+	if (prefix)
+	  utfcpy(utfprefix, prefix, strlen(prefix)+1);
+	ret = write_tree(sha1, missing_ok, prefix!=NULL ? utfprefix : NULL);
 	printf("%s\n", sha1_to_hex(sha1));
 
 	return ret;
diff --git a/diff.c b/diff.c
index 3315378..170ec5a 100644
--- a/diff.c
+++ b/diff.c
@@ -964,9 +964,14 @@ static void builtin_diff(const char *name_a,
 	char *a_one, *b_two;
 	const char *set = diff_get_color(o->color_diff, DIFF_METAINFO);
 	const char *reset = diff_get_color(o->color_diff, DIFF_RESET);
+	char localname_a[MAXPATHLEN];
+	char localname_b[MAXPATHLEN];
 
-	a_one = quote_two("a/", name_a);
-	b_two = quote_two("b/", name_b);
+	localcpy(localname_a, name_a, strlen(name_a) + 1);
+	localcpy(localname_b, name_b, strlen(name_b) + 1);
+
+	a_one = quote_two("a/", localname_a);
+	b_two = quote_two("b/", localname_b);
 	lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
 	lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
 	printf("%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
@@ -995,7 +1000,7 @@ static void builtin_diff(const char *name_a,
 		if ((one->mode ^ two->mode) & S_IFMT)
 			goto free_ab_and_return;
 		if (complete_rewrite) {
-			emit_rewrite_diff(name_a, name_b, one, two);
+			emit_rewrite_diff(localname_a, localname_b, one, two);
 			goto free_ab_and_return;
 		}
 	}
@@ -1372,18 +1377,22 @@ static void prepare_temp_file(const char *name,
 	    work_tree_matches(name, one->sha1)) {
 		struct stat st;
 		if (lstat(name, &st) < 0) {
+			char localname[MAXPATHLEN];
 			if (errno == ENOENT)
 				goto not_a_valid_file;
-			die("stat(%s): %s", name, strerror(errno));
+			localcpy(localname, name, strlen(name) + 1);
+			die("stat(%s): %s", localname, strerror(errno));
 		}
 		if (S_ISLNK(st.st_mode)) {
 			int ret;
 			char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
+			char localname[MAXPATHLEN];
+			localcpy(localname, name, strlen(name) + 1);
 			if (sizeof(buf) <= st.st_size)
-				die("symlink too long: %s", name);
+				die("symlink too long: %s", localname);
 			ret = readlink(name, buf, st.st_size);
 			if (ret < 0)
-				die("readlink(%s)", name);
+				die("readlink(%s)", localname);
 			prep_temp_blob(temp, buf, st.st_size,
 				       (one->sha1_valid ?
 					one->sha1 : null_sha1),
@@ -1522,7 +1531,9 @@ static void run_external_diff(const char *pgm,
 	retval = spawn_prog(pgm, spawn_arg);
 	remove_tempfile();
 	if (retval) {
-		fprintf(stderr, "external diff died, stopping at %s.\n", name);
+	  	char localname[MAXPATHLEN];
+	  	localcpy(localname, name, strlen(name) + 1);
+		fprintf(stderr, "external diff died, stopping at %s.\n", localname);
 		exit(1);
 	}
 }
@@ -1574,6 +1585,9 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
 	char *name_munged, *other_munged;
 	int complete_rewrite = 0;
 	int len;
+	char localname[MAXPATHLEN];
+	char localotherbuf[MAXPATHLEN];
+	char *localother;
 
 	if (DIFF_PAIR_UNMERGED(p)) {
 		/* unmerged */
@@ -1583,8 +1597,14 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
 
 	name = p->one->path;
 	other = (strcmp(name, p->two->path) ? p->two->path : NULL);
-	name_munged = quote_one(name);
-	other_munged = quote_one(other);
+	localcpy(localname, name, strlen(name) + 1);
+	if (other) {
+		localcpy(localotherbuf, other, strlen(other) + 1);
+		localother = localotherbuf;
+	} else
+		localother = NULL;
+	name_munged = quote_one(localname);
+	other_munged = quote_one(localother);
 	one = p->one; two = p->two;
 
 	diff_fill_sha1_info(one);
@@ -2093,12 +2113,15 @@ static void diff_flush_raw(struct diff_filepair *p,
 	const char *path_one, *path_two;
 	int inter_name_termination = '\t';
 	int line_termination = options->line_termination;
+	char localpath_one[MAXPATHLEN];
+	char localpath_two[MAXPATHLEN];
 
 	if (!line_termination)
 		inter_name_termination = 0;
-
-	path_one = p->one->path;
-	path_two = p->two->path;
+	localcpy(localpath_one, p->one->path, strlen(p->one->path) + 1);
+	localcpy(localpath_two, p->two->path, strlen(p->two->path) + 1);
+	path_one = localpath_one;
+	path_two = localpath_two;
 	if (line_termination) {
 		path_one = quote_one(path_one);
 		path_two = quote_one(path_two);
@@ -2135,20 +2158,22 @@ static void diff_flush_raw(struct diff_filepair *p,
 	if (two_paths)
 		printf("%c%s", inter_name_termination, path_two);
 	putchar(line_termination);
-	if (path_one != p->one->path)
+	if (path_one != localpath_one)
 		free((void*)path_one);
-	if (path_two != p->two->path)
+	if (path_two != localpath_two)
 		free((void*)path_two);
 }
 
 static void diff_flush_name(struct diff_filepair *p, int line_termination)
 {
-	char *path = p->two->path;
+	char localpath_two[MAXPATHLEN];
+	char *path = localpath_two;
+	localcpy(localpath_two, p->two->path, strlen(p->two->path) + 1);
 
 	if (line_termination)
-		path = quote_one(p->two->path);
+		path = quote_one(localpath_two);
 	printf("%s%c", path, line_termination);
-	if (p->two->path != path)
+	if (localpath_two != path)
 		free(path);
 }
 
@@ -2325,8 +2350,10 @@ static void diff_resolve_rename_copy(void)
 			/* This is a "no-change" entry and should not
 			 * happen anymore, but prepare for broken callers.
 			 */
+		        char localpath[MAXPATHLEN];
+			localcpy(localpath, p->one->path, strlen(p->one->path) + 1);
 			error("feeding unmodified %s to diffcore",
-			      p->one->path);
+			      localpath);
 			p->status = DIFF_STATUS_UNKNOWN;
 		}
 	}
@@ -2359,20 +2386,24 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
 
 static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
 {
+        char localpath[MAXPATHLEN];
+	localcpy(localpath, fs->path, strlen(fs->path) + 1);
 	if (fs->mode)
-		printf(" %s mode %06o %s\n", newdelete, fs->mode, fs->path);
+		printf(" %s mode %06o %s\n", newdelete, fs->mode, localpath);
 	else
-		printf(" %s %s\n", newdelete, fs->path);
+		printf(" %s %s\n", newdelete, localpath);
 }
 
 
 static void show_mode_change(struct diff_filepair *p, int show_name)
 {
 	if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
-		if (show_name)
+	        if (show_name) {
+		 	char localpath[MAXPATHLEN];
+			localcpy(localpath, p->two->path, strlen(p->two->path) + 1);
 			printf(" mode change %06o => %06o %s\n",
-			       p->one->mode, p->two->mode, p->two->path);
-		else
+			       p->one->mode, p->two->mode, localpath);
+		} else
 			printf(" mode change %06o => %06o\n",
 			       p->one->mode, p->two->mode);
 	}
@@ -2381,10 +2412,16 @@ static void show_mode_change(struct diff_filepair *p, int show_name)
 static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
 {
 	const char *old, *new;
+	char localpath_one[MAXPATHLEN];
+	char localpath_two[MAXPATHLEN];
+	char localpath_old[MAXPATHLEN];
+	char localpath_new[MAXPATHLEN];
 
 	/* Find common prefix */
-	old = p->one->path;
-	new = p->two->path;
+	localcpy(localpath_old, p->one->path, strlen(p->one->path) + 1);
+	localcpy(localpath_new, p->two->path, strlen(p->two->path) + 1);
+	old = localpath_old;
+	new = localpath_new;
 	while (1) {
 		const char *slash_old, *slash_new;
 		slash_old = strchr(old, '/');
@@ -2400,13 +2437,15 @@ static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
 	/* p->one->path thru old is the common prefix, and old and new
 	 * through the end of names are renames
 	 */
+	localcpy(localpath_one, p->one->path, strlen(p->one->path) + 1);
+	localcpy(localpath_two, p->two->path, strlen(p->two->path) + 1);
 	if (old != p->one->path)
 		printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
-		       (int)(old - p->one->path), p->one->path,
+		       (int)(old - localpath_one), localpath_one,
 		       old, new, (int)(0.5 + p->score * 100.0/MAX_SCORE));
 	else
 		printf(" %s %s => %s (%d%%)\n", renamecopy,
-		       p->one->path, p->two->path,
+		       localpath_one, localpath_two,
 		       (int)(0.5 + p->score * 100.0/MAX_SCORE));
 	show_mode_change(p, 0);
 }
@@ -2428,7 +2467,9 @@ static void diff_summary(struct diff_filepair *p)
 		break;
 	default:
 		if (p->score) {
-			printf(" rewrite %s (%d%%)\n", p->two->path,
+		  	char localpath[MAXPATHLEN];
+			localcpy(localpath, p->two->path, strlen(p->two->path) + 1);
+			printf(" rewrite %s (%d%%)\n", localpath,
 				(int)(0.5 + p->score * 100.0/MAX_SCORE));
 			show_mode_change(p, 0);
 		} else	show_mode_change(p, 1);
diff --git a/git-commit.sh b/git-commit.sh
index 5b1cf85..e2c647a 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -1,4 +1,9 @@
 #!/bin/sh
+if grep -q "^xALL_CFLAGS += -DDEBUG=1" $(dirname $0)/Makefile
+then
+    set -x
+    PS4='$0:$LINENO:'
+fi
 #
 # Copyright (c) 2005 Linus Torvalds
 # Copyright (c) 2006 Junio C Hamano
diff --git a/git-compat-util.h b/git-compat-util.h
index f83352b..6a61026 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -188,4 +188,46 @@ static inline int sane_case(int x, int high)
 	return x;
 }
 
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
+#endif
+
+#ifdef UTF8INTERNAL
+#ifdef NO_ICONV
+#error "NO_ICONV must NOT be set when UTF8INTERNAL is set"
+#endif
+extern int utf_lstat(const char *path,struct stat *buf);
+extern int utf_stat(const char *path,struct stat *buf);
+extern DIR *utf_opendir(const char *path);
+extern struct dirent* utf_readdir(DIR *dir);
+extern int utf_closedir(DIR *dir);
+extern FILE *utf_fopen(const char *path,char *mode);
+extern FILE *utf_freopen(const char *path,char *mode,FILE *stream);
+extern int utf_unlink(const char *path);
+extern int utf_rmdir(const char *path);
+extern int utf_open(const char *path,int flags, ...) __nonnull((1));
+extern int utf_access(const char *path, int mode);
+extern char *utf_getcwd(char *buf,int bufsize);
+extern int utf_creat(const char *path,int mode);
+extern int utf_mkdir(const char *path,int mode);
+extern ssize_t utf_readlink(const char *path,char *buf,size_t bufsiz);
+
+#define lstat(path,buf) utf_lstat(path,buf)
+#define stat(path,buf) utf_stat(path,buf)
+#define opendir(path) utf_opendir(path)
+#define readdir(dir) utf_readdir(dir)
+#define closedir(dir) utf_closedir(dir)
+#define fopen(name,mode) utf_fopen(name,mode)
+#define freopen(name,mode,stream) utf_freopen(name,mode,stream)
+#define unlink(name) utf_unlink(name)
+#define rmdir(name) utf_rmdir(name)
+//#define open(name,flags,mode) utf_open(name,flags,mode)
+#define open utf_open
+#define access(path,mode) utf_access(path,mode)
+#define getcwd(buf,bufsize) utf_getcwd(buf,bufsize)
+#define creat(path,mode) utf_creat(path,mode)
+#define mkdir(path,mode) utf_mkdir(path,mode)
+#define readlink(path,buf,bufsiz) utf_readlink(path,buf,bufsiz)
+#endif
+
 #endif
diff --git a/merge-index.c b/merge-index.c
index 646d090..8a98b49 100644
--- a/merge-index.c
+++ b/merge-index.c
@@ -17,14 +17,23 @@ static void run_program(void)
 	if (pid < 0)
 		die("unable to fork");
 	if (!pid) {
-		execlp(pgm, arguments[0],
-			    arguments[1],
-			    arguments[2],
-			    arguments[3],
-			    arguments[4],
-			    arguments[5],
-			    arguments[6],
-			    arguments[7],
+		char argbuf[8][MAXPATHLEN];
+		char* args[8];
+		int i;
+		for (i=0; i<8; ++i) {
+			if (arguments[i]) {
+			      args[i] = argbuf[i];
+			      localcpy(args[i], arguments[i], strlen(arguments[i]) + 1);
+			}
+		}
+		execlp(pgm, args[0],
+			    args[1],
+			    args[2],
+			    args[3],
+			    args[4],
+			    args[5],
+			    args[6],
+			    args[7],
 			    NULL);
 		die("unable to execute '%s'", pgm);
 	}
diff --git a/read-cache.c b/read-cache.c
index 97c3867..f7642ca 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -701,7 +701,9 @@ int refresh_cache(unsigned int flags)
 			i--;
 			if (allow_unmerged)
 				continue;
-			printf("%s: needs merge\n", ce->name);
+			char localname[MAXPATHLEN];
+			localcpy(localname, ce->name, strlen(ce->name) + 1);
+			printf("%s: needs merge\n", localname);
 			has_errors = 1;
 			continue;
 		}
@@ -721,7 +723,9 @@ int refresh_cache(unsigned int flags)
 			}
 			if (quiet)
 				continue;
-			printf("%s: needs update\n", ce->name);
+			char localname[MAXPATHLEN];
+			localcpy(localname, ce->name, strlen(ce->name) + 1);
+			printf("%s: needs update\n", localname);
 			has_errors = 1;
 			continue;
 		}
diff --git a/setup.c b/setup.c
index 9a46a58..9e500f1 100644
--- a/setup.c
+++ b/setup.c
@@ -43,6 +43,8 @@ const char *prefix_path(const char *prefix, int len, const char *path)
 		memcpy(n, prefix, len);
 		memcpy(n + len, path, speclen+1);
 		path = n;
+	} else {
+		path = xstrdup(path);
 	}
 	return path;
 }
@@ -107,6 +109,8 @@ void verify_non_filename(const char *prefix, const char *arg)
 
 const char **get_pathspec(const char *prefix, const char **pathspec)
 {
+	char utfprefixbuf[MAXPATHLEN];
+	char *utfprefix;
 	const char *entry = *pathspec;
 	const char **p;
 	int prefixlen;
@@ -114,20 +118,36 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
 	if (!prefix && !entry)
 		return NULL;
 
+	if (prefix) {
+	  utfcpy(utfprefixbuf, prefix, strlen(prefix)+1);
+	  utfprefix = utfprefixbuf;
+	} else {
+	  utfprefix = NULL;
+	}
+
 	if (!entry) {
 		static const char *spec[2];
-		spec[0] = prefix;
+		spec[0] = xstrdup(utfprefix);
 		spec[1] = NULL;
 		return spec;
 	}
 
 	/* Otherwise we have to re-write the entries.. */
+	int n;
+	for (n=0; pathspec[n]; ++n)
+		;
+	char **ret = xcalloc(n+1,sizeof(char*));
+	char **r = ret;
 	p = pathspec;
-	prefixlen = prefix ? strlen(prefix) : 0;
+	prefixlen = utfprefix ? strlen(utfprefix) : 0;
 	do {
-		*p = prefix_path(prefix, prefixlen, entry);
+	        char utfentry[MAXPATHLEN];
+		utfcpy(utfentry, entry, strlen(entry)+1);
+		*r = prefix_path(utfprefix, prefixlen, utfentry);
+		P(("*r=%s\n",*r));
+		++r;
 	} while ((entry = *++p) != NULL);
-	return (const char **) pathspec;
+	return (const char**)ret;
 }
 
 /*
diff --git a/t/t-utf-filenames.sh b/t/t-utf-filenames.sh
new file mode 100755
index 0000000..0731086
--- /dev/null
+++ b/t/t-utf-filenames.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='Test charset management.
+
+This assumes normal tests works fine
+and concentrates on filenames with non-ascii
+characters.'
+
+. ./test-lib.sh
+
+test_expect_success \
+    'add simple text file' \
+    'mkdir å &&
+    echo hej >å/åland.txt &&
+    git-add å/åland.txt &&
+    git-commit -a -m "Changed" &&
+    echo test $(git-ls-files) = "\"\\345/\\345land.txt\"" &&
+    LC_CTYPE=sv_SE.UTF-8 echo test $(git-ls-files) = "\"\\345/\\345land.txt\""
+    '
+
+test_expect_success \
+    'change single text file, first time' \
+    'echo san >>å/åland.txt &&
+    git-commit -a -m "Changed again"
+    '
+test_expect_success \
+    'add simple binary file' \
+    'dd if=/dev/urandom of=å/åäö bs=1 count=312 &&
+    git-add å/åäö &&
+    git-commit -a -m "Changed" &&
+    git-ls-files &&
+    test "$(git-ls-files)" = "\"\\345/\\345land.txt\"
+\"\\345/\\345\\344\\366\""
+    '
+test_expect_success \
+    'change single text file, second time' \
+    'echo san >>å/åland.txt &&
+    git-commit -a -m "Changed igen"
+    '
+test_expect_success \
+    'change single binary file' \
+    'dd if=/dev/urandom of=å/åäö bs=1 count=312 &&
+    git-commit -a -m "Changed igen"
+    '
+
+test_expect_success \
+    'branch and merge, new file' \
+    '
+    git-tag -f HERE &&
+    git-checkout -b "gren1" &&
+    echo >å/öland.txt hej &&
+    git-add . &&
+    git-commit -a -m "Ändrad" &&
+    git-checkout master &&
+    git-pull . gren1 &&
+    test "$(git-ls-files)" = "\"\\345/\\345land.txt\"
+\"\\345/\\345\\344\\366\"
+\"\\345/\\366land.txt\""
+    '
+test_expect_success \
+    'merge old file' \
+    '
+    git-checkout gren1 &&
+    echo >å/öland.txt hejsan &&
+    git-commit -a -m "Ändrad" &&
+    git-checkout master &&
+    git-pull . gren1
+    test "$(git-ls-files)" = "\"\\345/\\345land.txt\"
+\"\\345/\\345\\344\\366\"
+\"\\345/\\366land.txt\""
+    '
+
+test_expect_success \
+    'merge in-tree file' \
+    '
+    echo >>å/öland.txt in master &&
+    git-commit -a -m "in master" && 
+    git-checkout gren1 &&
+    echo >å/öland.txt in branch &&
+    git-update-index å/öland.txt &&
+    git-checkout -m master
+    test "$(git-ls-files)" = "\"\\345/\\345land.txt\"
+\"\\345/\\345\\344\\366\"
+\"\\345/\\366land.txt\""
+    test $(echo $(wc -l <å/öland.txt)) = 6
+    '
+
+test_expect_success \
+    'clone to UTF' \
+    '
+    rm -rf ../trash2 &&
+    LC_ALL=sv_SE.UTF-8 LC_CTYPE=sv_SE.UTF-8 git-clone . ../trash2
+    '
+
+test_done
diff --git a/utf.c b/utf.c
index eb430b2..7c44cac 100644
--- a/utf.c
+++ b/utf.c
@@ -180,6 +180,236 @@ void localcpy(char *tolocal, char *fromutf, size_t utflen)
 #endif
 }
 
+#define MAXRESOURCES 50
+struct resource {
+  void *key;
+  void *value;
+};
+
+static struct resource resources[MAXRESOURCES];
+static void put(void *key, void *value)
+{
+  int i;
+  for (i=0; i<MAXRESOURCES; ++i) {
+    if (resources[i].key == 0) {
+      resources[i].key = key;
+      resources[i].value = value;
+      return;
+    }
+  }
+}
+
+static void* get(void *key)
+{
+  int i;
+  for (i=0; i<MAXRESOURCES; ++i) {
+    if (resources[i].key == key) {
+      return resources[i].value;
+    }
+  }
+  return NULL;
+}
+
+static void* getandremove(void *key)
+{
+  int i;
+  for (i=0; i<MAXRESOURCES; ++i) {
+    if (resources[i].key == key) {
+      resources[i].key = NULL;
+      return resources[i].value;
+    }
+  }
+  return NULL;
+}
+ 
+static void zfree(void *ret)
+{
+  if (ret)
+    free(ret);
+}
+
+int utf_lstat(char *path, struct stat *buf)
+{
+  P(("utf_lstat(\"%s\",buf)[",path));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  int ret = lstat(localpath, buf);
+  if (ret >= 0 && (buf->st_mode & S_IFMT) == S_IFLNK) {
+    char sympath[MAXPATHLEN];
+    int n = utf_readlink(path, sympath, sizeof sympath);
+    if (n < 0)
+      die("Panic, cannot read link %s in utf_lstat\n", path);
+    buf->st_size = strlen(sympath);
+  }
+  return ret;
+}
+
+int utf_stat(char *path, struct stat *buf)
+{
+  P(("utf_stat(\"%s\",buf)[",path));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return stat(localpath, buf);
+}
+
+DIR *utf_opendir(char *path)
+{
+  P(("utf_opendir(\"%s\")\n",path));
+  char localpath[MAXPATHLEN];
+  DIR *ret = NULL;
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  ret = opendir(localpath);
+  if (ret)
+    put(ret, NULL);
+  return ret;
+}
+
+struct dirent* utf_readdir(DIR *dir)
+{
+  P(("utf_readdir(\"%p\")",dir));
+  struct dirent *ret;
+  int len;
+  char utfpath[256];
+  struct dirent *myret;
+
+  zfree(getandremove(dir));
+  ret = readdir(dir);
+  if (ret != NULL) {
+    utfcpy(utfpath, ret->d_name, strlen(ret->d_name)+1);
+    len=sizeof(struct dirent)+strlen(utfpath)+1;
+    myret=malloc(len);
+    memcpy(myret, ret, sizeof (struct dirent));
+    put(dir, myret);
+    strcpy(myret->d_name, utfpath);
+    P(("=>\"%s\"\n",myret->d_name));
+    return myret;
+  } else {
+    return NULL;
+  }
+}
+
+int utf_closedir(DIR *dir)
+{
+  P(("utf_closedir(%p)\n",dir));
+  zfree(getandremove(dir));
+  return closedir(dir);
+}
+
+FILE *utf_fopen(char *path, char *mode)
+{
+  P(("utf_fopen(\"%s\",\"%s\")[",path,mode));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return fopen(localpath, mode);
+} 
+
+FILE *utf_freopen(char *path, char *mode, FILE *stream)
+{
+  P(("utf_freopen(\"%s\",\"%s\",%p)[",path,mode,stream));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return freopen(localpath, mode, stream);
+} 
+
+int utf_unlink(char *path)
+{
+  P(("utf_unlink(\"%s\")[",path));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return unlink(localpath);
+}
+
+int utf_rmdir(char *path)
+{
+  P(("utf_rmdir(\"%s\")[",path));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return rmdir(localpath);
+}
+
+int utf_open(char *path, int flags,...)
+{
+  va_list va;
+  int mode;
+  va_start(va,flags);
+  mode = va_arg(va,int);
+  va_end(va);
+  P(("utf_open(\"%s\",%d,%d)[",path,flags,mode));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return open(localpath, flags, mode);
+}
+
+int utf_access(char *path, int mode)
+{
+  P(("utf_access(\"%s\",%d)[",path,mode));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return access(localpath,mode);
+}
+
+char *utf_getcwd(char *buf,int bufsize)
+{
+  char localbuf[MAXPATHLEN];
+  char *ret=getcwd(localbuf,sizeof localbuf);
+  if (ret != NULL) {
+    if (buf == NULL) {
+      if (bufsize == 0) {
+	buf = malloc(bufsize);
+      } else {
+	buf = malloc(utflen(localbuf,strlen(localbuf)) + 1);
+      }
+    }
+    utfcpy(buf, localbuf, strlen(localbuf) + 1);
+    return buf;
+  } else {
+    return NULL;    
+  }
+}
+
+int utf_creat(const char *path,int mode)
+{
+  P(("utf_creat(\"%s\",%d)[",path,mode));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return creat(localpath, mode);
+}
+
+int utf_mkdir(const char *path,int mode)
+{
+  P(("utf_mkdir(\"%s\",%d)[",path,mode));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("\"%s\"]\n",localpath));
+  return mkdir(localpath, mode);
+}
+
+ssize_t utf_readlink(const char *path,char *buf,size_t bufsiz)
+{
+  P(("utf_readlink(\"%s\",BUF,%d)[",path,bufsiz));
+  char localpath[MAXPATHLEN];
+  localcpy(localpath, path, strlen(path)+1);
+  P(("readlink(%s)\n", localpath));
+  char localret[MAXPATHLEN];
+  ssize_t ret = readlink(localpath, localret, bufsiz);
+  if (ret == -1)
+	return ret;
+  localret[ret] = 0;
+  utfcpy(buf, localret, ret+1);
+  P(("\"%s\"]\n",buf));
+  return strlen(buf);
+}
+
 int PP(const char *fmt,...)
 {
   va_list va;
-- 
1.6.3.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]