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
next prev parent 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 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).