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>
maint
Nguyễn Thái Ngọc Duy 2011-03-26 16:04:24 +07:00 committed by Junio C Hamano
parent 78bc466753
commit 9b125da490
3 changed files with 36 additions and 3 deletions

31
dir.c
View File

@ -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) int is_inside_dir(const char *dir)
{ {
char buffer[PATH_MAX]; char buffer[PATH_MAX];

1
dir.h
View File

@ -83,6 +83,7 @@ extern int file_exists(const char *);


extern char *get_relative_cwd(char *buffer, int size, const char *dir); extern char *get_relative_cwd(char *buffer, int size, const char *dir);
extern int is_inside_dir(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) static inline int is_dot_or_dotdot(const char *name)
{ {

View File

@ -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 *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
const char *worktree; const char *worktree;
char *gitfile; char *gitfile;
int offset;


if (PATH_MAX - 40 < strlen(gitdirenv)) if (PATH_MAX - 40 < strlen(gitdirenv))
die("'$%s' too big", GIT_DIR_ENVIRONMENT); die("'$%s' too big", GIT_DIR_ENVIRONMENT);
@ -387,15 +388,15 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
return NULL; return NULL;
} }


if (!prefixcmp(cwd, worktree) && offset = dir_inside_of(cwd, worktree);
cwd[strlen(worktree)] == '/') { /* cwd inside worktree */ if (offset >= 0) { /* cwd inside worktree? */
set_git_dir(make_absolute_path(gitdirenv)); set_git_dir(make_absolute_path(gitdirenv));
if (chdir(worktree)) if (chdir(worktree))
die_errno("Could not chdir to '%s'", worktree); die_errno("Could not chdir to '%s'", worktree);
cwd[len++] = '/'; cwd[len++] = '/';
cwd[len] = '\0'; cwd[len] = '\0';
free(gitfile); free(gitfile);
return cwd + strlen(worktree) + 1; return cwd + offset;
} }


/* cwd outside worktree */ /* cwd outside worktree */