update-manager: Drop untaring deltas with system() function 52/285752/10 accepted/tizen/unified/20230116.060914
authorAntoni Adaszkiewicz <a.adaszkiewi@samsung.com>
Mon, 19 Dec 2022 12:18:33 +0000 (13:18 +0100)
committerAntoni Adaszkiewicz <a.adaszkiewi@samsung.com>
Tue, 3 Jan 2023 13:20:33 +0000 (14:20 +0100)
Untaring deltas with system() function can be very slow,
especially for larger deltas. This can result in timouts while
verifying delta-device compatability.

Change-Id: I5ee01e9d8af6d88eb69aff0b8856ab396ea92f64

packaging/update-control.spec
update-manager/CMakeLists.txt
update-manager/common/common-tar.c [new file with mode: 0644]
update-manager/common/common-util.c

index 3030476fe295ee0f8b3f2b3b618492406f9f9857..4abcc82b4a44184883b7baa125a809cfe3248d3f 100644 (file)
@@ -32,6 +32,7 @@ BuildRequires:  pkgconfig(key-manager)
 BuildRequires:  pkgconfig(pkgmgr-info)
 BuildRequires:  pkgconfig(storage)
 BuildRequires:  pkgconfig(vconf)
+BuildRequires:  libtar-devel
 
 %description
 An Update Control library in Tizen C API
index 00475c480a99212881229ec8e075345a6e341f0c..a76e12e81b663486ba73c07acc1f9507fbfc5f46 100644 (file)
@@ -18,6 +18,7 @@ SET(PKG_MODULES
        pkgmgr-info
        storage
        vconf
+       zlib
 )
 INCLUDE(FindPkgConfig)
 pkg_check_modules(${PKG_NAME} REQUIRED ${PKG_MODULES})
@@ -40,4 +41,5 @@ FILE(GLOB SOURCE_FILES
 )
 ADD_EXECUTABLE(${PKG_NAME} ${SOURCE_FILES})
 TARGET_LINK_LIBRARIES(${PKG_NAME} ${${PKG_NAME}_LDFLAGS} "-ldl")
+TARGET_LINK_LIBRARIES(${PKG_NAME} libtar.a)
 INSTALL(TARGETS ${PKG_NAME} DESTINATION bin)
diff --git a/update-manager/common/common-tar.c b/update-manager/common/common-tar.c
new file mode 100644 (file)
index 0000000..c7de444
--- /dev/null
@@ -0,0 +1,180 @@
+#include "common.h"
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <zlib.h>
+#include <libtar.h>
+#include <string.h>
+
+// for the sake of simplicity this stays global
+static gzFile gz_tar = NULL;
+
+int gzip_open(const char *pathname, int oflags, ...)
+{
+       if (gz_tar != NULL) {
+               errno = EALREADY;
+               return -1;
+       }
+
+       // We assume oflags == O_RDONLY, since that's what we actually use.
+       // Also we don't care about the mode since we are lazy.
+       if (oflags != O_RDONLY) {
+               errno = ENOTSUP;
+               return -1;
+       }
+
+       gz_tar = gzopen(pathname, "r");
+       if (gz_tar == NULL) {
+               _CLOGE("gzopen() failed with errno: %d\n", errno);
+               return -1;
+       }
+
+       return 1;
+}
+
+int gzip_close(__attribute__((unused)) int useless_fd)
+{
+       if (gz_tar == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       int ret = gzclose(gz_tar);
+       if (ret != Z_OK)
+               _CLOGE("gzclose() failed with errno: %d\n", errno);
+
+       return ret;
+}
+
+ssize_t gzip_read(__attribute__((unused)) int useless_fd, void *buf, size_t len)
+{
+       if (gz_tar == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       int ret = gzread(gz_tar, buf, len);
+       if (ret <= 0) {
+               if (gzeof(gz_tar))
+                       _CLOGE("gzread() failed - EOF reached\n");
+               else
+                       _CLOGE("gzread() failed with error: %s\n", gzerror(gz_tar, NULL));
+       }
+
+       return ret;
+}
+
+ssize_t gzip_write(__attribute__((unused)) int useless_fd, __attribute__((unused)) const void *buf, __attribute__((unused)) size_t len)
+{
+       // Again, we do not use this.
+       errno = ENOTSUP;
+       return -1;
+}
+
+static int str_ends_with(const char *str, const char *suffix)
+{
+       size_t str_length = strlen(str);
+       size_t suffix_length = strlen(suffix);
+
+       return ((str_length > suffix_length) && (memcmp(str + str_length - suffix_length, suffix, suffix_length + 1) == 0));
+}
+
+static int tar_get_tartype(const char *tar_path, tartype_t **type)
+{
+       static tartype_t gzip_type = {gzip_open, gzip_close, gzip_read, gzip_write};
+
+       if (str_ends_with(tar_path, ".tar")) {
+               *type = NULL;
+       }
+       else if (str_ends_with(tar_path, ".tar.gz")) {
+               *type = &gzip_type;
+       }
+       else if (str_ends_with(tar_path, ".tgz")) {
+               *type = &gzip_type;
+       }
+       else {
+               _CLOGE("Unknown/unsupported file extension for delta - %s\n", tar_path);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int tar_init_with_type(TAR **tar, const char *tar_path, tartype_t *type)
+{
+       if (tar_open(tar, tar_path, type, O_RDONLY, 0, 0) < 0) {
+               *tar = NULL;
+               _CLOGE("tar_open() fail!\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+int util_file_untar(const char *tar_path, const char *dest_path, const char *extract_file_name)
+{
+       TAR  *tar;
+       tartype_t *type;
+       DIR *dir;
+
+       if (tar_get_tartype(tar_path, &type)) {
+               _CLOGE("tar_get_tartype() error!\n");
+               return -1;
+       }
+
+       dir = opendir(dest_path);
+       if (dir == NULL) {
+               _CLOGE("Directory %s could not be opened, errno: %d\n", dest_path, errno);
+               return -1;
+       }
+       closedir(dir);
+
+       if (tar_init_with_type(&tar, tar_path, type)) {
+               _CLOGE("tar_init_with_type() error!\n");
+               return -1;
+       }
+
+       int ret = 0;
+       char extracted_file_path[MAX_BUFFER_SIZE];
+       snprintf(extracted_file_path, MAX_BUFFER_SIZE, "%s/%s", dest_path, extract_file_name);
+
+       for (;;)
+       {
+               switch (th_read(tar))
+               {
+                       case -1:
+                               _CLOGE("th_read() fail!\n");
+                               ret = -1;
+                               goto cleanup;
+                       case 1:
+                               _CLOGE("EOF reached - incorrect delta!\n");
+                               ret = -1;
+                               goto cleanup;
+                       case 0:
+                               break;
+               }
+
+               char *current_pathname = th_get_pathname(tar);
+
+               if (strcmp(current_pathname, extract_file_name) == 0) {
+                       if (tar_extract_file(tar, extracted_file_path) < 0) {
+                               _CLOGE("tar_extract_file() fail!\n");
+                               ret = -1;
+                               goto cleanup;
+                       }
+                       _CLOGI("%s successfully extracted from %s\n", extract_file_name, tar_path);
+                       goto cleanup;
+               }
+
+               if (TH_ISREG(tar) && (tar_skip_regfile(tar) < 0)) {
+                       _CLOGE("tar_skip_regfile() fail!\n");
+                       ret = -1;
+                       goto cleanup;
+               }
+       }
+
+cleanup:
+       tar_close(tar);
+       gz_tar = NULL;
+       return ret;
+}
\ No newline at end of file
index 43a0a3fc258d00e3931b1526baf42794d84c2bf6..f584398ca27d63b4f4e924f96237bf2ea18d121f 100644 (file)
@@ -101,27 +101,6 @@ int util_file_write_line(const char *path, const char *msg)
        return status;
 }
 
-int util_file_untar(const char *tar_path, const char *dest_path, const char *extract_file_name)
-{
-       int ret = 0, status = 0;
-       char *command = NULL;
-
-       command = g_strjoin(" ",
-               "tar", "xvfp", tar_path, "-C", dest_path, extract_file_name, NULL);
-
-       ret = system(command);
-       if (ret < 0) {
-               _CLOGE("Failed to execute untar command %s : %m", command);
-               status = -1;
-       } else if (ret > 0) {
-               _CLOGE("Failed to untar : %d", ret);
-               status = -1;
-       }
-       free(command);
-
-       return status;
-}
-
 static int read_checksum_for(const char *checksum_path, const char *file_name, char *sha1_hex, size_t sha1_hex_len)
 {
        int result = -1;