Commit 618818dcb7ada52e64b694d00806d18d063b77e0

nulltoken 2011-01-23T16:15:11

Added git_prettify_file_path().

diff --git a/src/fileops.c b/src/fileops.c
index 00eb4fc..d23246d 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -456,3 +456,30 @@ int git_prettify_dir_path(char *buffer_out, const char *path)
 
 	return GIT_SUCCESS;
 }
+
+int git_prettify_file_path(char *buffer_out, const char *path)
+{
+	int error, path_len, i;
+	const char* pattern = "/..";
+
+	path_len = strlen(path);
+
+	/* Let's make sure the filename doesn't end with "/", "/." or "/.." */
+	for (i = 1; path_len > i && i < 4; i++) {
+		if (!strncmp(path + path_len - i, pattern, i))
+			return GIT_ERROR;
+	}
+
+	error =  git_prettify_dir_path(buffer_out, path);
+	if (error < GIT_SUCCESS)
+		return error;
+
+	path_len = strlen(buffer_out);
+	if (path_len < 2)
+		return GIT_ERROR;
+
+	/* Remove the trailing slash */
+	buffer_out[path_len - 1] = '\0';
+
+	return GIT_SUCCESS;
+}
diff --git a/src/fileops.h b/src/fileops.h
index d562dc7..1f17960 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -155,4 +155,26 @@ extern int gitfo_close_cached(gitfo_cache *ioc);
  */
 GIT_EXTERN(int) git_prettify_dir_path(char *buffer_out, const char *path);
 
+/**
+ * Clean up a provided absolute or relative file path.
+ * 
+ * This prettification relies on basic operations such as coalescing 
+ * multiple forward slashes into a single slash, removing '.' and 
+ * './' current directory segments, and removing parent directory 
+ * whenever '..' is encountered.
+ *
+ * For instance, this will turn "d1/s1///s2/..//../s3" into "d1/s3".
+ *
+ * This only performs a string based analysis of the path.
+ * No checks are done to make sure the path actually makes sense from 
+ * the file system perspective.
+ *
+ * @param buffer_out buffer to populate with the normalized path.
+ * @param path file path to clean up.
+ * @return
+ * - GIT_SUCCESS on success;
+ * - GIT_ERROR when the input path is invalid or escapes the current directory.
+ */
+GIT_EXTERN(int) git_prettify_file_path(char *buffer_out, const char *path);
+
 #endif /* INCLUDE_fileops_h__ */
diff --git a/tests/t0005-path.c b/tests/t0005-path.c
index dc2ccc9..087373c 100644
--- a/tests/t0005-path.c
+++ b/tests/t0005-path.c
@@ -1,12 +1,14 @@
 #include "test_lib.h"
 #include "fileops.h"
 
-static int ensure_normalized(const char *input_path, const char *expected_path)
+typedef int (normalize_path)(char *, const char *);
+
+static int ensure_normalized(const char *input_path, const char *expected_path, normalize_path normalizer)
 {
 	int error = GIT_SUCCESS;
 	char buffer_out[GIT_PATH_MAX];
 
-	error = git_prettify_dir_path(buffer_out, input_path);
+	error = normalizer(buffer_out, input_path);
 	if (error < GIT_SUCCESS)
 		return error;
 
@@ -19,75 +21,165 @@ static int ensure_normalized(const char *input_path, const char *expected_path)
 	return error;
 }
 
-BEGIN_TEST(path_prettifying)
-	must_pass(ensure_normalized("./testrepo.git", "testrepo.git/"));
-	must_pass(ensure_normalized("./.git", ".git/"));
-	must_pass(ensure_normalized("./git.", "git./"));
-	must_pass(ensure_normalized("git./", "git./"));
-	must_pass(ensure_normalized("", ""));
-	must_pass(ensure_normalized(".", ""));
-	must_pass(ensure_normalized("./", ""));
-	must_pass(ensure_normalized("./.", ""));
-	must_fail(ensure_normalized("./..", NULL));
-	must_fail(ensure_normalized("../.", NULL));
-	must_fail(ensure_normalized("./.././/", NULL));
-	must_pass(ensure_normalized("dir/..", ""));
-	must_pass(ensure_normalized("dir/sub/../..", ""));
-	must_pass(ensure_normalized("dir/sub/..///..", ""));
-	must_pass(ensure_normalized("dir/sub///../..", ""));
-	must_pass(ensure_normalized("dir/sub///..///..", ""));
-	must_fail(ensure_normalized("dir/sub/../../..", NULL));
-	must_pass(ensure_normalized("dir", "dir/"));
-	must_pass(ensure_normalized("dir//", "dir/"));
-	must_pass(ensure_normalized("./dir", "dir/"));
-	must_pass(ensure_normalized("dir/.", "dir/"));
-	must_pass(ensure_normalized("dir///./", "dir/"));
-	must_pass(ensure_normalized("dir/sub/..", "dir/"));
-	must_pass(ensure_normalized("dir//sub/..", "dir/"));
-	must_pass(ensure_normalized("dir//sub/../", "dir/"));
-	must_pass(ensure_normalized("dir/sub/../", "dir/"));
-	must_pass(ensure_normalized("dir/sub/../.", "dir/"));
-	must_pass(ensure_normalized("dir/s1/../s2/", "dir/s2/"));
-	must_pass(ensure_normalized("d1/s1///s2/..//../s3/", "d1/s3/"));
-	must_pass(ensure_normalized("d1/s1//../s2/../../d2", "d2/"));
-	must_pass(ensure_normalized("dir/sub/../", "dir/"));
-	must_fail(ensure_normalized("....", NULL));
-	must_fail(ensure_normalized("...", NULL));
-	must_fail(ensure_normalized("./...", NULL));
-	must_fail(ensure_normalized("d1/...", NULL));
-	must_fail(ensure_normalized("d1/.../", NULL));
-	must_fail(ensure_normalized("d1/.../d2", NULL));
+static int ensure_dir_path_normalized(const char *input_path, const char *expected_path)
+{
+	return ensure_normalized(input_path, expected_path, git_prettify_dir_path);
+}
+
+static int ensure_file_path_normalized(const char *input_path, const char *expected_path)
+{
+	return ensure_normalized(input_path, expected_path, git_prettify_file_path);
+}
+
+BEGIN_TEST(file_path_prettifying)
+	must_pass(ensure_file_path_normalized("a", "a"));
+	must_pass(ensure_file_path_normalized("./testrepo.git", "testrepo.git"));
+	must_pass(ensure_file_path_normalized("./.git", ".git"));
+	must_pass(ensure_file_path_normalized("./git.", "git."));
+	must_fail(ensure_file_path_normalized("git./", NULL));
+	must_fail(ensure_file_path_normalized("", NULL));
+	must_fail(ensure_file_path_normalized(".", NULL));
+	must_fail(ensure_file_path_normalized("./", NULL));
+	must_fail(ensure_file_path_normalized("./.", NULL));
+	must_fail(ensure_file_path_normalized("./..", NULL));
+	must_fail(ensure_file_path_normalized("../.", NULL));
+	must_fail(ensure_file_path_normalized("./.././/", NULL));
+	must_fail(ensure_file_path_normalized("dir/..", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub/../..", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub/..///..", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub///../..", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub///..///..", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub/../../..", NULL));
+	must_pass(ensure_file_path_normalized("dir", "dir"));
+	must_fail(ensure_file_path_normalized("dir//", NULL));
+	must_pass(ensure_file_path_normalized("./dir", "dir"));
+	must_fail(ensure_file_path_normalized("dir/.", NULL));
+	must_fail(ensure_file_path_normalized("dir///./", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub/..", NULL));
+	must_fail(ensure_file_path_normalized("dir//sub/..",NULL));
+	must_fail(ensure_file_path_normalized("dir//sub/../", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub/../", NULL));
+	must_fail(ensure_file_path_normalized("dir/sub/../.", NULL));
+	must_fail(ensure_file_path_normalized("dir/s1/../s2/", NULL));
+	must_fail(ensure_file_path_normalized("d1/s1///s2/..//../s3/", NULL));
+	must_pass(ensure_file_path_normalized("d1/s1//../s2/../../d2", "d2"));
+	must_fail(ensure_file_path_normalized("dir/sub/../", NULL));
+	must_fail(ensure_file_path_normalized("....", NULL));
+	must_fail(ensure_file_path_normalized("...", NULL));
+	must_fail(ensure_file_path_normalized("./...", NULL));
+	must_fail(ensure_file_path_normalized("d1/...", NULL));
+	must_fail(ensure_file_path_normalized("d1/.../", NULL));
+	must_fail(ensure_file_path_normalized("d1/.../d2", NULL));
+	
+	must_pass(ensure_file_path_normalized("/a", "/a"));
+	must_pass(ensure_file_path_normalized("/./testrepo.git", "/testrepo.git"));
+	must_pass(ensure_file_path_normalized("/./.git", "/.git"));
+	must_pass(ensure_file_path_normalized("/./git.", "/git."));
+	must_fail(ensure_file_path_normalized("/git./", NULL));
+	must_fail(ensure_file_path_normalized("/", NULL));
+	must_fail(ensure_file_path_normalized("/.", NULL));
+	must_fail(ensure_file_path_normalized("/./", NULL));
+	must_fail(ensure_file_path_normalized("/./.", NULL));
+	must_fail(ensure_file_path_normalized("/./..", NULL));
+	must_fail(ensure_file_path_normalized("/../.", NULL));
+	must_fail(ensure_file_path_normalized("/./.././/", NULL));
+	must_fail(ensure_file_path_normalized("/dir/..", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub/../..", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub/..///..", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub///../..", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub///..///..", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub/../../..", NULL));
+	must_pass(ensure_file_path_normalized("/dir", "/dir"));
+	must_fail(ensure_file_path_normalized("/dir//", NULL));
+	must_pass(ensure_file_path_normalized("/./dir", "/dir"));
+	must_fail(ensure_file_path_normalized("/dir/.", NULL));
+	must_fail(ensure_file_path_normalized("/dir///./", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub/..", NULL));
+	must_fail(ensure_file_path_normalized("/dir//sub/..",NULL));
+	must_fail(ensure_file_path_normalized("/dir//sub/../", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub/../", NULL));
+	must_fail(ensure_file_path_normalized("/dir/sub/../.", NULL));
+	must_fail(ensure_file_path_normalized("/dir/s1/../s2/", NULL));
+	must_fail(ensure_file_path_normalized("/d1/s1///s2/..//../s3/", NULL));
+	must_pass(ensure_file_path_normalized("/d1/s1//../s2/../../d2", "/d2"));
+	must_fail(ensure_file_path_normalized("/dir/sub/../", NULL));
+	must_fail(ensure_file_path_normalized("/....", NULL));
+	must_fail(ensure_file_path_normalized("/...", NULL));
+	must_fail(ensure_file_path_normalized("/./...", NULL));
+	must_fail(ensure_file_path_normalized("/d1/...", NULL));
+	must_fail(ensure_file_path_normalized("/d1/.../", NULL));
+	must_fail(ensure_file_path_normalized("/d1/.../d2", NULL));
+END_TEST
+
+BEGIN_TEST(dir_path_prettifying)
+	must_pass(ensure_dir_path_normalized("./testrepo.git", "testrepo.git/"));
+	must_pass(ensure_dir_path_normalized("./.git", ".git/"));
+	must_pass(ensure_dir_path_normalized("./git.", "git./"));
+	must_pass(ensure_dir_path_normalized("git./", "git./"));
+	must_pass(ensure_dir_path_normalized("", ""));
+	must_pass(ensure_dir_path_normalized(".", ""));
+	must_pass(ensure_dir_path_normalized("./", ""));
+	must_pass(ensure_dir_path_normalized("./.", ""));
+	must_fail(ensure_dir_path_normalized("./..", NULL));
+	must_fail(ensure_dir_path_normalized("../.", NULL));
+	must_fail(ensure_dir_path_normalized("./.././/", NULL));
+	must_pass(ensure_dir_path_normalized("dir/..", ""));
+	must_pass(ensure_dir_path_normalized("dir/sub/../..", ""));
+	must_pass(ensure_dir_path_normalized("dir/sub/..///..", ""));
+	must_pass(ensure_dir_path_normalized("dir/sub///../..", ""));
+	must_pass(ensure_dir_path_normalized("dir/sub///..///..", ""));
+	must_fail(ensure_dir_path_normalized("dir/sub/../../..", NULL));
+	must_pass(ensure_dir_path_normalized("dir", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir//", "dir/"));
+	must_pass(ensure_dir_path_normalized("./dir", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir/.", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir///./", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir/sub/..", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir//sub/..", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir//sub/../", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir/sub/../.", "dir/"));
+	must_pass(ensure_dir_path_normalized("dir/s1/../s2/", "dir/s2/"));
+	must_pass(ensure_dir_path_normalized("d1/s1///s2/..//../s3/", "d1/s3/"));
+	must_pass(ensure_dir_path_normalized("d1/s1//../s2/../../d2", "d2/"));
+	must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/"));
+	must_fail(ensure_dir_path_normalized("....", NULL));
+	must_fail(ensure_dir_path_normalized("...", NULL));
+	must_fail(ensure_dir_path_normalized("./...", NULL));
+	must_fail(ensure_dir_path_normalized("d1/...", NULL));
+	must_fail(ensure_dir_path_normalized("d1/.../", NULL));
+	must_fail(ensure_dir_path_normalized("d1/.../d2", NULL));
 
-	must_pass(ensure_normalized("/./testrepo.git", "/testrepo.git/"));
-	must_pass(ensure_normalized("/./.git", "/.git/"));
-	must_pass(ensure_normalized("/./git.", "/git./"));
-	must_pass(ensure_normalized("/git./", "/git./"));
-	must_pass(ensure_normalized("/", "/"));
-	must_pass(ensure_normalized("//", "/"));
-	must_pass(ensure_normalized("///", "/"));
-	must_pass(ensure_normalized("/.", "/"));
-	must_pass(ensure_normalized("/./", "/"));
-	must_fail(ensure_normalized("/./..", NULL));
-	must_fail(ensure_normalized("/../.", NULL));
-	must_fail(ensure_normalized("/./.././/", NULL));
-	must_pass(ensure_normalized("/dir/..", "/"));
-	must_pass(ensure_normalized("/dir/sub/../..", "/"));
-	must_fail(ensure_normalized("/dir/sub/../../..", NULL));
-	must_pass(ensure_normalized("/dir", "/dir/"));
-	must_pass(ensure_normalized("/dir//", "/dir/"));
-	must_pass(ensure_normalized("/./dir", "/dir/"));
-	must_pass(ensure_normalized("/dir/.", "/dir/"));
-	must_pass(ensure_normalized("/dir///./", "/dir/"));
-	must_pass(ensure_normalized("/dir//sub/..", "/dir/"));
-	must_pass(ensure_normalized("/dir/sub/../", "/dir/"));
-	must_pass(ensure_normalized("//dir/sub/../.", "/dir/"));
-	must_pass(ensure_normalized("/dir/s1/../s2/", "/dir/s2/"));
-	must_pass(ensure_normalized("/d1/s1///s2/..//../s3/", "/d1/s3/"));
-	must_pass(ensure_normalized("/d1/s1//../s2/../../d2", "/d2/"));
-	must_fail(ensure_normalized("/....", NULL));
-	must_fail(ensure_normalized("/...", NULL));
-	must_fail(ensure_normalized("/./...", NULL));
-	must_fail(ensure_normalized("/d1/...", NULL));
-	must_fail(ensure_normalized("/d1/.../", NULL));
-	must_fail(ensure_normalized("/d1/.../d2", NULL));
+	must_pass(ensure_dir_path_normalized("/./testrepo.git", "/testrepo.git/"));
+	must_pass(ensure_dir_path_normalized("/./.git", "/.git/"));
+	must_pass(ensure_dir_path_normalized("/./git.", "/git./"));
+	must_pass(ensure_dir_path_normalized("/git./", "/git./"));
+	must_pass(ensure_dir_path_normalized("/", "/"));
+	must_pass(ensure_dir_path_normalized("//", "/"));
+	must_pass(ensure_dir_path_normalized("///", "/"));
+	must_pass(ensure_dir_path_normalized("/.", "/"));
+	must_pass(ensure_dir_path_normalized("/./", "/"));
+	must_fail(ensure_dir_path_normalized("/./..", NULL));
+	must_fail(ensure_dir_path_normalized("/../.", NULL));
+	must_fail(ensure_dir_path_normalized("/./.././/", NULL));
+	must_pass(ensure_dir_path_normalized("/dir/..", "/"));
+	must_pass(ensure_dir_path_normalized("/dir/sub/../..", "/"));
+	must_fail(ensure_dir_path_normalized("/dir/sub/../../..", NULL));
+	must_pass(ensure_dir_path_normalized("/dir", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/dir//", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/./dir", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/dir/.", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/dir///./", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/dir//sub/..", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/dir/sub/../", "/dir/"));
+	must_pass(ensure_dir_path_normalized("//dir/sub/../.", "/dir/"));
+	must_pass(ensure_dir_path_normalized("/dir/s1/../s2/", "/dir/s2/"));
+	must_pass(ensure_dir_path_normalized("/d1/s1///s2/..//../s3/", "/d1/s3/"));
+	must_pass(ensure_dir_path_normalized("/d1/s1//../s2/../../d2", "/d2/"));
+	must_fail(ensure_dir_path_normalized("/....", NULL));
+	must_fail(ensure_dir_path_normalized("/...", NULL));
+	must_fail(ensure_dir_path_normalized("/./...", NULL));
+	must_fail(ensure_dir_path_normalized("/d1/...", NULL));
+	must_fail(ensure_dir_path_normalized("/d1/.../", NULL));
+	must_fail(ensure_dir_path_normalized("/d1/.../d2", NULL));
 END_TEST