{"thread":{"id":"13582","subject":"[PATCH 1/4] Implement normalize_absolute_path","startedAt":"2008-05-20T06:48:54Z","lastAt":"2008-05-22T12:48:54Z","messageCount":6,"participants":["David Reiss","Johannes Schindelin","Alex Riesen"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"77307","messageId":"48327456.1060202@facebook.com","threadId":"13582","inReplyTo":null,"subject":"[PATCH 1/4] Implement normalize_absolute_path","fromName":"David Reiss","fromEmail":"dreiss@facebook.com","sentAt":"2008-05-20T06:48:54Z","receivedAt":"2008-05-20T06:48:54Z","isPatch":true,"sender":{"key":"dreiss@facebook.com","avatar":null},"body":"normalize_absolute_path removes several oddities form absolute paths,\ngiving nice clean paths like \"/dir/sub1/sub2\".  Also add a test case\nfor this utility, based on a new test program (in the style of test-sha1).\n\nSigned-off-by: David Reiss <dreiss@facebook.com>\n---\nJunio thought it would be good to do normalization of paths in the\nGIT_CEILING_DIRECTORIES patch.  This function does the normalization.\n\nThe closest thing I could find to this in the existing code base was\nsanitary_path_copy, but it does not remove trailing slashes.\n\nIf this test suite takes too long to run, I'm fine with commenting\nmost of it out.\n\n .gitignore            |    1 +\n Makefile              |    2 +-\n cache.h               |    1 +\n path.c                |   50 +++++++++++++++++++++++++++++++++++++++++++++++++\n t/t0060-path-utils.sh |   40 +++++++++++++++++++++++++++++++++++++++\n test-path-utils.c     |   13 ++++++++++++\n 6 files changed, 106 insertions(+), 1 deletions(-)\n create mode 100755 t/t0060-path-utils.sh\n create mode 100644 test-path-utils.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 4ff2fec..c54c473 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -150,6 +150,7 @@ test-dump-cache-tree\n test-genrandom\n test-match-trees\n test-parse-options\n+test-path-utils\n test-sha1\n common-cmds.h\n *.tar.gz\ndiff --git a/Makefile b/Makefile\nindex 649ee56..d76c16b 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1182,7 +1182,7 @@ endif\n \n ### Testing rules\n \n-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X\n+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X test-path-utils$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/cache.h b/cache.h\nindex 9cee9a5..5fd1e5b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -514,6 +514,7 @@ static inline int is_absolute_path(const char *path)\n \treturn path[0] == '/';\n }\n const char *make_absolute_path(const char *path);\n+int normalize_absolute_path(char *buf, const char *path);\n \n /* Read and unpack a sha1 file into memory, write memory to a sha1 file */\n extern int sha1_object_info(const unsigned char *, unsigned long *);\ndiff --git a/path.c b/path.c\nindex b7c24a2..17921ac 100644\n--- a/path.c\n+++ b/path.c\n@@ -357,3 +357,53 @@ const char *make_absolute_path(const char *path)\n \n \treturn buf;\n }\n+\n+/*\n+ * path = absolute path\n+ * buf = buffer of at least max(2, strlen(path)+1) bytes\n+ * It is okay if buf == path, but they should not overlap otherwise.\n+ *\n+ * Performs the following normalizations on path, storing the result in buf:\n+ * - Removes trailing slashes.\n+ * - Removes empty components.\n+ * - Removes \".\" components.\n+ * - Removes \"..\" components, and the components the precede them.\n+ * \"\" and paths that contain only slashes are normalized to \"/\".\n+ * Returns the length of the output.\n+ *\n+ * Note that this function is purely textual.  It does not follow symlinks,\n+ * verify the existence of the path, or make any system calls.\n+ */\n+int normalize_absolute_path(char *buf, const char *path)\n+{\n+\tconst char *comp_start = path, *comp_end = path;\n+\tchar *dst = buf;\n+\tint comp_len;\n+\tassert(buf);\n+\tassert(path);\n+\n+\twhile (*comp_start) {\n+\t\twhile (*++comp_end && *comp_end != '/');\n+\t\tcomp_len = comp_end - comp_start;\n+\n+\t\tif (!strncmp(\"/\",  comp_start, comp_len) ||\n+\t\t    !strncmp(\"/.\", comp_start, comp_len))\n+\t\t\tgoto next;\n+\n+\t\tif (!strncmp(\"/..\", comp_start, comp_len)) {\n+\t\t\twhile (dst > buf && *--dst != '/');\n+\t\t\tgoto next;\n+\t\t}\n+\n+\t\tmemcpy(dst, comp_start, comp_len);\n+\t\tdst += comp_len;\n+\tnext:\n+\t\tcomp_start = comp_end;\n+\t}\n+\n+\tif (dst == buf)\n+\t\t*dst++ = '/';\n+\n+\t*dst = '\\0';\n+\treturn dst - buf;\n+}\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nnew file mode 100755\nindex 0000000..9076b3b\n--- /dev/null\n+++ b/t/t0060-path-utils.sh\n@@ -0,0 +1,40 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 David Reiss\n+#\n+\n+test_description='Test various path utilities'\n+\n+. ./test-lib.sh\n+\n+norm_abs() {\n+\ttest_expect_success \"normalize absolute\" \\\n+\t\"test \\$(test-path-utils normalize_absolute_path '$1') = '$2'\"\n+}\n+\n+norm_abs \"\" /\n+norm_abs / /\n+norm_abs // /\n+norm_abs /// /\n+norm_abs /. /\n+norm_abs /./ /\n+norm_abs /./.. /\n+norm_abs /../. /\n+norm_abs /./../.// /\n+norm_abs /dir/.. /\n+norm_abs /dir/sub/../.. /\n+norm_abs /dir /dir\n+norm_abs /dir// /dir\n+norm_abs /./dir /dir\n+norm_abs /dir/. /dir\n+norm_abs /dir///./ /dir\n+norm_abs /dir//sub/.. /dir\n+norm_abs /dir/sub/../ /dir\n+norm_abs //dir/sub/../. /dir\n+norm_abs /dir/s1/../s2/ /dir/s2\n+norm_abs /d1/s1///s2/..//../s3/ /d1/s3\n+norm_abs /d1/s1//../s2/../../d2 /d2\n+norm_abs /d1/.../d2 /d1/.../d2\n+norm_abs /d1/..././../d2 /d1/d2\n+\n+test_done\ndiff --git a/test-path-utils.c b/test-path-utils.c\nnew file mode 100644\nindex 0000000..1bd4321\n--- /dev/null\n+++ b/test-path-utils.c\n@@ -0,0 +1,13 @@\n+#include \"cache.h\"\n+\n+int main(int argc, char **argv)\n+{\n+\tif (argc == 3 && !strcmp(argv[1], \"normalize_absolute_path\")) {\n+\t\tchar *buf = xmalloc(strlen(argv[2])+1);\n+\t\tint rv = normalize_absolute_path(buf, argv[2]);\n+\t\tassert(strlen(buf) == rv);\n+\t\tputs(buf);\n+\t}\n+\n+\treturn 0;\n+}\n-- \n1.5.4\n"},{"id":"77321","messageId":"alpine.DEB.1.00.0805201321300.30431@racer","threadId":"13582","inReplyTo":"48327456.1060202@facebook.com","subject":"Re: [PATCH 1/4] Implement normalize_absolute_path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-05-20T12:22:41Z","receivedAt":"2008-05-20T12:22:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 19 May 2008, David Reiss wrote:\n\n> normalize_absolute_path removes several oddities form absolute paths, \n> giving nice clean paths like \"/dir/sub1/sub2\".  Also add a test case for \n> this utility, based on a new test program (in the style of test-sha1).\n\nI wonder why my advice to look at setup.c (I think I did not mention the \nfunction name \"sanitary_path_copy()\" in particular, because I figured you \nwould spot it right away) went unheeded.\n\nSo I think I will not even bother to look at your patches either.\n\nCiao,\nDscho\n"},{"id":"77327","messageId":"4832FFEA.7020905@facebook.com","threadId":"13582","inReplyTo":"alpine.DEB.1.00.0805201321300.30431@racer","subject":"Re: [PATCH 1/4] Implement normalize_absolute_path","fromName":"David Reiss","fromEmail":"dreiss@facebook.com","sentAt":"2008-05-20T16:44:26Z","receivedAt":"2008-05-20T16:44:26Z","isPatch":true,"sender":{"key":"dreiss@facebook.com","avatar":null},"body":"> I wonder why my advice to look at setup.c (I think I did not mention the\n> function name \"sanitary_path_copy()\" in particular, because I figured you\n> would spot it right away) went unheeded.\n\nI wonder why my comment in the patch went unheeded:\n> The closest thing I could find to this in the existing code base was\n> sanitary_path_copy, but it does not remove trailing slashes.\n\nHonestly, I found it quite daunting to try to track down all of the\nindirect callers of sanitary_path_copy and ensure that they would\ncontinue to work if I changed the behavior of a function that does not\ndocument what it is supposed to do.  Frankly, it would be easier for me\nto just keep rebasing my patches and apply them to my local builds.\n\n--David\n"},{"id":"77354","messageId":"20080520222447.GA13123@steel.home","threadId":"13582","inReplyTo":"48327456.1060202@facebook.com","subject":"Re: [PATCH 1/4] Implement normalize_absolute_path","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-05-20T22:24:47Z","receivedAt":"2008-05-20T22:24:47Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"David Reiss, Tue, May 20, 2008 08:48:54 +0200:\n> normalize_absolute_path removes several oddities form absolute paths,\n> giving nice clean paths like \"/dir/sub1/sub2\".  Also add a test case\n> for this utility, based on a new test program (in the style of test-sha1).\n\nHeh...\nhttp://thread.gmane.org/gmane.comp.version-control.git/68786/focus=68812\n\nThe test of the function has these cases:\n\nstatic void check(const char *cwd, const char *path, const char *good);\n\nint main(int argc, char **argv)\n{\n\t/* 1 */ check(\"/onelevel\", \"aa\", \"onelevel/aa\");\n\t/* 2 */ check(\"/\", \"..\", \"\");\n\t/* 3 */ check(\"/\", \"../..\", \"\");\n\t/* 4 */ check(\"/one\", \"aa/../bb\", \"one/bb\");\n\t/* 5 */ check(\"/one/two\", \"aa//bb\", \"one/two/aa/bb\");\n\t/* 6 */ check(\"\", \"/aa//bb\", \"aa/bb\");\n\t/* 7 */ check(\"/one/two\", \"\", \"one/two\");\n\t/* 8 */ check(\"/one/two\", \"aa/..bb/x/../cc/\", \"one/two/aa/..bb/cc\");\n\t/* 9 */ check(\"/one/two\", \"aa/x/././cc////\", \"one/two/aa/x/cc\");\n\t/* 10 */ check(\"/one/two\", \"../../../../aa\", \"aa\");\n\t/* 11 */ check(\"one/\", \"../one/two\", \"one/two\");\n\t/* 12 */ check(\"\", \"../../two\", \"two\");\n\t/* 13 */ check(\"a/b/c\", \"../../two\", \"a/two\");\n\t/* 14 */ check(\"a/b/\", \"../two\", \"a/two\");\n\t/* 15 */ check(\"///\", \"../two\", \"two\");\n\treturn 0;\n}\n\nstatic void check(const char *cwd, const char *path, const char *good)\n{\n\tstatic int n = 0;\n\tprintf(\"%-2d: %10s$ cd %s\", ++n, cwd, path);\n\tchar *t = pathexpand(cwd, path);\n\tif ( strcmp(t, good) )\n\t\tprintf(\" ____________________failed(%s)\\n\", t);\n\telse\n\t\tprintf(\" \\033[32m%s\\033[0m\\n\", t);\n\tfree(t);\n}\n"},{"id":"77379","messageId":"4833DE89.4000106@facebook.com","threadId":"13582","inReplyTo":"20080520222447.GA13123@steel.home","subject":"Re: [PATCH 1/4] Implement normalize_absolute_path","fromName":"David Reiss","fromEmail":"dreiss@facebook.com","sentAt":"2008-05-21T08:34:17Z","receivedAt":"2008-05-21T08:34:17Z","isPatch":true,"sender":{"key":"dreiss@facebook.com","avatar":null},"body":"This is close enough to what I want that I could definitely use it if it\nwere in the main tree.  I read through most of that thread, but I\ncouldn't figure out what ever happened to your patch.  (I couldn't find\na clear rejection, but I also don't see it in master.)\n\n--David\n\nAlex Riesen wrote:\n> David Reiss, Tue, May 20, 2008 08:48:54 +0200:\n>> normalize_absolute_path removes several oddities form absolute paths,\n>> giving nice clean paths like \"/dir/sub1/sub2\".  Also add a test case\n>> for this utility, based on a new test program (in the style of test-sha1).\n> \n> Heh...\n> http://thread.gmane.org/gmane.comp.version-control.git/68786/focus=68812\n> \n> The test of the function has these cases:\n> \n> static void check(const char *cwd, const char *path, const char *good);\n> \n> int main(int argc, char **argv)\n> {\n>         /* 1 */ check(\"/onelevel\", \"aa\", \"onelevel/aa\");\n>         /* 2 */ check(\"/\", \"..\", \"\");\n>         /* 3 */ check(\"/\", \"../..\", \"\");\n>         /* 4 */ check(\"/one\", \"aa/../bb\", \"one/bb\");\n>         /* 5 */ check(\"/one/two\", \"aa//bb\", \"one/two/aa/bb\");\n>         /* 6 */ check(\"\", \"/aa//bb\", \"aa/bb\");\n>         /* 7 */ check(\"/one/two\", \"\", \"one/two\");\n>         /* 8 */ check(\"/one/two\", \"aa/..bb/x/../cc/\", \"one/two/aa/..bb/cc\");\n>         /* 9 */ check(\"/one/two\", \"aa/x/././cc////\", \"one/two/aa/x/cc\");\n>         /* 10 */ check(\"/one/two\", \"../../../../aa\", \"aa\");\n>         /* 11 */ check(\"one/\", \"../one/two\", \"one/two\");\n>         /* 12 */ check(\"\", \"../../two\", \"two\");\n>         /* 13 */ check(\"a/b/c\", \"../../two\", \"a/two\");\n>         /* 14 */ check(\"a/b/\", \"../two\", \"a/two\");\n>         /* 15 */ check(\"///\", \"../two\", \"two\");\n>         return 0;\n> }\n> \n> static void check(const char *cwd, const char *path, const char *good)\n> {\n>         static int n = 0;\n>         printf(\"%-2d: %10s$ cd %s\", ++n, cwd, path);\n>         char *t = pathexpand(cwd, path);\n>         if ( strcmp(t, good) )\n>                 printf(\" ____________________failed(%s)\\n\", t);\n>         else\n>                 printf(\" \\033[32m%s\\033[0m\\n\", t);\n>         free(t);\n> }\n> \n> \n"},{"id":"77463","messageId":"20080522124854.GC3206@steel.home","threadId":"13582","inReplyTo":"4833DE89.4000106@facebook.com","subject":"Re: [PATCH 1/4] Implement normalize_absolute_path","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-05-22T12:48:54Z","receivedAt":"2008-05-22T12:48:54Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"David Reiss, Wed, May 21, 2008 10:34:17 +0200:\n> This is close enough to what I want that I could definitely use it if it\n> were in the main tree.  I read through most of that thread, but I\n> couldn't figure out what ever happened to your patch.  (I couldn't find\n> a clear rejection, but I also don't see it in master.)\n\nMe too. OTOH, it was not a clear proposal for inclusion.\n"}]}