Skip to content

Commit 9b125da

Browse files
pcloudsgitster
authored andcommitted
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>
1 parent 78bc466 commit 9b125da

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

dir.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,37 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
10481048
}
10491049
}
10501050

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

dir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ extern int file_exists(const char *);
8383

8484
extern char *get_relative_cwd(char *buffer, int size, const char *dir);
8585
extern int is_inside_dir(const char *dir);
86+
extern int dir_inside_of(const char *subdir, const char *dir);
8687

8788
static inline int is_dot_or_dotdot(const char *name)
8889
{

setup.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
322322
const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
323323
const char *worktree;
324324
char *gitfile;
325+
int offset;
325326

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

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? */
392393
set_git_dir(make_absolute_path(gitdirenv));
393394
if (chdir(worktree))
394395
die_errno("Could not chdir to '%s'", worktree);
395396
cwd[len++] = '/';
396397
cwd[len] = '\0';
397398
free(gitfile);
398-
return cwd + strlen(worktree) + 1;
399+
return cwd + offset;
399400
}
400401

401402
/* cwd outside worktree */

0 commit comments

Comments
 (0)