From 444a7c6cc169e84b15e124bf431ad172e1f00bda Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Sun, 29 Sep 2024 05:07:43 +0200
Subject: [PATCH] lib-sieve: sieve-storage - Pass error code from init vfunc
 through storage object

---
 src/lib-sieve/sieve-storage-private.h         |  3 +-
 src/lib-sieve/sieve-storage.c                 |  4 +-
 .../storage/data/sieve-data-storage.c         |  4 +-
 .../storage/dict/sieve-dict-storage.c         |  5 +-
 .../storage/file/sieve-file-storage.c         | 98 ++++++++-----------
 .../storage/ldap/sieve-ldap-storage.c         |  4 +-
 6 files changed, 45 insertions(+), 73 deletions(-)

diff --git a/src/lib-sieve/sieve-storage-private.h b/src/lib-sieve/sieve-storage-private.h
index 70f5fc88d..7dd007355 100644
--- a/src/lib-sieve/sieve-storage-private.h
+++ b/src/lib-sieve/sieve-storage-private.h
@@ -23,8 +23,7 @@ ARRAY_DEFINE_TYPE(sieve_storage_class, const struct sieve_storage *);
 struct sieve_storage_vfuncs {
 	struct sieve_storage *(*alloc)(void);
 	void (*destroy)(struct sieve_storage *storage);
-	int (*init)(struct sieve_storage *storage, const char *const *options,
-		    enum sieve_error *error_code_r);
+	int (*init)(struct sieve_storage *storage, const char *const *options);
 
 	int (*get_last_change)(struct sieve_storage *storage,
 			       time_t *last_change_r);
diff --git a/src/lib-sieve/sieve-storage.c b/src/lib-sieve/sieve-storage.c
index f9c964210..c4bde9f01 100644
--- a/src/lib-sieve/sieve-storage.c
+++ b/src/lib-sieve/sieve-storage.c
@@ -362,12 +362,12 @@ sieve_storage_init_real(struct sieve_instance *svinst, struct event *event,
 			event_add_str(event, "script_location",
 				      storage->location);
 
-			ret = storage_class->v.init(storage, options,
-						    error_code_r);
+			ret = storage_class->v.init(storage, options);
 			i_assert(ret <= 0);
 		}
 	} T_END;
 	if (ret < 0) {
+		*error_code_r = storage->error_code;
 		sieve_storage_unref(&storage);
 		return -1;
 	}
diff --git a/src/lib-sieve/storage/data/sieve-data-storage.c b/src/lib-sieve/storage/data/sieve-data-storage.c
index 73906c93d..4f645532f 100644
--- a/src/lib-sieve/storage/data/sieve-data-storage.c
+++ b/src/lib-sieve/storage/data/sieve-data-storage.c
@@ -27,10 +27,8 @@ static struct sieve_storage *sieve_data_storage_alloc(void)
 
 static int
 sieve_data_storage_init(struct sieve_storage *storage ATTR_UNUSED,
-			const char *const *options ATTR_UNUSED,
-			enum sieve_error *error_code_r ATTR_UNUSED)
+			const char *const *options ATTR_UNUSED)
 {
-	*error_code_r = SIEVE_ERROR_NONE;
 	return 0;
 }
 
diff --git a/src/lib-sieve/storage/dict/sieve-dict-storage.c b/src/lib-sieve/storage/dict/sieve-dict-storage.c
index d94ebdd5a..a8f48936d 100644
--- a/src/lib-sieve/storage/dict/sieve-dict-storage.c
+++ b/src/lib-sieve/storage/dict/sieve-dict-storage.c
@@ -28,8 +28,7 @@ static struct sieve_storage *sieve_dict_storage_alloc(void)
 
 static int
 sieve_dict_storage_init(struct sieve_storage *storage,
-			const char *const *options,
-			enum sieve_error *error_code_r)
+			const char *const *options)
 {
 	struct sieve_dict_storage *dstorage =
 		container_of(storage, struct sieve_dict_storage, storage);
@@ -46,7 +45,6 @@ sieve_dict_storage_init(struct sieve_storage *storage,
 			} else {
 				sieve_storage_set_critical(
 					storage, "Invalid option '%s'", option);
-				*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 				return -1;
 			}
 
@@ -58,7 +56,6 @@ sieve_dict_storage_init(struct sieve_storage *storage,
 		sieve_storage_set_critical(
 			storage,
 			"BUG: Sieve interpreter is initialized without a base_dir");
-		*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 		return -1;
 	}
 
diff --git a/src/lib-sieve/storage/file/sieve-file-storage.c b/src/lib-sieve/storage/file/sieve-file-storage.c
index 72a0562f4..51cc7c4d1 100644
--- a/src/lib-sieve/storage/file/sieve-file-storage.c
+++ b/src/lib-sieve/storage/file/sieve-file-storage.c
@@ -47,8 +47,7 @@ sieve_file_storage_path_extend(struct sieve_file_storage *fstorage,
  */
 
 static int
-sieve_file_storage_stat(struct sieve_file_storage *fstorage, const char *path,
-			enum sieve_error *error_code_r)
+sieve_file_storage_stat(struct sieve_file_storage *fstorage, const char *path)
 {
 	struct sieve_storage *storage = &fstorage->storage;
 	struct stat st;
@@ -69,24 +68,22 @@ sieve_file_storage_stat(struct sieve_file_storage *fstorage, const char *path,
 			sieve_storage_set_critical(
 				storage, "t_abspath(%s) failed: %s", path,
 				error);
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 			break;
 		}
 		e_debug(storage->event, "Storage path '%s' not found", abspath);
 		sieve_storage_set_internal_error(storage); // should be overriden
-		*error_code_r = SIEVE_ERROR_NOT_FOUND;
+		storage->error_code = SIEVE_ERROR_NOT_FOUND;
 		break;
 	case EACCES:
 		sieve_storage_set_critical(
 			storage, "Failed to stat sieve storage path: %s",
 			eacces_error_get("stat", path));
-		*error_code_r = SIEVE_ERROR_NO_PERMISSION;
+		storage->error_code = SIEVE_ERROR_NO_PERMISSION;
 		break;
 	default:
 		sieve_storage_set_critical(
 			storage, "Failed to stat sieve storage path: "
 			"stat(%s) failed: %m", path);
-		*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 		break;
 	}
 
@@ -141,11 +138,13 @@ mkdir_verify(struct sieve_storage *storage, const char *dir,
 		return 0;
 
 	if (errno == EACCES) {
-		e_error(storage->event,	"mkdir_verify: %s",
+		sieve_storage_set_critical(
+			storage, "mkdir_verify: %s",
 			eacces_error_get("stat", dir));
 		return -1;
 	} else if (errno != ENOENT) {
-		e_error(storage->event, "mkdir_verify: "
+		sieve_storage_set_critical(
+			storage, "mkdir_verify: "
 			"stat(%s) failed: %m", dir);
 		return -1;
 	}
@@ -159,15 +158,15 @@ mkdir_verify(struct sieve_storage *storage, const char *dir,
 	case EEXIST:
 		return 0;
 	case ENOENT:
-		e_error(storage->event,
+		sieve_storage_set_critical(storage,
 			"Storage was deleted while it was being created");
 		break;
 	case EACCES:
-		e_error(storage->event, "%s",
+		sieve_storage_set_critical(storage, "%s",
 			eacces_error_get_creating("mkdir_parents_chgrp", dir));
 		break;
 	default:
-		e_error(storage->event,
+		sieve_storage_set_critical(storage,
 			"mkdir_parents_chgrp(%s) failed: %m", dir);
 		break;
 	}
@@ -184,11 +183,13 @@ static int check_tmp(struct sieve_storage *storage, const char *path)
 		if (errno == ENOENT)
 			return 0;
 		if (errno == EACCES) {
-			e_error(storage->event, "check_tmp: %s",
+			sieve_storage_set_critical(storage,
+				"check_tmp: %s",
 				eacces_error_get("stat", path));
 			return -1;
 		}
-		e_error(storage->event, "check_tmp: stat(%s) failed: %m", path);
+		sieve_storage_set_critical(storage,
+			"check_tmp: stat(%s) failed: %m", path);
 		return -1;
 	}
 
@@ -220,8 +221,7 @@ static struct sieve_storage *sieve_file_storage_alloc(void)
 
 static int
 sieve_file_storage_get_full_path(struct sieve_file_storage *fstorage,
-				 const char **storage_path,
-				 enum sieve_error *error_code_r)
+				 const char **storage_path)
 {
 	struct sieve_storage *storage = &fstorage->storage;
 	struct sieve_instance *svinst = storage->svinst;
@@ -247,7 +247,6 @@ sieve_file_storage_get_full_path(struct sieve_file_storage *fstorage,
 				storage,
 				"Sieve storage path '%s' is relative to home directory, "
 				"but home directory is not available.", path);
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 			return -1;
 		}
 	}
@@ -257,8 +256,7 @@ sieve_file_storage_get_full_path(struct sieve_file_storage *fstorage,
 
 static int
 sieve_file_storage_get_full_active_path(struct sieve_file_storage *fstorage,
-					const char **active_path,
-					enum sieve_error *error_code_r)
+					const char **active_path)
 {
 	struct sieve_storage *storage = &fstorage->storage;
 	struct sieve_instance *svinst = storage->svinst;
@@ -282,7 +280,6 @@ sieve_file_storage_get_full_active_path(struct sieve_file_storage *fstorage,
 				storage,
 				"Sieve storage active script path '%s' is relative to home directory, "
 				"but home directory is not available.", path);
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 			return -1;
 		}
 	}
@@ -293,8 +290,7 @@ sieve_file_storage_get_full_active_path(struct sieve_file_storage *fstorage,
 static int
 sieve_file_storage_init_common(struct sieve_file_storage *fstorage,
 			       const char *active_path,
-			       const char *storage_path, bool exists,
-			       enum sieve_error *error_code_r)
+			       const char *storage_path, bool exists)
 {
 	struct sieve_storage *storage = &fstorage->storage;
 	const char *tmp_dir, *link_path, *active_fname, *storage_dir, *error;
@@ -307,8 +303,7 @@ sieve_file_storage_init_common(struct sieve_file_storage *fstorage,
 
 	/* Get active script path */
 
-	if (sieve_file_storage_get_full_active_path(fstorage, &active_path,
-						    error_code_r) < 0)
+	if (sieve_file_storage_get_full_active_path(fstorage, &active_path) < 0)
 		return -1;
 
 	/* Get the filename for the active script link */
@@ -333,16 +328,14 @@ sieve_file_storage_init_common(struct sieve_file_storage *fstorage,
 				"Path to %sscript must include the filename (path=%s)",
 				(storage_path != NULL ? "active link/" : ""),
 				active_path);
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 			return -1;
 		}
 
 		if (t_realpath(active_dir, &active_dir, &error) < 0) {
 			if (errno != ENOENT) {
-				e_error(storage->event,
+				sieve_storage_set_critical(storage,
 					"Failed to normalize active script directory "
 					"(path=%s): %s", active_dir, error);
-				*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 				return -1;
 			}
 			e_debug(storage->event,
@@ -372,7 +365,6 @@ sieve_file_storage_init_common(struct sieve_file_storage *fstorage,
 		if ((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0) {
 			sieve_storage_set_critical(storage,
 				"Storage path cannot be empty for write access");
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 			return -1;
 		}
 
@@ -440,34 +432,28 @@ sieve_file_storage_init_common(struct sieve_file_storage *fstorage,
 
 		/* Try to find and clean up tmp dir */
 		ret = check_tmp(storage, tmp_dir);
-		if (ret < 0) {
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
+		if (ret < 0)
 			return -1;
-		}
 
 		/* Auto-create if necessary */
 		if (ret == 0 && mkdir_verify(storage, tmp_dir, dir_create_mode,
 					     file_create_gid,
-					     file_create_gid_origin) < 0) {
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
+					     file_create_gid_origin) < 0)
 			return -1;
-		}
 
 		fstorage->dir_create_mode = dir_create_mode;
 		fstorage->file_create_mode = file_create_mode;
 		fstorage->file_create_gid = file_create_gid;
 	}
 
-	if (!exists && sieve_file_storage_stat(fstorage, storage_path,
-					       error_code_r) < 0)
+	if (!exists && sieve_file_storage_stat(fstorage, storage_path) < 0)
 		return -1;
 
 	if (have_link) {
 		if (t_realpath(storage_path, &storage_path, &error) < 0) {
-			e_error(storage->event,
+			sieve_storage_set_critical(storage,
 				"Failed to normalize storage path (path=%s): %s",
 				storage_path, error);
-			*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 			return -1;
 		}
 		if (active_path != NULL && *active_path != '\0') {
@@ -494,8 +480,7 @@ sieve_file_storage_init_common(struct sieve_file_storage *fstorage,
 
 static int
 sieve_file_storage_init(struct sieve_storage *storage,
-			const char *const *options,
-			enum sieve_error *error_code_r)
+			const char *const *options)
 {
 	struct sieve_file_storage *fstorage =
 		container_of(storage, struct sieve_file_storage, storage);
@@ -513,7 +498,6 @@ sieve_file_storage_init(struct sieve_storage *storage,
 			} else {
 				sieve_storage_set_critical(
 					storage, "Invalid option '%s'", option);
-				*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 				return -1;
 			}
 
@@ -523,16 +507,14 @@ sieve_file_storage_init(struct sieve_storage *storage,
 
 	/* Get full storage path */
 
-	if (sieve_file_storage_get_full_path(fstorage, &storage_path,
-					     error_code_r) < 0)
+	if (sieve_file_storage_get_full_path(fstorage, &storage_path) < 0)
 		return -1;
 
 	/* Stat storage directory */
 
 	if (storage_path != NULL && *storage_path != '\0') {
-		if (sieve_file_storage_stat(fstorage, storage_path,
-					    error_code_r) < 0) {
-			if (*error_code_r != SIEVE_ERROR_NOT_FOUND)
+		if (sieve_file_storage_stat(fstorage, storage_path) < 0) {
+			if (storage->error_code != SIEVE_ERROR_NOT_FOUND)
 				return -1;
 			if ((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) == 0) {
 				/* For backwards compatibility, recognize when
@@ -542,12 +524,10 @@ sieve_file_storage_init(struct sieve_storage *storage,
 				if (active_path == NULL || *active_path == '\0')
 					return -1;
 				if (sieve_file_storage_get_full_active_path(
-					fstorage, &active_path,
-					error_code_r) < 0)
+					fstorage, &active_path) < 0)
 					return -1;
-				if (sieve_file_storage_stat(
-					fstorage, active_path,
-					error_code_r) < 0)
+				if (sieve_file_storage_stat(fstorage,
+							    active_path) < 0)
 					return -1;
 				if (!S_ISREG(fstorage->lnk_st.st_mode))
 					return -1;
@@ -566,7 +546,6 @@ sieve_file_storage_init(struct sieve_storage *storage,
 					sieve_storage_set_critical(storage,
 						"Sieve storage path '%s' is not a directory, "
 						"but it is to be opened for write access", storage_path);
-					*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 					return -1;
 				}
 				if (active_path != NULL && *active_path != '\0') {
@@ -593,8 +572,7 @@ sieve_file_storage_init(struct sieve_storage *storage,
 	}
 
 	return sieve_file_storage_init_common(fstorage, active_path,
-					      storage_path, exists,
-					      error_code_r);
+					      storage_path, exists);
 }
 
 static void
@@ -642,9 +620,8 @@ sieve_file_storage_do_init_default(struct sieve_file_storage *fstorage,
 
 	if (storage_path != NULL && *storage_path != '\0') {
 		/* Got something: stat it */
-		if (sieve_file_storage_stat(fstorage, storage_path,
-					    error_code_r) < 0) {
-			if (*error_code_r != SIEVE_ERROR_NOT_FOUND) {
+		if (sieve_file_storage_stat(fstorage, storage_path) < 0) {
+			if (storage->error_code != SIEVE_ERROR_NOT_FOUND) {
 				/* Error */
 				return -1;
 			}
@@ -659,7 +636,7 @@ sieve_file_storage_do_init_default(struct sieve_file_storage *fstorage,
 		sieve_storage_set_critical(storage,
 			"Could not find storage root directory for write access; "
 			"path was left unconfigured and autodetection failed");
-		*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
+		*error_code_r = storage->error_code;
 		return -1;
 	}
 
@@ -681,8 +658,10 @@ sieve_file_storage_do_init_default(struct sieve_file_storage *fstorage,
 		storage_path = NULL;
 
 	if (sieve_file_storage_init_common(fstorage, active_path, storage_path,
-					   exists, error_code_r) < 0)
+					   exists) < 0) {
+		*error_code_r = storage->error_code;
 		return -1;
+	}
 	return 0;
 }
 
@@ -735,9 +714,10 @@ int sieve_file_storage_init_from_path(struct sieve_instance *svinst,
 
 	T_BEGIN {
 		ret = sieve_file_storage_init_common(fstorage, path, NULL,
-						     FALSE, error_code_r);
+						     FALSE);
 	} T_END;
 	if (ret < 0) {
+		*error_code_r = storage->error_code;
 		sieve_storage_unref(&storage);
 		return -1;
 	}
diff --git a/src/lib-sieve/storage/ldap/sieve-ldap-storage.c b/src/lib-sieve/storage/ldap/sieve-ldap-storage.c
index a0974002e..8a7e0980c 100644
--- a/src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+++ b/src/lib-sieve/storage/ldap/sieve-ldap-storage.c
@@ -42,8 +42,7 @@ static struct sieve_storage *sieve_ldap_storage_alloc(void)
 
 static int
 sieve_ldap_storage_init(struct sieve_storage *storage,
-			const char *const *options,
-			enum sieve_error *error_code_r)
+			const char *const *options)
 {
 	struct sieve_ldap_storage *lstorage =
 		container_of(storage, struct sieve_ldap_storage, storage);
@@ -60,7 +59,6 @@ sieve_ldap_storage_init(struct sieve_storage *storage,
 			} else {
 				sieve_storage_set_critical(
 					storage, "Invalid option '%s'", option);
-				*error_code_r = SIEVE_ERROR_TEMP_FAILURE;
 				return -1;
 			}
 
-- 
GitLab