From 8279090b0268d7efac63b5cb9bf8d08ebf68c529 Mon Sep 17 00:00:00 2001
From: Mauro Condarelli <mc5686@mclink.it>
Date: Fri, 28 Aug 2020 15:36:20 +0200
Subject: [PATCH] Move artifact version check to inner parsing loop.

Artifact version, when install-if-differet/install-if-higher is specified,
is now done before call to parsing hook (if any).

To do this:
- functions is_image_installed() and is_image_higher() moved from core/parser.c
  to parser/parser.c
- calls to these functions, together with loops in remove_installed_image_list()
  and remove_higher_image_list() were completely removed from core/parser.c
- boolean `required` in `struct img_type` was replaced with `enum skip_t skip`
- field `img_type.skip` is assigned a value detailing reason for skip (if any)
- field `img_type.skip` is inserted into table passed to Lua hook (if any) end
  retrieved after Lua call so hook function can override setting.
- if `img_type.skip` is non-zero the image is considered "skippable" and the
  whole `img_type` structure is removed from handling list.

Signed-off-by: Mauro Condarelli <mc5686@mclink.it>
---
 core/parser.c           | 98 -----------------------------------------
 core/stream_interface.c |  2 +-
 corelib/lua_interface.c |  5 ++-
 include/swupdate.h      |  9 +++-
 parser/parser.c         | 91 +++++++++++++++++++++++++++++++++-----
 5 files changed, 93 insertions(+), 112 deletions(-)

diff --git a/core/parser.c b/core/parser.c
index 7f281cf..bc13d26 100644
--- a/core/parser.c
+++ b/core/parser.c
@@ -130,100 +130,6 @@ static int check_handler_list(struct imglist *list,
 	return 0;
 }
 
-static int is_image_installed(struct swver *sw_ver_list,
-				struct img_type *img)
-{
-	struct sw_version *swver;
-
-	if (!sw_ver_list)
-		return false;
-
-	if (!strlen(img->id.name) || !strlen(img->id.version) ||
-		!img->id.install_if_different)
-		return false;
-
-	LIST_FOREACH(swver, sw_ver_list, next) {
-		/*
-		 * Check if name and version are identical
-		 */
-		if (!strncmp(img->id.name, swver->name, sizeof(img->id.name)) &&
-		    !compare_versions(img->id.version, swver->version)) {
-			TRACE("%s(%s) already installed, skipping...",
-				img->id.name,
-				img->id.version);
-
-			return true;
-		}
-	}
-
-	return false;
-}
-
-static int is_image_higher(struct swver *sw_ver_list,
-				struct img_type *img)
-{
-	struct sw_version *swver;
-
-	if (!sw_ver_list)
-		return false;
-
-	if (!strlen(img->id.name) || !strlen(img->id.version) ||
-		!img->id.install_if_higher)
-		return false;
-
-	LIST_FOREACH(swver, sw_ver_list, next) {
-		const char* current_version = swver->version;
-		const char* proposed_version = img->id.version;
-
-		/*
-		 * Check if name are identical and the new version is lower
-		 * or equal.
-		 */
-		if (!strncmp(img->id.name, swver->name, sizeof(img->id.name)) &&
-		    (compare_versions(proposed_version, current_version) < 0)) {
-			TRACE("%s(%s) has a higher version installed, skipping...",
-			      img->id.name,
-			      img->id.version);
-
-			return true;
-		}
-	}
-
-	return false;
-}
-
-/*
- * Remove the image if the same version is already installed
- */
-static void remove_installed_image_list(struct imglist *img_list,
-				struct swver *sw_ver_list)
-{
-	struct img_type *img, *tmp;
-
-	LIST_FOREACH_SAFE(img, img_list, next, tmp) {
-		if (is_image_installed(sw_ver_list, img)) {
-			LIST_REMOVE(img, next);
-			free_image(img);
-		}
-	}
-}
-
-/*
- * Remove the image if a higher version is already installed
- */
-static void remove_higher_image_list(struct imglist *img_list,
-				struct swver *sw_ver_list)
-{
-	struct img_type *img, *tmp;
-
-	LIST_FOREACH_SAFE(img, img_list, next, tmp) {
-		if (is_image_higher(sw_ver_list, img)) {
-			LIST_REMOVE(img, next);
-			free_image(img);
-		}
-	}
-}
-
 int parse(struct swupdate_cfg *sw, const char *descfile)
 {
 	int ret = -1;
@@ -326,10 +232,6 @@ int parse(struct swupdate_cfg *sw, const char *descfile)
 		}
 	}
 
-	remove_installed_image_list(&sw->images, &sw->installed_sw_list);
-
-	remove_higher_image_list(&sw->images, &sw->installed_sw_list);
-
 	/*
 	 * Compute the total number of installer
 	 * to initialize the progress bar
diff --git a/core/stream_interface.c b/core/stream_interface.c
index 99e5c62..228c78a 100644
--- a/core/stream_interface.c
+++ b/core/stream_interface.c
@@ -281,7 +281,7 @@ static int extract_files(int fd, struct swupdate_cfg *software)
 			 */
 
 			LIST_FOREACH(img, &software->images, next) {
-				if (! img->required)
+				if (  img->skip)
 					continue;
 				if (! img->fname[0])
 					continue;
diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index eb05429..2025942 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -336,6 +336,8 @@ static void lua_number_to_img(struct img_type *img, const char *key,
 		img->size = (long long)val;
 	if (!strcmp(key, "checksum"))
 		img->checksum = (unsigned int)val;
+	if (!strcmp(key, "skip"))
+		img->skip = (unsigned int)val;
 }
 
 #ifdef CONFIG_HANDLER_IN_LUA
@@ -492,6 +494,7 @@ static void update_table(lua_State* L, struct img_type *img)
 		LUA_PUSH_IMG_NUMBER(img, "offset", seek);
 		LUA_PUSH_IMG_NUMBER(img, "size", size);
 		LUA_PUSH_IMG_NUMBER(img, "checksum", checksum);
+		LUA_PUSH_IMG_NUMBER(img, "skip", skip);
 
 		switch (img->compressed) {
 			case COMPRESSED_ZLIB:
@@ -540,7 +543,7 @@ static void update_table(lua_State* L, struct img_type *img)
 #endif
 
 		lua_getfield(L, -1, "_private");
-		LUA_PUSH_IMG_NUMBER(img, "offset", offset);
+        LUA_PUSH_IMG_NUMBER(img, "offset", offset);
 		lua_pop(L, 1);
 
 		char *hashstring = alloca(2 * SHA256_HASH_LENGTH + 1);
diff --git a/include/swupdate.h b/include/swupdate.h
index 8854d2f..29b756d 100644
--- a/include/swupdate.h
+++ b/include/swupdate.h
@@ -41,6 +41,13 @@ enum {
 	INSTALL_FROM_STREAM
 };
 
+typedef enum {
+	SKIP_NONE=0,
+	SKIP_SAME,
+	SKIP_HIGHER,
+	SKIP_SCRIPT
+} skip_t;
+
 enum {
   COMPRESSED_FALSE,
   COMPRESSED_TRUE,
@@ -70,7 +77,7 @@ struct img_type {
 	char extract_file[MAX_IMAGE_FNAME];
 	char filesystem[MAX_IMAGE_FNAME];
 	unsigned long long seek;
-	int required;
+	skip_t skip;
 	int provided;
 	int compressed;
 	int preserve_attributes; /* whether to preserve attributes in archives */
diff --git a/parser/parser.c b/parser/parser.c
index dce5180..8f8b25c 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -248,6 +248,68 @@ static int parse_hw_compatibility(parsertype __attribute__ ((__unused__))p,
 }
 #endif
 
+static int is_image_installed(struct swver *sw_ver_list,
+                              struct img_type *img)
+{
+    struct sw_version *swver;
+
+    if (!sw_ver_list)
+        return false;
+
+    if (!strlen(img->id.name) || !strlen(img->id.version) ||
+        !img->id.install_if_different)
+        return false;
+
+    LIST_FOREACH(swver, sw_ver_list, next) {
+        /*
+         * Check if name and version are identical
+         */
+        if (!strncmp(img->id.name, swver->name, sizeof(img->id.name)) &&
+            !compare_versions(img->id.version, swver->version)) {
+            TRACE("%s(%s) already installed, skipping...",
+                  img->id.name,
+                  img->id.version);
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static int is_image_higher(struct swver *sw_ver_list,
+                           struct img_type *img)
+{
+    struct sw_version *swver;
+
+    if (!sw_ver_list)
+        return false;
+
+    if (!strlen(img->id.name) || !strlen(img->id.version) ||
+        !img->id.install_if_higher)
+        return false;
+
+    LIST_FOREACH(swver, sw_ver_list, next) {
+        const char* current_version = swver->version;
+        const char* proposed_version = img->id.version;
+
+        /*
+         * Check if name are identical and the new version is lower
+         * or equal.
+         */
+        if (!strncmp(img->id.name, swver->name, sizeof(img->id.name)) &&
+            (compare_versions(proposed_version, current_version) < 0)) {
+            TRACE("%s(%s) has a higher version installed, skipping...",
+                  img->id.name,
+                  img->id.version);
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
 static int run_embscript(parsertype p, void *elem, struct img_type *img,
 			 lua_State *L, const char *embscript)
 {
@@ -260,7 +322,7 @@ static int run_embscript(parsertype p, void *elem, struct img_type *img,
 	return lua_parser_fn(L, embfcn, img);
 }
 
-static int parse_common_attributes(parsertype p, void *elem, struct img_type *image)
+static int parse_common_attributes(parsertype p, void *elem, struct img_type *image, struct swupdate_cfg *cfg)
 {
 	char seek_str[MAX_SEEK_STRING_SIZE];
 	const char* compressed;
@@ -310,6 +372,14 @@ static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
 	get_field(p, elem, "encrypted", &image->is_encrypted);
 	GET_FIELD_STRING(p, elem, "ivt", image->ivt_ascii);
 
+	if (is_image_installed(&cfg->installed_sw_list, image)) {
+		image->skip = SKIP_SAME;
+	} else if (is_image_higher(&cfg->installed_sw_list, image)) {
+		image->skip = SKIP_HIGHER;
+	} else {
+		image->skip = SKIP_NONE;
+	}
+
 	return 0;
 }
 
@@ -340,7 +410,7 @@ static int parse_partitions(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
 			ERROR("No memory: malloc failed");
 			return -ENOMEM;
 		}
-		if (parse_common_attributes(p, elem, partition) < 0) {
+		if (parse_common_attributes(p, elem, partition, swcfg) < 0) {
 			free_image(partition);
 			return -1;
 		}
@@ -407,7 +477,7 @@ static int parse_scripts(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lu
 			return -ENOMEM;
 		}
 
-		if (parse_common_attributes(p, elem, script) < 0) {
+		if (parse_common_attributes(p, elem, script, swcfg) < 0) {
 			free_image(script);
 			return -1;
 		}
@@ -430,7 +500,7 @@ static int parse_scripts(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lu
 			skip ? "Skip" : "Found",
 			script->fname);
 
-		if (skip) {
+		if (skip || script->skip != SKIP_NONE) {
 			free_image(script);
 			continue;
 		}
@@ -500,7 +570,7 @@ static int parse_bootloader(parsertype p, void *cfg, struct swupdate_cfg *swcfg,
 			return -ENOMEM;
 		}
 
-		if (parse_common_attributes(p, elem, script) < 0) {
+		if (parse_common_attributes(p, elem, script, swcfg) < 0) {
 			free_image(script);
 			return -1;
 		}
@@ -508,7 +578,7 @@ static int parse_bootloader(parsertype p, void *cfg, struct swupdate_cfg *swcfg,
 		script->is_script = 1;
 
 		skip = run_embscript(p, elem, script, L, swcfg->embscript);
-		if (skip != 0) {
+		if (skip != 0 || script->skip != SKIP_NONE) {
 			free_image(script);
 			if (skip < 0)
 				return -1;
@@ -557,7 +627,7 @@ static int parse_images(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lua
 			return -ENOMEM;
 		}
 
-		if (parse_common_attributes(p, elem, image) < 0) {
+		if (parse_common_attributes(p, elem, image, swcfg) < 0) {
 			free_image(image);
 			return -1;
 		}
@@ -595,8 +665,7 @@ static int parse_images(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lua
 						    image->id.install_if_higher)) ?
 					" Version must be checked" : ""
 			);
-
-		if (skip) {
+		if (skip || image->skip != SKIP_NONE) {
 			free_image(image);
 			continue;
 		}
@@ -640,7 +709,7 @@ static int parse_files(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lua_
 			return -ENOMEM;
 		}
 
-		if (parse_common_attributes(p, elem, file) < 0) {
+		if (parse_common_attributes(p, elem, file, swcfg) < 0) {
 			free_image(file);
 			return -1;
 		}
@@ -670,7 +739,7 @@ static int parse_files(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lua_
 			(strlen(file->id.name) && file->id.install_if_different) ?
 					"; Version must be checked" : "");
 
-		if (skip) {
+		if (skip || file->skip != SKIP_NONE) {
 			free_image(file);
 			continue;
 		}
-- 
2.25.1

