Add upgrade-apply tool 72/275472/12
authorMateusz Majewski <m.majewski2@samsung.com>
Tue, 31 May 2022 07:12:30 +0000 (09:12 +0200)
committerMateusz Majewski <m.majewski2@samsung.com>
Wed, 1 Jun 2022 11:14:17 +0000 (13:14 +0200)
This is a tool that allows us to apply an upgrade provided in a tar
archive to a partition. Hopefully this will allow us to simplify the
upgrade codebase a bit.

Change-Id: Ibe876dd0141065e8c150a360b329f67ca6935c69

CMakeLists.txt
packaging/tota-ua.spec
upgrade-apply/CMakeLists.txt [new file with mode: 0644]
upgrade-apply/main.c [new file with mode: 0644]
upgrade-apply/ss_brotli_patch/NOTES.md [new file with mode: 0644]
upgrade-apply/ss_brotli_patch/ss_brotli_patch.c
upgrade-apply/ss_brotli_patch/ss_brotli_patch.h

index 93fa8a1..3d1d51b 100755 (executable)
@@ -113,3 +113,4 @@ INSTALL(TARGETS ${BLKIDEXENAME} DESTINATION ${BINDIR})
 
 ADD_SUBDIRECTORY(dmverity)
 ADD_SUBDIRECTORY(img-verifier)
+ADD_SUBDIRECTORY(upgrade-apply)
index a2dbaa3..97b5aa0 100755 (executable)
@@ -18,6 +18,7 @@ BuildRequires:  pkgconfig(libtzplatform-config)
 BuildRequires:  pkgconfig(dlog)
 Buildrequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(hal-api-device)
+BuildRequires:  libtar-devel
 
 Requires:       tar
 Requires:       gzip
@@ -105,3 +106,6 @@ ln -s ../clone_partitions_recovery.service %{buildroot}%{_unitdir}/tizen-recover
 
 # blkid-print
 %{_bindir}/blkid-print
+
+# upgrade-apply
+%{_bindir}/upgrade-apply
diff --git a/upgrade-apply/CMakeLists.txt b/upgrade-apply/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e7cf40e
--- /dev/null
@@ -0,0 +1,16 @@
+find_package(PkgConfig)
+pkg_check_modules(DEPS REQUIRED IMPORTED_TARGET
+       zlib
+       libbrotlidec
+)
+
+set(
+       upgrade-apply_SRCS
+       main.c
+       ss_brotli_patch/ss_brotli_patch.c
+)
+add_executable(upgrade-apply ${upgrade-apply_SRCS})
+target_link_libraries(upgrade-apply PRIVATE PkgConfig::DEPS)
+# Unfortunately, libtar is neither CMake- nor pkgconfig-aware.
+target_link_libraries(upgrade-apply PRIVATE tar)
+install(TARGETS upgrade-apply)
diff --git a/upgrade-apply/main.c b/upgrade-apply/main.c
new file mode 100644 (file)
index 0000000..63f13d9
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * tota-ua
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libtar.h>
+#include <zlib.h>
+
+#include "ss_brotli_patch/ss_brotli_patch.h"
+
+void fd_cleanup(int *fd)
+{
+       if (!fd || *fd < 0)
+               return;
+       close(*fd);
+}
+
+void tar_cleanup(TAR **tar)
+{
+       if (!tar || !*tar)
+               return;
+       tar_close(*tar);
+}
+
+enum archive_kind {
+       KIND_RAW,
+       KIND_BROTLI_PATCH,
+};
+
+struct parse_result {
+       enum {
+               PARSE_OK,
+               PARSE_HELP,
+               PARSE_REPEATED_ARGUMENT,
+               PARSE_MISSING_ARGUMENT,
+               PARSE_PATCH_MISTAKE,
+               PARSE_BAD_KIND,
+               PARSE_NO_PARSE,
+       } result;
+
+       const char *archive;
+       const char *dest;
+       const char *archive_file;
+       const char *patch_orig;
+       enum archive_kind kind;
+};
+
+struct parse_result parse_args(int argc, char **argv)
+{
+       const char *archive = NULL;
+       const char *dest = NULL;
+       const char *archive_file = NULL;
+       const char *patch_orig = NULL;
+       enum archive_kind kind = -1;
+       bool help = false;
+
+       for (;;) {
+               const struct option long_options[] = {
+                       {"archive",      required_argument, NULL, 0  },
+                       {"dest",         required_argument, NULL, 1  },
+                       {"archive-file", required_argument, NULL, 2  },
+                       {"kind",         required_argument, NULL, 3  },
+                       {"patch-orig",   required_argument, NULL, 4  },
+                       {"help",         no_argument,       NULL, 'h'},
+                       {0}
+               };
+               int option = getopt_long(argc, argv, "h", long_options, NULL);
+               if (option < 0)
+                       break;
+
+               switch (option) {
+               case 0: // archive
+                       if (archive != NULL)
+                               return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+                       archive = optarg;
+                       break;
+
+               case 1: // dest
+                       if (dest != NULL)
+                               return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+                       dest = optarg;
+                       break;
+
+               case 2: // archive-file
+                       if (archive_file != NULL)
+                               return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+                       archive_file = optarg;
+                       break;
+
+               case 3: // kind
+                       if (kind != -1)
+                               return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+                       if (strcmp(optarg, "raw") == 0)
+                               kind = KIND_RAW;
+                       else if (strcmp(optarg, "ss_brotli_patch") == 0)
+                               kind = KIND_BROTLI_PATCH;
+                       else
+                               return (struct parse_result) { .result = PARSE_BAD_KIND };
+                       break;
+
+               case 4: // patch-orig
+                       if (patch_orig != NULL)
+                               return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+                       patch_orig = optarg;
+                       break;
+
+               case 'h': // help
+                       if (help)
+                               return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+                       help = true;
+                       break;
+
+               default:
+                       return (struct parse_result) { .result = PARSE_NO_PARSE };
+               }
+       }
+
+       if (help) {
+               if (archive != NULL || dest != NULL || archive_file != NULL || patch_orig != NULL || kind != -1)
+                       return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT };
+               return (struct parse_result) { .result = PARSE_HELP };
+       }
+
+       if (archive == NULL)
+               return (struct parse_result) { .result = PARSE_MISSING_ARGUMENT };
+       if (dest == NULL)
+               return (struct parse_result) { .result = PARSE_MISSING_ARGUMENT };
+       if (archive_file == NULL)
+               return (struct parse_result) { .result = PARSE_MISSING_ARGUMENT };
+       if (kind == -1)
+               return (struct parse_result) { .result = PARSE_MISSING_ARGUMENT };
+
+       if (patch_orig == NULL && kind == KIND_BROTLI_PATCH)
+               return (struct parse_result) { .result = PARSE_PATCH_MISTAKE };
+       if (patch_orig != NULL && kind == KIND_RAW)
+               return (struct parse_result) { .result = PARSE_PATCH_MISTAKE };
+
+       return (struct parse_result) {
+               .result = PARSE_OK,
+               .archive = archive,
+               .dest = dest,
+               .archive_file = archive_file,
+               .patch_orig = patch_orig,
+               .kind = kind,
+       };
+}
+
+// The TAR structure can only hold an int as a FD.
+// libtar example uses some brutal hack which we don't want to do.
+// We don't want to open multiple archive at the time, so let's just have 1 as FD,
+// and instead hold the gzip structure globally.
+static gzFile gzip_file;
+
+int gzip_open(const char *pathname, int oflags, ...)
+{
+       if (gzip_file != 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;
+       }
+
+       __attribute__((cleanup(fd_cleanup))) int inner_fd = open(pathname, O_RDONLY);
+       if (inner_fd == -1)
+               return -1;
+
+       gzip_file = gzopen(pathname, "r");
+       if (gzip_file == NULL)
+               return -1;
+       inner_fd = -1;
+
+       return 1;
+}
+
+int gzip_close(__attribute__((unused)) int useless_fd)
+{
+       if (gzip_file == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return gzclose(gzip_file);
+}
+
+ssize_t gzip_read(__attribute__((unused)) int useless_fd, void *buf, size_t len)
+{
+       if (gzip_file == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return gzread(gzip_file, buf, len);
+}
+
+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;
+}
+
+void help(char *name)
+{
+       fprintf(stderr,
+               "Usage: %s --archive ARCHIVE --archive-file FILE --dest DESTINATION --kind KIND [--patch-orig ORIGIN]\n"
+               "\n"
+               "Patches a partition using an archive.\n"
+               "It will look for a file named FILE in an archive called ARCHIVE; the archive should have an extension\n"
+               "of either .tar, .tar.gz or .tgz; it will be read in the way corresponding to the extension.\n"
+               "The KIND parameter specifies how the file will be treated:\n"
+               " - raw means that the file should be treated as an image to be written,\n"
+               " - ss_brotli_patch means that the file should be treated as a delta in the (Tizen-specific) ss_brotli_patch\n"
+               "   format. In this case, ORIGIN is needed and specifies the partition that a delta is based on.\n"
+               "The results will be written to the DESTINATION partition.\n",
+       name);
+}
+
+int apply_raw(const char *dest, TAR *tar)
+{
+       int size = th_get_size(tar);
+
+       __attribute__((cleanup(fd_cleanup))) int out = open(dest, O_WRONLY);
+       if (out == -1) {
+               fprintf(stderr, "Couldn't open the target (errno: %m)\n");
+               return -1;
+       }
+
+       while (size > 0) {
+               char buf[T_BLOCKSIZE];
+               int r_read = tar_block_read(tar, buf);
+               switch (r_read) {
+               case -1:
+                       fprintf(stderr, "Couldn't read from the archive (errno: %m)\n");
+                       return -1;
+               case 0:
+                       fprintf(stderr, "We have reached EOF unexpectedly\n");
+                       return -1;
+               }
+
+               if (r_read > size) {
+                       r_read = size;
+               }
+               size -= r_read;
+
+               int written = 0;
+               while (written - r_read) {
+                       int r_write = write(out, buf + written, r_read - written);
+                       if (r_write == -1) {
+                               fprintf(stderr, "Couldn't write to the partition (errno: %m)\n");
+                               return -1;
+                       }
+                       written += r_write;
+               }
+       }
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       struct parse_result parsed = parse_args(argc, argv);
+       switch (parsed.result) {
+       case PARSE_REPEATED_ARGUMENT:
+               fprintf(stderr, "Argument incorrectly repeated\n");
+               help(argv[0]);
+               return EXIT_FAILURE;
+       case PARSE_MISSING_ARGUMENT:
+               fprintf(stderr, "Argument incorrectly missing\n");
+               help(argv[0]);
+               return EXIT_FAILURE;
+       case PARSE_PATCH_MISTAKE:
+               fprintf(stderr, "`patch-orig` parameter doesn't fit the kind\n");
+               help(argv[0]);
+               return EXIT_FAILURE;
+       case PARSE_BAD_KIND:
+               fprintf(stderr, "Invalid `kind` parameter (possible: `raw`, `ss_brotli_patch`)\n");
+               help(argv[0]);
+               return EXIT_FAILURE;
+       case PARSE_NO_PARSE:
+               fprintf(stderr, "Invalid parameters passed\n");
+               help(argv[0]);
+               return EXIT_FAILURE;
+       case PARSE_HELP:
+               help(argv[0]);
+               return EXIT_SUCCESS;
+       case PARSE_OK:
+               break;
+       }
+
+       tartype_t *type;
+       static tartype_t gzip_type = { gzip_open, gzip_close, gzip_read, gzip_write };
+       if (strcmp(parsed.archive + strlen(parsed.archive) - strlen(".tar"), ".tar") == 0)
+               type = NULL;
+       else if (strcmp(parsed.archive + strlen(parsed.archive) - strlen(".tar.gz"), ".tar.gz") == 0)
+               type = &gzip_type;
+       else if (strcmp(parsed.archive + strlen(parsed.archive) - strlen(".tgz"), ".tgz") == 0)
+               type = &gzip_type;
+       else {
+               fprintf(stderr, "Unknown archive extension\n");
+               help(argv[0]);
+               return EXIT_FAILURE;
+       }
+
+       __attribute__ ((cleanup(tar_cleanup))) TAR *tar;
+       if (tar_open(&tar, parsed.archive, type, O_RDONLY, 0, 0) == -1) {
+               /* Usually we would instead initialize tar to NULL, and tar_open would not touch it in case of failure.
+                * Alas, that's not what happens; tar_open sets tar to a newly allocated address, does stuff there,
+                * and in case of failure frees the address but does not reset it. This means that in case of failure
+                * tar contains an invalid address. So we have to NULL it out (so tar_cleanup doesn't crash our program),
+                * and then we don't have to initialize tar to NULL in first place. */
+               tar = NULL;
+
+               fprintf(stderr, "Couldn't open the archive (errno: %m)\n");
+               return EXIT_FAILURE;
+       }
+
+       for (;;) {
+               switch (th_read(tar)) {
+               case -1:
+                       fprintf(stderr, "Couldn't read the archive header (errno: %m)\n");
+                       return EXIT_FAILURE;
+               case 1:
+                       // All files processed, which means...
+                       fprintf(stderr, "File not found in archive\n");
+                       return EXIT_FAILURE;
+               case 0:
+                       break;
+               }
+
+               const char *this_name = th_get_pathname(tar);
+               if (this_name == NULL) {
+                       // TODO: Can this even happen? I don't think docs say anything about this.
+                       fprintf(stderr, "Couldn't extract the filename from the archive (malformed archive?)\n");
+                       return EXIT_FAILURE;
+               }
+
+               if (strcmp(this_name, parsed.archive_file) != 0) {
+                       if (TH_ISREG(tar)) {
+                               if (tar_skip_regfile(tar) == -1) {
+                                       fprintf(stderr, "Couldn't skip an intermediate file from the archive (errno: %m; malformed archive?)\n");
+                                       return EXIT_FAILURE;
+                               }
+                       }
+                       continue;
+               }
+
+               fprintf(stderr, "File found. Starting to write\n");
+
+               int r;
+               switch (parsed.kind) {
+               case KIND_RAW:
+                       r = apply_raw(parsed.dest, tar);
+                       break;
+
+               case KIND_BROTLI_PATCH:
+                       r = apply_patch_brotli(parsed.patch_orig, parsed.dest, tar);
+                       break;
+               }
+
+               if (r != 0) {
+                       fprintf(stderr, "Couldn't apply; you might need to restore from the backup!\n");
+                       return EXIT_FAILURE;
+               }
+
+               fprintf(stderr, "Everything written successfully\n");
+               return EXIT_SUCCESS;
+       }
+}
diff --git a/upgrade-apply/ss_brotli_patch/NOTES.md b/upgrade-apply/ss_brotli_patch/NOTES.md
new file mode 100644 (file)
index 0000000..27abb13
--- /dev/null
@@ -0,0 +1,3 @@
+This is copied from platform/core/system/libtota @ b25d02d618797b5fb2fbe61a188d6a28dc720bf8.
+
+The code has been adapted to read patch from a tarball instead of a file descriptor, as well as some other minor improvements. It's mostly untouched otherwise.
index 6574d80..50227fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * libtota
+ * tota-ua (previously libtota)
  *
  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
@@ -27,7 +27,7 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <unistd.h>
-#include "fota_log.h"
+#include <libtar.h>
 
 #define PF_OK 0
 #define PF_ERROR_OPEN_FILE 1
@@ -35,7 +35,6 @@
 #define PF_ERROR_INVALID_PATCH_FILE 3
 #define PF_ERROR_DECOMPRESSION 4
 
-#define BUFF_IN_LEN 4096
 #define BUFF_OUT_LEN 4096
 #define SSINT_LEN 8
 #define BLOCK_COUNT_REPORT 5000
 const char SSDIFF_MAGIC[] = "SSDIFF40";
 
 struct bs_data {
-    int src_fd, dest_fd, patch_fd;
-    void *src_ptr, *dest_ptr, *patch_ptr;
+    int src_fd, dest_fd;
+    void *src_ptr, *dest_ptr;
+    TAR *patch_tar;
     size_t src_len, dest_len, patch_len;
-    unsigned char buff_in[BUFF_IN_LEN];
-    unsigned char buff_out[BUFF_IN_LEN];
+    unsigned char buff_in[T_BLOCKSIZE];
+    unsigned char buff_out[BUFF_OUT_LEN];
     uint8_t *dest_pos;
     uint8_t *src_pos;
+    size_t patch_remaining;
     size_t available_in, available_out;
     const uint8_t *compressed_pos;
     uint8_t *decompressed_pos;
@@ -64,19 +65,17 @@ static void free_data(struct bs_data *data)
 
     if (data->src_ptr) munmap(data->src_ptr, data->src_len);
     if (data->dest_ptr) munmap(data->dest_ptr, data->dest_len);
-    if (data->patch_ptr) munmap(data->patch_ptr, data->patch_len);
 
     if (data->src_fd) close(data->src_fd);
-    if (data->patch_fd) close(data->patch_fd);
     if (data->dest_fd) close(data->dest_fd);
 }
 
-static int open_file(char *file_name, int mode)
+static int open_file(const char *file_name, int mode)
 {
     assert(file_name);
     int fd = open(file_name, mode, S_IWUSR | S_IRUSR);
     if (fd < 0)
-        LOGE("Open file %s error: %m (%d)\n", file_name, errno);
+        fprintf(stderr, "Open file %s error: %m (%d)\n", file_name, errno);
     return fd;
 }
 
@@ -98,65 +97,83 @@ static size_t decompress_bytes(struct bs_data *data, size_t keep_offset)
     data->decompressed_pos = data->buff_out + keep_offset;
     data->available_out = sizeof(data->buff_out) - keep_offset;
 
-    BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
-
-    result = BrotliDecoderDecompressStream(data->bstate,
-            &data->available_in,
-            &data->compressed_pos,
-            &data->available_out,
-            &data->decompressed_pos,
-            &data->total_size);
-
-    if (result == BROTLI_DECODER_RESULT_ERROR) {
-        LOGE("Decoder error\n");
-        return PF_ERROR_DECOMPRESSION;
-    } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
-        LOGE("Invalid source file\n");
-        return PF_ERROR_DECOMPRESSION;
+    BrotliDecoderResult result;
+
+    for (;;) {
+        result =
+            BrotliDecoderDecompressStream(data->bstate,
+                &data->available_in,
+                &data->compressed_pos,
+                &data->available_out,
+                &data->decompressed_pos,
+                &data->total_size);
+
+        if (result == BROTLI_DECODER_RESULT_ERROR) {
+            fprintf(stderr, "Brotli decompression errored\n");
+            return PF_ERROR_DECOMPRESSION;
+        } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
+            if (data->patch_remaining <= 0) {
+                fprintf(stderr, "We have ran out of data and decompression is still in progress\n");
+                return PF_ERROR_DECOMPRESSION;
+            }
+
+            int r_read = tar_block_read(data->patch_tar, data->buff_in);
+            switch (r_read) {
+            case -1:
+                fprintf(stderr, "Couldn't read from the archive (errno: %m)\n");
+                return PF_ERROR_DECOMPRESSION;
+            case 0:
+                fprintf(stderr, "We have reached EOF unexpectedly\n");
+                return PF_ERROR_DECOMPRESSION;
+            }
+
+            if (r_read > data->patch_remaining) {
+                r_read = data->patch_remaining;
+            }
+            data->patch_remaining -= r_read;
+
+            data->available_in = r_read;
+            data->compressed_pos = data->buff_in;
+        } else {
+            break;
+        }
     }
 
     return PF_OK;
 }
 
-static int open_files(struct bs_data *data, char *source_file, size_t source_size, char *dest_file, size_t dest_size, char *patch_file)
+static int open_files(struct bs_data *data, const char *source_file, const char *dest_file, TAR *patch_tar)
 {
     assert(data);
     assert(source_file);
     assert(dest_file);
-    assert(patch_file);
+    assert(patch_tar);
 
     data->src_fd = open_file(source_file, O_RDONLY);
-    data->patch_fd = open_file(patch_file, O_RDONLY);
     data->dest_fd = open_file(dest_file, O_RDWR);
     if (data->src_fd < 0 ||
-        data->patch_fd < 0 ||
         data->dest_fd < 0)
         return PF_ERROR_OPEN_FILE;
 
-    data->src_len = source_size;
-    data->patch_len = get_file_len(data->patch_fd);
-    data->dest_len = dest_size;
+    data->patch_tar = patch_tar;
+
+    data->src_len = get_file_len(data->src_fd);
+    data->patch_len = th_get_size(data->patch_tar);
+    data->dest_len = get_file_len(data->dest_fd);
 
     data->src_ptr = mmap(NULL, data->src_len, PROT_READ, MAP_PRIVATE, data->src_fd, 0);
     if (data->src_ptr == MAP_FAILED) {
-        LOGE("mmap source file error: %m (%d)", errno);
-        return PF_ERROR_MMAP;
-    }
-
-    data->patch_ptr = mmap(NULL, data->patch_len, PROT_READ, MAP_PRIVATE, data->patch_fd, 0);
-    if (data->patch_ptr == MAP_FAILED) {
-        LOGE("mmap patch file error: %m (%d)", errno);
+        fprintf(stderr, "mmap source file error: %m (%d)\n", errno);
         return PF_ERROR_MMAP;
     }
 
     data->dest_ptr = mmap(NULL, data->dest_len, PROT_WRITE, MAP_SHARED, data->dest_fd, 0);
     if (data->dest_ptr == MAP_FAILED) {
-        LOGE("mmap destination error: %m (%d)\n", errno);
+        fprintf(stderr, "mmap destination error: %m (%d)\n", errno);
         return PF_ERROR_MMAP;
     }
 
-    data->compressed_pos = data->patch_ptr;
-    data->available_in = data->patch_len;
+    data->patch_remaining = data->patch_len;
 
     return PF_OK;
 }
@@ -166,14 +183,14 @@ static void init_data(struct bs_data *data)
     assert(data);
 
     data->src_fd = -1;
-    data->patch_fd = -1;
     data->dest_fd = -1;
     data->src_ptr = NULL;
     data->dest_ptr = NULL;
-    data->patch_ptr = NULL;
+    data->patch_tar = NULL;
     data->src_len = 0;
     data->dest_len = 0;
     data->patch_len = 0;
+    data->patch_remaining = 0;
     data->available_in = 0;
     data->compressed_pos = 0;
     data->available_out = 0;
@@ -225,10 +242,10 @@ int read_header(struct bs_data *data, uint8_t **buff_out_pos)
 
     if (*buff_out_pos + sizeof(SSDIFF_MAGIC) > data->decompressed_pos ||
         memcmp(data->buff_out, SSDIFF_MAGIC, sizeof(SSDIFF_MAGIC) - 1) != 0) {
-        LOGE("Invalid patch file\n");
+        fprintf(stderr, "Invalid patch file\n");
         return PF_ERROR_INVALID_PATCH_FILE;
     } else {
-        LOGL(LOG_SSENGINE, "Looks like SSDIFF\n");
+        fprintf(stderr, "Looks like SSDIFF\n");
     }
 
     *buff_out_pos += sizeof(SSDIFF_MAGIC) - 1;
@@ -239,10 +256,10 @@ int read_header(struct bs_data *data, uint8_t **buff_out_pos)
     }
 
     size_t target_size = parse_ssint(*buff_out_pos);
-    LOGL(LOG_SSENGINE, "target_size: 0x%lx (%ld)\n", target_size, target_size);
+    fprintf(stderr, "target_size: 0x%lx (%ld)\n", target_size, target_size);
 
     if (target_size != data->dest_len) {
-        LOGE("Declared target size differs from that read from the patch\n");
+        fprintf(stderr, "Declared target size differs from that read from the patch\n");
         return PF_ERROR_INVALID_PATCH_FILE;
     }
 
@@ -251,11 +268,11 @@ int read_header(struct bs_data *data, uint8_t **buff_out_pos)
     return PF_OK;
 }
 
-int apply_patch_brotli(char *source_file, size_t source_size, char *dest_file, size_t dest_size, char *patch_file)
+int apply_patch_brotli(const char *source_file, const char *dest_file, TAR *patch_tar)
 {
     assert(source_file);
     assert(dest_file);
-    assert(patch_file);
+    assert(patch_tar);
 
     int result;
     uint64_t blocks = 0;
@@ -263,7 +280,7 @@ int apply_patch_brotli(char *source_file, size_t source_size, char *dest_file, s
 
     init_data(&data);
 
-    if ((result = open_files(&data, source_file, source_size, dest_file, dest_size, patch_file)) != PF_OK)
+    if ((result = open_files(&data, source_file, dest_file, patch_tar)) != PF_OK)
         goto exit;
 
     if ((result = decompress_bytes(&data, 0)) != PF_OK)
@@ -342,14 +359,14 @@ int apply_patch_brotli(char *source_file, size_t source_size, char *dest_file, s
 
         blocks++;
         if (blocks % BLOCK_COUNT_REPORT == 0) {
-            printf("Number of processed patch blocks: %lld\n", blocks);
+            fprintf(stderr, "Number of processed patch blocks: %lu\n", blocks);
         }
     }
 
     result = PF_OK;
 
 exit:
-    printf("Total processed blocks: %lld\n", blocks);
+    fprintf(stderr, "Total processed blocks: %lu\n", blocks);
     free_data(&data);
     return result;
 }
index 47694b9..7c5603c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * libtota
+ * tota-ua (previously libtota)
  *
  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
@@ -19,4 +19,6 @@
 
 #include <unistd.h>
 
-extern int apply_patch_brotli(char *source_file, size_t source_size, char *dest_file, size_t dest_size, char *patch_file);
+#include <libtar.h>
+
+extern int apply_patch_brotli(const char *source_file, const char *dest_file, TAR *patch_tar);