From 03434fa48248290d03802d85f580343d4a6a50f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martti=20Rannanj=C3=A4rvi?= <martti.rannanjarvi@dovecot.fi>
Date: Mon, 28 Nov 2016 18:55:10 +0200
Subject: [PATCH] global: Replace realpath with path-util from core.

path-util is a merge of realpath from Pigeonhole and abspath from core.
---
 src/lib-sieve-tool/mail-raw.c                 |   8 +-
 .../storage/file/sieve-file-script.c          |  14 +-
 .../storage/file/sieve-file-storage-active.c  |  18 +-
 .../storage/file/sieve-file-storage.c         |  27 +-
 src/lib-sieve/util/Makefile.am                |   6 +-
 src/lib-sieve/util/realpath.c                 | 239 ------------------
 src/lib-sieve/util/realpath.h                 |  33 ---
 src/managesieve/main.c                        |  19 +-
 src/testsuite/testsuite-mailstore.c           |   8 +-
 src/testsuite/testsuite.c                     |   8 +-
 10 files changed, 68 insertions(+), 312 deletions(-)
 delete mode 100644 src/lib-sieve/util/realpath.c
 delete mode 100644 src/lib-sieve/util/realpath.h

diff --git a/src/lib-sieve-tool/mail-raw.c b/src/lib-sieve-tool/mail-raw.c
index d3c773f48..5417dc49e 100644
--- a/src/lib-sieve-tool/mail-raw.c
+++ b/src/lib-sieve-tool/mail-raw.c
@@ -9,7 +9,7 @@
 #include "str-sanitize.h"
 #include "strescape.h"
 #include "safe-mkstemp.h"
-#include "abspath.h"
+#include "path-util.h"
 #include "message-address.h"
 #include "mbox-from.h"
 #include "raw-storage.h"
@@ -153,11 +153,13 @@ static struct mail_raw *mail_raw_create
 {
 	struct mail_raw *mailr;
 	struct mailbox_header_lookup_ctx *headers_ctx;
-	const char *envelope_sender;
+	const char *envelope_sender, *error;
 	int ret;
 
 	if ( mailfile != NULL && *mailfile != '/' )
-		mailfile = t_abspath(mailfile);
+		if (t_abspath(mailfile, &mailfile, &error) < 0)
+			i_fatal("t_abspath(%s) failed: %s",
+				mailfile, error);
 
 	mailr = i_new(struct mail_raw, 1);
 
diff --git a/src/lib-sieve/storage/file/sieve-file-script.c b/src/lib-sieve/storage/file/sieve-file-script.c
index 4c3e722d9..ec0b97d65 100644
--- a/src/lib-sieve/storage/file/sieve-file-script.c
+++ b/src/lib-sieve/storage/file/sieve-file-script.c
@@ -3,7 +3,7 @@
 
 #include "lib.h"
 #include "mempool.h"
-#include "abspath.h"
+#include "path-util.h"
 #include "istream.h"
 #include "time-util.h"
 #include "eacces-error.h"
@@ -55,10 +55,20 @@ static void sieve_file_script_handle_error
 	const char *name, enum sieve_error *error_r)
 {
 	struct sieve_script *script = &fscript->script;
+	const char *abspath, *error;
 
 	switch ( errno ) {
 	case ENOENT:
-		sieve_script_sys_debug(script, "File `%s' not found", t_abspath(path));
+		if (t_abspath(path, &abspath, &error) < 0) {
+			sieve_script_set_error(script,
+				SIEVE_ERROR_TEMP_FAILURE,
+				"t_abspath(%s) failed: %s",
+				path, error);
+			*error_r = SIEVE_ERROR_TEMP_FAILURE;
+			break;
+		}
+		sieve_script_sys_debug(script, "File `%s' not found",
+				       abspath);
 		sieve_script_set_error(script,
 			SIEVE_ERROR_NOT_FOUND,
 			"Sieve script `%s' not found", name);
diff --git a/src/lib-sieve/storage/file/sieve-file-storage-active.c b/src/lib-sieve/storage/file/sieve-file-storage-active.c
index cef80560c..5cbdd759d 100644
--- a/src/lib-sieve/storage/file/sieve-file-storage-active.c
+++ b/src/lib-sieve/storage/file/sieve-file-storage-active.c
@@ -2,13 +2,11 @@
  */
 
 #include "lib.h"
-#include "abspath.h"
+#include "path-util.h"
 #include "ioloop.h"
 #include "hostpid.h"
 #include "file-copy.h"
 
-#include "realpath.h"
-
 #include "sieve-file-storage.h"
 
 #include <unistd.h>
@@ -21,9 +19,10 @@ static int sieve_file_storage_active_read_link
 (struct sieve_file_storage *fstorage, const char **link_r)
 {
 	struct sieve_storage *storage = &fstorage->storage;
+	const char *error = NULL;
 	int ret;
 
-	ret = t_readlink(fstorage->active_path, link_r);
+	ret = t_readlink(fstorage->active_path, link_r, &error);
 
 	if ( ret < 0 ) {
 		*link_r = NULL;
@@ -49,8 +48,8 @@ static int sieve_file_storage_active_read_link
 
 		/* We do need to panic otherwise */
 		sieve_storage_set_critical(storage,
-			"Performing readlink() on active sieve symlink '%s' failed: %m",
-			fstorage->active_path);
+			"Performing t_readlink() on active sieve symlink '%s' failed: %s",
+			fstorage->active_path, error);
 		return -1;
 	}
 
@@ -95,11 +94,12 @@ static const char *sieve_file_storage_active_parse_link
 	}
 
 	/* Check whether the path is any good */
-	if ( t_normpath_to(scriptpath, link_dir, &scriptpath) < 0 ) {
+	const char *error = NULL;
+	if ( t_normpath_to(scriptpath, link_dir, &scriptpath, &error) < 0 ) {
 		sieve_storage_sys_warning(storage,
 			"Failed to check active Sieve script symlink %s: "
-			"Failed to normalize path (points to %s).",
-			fstorage->active_path, scriptpath);
+			"Failed to normalize path (points to %s): %s",
+			fstorage->active_path, scriptpath, error);
 		return NULL;
 	}
 	if ( strcmp(scriptpath, fstorage->path) != 0 ) {
diff --git a/src/lib-sieve/storage/file/sieve-file-storage.c b/src/lib-sieve/storage/file/sieve-file-storage.c
index eacff8c15..e5468bf11 100644
--- a/src/lib-sieve/storage/file/sieve-file-storage.c
+++ b/src/lib-sieve/storage/file/sieve-file-storage.c
@@ -2,7 +2,7 @@
  */
 
 #include "lib.h"
-#include "abspath.h"
+#include "path-util.h"
 #include "home-expand.h"
 #include "ioloop.h"
 #include "mkdir-parents.h"
@@ -10,8 +10,6 @@
 #include "unlink-old-files.h"
 #include "mail-storage-private.h"
 
-#include "realpath.h"
-
 #include "sieve.h"
 #include "sieve-common.h"
 #include "sieve-settings.h"
@@ -54,6 +52,7 @@ static int sieve_file_storage_stat
 {
 	struct sieve_storage *storage = &fstorage->storage;
 	struct stat st;
+	const char *abspath, *error;
 
 	if ( lstat(path, &st) == 0 ) {
 		fstorage->lnk_st = st;
@@ -66,8 +65,14 @@ static int sieve_file_storage_stat
 
 	switch ( errno ) {
 	case ENOENT:
+		if (t_abspath(path, &abspath, &error) < 0) {
+			sieve_storage_set_critical(storage,
+				"t_abspath(%s) failed: %s", path, error);
+			*error_r = SIEVE_ERROR_TEMP_FAILURE;
+			break;
+		}
 		sieve_storage_sys_debug(storage,
-			"Storage path `%s' not found", t_abspath(path));
+			"Storage path `%s' not found", abspath);
 		sieve_storage_set_internal_error(storage); // should be overriden
 		*error_r = SIEVE_ERROR_NOT_FOUND;
 		break;
@@ -294,7 +299,7 @@ static int sieve_file_storage_init_common
 	ATTR_NULL(2, 3)
 {
 	struct sieve_storage *storage = &fstorage->storage;
-	const char *tmp_dir, *link_path, *active_fname, *storage_dir;
+	const char *tmp_dir, *link_path, *active_fname, *storage_dir, *error;
 	bool have_link = FALSE;
 	int ret;
 
@@ -333,11 +338,11 @@ static int sieve_file_storage_init_common
 			return -1;
 		}
 
-		if (t_realpath(active_dir, &active_dir) < 0) {
+		if (t_realpath(active_dir, &active_dir, &error) < 0) {
 			if (errno != ENOENT) {
 				sieve_storage_sys_error(storage,
-					"Failed to normalize active script directory (path=%s): %m",
-					active_dir);
+					"Failed to normalize active script directory (path=%s): %s",
+					active_dir, error);
 				*error_r = SIEVE_ERROR_TEMP_FAILURE;
 				return -1;
 			} 
@@ -455,10 +460,10 @@ static int sieve_file_storage_init_common
 		return -1;
 
 	if ( have_link ) {
-		if ( t_realpath(storage_path, &storage_path) < 0 ) {
+		if ( t_realpath(storage_path, &storage_path, &error) < 0 ) {
 			sieve_storage_sys_error(storage,
-				"Failed to normalize storage path (path=%s): %m",
-				storage_path);
+				"Failed to normalize storage path (path=%s): %s",
+				storage_path, error);
 			*error_r = SIEVE_ERROR_TEMP_FAILURE;
 			return -1;
 		}
diff --git a/src/lib-sieve/util/Makefile.am b/src/lib-sieve/util/Makefile.am
index b57fa041d..8f2d8c5e8 100644
--- a/src/lib-sieve/util/Makefile.am
+++ b/src/lib-sieve/util/Makefile.am
@@ -9,13 +9,11 @@ libsieve_util_la_DEPENDENCIES = $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS)
 
 libsieve_util_la_SOURCES = \
 	edit-mail.c \
-	rfc2822.c \
-	realpath.c
+	rfc2822.c
 
 headers = \
 	edit-mail.h \
-	rfc2822.h \
-	realpath.h
+	rfc2822.h
 
 pkginc_libdir=$(dovecot_pkgincludedir)/sieve
 pkginc_lib_HEADERS = $(headers)
diff --git a/src/lib-sieve/util/realpath.c b/src/lib-sieve/util/realpath.c
deleted file mode 100644
index a8cfdc2b9..000000000
--- a/src/lib-sieve/util/realpath.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "str.h"
-
-#include "realpath.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-// FIXME: move/merge to Dovecot
-
-#define REALPATH_MAX_PATH      8*1024
-#define REALPATH_MAX_SYMLINKS  80
-
-static int t_getcwd_alloc(char **dir_r, size_t *asize_r)
-{
-	/* @UNSAFE */
-	char *dir;
-	size_t asize = 128;
-
-	dir = t_buffer_get(asize);
-	while (getcwd(dir, asize) == NULL) {
-		if (errno != ERANGE)
-			return -1;
-		asize = nearest_power(asize+1);
-		dir = t_buffer_get(asize);
-	}
-	*asize_r = asize;
-	*dir_r = dir;
-	return 0;
-}
-
-static int path_normalize(const char *path, bool resolve_links,
-	const char **npath_r)
-{
-	/* @UNSAFE */
-	unsigned int link_count = 0;
-	char *npath, *npath_pos;
-	const char *p;
-	size_t asize;
-
-	if (path[0] != '/') {
-		/* relative; initialize npath with current directory */
-		if (t_getcwd_alloc(&npath, &asize) < 0)
-			return -1;
-		npath_pos = npath + strlen(npath);
-		i_assert(npath[0] == '/');
-	} else {
-		/* absolute; initialize npath with root */
-		asize = 128;
-		npath = t_buffer_get(asize);
-		npath[0] = '/';
-		npath_pos = npath + 1;
-	}
-
-	p = path;
-	while (*p != '\0') {
-		struct stat st;
-		ptrdiff_t seglen;
-		const char *segend;
-
-		/* skip duplicate shashes */
-		while (*p == '/')
-			p++;
-
-		/* find end of path segment */
-		for (segend = p; *segend != '\0' && *segend != '/'; segend++);
-
-		if (segend == p)
-			break; /* '\0' */
-		seglen = segend - p;
-		if (seglen == 1 && p[0] == '.') {
-			/* a reference to this segment; nothing to do */
-    } else if (seglen == 2 && p[0] == '.' && p[1] == '.') {
-  		/* a reference to parent segment; back up to previous slash */
-			if (npath_pos > npath + 1) {
-				if (*(npath_pos-1) == '/')
-					npath_pos--;
-				for (; *(npath_pos-1) != '/'; npath_pos--);
-			}
-		} else {
-			/* make sure npath now ends in slash */
-			if (*(npath_pos-1) != '/')
-				*(npath_pos++) = '/';
-
-			/* allocate space if necessary */
-			if ((npath_pos + seglen + 1) >= (npath + asize)) {
-				ptrdiff_t npath_offset = npath_pos - npath;
-				asize = nearest_power(npath_offset + seglen + 2);
-				npath = t_buffer_reget(npath, asize);
-				npath_pos = npath + npath_offset;
-			}
-
-			/* copy segment to normalized path */
-			(void)memmove(npath_pos, p, seglen);
-			npath_pos += seglen;
-		}
-
-		if (resolve_links) {
-			/* stat path up to here (segend points to tail) */
-			*npath_pos = '\0';
-			if (lstat(npath, &st) < 0)
-				return -1;
-
-			if (S_ISLNK (st.st_mode)) {
-				/* symlink */
-				char *npath_link;
-				size_t lsize = 128, tlen = strlen(segend), espace;
-				size_t ltlen = (link_count == 0 ? 0 : tlen);
-				ssize_t ret;
-
-				/* limit link dereferences */
-				if (++link_count > REALPATH_MAX_SYMLINKS) {
-					errno = ELOOP;
-					return -1;
-				}
-
-				/* allocate space for preserving tail of previous symlink and
-				   first attempt at reading symlink with room for the tail
-
-				   buffer will look like this:
-				   [npath][0][preserved tail][link buffer][room for tail][0]
-				 */
-				espace = ltlen + tlen + 2;
-				if ((npath_pos + espace + lsize) >= (npath + asize)) {
-					ptrdiff_t npath_offset = npath_pos - npath;
-					asize = nearest_power((npath_offset + espace + lsize) + 1);
-					lsize = asize - (npath_offset + espace);
-					npath = t_buffer_reget(npath, asize);
-					npath_pos = npath + npath_offset;
-				}
-
-				if (ltlen > 0) {
-					/* preserve tail just after end of npath */
-					(void)memmove(npath_pos + 1, segend, ltlen);
-				}
-
-				/* read the symlink after the preserved tail */
-				for (;;) {
-					npath_link = (npath_pos + 1) + ltlen;
-
-					/* attempt to read the link */
-					if ((ret=readlink(npath, npath_link, lsize)) < 0)
-						return -1;
-					if ((size_t)ret < lsize) {
-						/* make static analyzers happy */
-						npath_link[ret] = '\0';
-						break;
-					}
-
-					/* sum of new symlink content length and path tail length may not
-					   exeed maximum */
-					if ((size_t)(ret + tlen) >= REALPATH_MAX_PATH) {
-						errno = ENAMETOOLONG;
-						return -1;
-					}
-
-					/* try again with bigger buffer */
-					espace = ltlen + tlen + 2;
-					if ((npath_pos + espace + lsize) >= (npath + asize)) {
-						ptrdiff_t npath_offset = npath_pos - npath;
-						asize = nearest_power((npath_offset + espace + lsize) + 1);
-						lsize = asize - (npath_offset + espace);
-						npath = t_buffer_reget(npath, asize);
-						npath_pos = npath + npath_offset;
-					}
-				}
-
-				/* add tail of previous path at end of symlink */
-				if (ltlen > 0)
-					(void)memcpy(npath_link + ret, npath_pos + 1, tlen);
-				else
-					(void)memcpy(npath_link + ret, segend, tlen);
-				*(npath_link+ret+tlen) = '\0';
-
-				/* use as new source path */
-				path = segend = npath_link;
-
-				if (path[0] == '/') {
-					/* absolute symlink; start over at root */
-					npath_pos = npath + 1;
-				} else {
-					/* relative symlink; back up to previous segment */
-					if (npath_pos > npath + 1) {
-						if (*(npath_pos-1) == '/')
-							npath_pos--;
-						for (; *(npath_pos-1) != '/'; npath_pos--);
-					}
-				}
-
-			} else if (*segend != '\0' && !S_ISDIR (st.st_mode)) {
-				/* not last segment, but not a directory either */
-				errno = ENOTDIR;
-				return -1;
-			}
-		}
-
-		p = segend;
-	}
-
-	/* remove any trailing slash */
- 	if (npath_pos > npath + 1 && *(npath_pos-1) == '/')
- 	  npath_pos--;
- 	*npath_pos = '\0';
-
-	t_buffer_alloc(npath_pos - npath + 1);
-	*npath_r = npath;
-	return 0;
-}
-
-int t_normpath(const char *path, const char **npath_r)
-{
-	return path_normalize(path, FALSE, npath_r);
-}
-
-int t_normpath_to(const char *path, const char *root,
-	const char **npath_r)
-{
-	if (*path == '/')
-		return t_normpath(path, npath_r);
-
-	return t_normpath(t_strconcat(root, "/", path, NULL), npath_r);
-}
-
-int t_realpath(const char *path, const char **npath_r)
-{
-	return path_normalize(path, TRUE, npath_r);
-}
-
-int t_realpath_to(const char *path, const char *root,
-	const char **npath_r)
-{
-	if (*path == '/')
-		return t_realpath(path, npath_r);
-
-	return t_realpath(t_strconcat(root, "/", path, NULL), npath_r);
-}
diff --git a/src/lib-sieve/util/realpath.h b/src/lib-sieve/util/realpath.h
deleted file mode 100644
index 4a5d34288..000000000
--- a/src/lib-sieve/util/realpath.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef REALPATH_H
-#define REALPATH_H
-
-/* Returns path as the normalized absolute path, which means that './'
-   and '../' components are resolved, and that duplicate and trailing
-   slashes are removed. If it's not already the absolute path, it's
-   assumed to be relative to the current working directory.
-
-   NOTE: Be careful with this function. The resolution of '../' components
-   with the parent component as if it were a normal directory is not valid
-   if the path contains symbolic links.
- */
-int t_normpath(const char *path, const char **npath_r);
-/* Like t_normpath(), but path is relative to given root. */
-int t_normpath_to(const char *path, const char *root,
-	const char **npath_r);
-
-/* Returns path as the real normalized absolute path, which means that all
-   symbolic links in the path are resolved, that './' and '../' components
-   are resolved, and that duplicate and trailing slashes are removed. If it's
-   not already the absolute path, it's assumed to be relative to the current
-   working directory.
-
-   NOTE: This function calls stat() for each path component and more when
-   there are symbolic links (just like POSIX realpath()).
- */
-int t_realpath(const char *path, const char **npath_r);
-/* Like t_realpath(), but path is relative to given root. */
-int t_realpath_to(const char *path, const char *root,
-	const char **npath_r);
-
-#endif
-
diff --git a/src/managesieve/main.c b/src/managesieve/main.c
index 43bd02686..93eb9e24e 100644
--- a/src/managesieve/main.c
+++ b/src/managesieve/main.c
@@ -6,7 +6,7 @@
 #include "ioloop.h"
 #include "istream.h"
 #include "ostream.h"
-#include "abspath.h"
+#include "path-util.h"
 #include "str.h"
 #include "base64.h"
 #include "process-title.h"
@@ -248,7 +248,7 @@ int main(int argc, char *argv[])
 	struct master_login_settings login_set;
 	enum master_service_flags service_flags = 0;
 	enum mail_storage_service_flags storage_service_flags = 0;
-	const char *username = NULL;
+	const char *username = NULL, *error = NULL;
 	int c;
 
 	i_zero(&login_set);
@@ -314,9 +314,18 @@ int main(int argc, char *argv[])
 			main_stdio_run(username);
 		} T_END;
 	} else {
-		login_set.auth_socket_path = t_abspath("auth-master");
-		if (argv[optind] != NULL)
-			login_set.postlogin_socket_path = t_abspath(argv[optind]);
+		if (t_abspath("auth-master",
+			&login_set.auth_socket_path, &error) < 0) {
+			i_fatal("t_abspath(%s) failed: %s",
+				"auth-master", error);
+		}
+
+		if (argv[optind] != NULL && t_abspath(argv[optind],
+			&login_set.postlogin_socket_path, &error) < 0) {
+			i_fatal("t_abspath(%s) failed: %s",
+				argv[optind], error);
+		}
+
 		login_set.callback = login_client_connected;
 		login_set.failure_callback = login_client_failed;
 
diff --git a/src/testsuite/testsuite-mailstore.c b/src/testsuite/testsuite-mailstore.c
index 10b7eaa26..f7dcaa816 100644
--- a/src/testsuite/testsuite-mailstore.c
+++ b/src/testsuite/testsuite-mailstore.c
@@ -7,7 +7,7 @@
 #include "array.h"
 #include "strfuncs.h"
 #include "str-sanitize.h"
-#include "abspath.h"
+#include "path-util.h"
 #include "unlink-directory.h"
 #include "env-util.h"
 #include "mail-namespace.h"
@@ -57,7 +57,7 @@ void testsuite_mailstore_init(void)
 	struct mail_namespace *ns;
 	struct mail_namespace_settings *ns_set;
 	struct mail_storage_settings *mail_set;
-	const char *tmpdir, *error;
+	const char *tmpdir, *error, *cwd;
 
 	tmpdir = testsuite_tmp_dir_get();
 	testsuite_mailstore_location =
@@ -74,7 +74,9 @@ void testsuite_mailstore_init(void)
 	mail_user = mail_user_alloc("testsuite mail user",
 		mail_user_dovecot->set_info, mail_user_dovecot->unexpanded_set);
 	mail_user->autocreated = TRUE;
-	mail_user_set_home(mail_user, t_abspath(""));
+	if (t_get_working_dir(&cwd, &error) < 0)
+		i_fatal("Failed to get working directory: %s", error);
+	mail_user_set_home(mail_user, cwd);
 	if (mail_user_init(mail_user, &error) < 0)
 		i_fatal("Testsuite user initialization failed: %s", error);
 
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index 6d4b4e9c8..bf0068fcd 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -7,7 +7,7 @@
 #include "env-util.h"
 #include "ostream.h"
 #include "hostpid.h"
-#include "abspath.h"
+#include "path-util.h"
 
 #include "sieve.h"
 #include "sieve-extensions.h"
@@ -86,7 +86,7 @@ int main(int argc, char **argv)
 	const char *scriptfile, *dumpfile, *tracefile;
 	struct sieve_trace_config trace_config;
 	struct sieve_binary *sbin;
-	const char *sieve_dir;
+	const char *sieve_dir, *cwd, *error;
 	bool log_stdout = FALSE;
 	int ret, c;
 
@@ -133,8 +133,10 @@ int main(int argc, char **argv)
 		i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
 	}
 
+	if (t_get_working_dir(&cwd, &error) < 0)
+		i_fatal("Failed to get working directory: %s", error);
 	/* Initialize mail user */
-	sieve_tool_set_homedir(sieve_tool, t_abspath(""));
+	sieve_tool_set_homedir(sieve_tool, cwd);
 
 	/* Initialize settings environment */
 	testsuite_settings_init();
-- 
GitLab