{"thread":{"id":"704","subject":"[PATCH 1/1] bugfix for git-checkout-cache --prefix=/symlink/export_dir/ -a","startedAt":"2005-05-23T08:49:38Z","lastAt":"2005-05-24T08:51:27Z","messageCount":4,"participants":["David Greaves","Linus Torvalds","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"3803","messageId":"E1Da8d0-0002GR-4m@ash.dgreaves.com","threadId":"704","inReplyTo":null,"subject":"[PATCH 1/1] bugfix for git-checkout-cache --prefix=/symlink/export_dir/ -a","fromName":"David Greaves","fromEmail":"david@dgreaves.com","sentAt":"2005-05-23T08:49:38Z","receivedAt":"2005-05-23T08:49:38Z","isPatch":true,"sender":{"key":"david@dgreaves.com","avatar":"https://gravatar.com/avatar/ca67bad50999edcdd137c9a65da2381557d175bea99ae956afdabc5785e42b79?d=mp&s=160"},"body":"If there's a prefix then allow symlinks to directories in it.\nThis fixes a bug where\n  git-checkout-cache --prefix=/symlink/export_dir/ -a\notherwise fails.\n\nSigned-off-by: David Greaves <david@dgreaves.com>\n\n---\ncommit 18006ac69ae9db97b7d96fd0bfb1bdb6893e318d\ntree 37580a3d32262d2cee7d28b20474c0f2ceb6faaa\nparent 2aef5bbae99aeba3551408eae13faea02bf55b67\nauthor David Greaves <david@dgreaves.com> Mon, 23 May 2005 09:42:04 +0100\ncommitter David Greaves <david@dgreaves.com> Mon, 23 May 2005 09:42:04 +0100\n\n checkout-cache.c |    8 ++++++--\n 1 files changed, 6 insertions(+), 2 deletions(-)\n\nIndex: checkout-cache.c\n===================================================================\n--- 99282828d5af15b0af0d0eac13a5b1194e88342c/checkout-cache.c  (mode:100644)\n+++ 37580a3d32262d2cee7d28b20474c0f2ceb6faaa/checkout-cache.c  (mode:100644)\n@@ -37,20 +37,25 @@\n #include \"cache.h\"\n \n static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;\n+const char *base_dir = \"\";\n \n static void create_directories(const char *path)\n {\n \tint len = strlen(path);\n \tchar *buf = xmalloc(len + 1);\n \tconst char *slash = path;\n+\tint baselen = strlen(base_dir);\n \n \twhile ((slash = strchr(slash+1, '/')) != NULL) {\n+\t\tstruct stat st;\n \t\tlen = slash - path;\n \t\tmemcpy(buf, path, len);\n \t\tbuf[len] = 0;\n+\t\tif (slash - path <= baselen &&\n+\t\t    !stat(buf, &st) && S_ISDIR(st.st_mode))\n+\t\t\tcontinue; /* allow symlinks only in --prefix */\n \t\tif (mkdir(buf, 0755)) {\n \t\t\tif (errno == EEXIST) {\n-\t\t\t\tstruct stat st;\n \t\t\t\tif (!lstat(buf, &st) && S_ISDIR(st.st_mode))\n \t\t\t\t\tcontinue; /* ok */\n \t\t\t\tif (force && !unlink(buf) && !mkdir(buf, 0755))\n@@ -229,7 +234,6 @@\n int main(int argc, char **argv)\n {\n \tint i, force_filename = 0;\n-\tconst char *base_dir = \"\";\n \tstruct cache_file cache_file;\n \tint newfd = -1;\n \n"},{"id":"3811","messageId":"Pine.LNX.4.58.0505231145190.2307@ppc970.osdl.org","threadId":"704","inReplyTo":"E1Da8d0-0002GR-4m@ash.dgreaves.com","subject":"Re: [PATCH 1/1] bugfix for git-checkout-cache --prefix=/symlink/export_dir/ -a","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-23T18:45:47Z","receivedAt":"2005-05-23T18:45:47Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 23 May 2005, David Greaves wrote:\n>\n> If there's a prefix then allow symlinks to directories in it.\n> This fixes a bug where\n>   git-checkout-cache --prefix=/symlink/export_dir/ -a\n> otherwise fails.\n\nHmm.. Does this alternative work for you instead?\n\n[ Totally untested, please check for sanity first!! ]\n\n\t\tLinus\n\n---\ndiff --git a/checkout-cache.c b/checkout-cache.c\n--- a/checkout-cache.c\n+++ b/checkout-cache.c\n@@ -37,6 +37,8 @@\n #include \"cache.h\"\n \n static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;\n+static const char *base_dir = \"\";\n+static int base_dir_len = 0;\n \n static void create_directories(const char *path)\n {\n@@ -51,10 +53,10 @@ static void create_directories(const cha\n \t\tif (mkdir(buf, 0755)) {\n \t\t\tif (errno == EEXIST) {\n \t\t\t\tstruct stat st;\n-\t\t\t\tif (!lstat(buf, &st) && S_ISDIR(st.st_mode))\n-\t\t\t\t\tcontinue; /* ok */\n-\t\t\t\tif (force && !unlink(buf) && !mkdir(buf, 0755))\n+\t\t\t\tif (len > base_dir_len && force && !unlink(buf) && !mkdir(buf, 0755))\n \t\t\t\t\tcontinue;\n+\t\t\t\tif (!stat(buf, &st) && S_ISDIR(st.st_mode))\n+\t\t\t\t\tcontinue; /* ok */\n \t\t\t}\n \t\t\tdie(\"cannot create directory at %s\", buf);\n \t\t}\n@@ -163,11 +165,11 @@ static int write_entry(struct cache_entr\n \treturn 0;\n }\n \n-static int checkout_entry(struct cache_entry *ce, const char *base_dir)\n+static int checkout_entry(struct cache_entry *ce)\n {\n \tstruct stat st;\n \tstatic char path[MAXPATHLEN+1];\n-\tint len = strlen(base_dir);\n+\tint len = base_dir_len;\n \n \tmemcpy(path, base_dir, len);\n \tstrcpy(path + len, ce->name);\n@@ -194,7 +196,7 @@ static int checkout_entry(struct cache_e\n \treturn write_entry(ce, path);\n }\n \n-static int checkout_file(const char *name, const char *base_dir)\n+static int checkout_file(const char *name)\n {\n \tint pos = cache_name_pos(name, strlen(name));\n \tif (pos < 0) {\n@@ -209,10 +211,10 @@ static int checkout_file(const char *nam\n \t\t}\n \t\treturn -1;\n \t}\n-\treturn checkout_entry(active_cache[pos], base_dir);\n+\treturn checkout_entry(active_cache[pos]);\n }\n \n-static int checkout_all(const char *base_dir)\n+static int checkout_all(void)\n {\n \tint i;\n \n@@ -220,7 +222,7 @@ static int checkout_all(const char *base\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tif (ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (checkout_entry(ce, base_dir) < 0)\n+\t\tif (checkout_entry(ce) < 0)\n \t\t\treturn -1;\n \t}\n \treturn 0;\n@@ -229,7 +231,6 @@ static int checkout_all(const char *base\n int main(int argc, char **argv)\n {\n \tint i, force_filename = 0;\n-\tconst char *base_dir = \"\";\n \tstruct cache_file cache_file;\n \tint newfd = -1;\n \n@@ -241,7 +242,7 @@ int main(int argc, char **argv)\n \t\tconst char *arg = argv[i];\n \t\tif (!force_filename) {\n \t\t\tif (!strcmp(arg, \"-a\")) {\n-\t\t\t\tcheckout_all(base_dir);\n+\t\t\t\tcheckout_all();\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--\")) {\n@@ -272,10 +273,11 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\tif (!memcmp(arg, \"--prefix=\", 9)) {\n \t\t\t\tbase_dir = arg+9;\n+\t\t\t\tbase_dir_len = strlen(base_dir);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\tif (base_dir[0]) {\n+\t\tif (base_dir_len) {\n \t\t\t/* when --prefix is specified we do not\n \t\t\t * want to update cache.\n \t\t\t */\n@@ -285,7 +287,7 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\trefresh_cache = 0;\n \t\t}\n-\t\tcheckout_file(arg, base_dir);\n+\t\tcheckout_file(arg);\n \t}\n \n \tif (0 <= newfd &&\n"},{"id":"3814","messageId":"Pine.LNX.4.58.0505231208460.2307@ppc970.osdl.org","threadId":"704","inReplyTo":"Pine.LNX.4.58.0505231145190.2307@ppc970.osdl.org","subject":"Re: [PATCH 1/1] bugfix for git-checkout-cache --prefix=/symlink/export_dir/ -a","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-23T19:09:20Z","receivedAt":"2005-05-23T19:09:20Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 23 May 2005, Linus Torvalds wrote:\n> > otherwise fails.\n> \n> Hmm.. Does this alternative work for you instead?\n> \n> [ Totally untested, please check for sanity first!! ]\n\nBtw, I'm not going to apply this, and expect that David or somebody else \ncan validate it and send it back to me as \"tested\".\n\n\t\tLinus\n"},{"id":"3852","messageId":"7vacmlvwfk.fsf_-_@assigned-by-dhcp.cox.net","threadId":"704","inReplyTo":"Pine.LNX.4.58.0505231208460.2307@ppc970.osdl.org","subject":"[PATCH] Allow symlinks in the leading path in checkout-cache --prefix=","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-24T08:51:27Z","receivedAt":"2005-05-24T08:51:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is what Linus wrote, improving what David Greaves\noriginally submitted.\n\n    Hmm.. Does this alternative work for you instead?\n    [ Totally untested, please check for sanity first!! ]\n    Btw, I'm not going to apply this, and expect that David or somebody else \n    can validate it and send it back to me as \"tested\".\n\nI just added a test case and verified the patch works.\n\nAuthor: David Greaves <david@dgreaves.com>\nAuthor: Linus Torvalds <torvalds@osdl.org>\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ncheckout-cache.c                |   28 ++++++-----\nt/t2003-checkout-cache-mkdir.sh |   95 ++++++++++++++++++++++++++++++++++++++++\n2 files changed, 110 insertions(+), 13 deletions(-)\nnew file (100755): t/t2003-checkout-cache-mkdir.sh\n\ndiff --git a/checkout-cache.c b/checkout-cache.c\n--- a/checkout-cache.c\n+++ b/checkout-cache.c\n@@ -37,6 +37,8 @@\n #include \"cache.h\"\n \n static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;\n+static const char *base_dir = \"\";\n+static int base_dir_len = 0;\n \n static void create_directories(const char *path)\n {\n@@ -51,10 +53,10 @@ static void create_directories(const cha\n \t\tif (mkdir(buf, 0755)) {\n \t\t\tif (errno == EEXIST) {\n \t\t\t\tstruct stat st;\n-\t\t\t\tif (!lstat(buf, &st) && S_ISDIR(st.st_mode))\n-\t\t\t\t\tcontinue; /* ok */\n-\t\t\t\tif (force && !unlink(buf) && !mkdir(buf, 0755))\n+\t\t\t\tif (len > base_dir_len && force && !unlink(buf) && !mkdir(buf, 0755))\n \t\t\t\t\tcontinue;\n+\t\t\t\tif (!stat(buf, &st) && S_ISDIR(st.st_mode))\n+\t\t\t\t\tcontinue; /* ok */\n \t\t\t}\n \t\t\tdie(\"cannot create directory at %s\", buf);\n \t\t}\n@@ -163,11 +165,11 @@ static int write_entry(struct cache_entr\n \treturn 0;\n }\n \n-static int checkout_entry(struct cache_entry *ce, const char *base_dir)\n+static int checkout_entry(struct cache_entry *ce)\n {\n \tstruct stat st;\n \tstatic char path[MAXPATHLEN+1];\n-\tint len = strlen(base_dir);\n+\tint len = base_dir_len;\n \n \tmemcpy(path, base_dir, len);\n \tstrcpy(path + len, ce->name);\n@@ -194,7 +196,7 @@ static int checkout_entry(struct cache_e\n \treturn write_entry(ce, path);\n }\n \n-static int checkout_file(const char *name, const char *base_dir)\n+static int checkout_file(const char *name)\n {\n \tint pos = cache_name_pos(name, strlen(name));\n \tif (pos < 0) {\n@@ -209,10 +211,10 @@ static int checkout_file(const char *nam\n \t\t}\n \t\treturn -1;\n \t}\n-\treturn checkout_entry(active_cache[pos], base_dir);\n+\treturn checkout_entry(active_cache[pos]);\n }\n \n-static int checkout_all(const char *base_dir)\n+static int checkout_all(void)\n {\n \tint i;\n \n@@ -220,7 +222,7 @@ static int checkout_all(const char *base\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tif (ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (checkout_entry(ce, base_dir) < 0)\n+\t\tif (checkout_entry(ce) < 0)\n \t\t\treturn -1;\n \t}\n \treturn 0;\n@@ -229,7 +231,6 @@ static int checkout_all(const char *base\n int main(int argc, char **argv)\n {\n \tint i, force_filename = 0;\n-\tconst char *base_dir = \"\";\n \tstruct cache_file cache_file;\n \tint newfd = -1;\n \n@@ -241,7 +242,7 @@ int main(int argc, char **argv)\n \t\tconst char *arg = argv[i];\n \t\tif (!force_filename) {\n \t\t\tif (!strcmp(arg, \"-a\")) {\n-\t\t\t\tcheckout_all(base_dir);\n+\t\t\t\tcheckout_all();\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--\")) {\n@@ -272,10 +273,11 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\tif (!memcmp(arg, \"--prefix=\", 9)) {\n \t\t\t\tbase_dir = arg+9;\n+\t\t\t\tbase_dir_len = strlen(base_dir);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\tif (base_dir[0]) {\n+\t\tif (base_dir_len) {\n \t\t\t/* when --prefix is specified we do not\n \t\t\t * want to update cache.\n \t\t\t */\n@@ -285,7 +287,7 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\trefresh_cache = 0;\n \t\t}\n-\t\tcheckout_file(arg, base_dir);\n+\t\tcheckout_file(arg);\n \t}\n \n \tif (0 <= newfd &&\ndiff --git a/t/t2003-checkout-cache-mkdir.sh b/t/t2003-checkout-cache-mkdir.sh\nnew file mode 100755\n--- /dev/null\n+++ b/t/t2003-checkout-cache-mkdir.sh\n@@ -0,0 +1,95 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Junio C Hamano\n+#\n+\n+test_description='git-checkout-cache --prefix test.\n+\n+This test makes sure that --prefix option works as advertised, and\n+also verifies that such leading path may contain symlinks, unlike\n+the GIT controlled paths.\n+'\n+\n+. ./test-lib.sh\n+\n+test_expect_success \\\n+    'setup' \\\n+    'mkdir path1 &&\n+    echo frotz >path0 &&\n+    echo rezrov >path1/file1 &&\n+    git-update-cache --add path0 path1/file1'\n+\n+test_expect_success \\\n+    'have symlink in place where dir is expected.' \\\n+    'rm -fr path0 path1 &&\n+     mkdir path2 &&\n+     ln -s path2 path1 &&\n+     git-checkout-cache -f -a &&\n+     test ! -h path1 && test -d path1 &&\n+     test -f path1/file1 && test ! -f path2/file1'\n+\n+test_expect_success \\\n+    'use --prefix=path2/' \\\n+    'rm -fr path0 path1 path2 &&\n+     mkdir path2 &&\n+     git-checkout-cache --prefix=path2/ -f -a &&\n+     test -f path2/path0 &&\n+     test -f path2/path1/file1 &&\n+     test ! -f path0 &&\n+     test ! -f path1/file1'\n+\n+test_expect_success \\\n+    'use --prefix=tmp-' \\\n+    'rm -fr path0 path1 path2 tmp* &&\n+     git-checkout-cache --prefix=tmp- -f -a &&\n+     test -f tmp-path0 &&\n+     test -f tmp-path1/file1 &&\n+     test ! -f path0 &&\n+     test ! -f path1/file1'\n+\n+test_expect_success \\\n+    'use --prefix=tmp- but with a conflicting file and dir' \\\n+    'rm -fr path0 path1 path2 tmp* &&\n+     echo nitfol >tmp-path1 &&\n+     mkdir tmp-path0 &&\n+     git-checkout-cache --prefix=tmp- -f -a &&\n+     test -f tmp-path0 &&\n+     test -f tmp-path1/file1 &&\n+     test ! -f path0 &&\n+     test ! -f path1/file1'\n+\n+# Linus fix #1\n+test_expect_success \\\n+    'use --prefix=tmp/orary/ where tmp is a symlink' \\\n+    'rm -fr path0 path1 path2 tmp* &&\n+     mkdir tmp1 tmp1/orary &&\n+     ln -s tmp1 tmp &&\n+     git-checkout-cache --prefix=tmp/orary/ -f -a &&\n+     test -d tmp1/orary &&\n+     test -f tmp1/orary/path0 &&\n+     test -f tmp1/orary/path1/file1 &&\n+     test -h tmp'\n+\n+# Linus fix #2\n+test_expect_success \\\n+    'use --prefix=tmp/orary- where tmp is a symlink' \\\n+    'rm -fr path0 path1 path2 tmp* &&\n+     mkdir tmp1 &&\n+     ln -s tmp1 tmp &&\n+     git-checkout-cache --prefix=tmp/orary- -f -a &&\n+     test -f tmp1/orary-path0 &&\n+     test -f tmp1/orary-path1/file1 &&\n+     test -h tmp'\n+\n+# Linus fix #3\n+test_expect_success \\\n+    'use --prefix=tmp- where tmp-path1 is a symlink' \\\n+    'rm -fr path0 path1 path2 tmp* &&\n+     mkdir tmp1 &&\n+     ln -s tmp1 tmp-path1 &&\n+     git-checkout-cache --prefix=tmp- -f -a &&\n+     test -f tmp-path0 &&\n+     test ! -h tmp-path1 &&\n+     test -d tmp-path1 &&\n+     test -f tmp-path1/file1'\n+\n------------------------------------------------\n\n"}]}