From 9b125da490990ae4d08dd1517dc38b188b874fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 26 Mar 2011 16:04:24 +0700 Subject: [PATCH 1/2] setup: return correct prefix if worktree is '/' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- dir.c | 31 +++++++++++++++++++++++++++++++ dir.h | 1 + setup.c | 7 ++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/dir.c b/dir.c index 570b651a1..b0100f553 100644 --- a/dir.c +++ b/dir.c @@ -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]; diff --git a/dir.h b/dir.h index 72a764ed8..86a99ed9c 100644 --- a/dir.h +++ b/dir.h @@ -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) { diff --git a/setup.c b/setup.c index dadc66659..f0468c686 100644 --- a/setup.c +++ b/setup.c @@ -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 */ From b892913d51795ee66d825bedd23e5c4ffe85ebb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 26 Mar 2011 16:04:25 +0700 Subject: [PATCH 2/2] Kill off get_relative_cwd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function dir_inside_of() does something similar (correctly), but looks easier to understand and does not bundle cwd to its business. Given get_relative_cwd's only user is is_inside_dir, we can kill it for good. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- dir.c | 55 ++++++------------------------------------------------- dir.h | 1 - 2 files changed, 6 insertions(+), 50 deletions(-) diff --git a/dir.c b/dir.c index b0100f553..522a6fe9d 100644 --- a/dir.c +++ b/dir.c @@ -1001,53 +1001,6 @@ int file_exists(const char *f) } /* - * get_relative_cwd() gets the prefix of the current working directory - * relative to 'dir'. If we are not inside 'dir', it returns NULL. - * - * As a convenience, it also returns NULL if 'dir' is already NULL. The - * reason for this behaviour is that it is natural for functions returning - * directory names to return NULL to say "this directory does not exist" - * or "this directory is invalid". These cases are usually handled the - * same as if the cwd is not inside 'dir' at all, so get_relative_cwd() - * returns NULL for both of them. - * - * Most notably, get_relative_cwd(buffer, size, get_git_work_tree()) - * unifies the handling of "outside work tree" with "no work tree at all". - */ -char *get_relative_cwd(char *buffer, int size, const char *dir) -{ - char *cwd = buffer; - - if (!dir) - return NULL; - if (!getcwd(buffer, size)) - die_errno("can't find the current directory"); - - if (!is_absolute_path(dir)) - dir = make_absolute_path(dir); - - while (*dir && *dir == *cwd) { - dir++; - cwd++; - } - if (*dir) - return NULL; - switch (*cwd) { - case '\0': - return cwd; - case '/': - return cwd + 1; - default: - /* - * dir can end with a path separator when it's root - * directory. Return proper prefix in that case. - */ - if (dir[-1] == '/') - return cwd; - return NULL; - } -} - * 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. @@ -1081,8 +1034,12 @@ int dir_inside_of(const char *subdir, const char *dir) int is_inside_dir(const char *dir) { - char buffer[PATH_MAX]; - return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL; + char cwd[PATH_MAX]; + if (!dir) + return 0; + if (!getcwd(cwd, sizeof(cwd))) + die_errno("can't find the current directory"); + return dir_inside_of(cwd, dir) >= 0; } int is_empty_dir(const char *path) diff --git a/dir.h b/dir.h index 86a99ed9c..1cf271098 100644 --- a/dir.h +++ b/dir.h @@ -81,7 +81,6 @@ extern void add_exclude(const char *string, const char *base, extern void free_excludes(struct exclude_list *el); 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);