@matheusbsbs / matheus-bagliano / commits / 9b125da490
Fork 0

setup: return correct prefix if worktree is '/'

The same old problem reappears after setup code is reworked. We tend to assume there is at least one path component in a path and forget that path can be simply '/'. Reported-by: Matthijs Kooijman <matthijs@stdin.nl> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Mar 26, 2011 at 16:04 UTC 9b125da490990ae4d08dd1517dc38b188b874fa8
3 files changed +36 -3
dir.c
+31
@@ -1048,6 +1048,37 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
1048 }
1049 }
1050
1051 + * Given two normalized paths (a trailing slash is ok), if subdir is
1052 + * outside dir, return -1. Otherwise return the offset in subdir that
1053 + * can be used as relative path to dir.
1054 + */
1055 +int dir_inside_of(const char *subdir, const char *dir)
1056 +{
1057 + int offset = 0;
1058 +
1059 + assert(dir && subdir && *dir && *subdir);
1060 +
1061 + while (*dir && *subdir && *dir == *subdir) {
1062 + dir++;
1063 + subdir++;
1064 + offset++;
1065 + }
1066 +
1067 + /* hel[p]/me vs hel[l]/yeah */
1068 + if (*dir && *subdir)
1069 + return -1;
1070 +
1071 + if (!*subdir)
1072 + return !*dir ? offset : -1; /* same dir */
1073 +
1074 + /* foo/[b]ar vs foo/[] */
1075 + if (is_dir_sep(dir[-1]))
1076 + return is_dir_sep(subdir[-1]) ? offset : -1;
1077 +
1078 + /* foo[/]bar vs foo[] */
1079 + return is_dir_sep(*subdir) ? offset + 1 : -1;
1080 +}
1081 +
1082 int is_inside_dir(const char *dir)
1083 {
1084 char buffer[PATH_MAX];
dir.h
+1
@@ -83,6 +83,7 @@ extern int file_exists(const char *);
83
84 extern char *get_relative_cwd(char *buffer, int size, const char *dir);
85 extern int is_inside_dir(const char *dir);
86 +extern int dir_inside_of(const char *subdir, const char *dir);
87
88 static inline int is_dot_or_dotdot(const char *name)
89 {
setup.c
+4 -3
@@ -322,6 +322,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
322 const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
323 const char *worktree;
324 char *gitfile;
325 + int offset;
326
327 if (PATH_MAX - 40 < strlen(gitdirenv))
328 die("'$%s' too big", GIT_DIR_ENVIRONMENT);
@@ -387,15 +388,15 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
388 return NULL;
389 }
390
390 - if (!prefixcmp(cwd, worktree) &&
391 - cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
391 + offset = dir_inside_of(cwd, worktree);
392 + if (offset >= 0) { /* cwd inside worktree? */
393 set_git_dir(make_absolute_path(gitdirenv));
394 if (chdir(worktree))
395 die_errno("Could not chdir to '%s'", worktree);
396 cwd[len++] = '/';
397 cwd[len] = '\0';
398 free(gitfile);
398 - return cwd + strlen(worktree) + 1;
399 + return cwd + offset;
400 }
401
402 /* cwd outside worktree */