test-path-util.c revision 796beea86bcdc92e4ba2f4865414a951b1717e5c
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "test-lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "path-util.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "unlink-directory.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <unistd.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdlib.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <sys/stat.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define TEMP_DIRNAME ".test-path-util"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic const char *tmpdir;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic const char *cwd;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic const char *link1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic const char *link2;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic const char *link3;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void test_local_path() {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const char *expected = t_strconcat(cwd, "/README.md", NULL);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen const char *npath = NULL, *error = NULL;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen test_assert(t_normpath_to("README.md", cwd, &npath, &error) == 0);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen test_assert_strcmp(npath, expected);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic void test_absolute_path_no_change(void) {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen const char *npath = NULL, *error = NULL;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen test_assert(t_normpath_to("/", "/", &npath, &error) == 0);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen test_assert_strcmp(npath, "/");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen test_assert(t_normpath_to(cwd, cwd, &npath, &error) == 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert_strcmp(npath, cwd);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int path_height(const char* p) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen int n;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen for (n = 0; *p != '\0'; ++p)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen n += *p == '/';
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return n;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic void test_travel_to_root(void) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen int l = path_height(cwd);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *npath = cwd;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen for (npath = cwd; l != 0; l--) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *error;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert_idx(t_normpath_to("../", npath, &npath, &error) == 0, l);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen test_assert_strcmp(npath, "/");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void test_extra_slashes(void) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *npath = NULL, *error = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert(t_normpath_to(".", cwd, &npath, &error) == 0);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen test_assert_strcmp(npath, cwd);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen test_assert(t_normpath_to("./", cwd, &npath, &error) == 0);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen test_assert_strcmp(npath, cwd);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen test_assert(t_normpath_to(".////", cwd, &npath, &error) == 0);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen test_assert_strcmp(npath, cwd);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void test_nonexistent_path(void) {
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen const char *npath = NULL, *error = NULL;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen const char *expected = t_strconcat(cwd, "/nonexistent", NULL);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen test_assert(t_normpath_to("nonexistent", cwd, &npath, &error) == 0);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen test_assert_strcmp(npath, expected);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen test_assert(t_realpath_to("nonexistent", cwd, &npath, &error) == -1);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen test_assert(error != NULL);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void test_relative_dotdot() {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const char *rel_path = "../"TEMP_DIRNAME;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *npath = NULL, *error = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert(t_normpath_to(rel_path, tmpdir, &npath, &error) == 0);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen test_assert_strcmp(npath, tmpdir);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen test_assert(t_normpath_to("..", tmpdir, &npath, &error) == 0);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen test_assert_strcmp(npath, cwd);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen test_assert(t_normpath_to("../", tmpdir, &npath, &error) == 0);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen test_assert_strcmp(npath, cwd);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert(t_normpath_to("../.", tmpdir, &npath, &error) == 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert_strcmp(npath, cwd);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void test_link1() {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *npath = NULL, *error = NULL;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen test_assert(t_realpath_to(link1, "/", &npath, &error) == 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert_strcmp(npath, tmpdir);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void test_link_loop() {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *npath = NULL, *error = NULL;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_assert(t_realpath_to(link2, "/", &npath, &error) == -1);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen test_assert(errno == ELOOP);
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen test_assert(error != NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainenstatic void test_abspath_vs_normpath() {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *abs = t_abspath_to("../../bin", "/usr/lib/");
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen test_assert_strcmp(abs, "/usr/lib//../../bin");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen const char *norm = NULL, *error = NULL;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen test_assert(t_normpath_to("../../bin", "/usr///lib/", &norm, &error) == 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen test_assert_strcmp(norm, "/bin");
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainenstatic void test_cleanup(void)
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *error;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (unlink_directory(tmpdir, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen i_error("unlink_directory() failed: %s", error);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen}
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenstatic void test_init(void) {
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen const char *error;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen test_assert(t_get_working_dir(&cwd, &error) == 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen tmpdir = t_strconcat(cwd, "/"TEMP_DIRNAME, NULL);
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen test_cleanup();
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (mkdir(tmpdir, 0700) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("mkdir: %m");
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen link1 = t_strconcat(tmpdir, "/link1", NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (symlink(tmpdir, link1) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("symlink(%s, %s) failed: %m", tmpdir, link1);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen }
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen /* link2 and link3 point to each other to create a loop */
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen link2 = t_strconcat(tmpdir, "/link2", NULL);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen link3 = t_strconcat(tmpdir, "/link3", NULL);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen if (symlink(link3, link2) < 0) {
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen i_fatal("symlink(%s, %s) failed: %m", link3, link2);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (symlink(link2, link3) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("symlink(%s, %s) failed: %m", link2, link3);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainenvoid test_path_util(void) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_begin("test_path_util");
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen test_init();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_local_path();
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen test_absolute_path_no_change();
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen test_travel_to_root();
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen test_extra_slashes();
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen test_nonexistent_path();
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen test_relative_dotdot();
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen test_link1();
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen test_link_loop();
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen test_abspath_vs_normpath();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_cleanup();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen test_end();
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen