{"thread":{"id":"2301","subject":"[PATCH 2/4] Library code for user-relative paths.","startedAt":"2005-11-01T22:59:21Z","lastAt":"2005-11-02T08:40:32Z","messageCount":3,"participants":["Andreas Ericsson","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"10957","messageId":"20051101225921.2C6035BA82@nox.op5.se","threadId":"2301","inReplyTo":null,"subject":"[PATCH 2/4] Library code for user-relative paths.","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-11-01T22:59:21Z","receivedAt":"2005-11-01T22:59:21Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"See this discussion, \"[RFC] GIT paths\", on the git-list:\nhttp://www.gelato.unsw.edu.au/archives/git/0510/10924.html\n\nThis patch provides the work-horse of the user-relative paths, using Linus'\nidea of a blind chdir() and getcwd(), which makes it remarkably simple.\n\nSigned-off-by: Andreas Ericsson <ae@op5.se>\n\n---\n\n cache.h |    1 +\n path.c  |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 73 insertions(+), 0 deletions(-)\n\napplies-to: bf640ae3d5bb5f5f283c62d4f5198a3c5e5086f0\n1c4e7bb2383e2b67f0e877a46ea1eba4ec7e45e7\ndiff --git a/cache.h b/cache.h\nindex 677c6ac..aea2097 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -190,6 +190,7 @@ extern int trust_executable_bit;\n \n /* Return a statically allocated filename matching the sha1 signature */\n extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+extern const char *is_git_repo(const char *path, int strict);\n extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n extern char *sha1_file_name(const unsigned char *sha1);\n extern char *sha1_pack_name(const unsigned char *sha1);\ndiff --git a/path.c b/path.c\nindex 495d17c..4f4018d 100644\n--- a/path.c\n+++ b/path.c\n@@ -11,6 +11,7 @@\n  * which is what it's designed for.\n  */\n #include \"cache.h\"\n+#include <pwd.h>\n \n static char pathname[PATH_MAX];\n static char bad_path[] = \"/bad-path/\";\n@@ -89,3 +90,74 @@ char *safe_strncpy(char *dest, const cha\n \n \treturn dest;\n }\n+\n+static const char *current_dir()\n+{\n+\treturn getcwd(pathname, sizeof(pathname));\n+}\n+\n+/* Take a raw path from is_git_repo() and canonicalize it using Linus'\n+ * idea of a blind chdir() and getcwd(). */\n+static const char *canonical_path(const char *path, int strict)\n+{\n+\tconst char *dir = path;\n+\n+\tif(strict && *dir != '/')\n+\t\treturn NULL;\n+\n+\tif(*dir == '~') {\t\t/* user-relative path */\n+\t\tstruct passwd *pw;\n+\t\tchar *slash = NULL;\n+\n+\t\tdir++;\n+\t\t/* '~/' and '~' (no slash) means users own home-dir */\n+\t\tif(!*dir || *dir == '/')\n+\t\t\tpw = getpwuid(getuid());\n+\t\telse {\n+\t\t\tif((slash = strchr(dir, '/'))) {\n+\t\t\t\t*slash = '\\0';\n+\t\t\t\tpw = getpwnam(dir);\n+\t\t\t\t*slash = '/';\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\tpw = getpwnam(dir);\n+\t\t}\n+\n+\t\t/* make sure we got something back that we can chdir() to */\n+\t\tif(!pw || chdir(pw->pw_dir) < 0)\n+\t\t\treturn NULL;\n+\n+\t\tif(slash && *slash + 1)\n+\t\t\tdir = slash + 1;\n+\t\telse\n+\t\t\tdir = current_dir();\n+\t}\n+\n+\t/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */\n+\tif(chdir(dir) < 0)\n+\t\treturn NULL;\n+\n+\treturn current_dir();\n+}\n+\n+const char *is_git_repo(const char *path, int strict)\n+{\n+\tif(!path)\n+\t\treturn NULL;\n+\n+\tif(!canonical_path(path, strict)) {\n+\t\tif(strict || !canonical_path(mkpath(\"%s.git\", path), strict))\n+\t\t\treturn NULL;\n+\t}\n+\n+\t/* This is perfectly safe, and people tend to think of the directory\n+\t * where they ran git-init-db as their repository, so humour them. */\n+\t(void)chdir(\".git\");\n+\n+\tif(access(\"objects\", X_OK) == 0 && access(\"refs\", X_OK) == 0) {\n+\t\tputenv(\"GIT_DIR=.\");\n+\t\treturn current_dir();\n+\t}\n+\n+\treturn NULL;\n+}\n---\n0.99.9.GIT\n"},{"id":"10968","messageId":"7vk6fr6h3j.fsf@assigned-by-dhcp.cox.net","threadId":"2301","inReplyTo":"20051101225921.2C6035BA82@nox.op5.se","subject":"Re: [PATCH 2/4] Library code for user-relative paths.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-02T00:14:40Z","receivedAt":"2005-11-02T00:14:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n> +\t\t\tif((slash = strchr(dir, '/'))) {\n> +\t\t\t\t*slash = '\\0';\n> +\t\t\t\tpw = getpwnam(dir);\n> +\t\t\t\t*slash = '/';\n\nShould you be writing into *slash when dir and path are const\nchar *?  I know strchr returns \"char *\" and the compiler would\nnot complain but this sounds somewhat yucky.\n\n> +\t\tif(slash && *slash + 1)\n\nI think you mean \"if (slash && slash[1])\" here.  While we are at\nit, please have a SP betweeen if and open parenthesis.\n\n> +\t\t\tdir = slash + 1;\n> +\t\telse\n> +\t\t\tdir = current_dir();\n> +\t}\n> +\n> +\t/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */\n> +\tif(chdir(dir) < 0)\n> +\t\treturn NULL;\n\nHmm.  It's not wrong, but \"dir = current_dir()\" immediately\nfollowed by \"chdir(dir)\" does not feel right.\n"},{"id":"11001","messageId":"43687B80.1020600@op5.se","threadId":"2301","inReplyTo":"7vk6fr6h3j.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/4] Library code for user-relative paths.","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-11-02T08:40:32Z","receivedAt":"2005-11-02T08:40:32Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Andreas Ericsson <ae@op5.se> writes:\n> \n> \n>>+\t\t\tif((slash = strchr(dir, '/'))) {\n>>+\t\t\t\t*slash = '\\0';\n>>+\t\t\t\tpw = getpwnam(dir);\n>>+\t\t\t\t*slash = '/';\n> \n> \n> Should you be writing into *slash when dir and path are const\n> char *?  I know strchr returns \"char *\" and the compiler would\n> not complain but this sounds somewhat yucky.\n> \n\nTrue. Although path isn't, strictly speaking, const char *, so perhaps \nthat's what needs fixing. It's only ever called with path coming from \nargv, which isn't const. I can't really imagine anywhere where the \nrepo-path might be const char * now that I think of it.\n\n> \n>>+\t\tif(slash && *slash + 1)\n> \n> \n> I think you mean \"if (slash && slash[1])\" here.  While we are at\n> it, please have a SP betweeen if and open parenthesis.\n> \n\nActually *(slash + 1), but it amounts to the same thing I suppose. ;)\n\nI looked around for indentation guide-lines but didn't found any, and \nthe current code isn't exactly consistent about it. Perhaps it needs adding?\n\n> \n>>+\t\t\tdir = slash + 1;\n>>+\t\telse\n>>+\t\t\tdir = current_dir();\n>>+\t}\n>>+\n>>+\t/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */\n>>+\tif(chdir(dir) < 0)\n>>+\t\treturn NULL;\n> \n> \n> Hmm.  It's not wrong, but \"dir = current_dir()\" immediately\n> followed by \"chdir(dir)\" does not feel right.\n> \n\nIt could be \"return current_dir();\" immediately, I suppose. Would that \nbe satisfactory?\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"}]}