All of lore.kernel.org
 help / color / mirror / Atom feed
From: Robin Rosenberg <robin.rosenberg@dewire.com>
To: git@vger.kernel.org
Cc: Robin Rosenberg <robin.rosenberg@dewire.com>
Subject: [RFC 4/8] UTF file names.
Date: Wed, 13 May 2009 00:50:27 +0200	[thread overview]
Message-ID: <1242168631-30753-5-git-send-email-robin.rosenberg@dewire.com> (raw)
In-Reply-To: <1242168631-30753-4-git-send-email-robin.rosenberg@dewire.com>

---
 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

  reply	other threads:[~2009-05-12 22:50 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-12 22:50 [RFC 0/8] Antique UTF-8 filename support Robin Rosenberg
2009-05-12 22:50 ` [RFC 1/8] UTF helpers Robin Rosenberg
2009-05-12 22:50   ` [RFC 2/8] Messages in locale Robin Rosenberg
2009-05-12 22:50     ` [RFC 3/8] Extend tests to cover locale wrt to commit messages Robin Rosenberg
2009-05-12 22:50       ` Robin Rosenberg [this message]
     [not found]         ` <1242168631-30753-6-git-send-email-robin.rosenberg@dewire.com>
2009-05-12 22:50           ` [RFC 6/8] test of utf_locallinks Robin Rosenberg
2009-05-12 22:50             ` [RFC 7/8] Convert symlink dest in diff Robin Rosenberg
2009-05-12 22:50               ` [RFC 8/8] UTF-8 in non-SHA1-objects Robin Rosenberg
2009-05-13  0:20   ` [RFC 1/8] UTF helpers Johannes Schindelin
2009-05-13  5:24     ` Robin Rosenberg
2009-05-13  9:24       ` Esko Luontola
2009-05-13 10:02         ` Andreas Ericsson
2009-05-13 10:21           ` Esko Luontola
2009-05-13 11:44             ` Alex Riesen
2009-05-13 18:48         ` Junio C Hamano
2009-05-13 19:31           ` Esko Luontola
2009-05-13 20:10             ` Junio C Hamano
2009-05-13 10:14       ` Johannes Schindelin
2009-05-14  4:38       ` Junio C Hamano
2009-05-14 13:57         ` Jay Soffian

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=1242168631-30753-5-git-send-email-robin.rosenberg@dewire.com \
    --to=robin.rosenberg@dewire.com \
    --cc=git@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.