{"thread":{"id":"26871","subject":"[PATCH 1/2 v2] setup: return correct prefix if worktree is '/'","startedAt":"2011-03-26T09:04:24Z","lastAt":"2011-03-26T09:04:25Z","messageCount":2,"participants":["Nguyễn Thái Ngọc Duy"],"isPatch":true,"patchVersion":2,"patchTotal":2},"messages":[{"id":"164354","messageId":"1301130265-27287-1-git-send-email-pclouds@gmail.com","threadId":"26871","inReplyTo":null,"subject":"[PATCH 1/2 v2] setup: return correct prefix if worktree is '/'","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-26T09:04:24Z","receivedAt":"2011-03-26T09:04:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The same old problem reappears after setup code is reworked.  We tend\nto assume there is at least one path component in a path and forget\nthat path can be simply '/'.\n\nReported-by: Matthijs Kooijman <matthijs@stdin.nl>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n It just looks better than previous version.\n\n dir.c   |   31 +++++++++++++++++++++++++++++++\n dir.h   |    1 +\n setup.c |    7 ++++---\n 3 files changed, 36 insertions(+), 3 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 325fb56..6c49a73 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1152,6 +1152,37 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)\n \t}\n }\n \n+ * Given two normalized paths (a trailing slash is ok), if subdir is\n+ * outside dir, return -1.  Otherwise return the offset in subdir that\n+ * can be used as relative path to dir.\n+ */\n+int dir_inside_of(const char *subdir, const char *dir)\n+{\n+\tint offset = 0;\n+\n+\tassert(dir && subdir && *dir && *subdir);\n+\n+\twhile (*dir && *subdir && *dir == *subdir) {\n+\t\tdir++;\n+\t\tsubdir++;\n+\t\toffset++;\n+\t}\n+\n+\t/* hel[p]/me vs hel[l]/yeah */\n+\tif (*dir && *subdir)\n+\t\treturn -1;\n+\n+\tif (!*subdir)\n+\t\treturn !*dir ? offset : -1; /* same dir */\n+\n+\t/* foo/[b]ar vs foo/[] */\n+\tif (is_dir_sep(dir[-1]))\n+\t\treturn is_dir_sep(subdir[-1]) ? offset : -1;\n+\n+\t/* foo[/]bar vs foo[] */\n+\treturn is_dir_sep(*subdir) ? offset + 1 : -1;\n+}\n+\n int is_inside_dir(const char *dir)\n {\n \tchar buffer[PATH_MAX];\ndiff --git a/dir.h b/dir.h\nindex aa511da..83e2992 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -87,6 +87,7 @@ extern int file_exists(const char *);\n \n extern char *get_relative_cwd(char *buffer, int size, const char *dir);\n extern int is_inside_dir(const char *dir);\n+extern int dir_inside_of(const char *subdir, const char *dir);\n \n static inline int is_dot_or_dotdot(const char *name)\n {\ndiff --git a/setup.c b/setup.c\nindex 03cd84f..b6e6b5a 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -325,6 +325,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,\n \tconst char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);\n \tconst char *worktree;\n \tchar *gitfile;\n+\tint offset;\n \n \tif (PATH_MAX - 40 < strlen(gitdirenv))\n \t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n@@ -390,15 +391,15 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,\n \t\treturn NULL;\n \t}\n \n-\tif (!prefixcmp(cwd, worktree) &&\n-\t    cwd[strlen(worktree)] == '/') { /* cwd inside worktree */\n+\toffset = dir_inside_of(cwd, worktree);\n+\tif (offset >= 0) {\t/* cwd inside worktree? */\n \t\tset_git_dir(real_path(gitdirenv));\n \t\tif (chdir(worktree))\n \t\t\tdie_errno(\"Could not chdir to '%s'\", worktree);\n \t\tcwd[len++] = '/';\n \t\tcwd[len] = '\\0';\n \t\tfree(gitfile);\n-\t\treturn cwd + strlen(worktree) + 1;\n+\t\treturn cwd + offset;\n \t}\n \n \t/* cwd outside worktree */\n-- \n1.7.4.74.g639db\n"},{"id":"164355","messageId":"1301130265-27287-2-git-send-email-pclouds@gmail.com","threadId":"26871","inReplyTo":"1301130265-27287-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/2] Kill off get_relative_cwd()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-26T09:04:25Z","receivedAt":"2011-03-26T09:04:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Function dir_inside_of() does something similar (correctly), but looks\neasier to understand and does not bundle cwd to its business. Given\nget_relative_cwd's only user is is_inside_dir, we can kill it for\ngood.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n 2011/3/25 Michael J Gruber <git@drmicha.warpmail.net>:\n > get_relative_cwd() tries to determine a common prefix for dir and\n > cwd.\n > The fix in\n > 490544b (get_cwd_relative(): do not misinterpret suffix as\n > subdirectory, 2010-05-22)\n > made the logic less naive (so that foo-bar is not misdetected as\n > being\n > within foo) but broke some other cases, in particular foo not being\n > detected as being within foo/ any more.\n >\n > Fix it by taking into a account that a directory name may or may\n > not end\n > in /.\n\n OK I stared at the code long enough and have come to the conclusion\n that your fix is essentially fbbb4e1 (get_cwd_relative(): do not\n misinterpret root path - 2010-11-20) but the structure is similar to\n my old is_subdir_or_same() (now dir_inside_of). So let's kill that\n cryptic switch.\n\n dir.c |   55 ++++++-------------------------------------------------\n dir.h |    1 -\n 2 files changed, 6 insertions(+), 50 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 6c49a73..bd9e989 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1105,53 +1105,6 @@ int file_exists(const char *f)\n }\n \n /*\n- * get_relative_cwd() gets the prefix of the current working directory\n- * relative to 'dir'.  If we are not inside 'dir', it returns NULL.\n- *\n- * As a convenience, it also returns NULL if 'dir' is already NULL.  The\n- * reason for this behaviour is that it is natural for functions returning\n- * directory names to return NULL to say \"this directory does not exist\"\n- * or \"this directory is invalid\".  These cases are usually handled the\n- * same as if the cwd is not inside 'dir' at all, so get_relative_cwd()\n- * returns NULL for both of them.\n- *\n- * Most notably, get_relative_cwd(buffer, size, get_git_work_tree())\n- * unifies the handling of \"outside work tree\" with \"no work tree at all\".\n- */\n-char *get_relative_cwd(char *buffer, int size, const char *dir)\n-{\n-\tchar *cwd = buffer;\n-\n-\tif (!dir)\n-\t\treturn NULL;\n-\tif (!getcwd(buffer, size))\n-\t\tdie_errno(\"can't find the current directory\");\n-\n-\tif (!is_absolute_path(dir))\n-\t\tdir = real_path(dir);\n-\n-\twhile (*dir && *dir == *cwd) {\n-\t\tdir++;\n-\t\tcwd++;\n-\t}\n-\tif (*dir)\n-\t\treturn NULL;\n-\tswitch (*cwd) {\n-\tcase '\\0':\n-\t\treturn cwd;\n-\tcase '/':\n-\t\treturn cwd + 1;\n-\tdefault:\n-\t\t/*\n-\t\t * dir can end with a path separator when it's root\n-\t\t * directory. Return proper prefix in that case.\n-\t\t */\n-\t\tif (dir[-1] == '/')\n-\t\t\treturn cwd;\n-\t\treturn NULL;\n-\t}\n-}\n-\n  * Given two normalized paths (a trailing slash is ok), if subdir is\n  * outside dir, return -1.  Otherwise return the offset in subdir that\n  * can be used as relative path to dir.\n@@ -1185,8 +1138,12 @@ int dir_inside_of(const char *subdir, const char *dir)\n \n int is_inside_dir(const char *dir)\n {\n-\tchar buffer[PATH_MAX];\n-\treturn get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;\n+\tchar cwd[PATH_MAX];\n+\tif (!dir)\n+\t\treturn 0;\n+\tif (!getcwd(cwd, sizeof(cwd)))\n+\t\tdie_errno(\"can't find the current directory\");\n+\treturn dir_inside_of(cwd, dir) >= 0;\n }\n \n int is_empty_dir(const char *path)\ndiff --git a/dir.h b/dir.h\nindex 83e2992..433b5b4 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -85,7 +85,6 @@ extern void add_exclude(const char *string, const char *base,\n extern void free_excludes(struct exclude_list *el);\n extern int file_exists(const char *);\n \n-extern char *get_relative_cwd(char *buffer, int size, const char *dir);\n extern int is_inside_dir(const char *dir);\n extern int dir_inside_of(const char *subdir, const char *dir);\n \n-- \n1.7.4.74.g639db\n"}]}