diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-03-26 16:04:24 +0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2011-03-28 17:01:15 -0700 |
commit | 9b125da490990ae4d08dd1517dc38b188b874fa8 (patch) | |
tree | 1da0d8359926faf97b67946095f5e5e9937186cc | |
parent | Git 1.7.4.2 (diff) | |
download | tgif-9b125da490990ae4d08dd1517dc38b188b874fa8.tar.xz |
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>
-rw-r--r-- | dir.c | 31 | ||||
-rw-r--r-- | dir.h | 1 | ||||
-rw-r--r-- | setup.c | 7 |
3 files changed, 36 insertions, 3 deletions
@@ -1048,6 +1048,37 @@ char *get_relative_cwd(char *buffer, int size, const char *dir) } } + * Given two normalized paths (a trailing slash is ok), if subdir is + * outside dir, return -1. Otherwise return the offset in subdir that + * can be used as relative path to dir. + */ +int dir_inside_of(const char *subdir, const char *dir) +{ + int offset = 0; + + assert(dir && subdir && *dir && *subdir); + + while (*dir && *subdir && *dir == *subdir) { + dir++; + subdir++; + offset++; + } + + /* hel[p]/me vs hel[l]/yeah */ + if (*dir && *subdir) + return -1; + + if (!*subdir) + return !*dir ? offset : -1; /* same dir */ + + /* foo/[b]ar vs foo/[] */ + if (is_dir_sep(dir[-1])) + return is_dir_sep(subdir[-1]) ? offset : -1; + + /* foo[/]bar vs foo[] */ + return is_dir_sep(*subdir) ? offset + 1 : -1; +} + int is_inside_dir(const char *dir) { char buffer[PATH_MAX]; @@ -83,6 +83,7 @@ extern int file_exists(const char *); extern char *get_relative_cwd(char *buffer, int size, const char *dir); extern int is_inside_dir(const char *dir); +extern int dir_inside_of(const char *subdir, const char *dir); static inline int is_dot_or_dotdot(const char *name) { @@ -322,6 +322,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv, const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *worktree; char *gitfile; + int offset; if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); @@ -387,15 +388,15 @@ static const char *setup_explicit_git_dir(const char *gitdirenv, return NULL; } - if (!prefixcmp(cwd, worktree) && - cwd[strlen(worktree)] == '/') { /* cwd inside worktree */ + offset = dir_inside_of(cwd, worktree); + if (offset >= 0) { /* cwd inside worktree? */ set_git_dir(make_absolute_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); cwd[len++] = '/'; cwd[len] = '\0'; free(gitfile); - return cwd + strlen(worktree) + 1; + return cwd + offset; } /* cwd outside worktree */ |