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