diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch b/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch new file mode 100644 index 000000000..8784f33ad --- /dev/null +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch @@ -0,0 +1,694 @@ +From: Sergey Nazaryev +Date: Thu, 27 Jan 2022 19:41:23 +0200 +Subject: [PATCH 1/1] handlers: rdiff handler for applying librsync's rdiff + patches to UBI volumes + +The ubivol rdiff handler adds support for applying binary +delta patches generated by librsync's rdiff tool to UBI volumes, +see http://librsync.sourcefrog.net + +Signed-off-by: Sergey Nazaryev +Signed-off-by: David Escalona +--- + Makefile.flags | 4 + + configs/all_handlers_defconfig | 1 + + handlers/Config.in | 13 + + handlers/Makefile | 1 + + handlers/ubivol_rdiff_handler.c | 606 ++++++++++++++++++++++++++++++++ + 5 files changed, 625 insertions(+) + create mode 100644 handlers/ubivol_rdiff_handler.c + +diff --git a/Makefile.flags b/Makefile.flags +index 2a021c8..b542358 100644 +--- a/Makefile.flags ++++ b/Makefile.flags +@@ -209,6 +209,10 @@ ifeq ($(CONFIG_RDIFFHANDLER),y) + LDLIBS += rsync + endif + ++ifeq ($(CONFIG_UBIVOL_RDIFFHANDLER),y) ++LDLIBS += rsync ++endif ++ + ifeq ($(CONFIG_REMOTE_HANDLER),y) + LDLIBS += zmq + endif +diff --git a/configs/all_handlers_defconfig b/configs/all_handlers_defconfig +index 8f6f8e0..9077220 100644 +--- a/configs/all_handlers_defconfig ++++ b/configs/all_handlers_defconfig +@@ -31,5 +31,6 @@ CONFIG_SHELLSCRIPTHANDLER=y + CONFIG_SWUFORWARDER_HANDLER=y + CONFIG_SSBLSWITCH=y + CONFIG_UBIVOL=y ++CONFIG_UBIVOL_RDIFFHANDLER=y + CONFIG_UCFWHANDLER=y + CONFIG_UNIQUEUUID=y +diff --git a/handlers/Config.in b/handlers/Config.in +index 107ffeb..62d54bd 100644 +--- a/handlers/Config.in ++++ b/handlers/Config.in +@@ -166,6 +166,19 @@ config RDIFFHANDLER + comment "rdiff support needs librsync" + depends on !HAVE_LIBRSYNC + ++config UBIVOL_RDIFFHANDLER ++ bool "ubirdiff" ++ depends on HAVE_LIBRSYNC ++ depends on HAVE_LIBUBI ++ depends on MTD ++ default n ++ help ++ Add support for applying librsync's rdiff patches to UBI volumes, ++ see http://librsync.sourcefrog.net/ ++ ++comment "ubirdiff support needs libubi and librsync" ++ depends on !HAVE_LIBRSYNC || !HAVE_LIBUBI ++ + config READBACKHANDLER + bool "readback" + depends on HASH_VERIFY +diff --git a/handlers/Makefile b/handlers/Makefile +index b5203f9..bd47d3b 100644 +--- a/handlers/Makefile ++++ b/handlers/Makefile +@@ -21,6 +21,7 @@ obj-$(CONFIG_CFIHAMMING1)+= flash_hamming1_handler.o + obj-$(CONFIG_LUASCRIPTHANDLER) += lua_scripthandler.o + obj-$(CONFIG_RAW) += raw_handler.o + obj-$(CONFIG_RDIFFHANDLER) += rdiff_handler.o ++obj-$(CONFIG_UBIVOL_RDIFFHANDLER) += ubivol_rdiff_handler.o + obj-$(CONFIG_READBACKHANDLER) += readback_handler.o + obj-$(CONFIG_REMOTE_HANDLER) += remote_handler.o + obj-$(CONFIG_SHELLSCRIPTHANDLER) += shell_scripthandler.o +diff --git a/handlers/ubivol_rdiff_handler.c b/handlers/ubivol_rdiff_handler.c +new file mode 100644 +index 0000000..3b6073d +--- /dev/null ++++ b/handlers/ubivol_rdiff_handler.c +@@ -0,0 +1,606 @@ ++/* ++ * Author: Christian Storm ++ * Copyright (C) 2018, Siemens AG ++ * ++ * SPDX-License-Identifier: GPL-2.0-only ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "swupdate.h" ++#include "handler.h" ++#include "flash.h" ++#include "util.h" ++ ++/* Use rdiff's default inbuf and outbuf size of 64K */ ++#define RDIFF_BUFFER_SIZE 64 * 1024 ++ ++#define TEST_OR_FAIL(expr, failret) \ ++ if (expr) { \ ++ } else { \ ++ ERROR("Assertion violated: %s.", #expr); \ ++ return failret; \ ++ } ++ ++void ubivol_rdiff_image_handler(void); ++ ++struct rdiff_t ++{ ++ rs_job_t *job; ++ rs_buffers_t buffers; ++ ++ int dest_file_fd; ++ FILE *base_file; ++ ++ char *inbuf; ++ char *outbuf; ++ ++ uint8_t type; ++}; ++ ++static void rdiff_log(rs_loglevel level, char const *msg) ++{ ++ int loglevelmap[] = ++ { ++ [RS_LOG_EMERG] = ERRORLEVEL, ++ [RS_LOG_ALERT] = ERRORLEVEL, ++ [RS_LOG_CRIT] = ERRORLEVEL, ++ [RS_LOG_ERR] = ERRORLEVEL, ++ [RS_LOG_WARNING] = WARNLEVEL, ++ [RS_LOG_NOTICE] = INFOLEVEL, ++ [RS_LOG_INFO] = INFOLEVEL, ++ [RS_LOG_DEBUG] = TRACELEVEL ++ }; ++ *strchrnul(msg, '\n') = '\0'; ++ swupdate_notify(RUN, "%s", loglevelmap[level], msg); ++} ++ ++static rs_result base_file_read_cb(void *fp, rs_long_t pos, size_t *len, void **buf) ++{ ++ FILE *f = (FILE *)fp; ++ ++ if (fseek(f, pos, SEEK_SET) != 0) { ++ ERROR("Error seeking rdiff base file: %s", strerror(errno)); ++ return RS_IO_ERROR; ++ } ++ ++ int ret = fread(*buf, 1, *len, f); ++ if (ret == -1) { ++ ERROR("Error reading rdiff base file: %s", strerror(errno)); ++ return RS_IO_ERROR; ++ } ++ if (ret == 0) { ++ ERROR("Unexpected EOF on rdiff base file."); ++ return RS_INPUT_ENDED; ++ } ++ *len = ret; ++ ++ return RS_DONE; ++} ++ ++static rs_result fill_inbuffer(struct rdiff_t *rdiff_state, const void *buf, unsigned int *len) ++{ ++ rs_buffers_t *buffers = &rdiff_state->buffers; ++ ++ if (buffers->eof_in == true) { ++ TRACE("EOF on rdiff chunk input, not reading more data."); ++ return RS_DONE; ++ } ++ ++ if (*len == 0) { ++ TRACE("No rdiff chunk input to consume."); ++ return RS_DONE; ++ } ++ ++ if (buffers->avail_in == 0) { ++ /* No more buffered input data pending, get some... */ ++ TEST_OR_FAIL(*len <= RDIFF_BUFFER_SIZE, RS_IO_ERROR); ++ buffers->next_in = rdiff_state->inbuf; ++ buffers->avail_in = *len; ++ TRACE("Writing %d bytes to rdiff input buffer.", *len); ++ (void)memcpy(rdiff_state->inbuf, buf, *len); ++ *len = 0; ++ } else { ++ /* There's more input, try to append it to input buffer. */ ++ char *target = buffers->next_in + buffers->avail_in; ++ unsigned int buflen = rdiff_state->inbuf + RDIFF_BUFFER_SIZE - target; ++ buflen = buflen > *len ? *len : buflen; ++ TEST_OR_FAIL(target + buflen <= rdiff_state->inbuf + RDIFF_BUFFER_SIZE, RS_IO_ERROR); ++ ++ if (buflen == 0) { ++ TRACE("Not consuming rdiff chunk input, buffer already filled."); ++ return RS_BLOCKED; ++ } ++ TRACE("Appending %d bytes to rdiff input buffer.", buflen); ++ buffers->avail_in += buflen; ++ (void)memcpy(target, buf, buflen); ++ *len -= buflen; ++ } ++ return RS_DONE; ++} ++ ++static rs_result drain_outbuffer(struct rdiff_t *rdiff_state) ++{ ++ rs_buffers_t *buffers = &rdiff_state->buffers; ++ ++ int len = buffers->next_out - rdiff_state->outbuf; ++ TEST_OR_FAIL(len <= RDIFF_BUFFER_SIZE, RS_IO_ERROR); ++ TEST_OR_FAIL(buffers->next_out >= rdiff_state->outbuf, RS_IO_ERROR); ++ TEST_OR_FAIL(buffers->next_out <= rdiff_state->outbuf + RDIFF_BUFFER_SIZE, RS_IO_ERROR); ++ ++ if (len > 0) { ++ TRACE("Draining %d bytes from rdiff output buffer", len); ++ buffers->next_out = rdiff_state->outbuf; ++ buffers->avail_out = RDIFF_BUFFER_SIZE; ++ if (copy_write(&rdiff_state->dest_file_fd, buffers->next_out, len) != 0) { ++ ERROR("Cannot drain rdiff output buffer."); ++ return RS_IO_ERROR; ++ } ++ } else { ++ TRACE("No output rdiff buffer data to drain."); ++ } ++ return RS_DONE; ++} ++ ++static inline void rdiff_stats(const char* msg, struct rdiff_t *rdiff_state, rs_result result) { ++ rs_buffers_t *buffers = &rdiff_state->buffers; ++ char *strresult = (char*)"ERROR"; ++ switch (result) { ++ case RS_DONE: strresult = (char*)"DONE"; break; ++ case RS_BLOCKED: strresult = (char*)"BLOCKED"; break; ++ case RS_RUNNING: strresult = (char*)"RUNNING"; break; ++ default: break; ++ } ++ TRACE("%s avail_in=%ld avail_out=%ld result=%s", ++ msg, buffers->avail_in, buffers->avail_out, strresult); ++} ++ ++/** ++ * check_ubi_alwaysremove - check the property always-remove for this image ++ * @img: image information ++ * ++ * Return: 1 if the property always-remove is true, otherwise 0. ++ */ ++static bool check_ubi_alwaysremove(struct img_type *img) ++{ ++ return strtobool(dict_get_value(&img->properties, "always-remove")); ++} ++ ++static struct ubi_part *search_volume(const char *str, struct ubilist *list) ++{ ++ struct ubi_part *vol; ++ ++ LIST_FOREACH(vol, list, next) { ++ if (strcmp(vol->vol_info.name, str) == 0) ++ return vol; ++ } ++ return NULL; ++} ++ ++/* search a UBI volume by name across all mtd partitions */ ++static struct ubi_part *search_volume_global(const char *str) ++{ ++ struct flash_description *flash = get_flash_info(); ++ struct mtd_info *mtd_info = &flash->mtd; ++ struct mtd_ubi_info *mtd_ubi_info; ++ struct ubi_part *ubivol; ++ int i; ++ ++ for (i = mtd_info->lowest_mtd_num; i <= mtd_info->highest_mtd_num; i++) { ++ mtd_ubi_info = &flash->mtd_info[i]; ++ ubivol = search_volume(str, &mtd_ubi_info->ubi_partitions); ++ if (ubivol) ++ return ubivol; ++ } ++ return NULL; ++} ++ ++static int resize_volume(struct img_type *cfg, long long size) ++{ ++ struct flash_description *nandubi = get_flash_info(); ++ struct ubi_part *ubivol; ++ struct ubi_mkvol_request req; ++ struct mtd_ubi_info *mtd_info; ++ int mtdnum, req_vol_type; ++ char node[64]; ++ int err; ++ struct flash_description *flash = get_flash_info(); ++ ++ /* determine the requested volume type */ ++ if (!strcmp(cfg->type_data, "static")) ++ req_vol_type = UBI_STATIC_VOLUME; ++ else ++ req_vol_type = UBI_DYNAMIC_VOLUME; ++ ++ /* ++ * Partition are adjusted only in one MTD device ++ * Other MTD are not touched ++ */ ++ mtdnum = get_mtd_from_device(cfg->device); ++ if (mtdnum < 0) { ++ /* Allow device to be specified by name OR number */ ++ mtdnum = get_mtd_from_name(cfg->device); ++ } ++ if (mtdnum < 0 || !mtd_dev_present(flash->libmtd, mtdnum)) { ++ ERROR("%s does not exist: partitioning not possible", ++ cfg->device); ++ return -ENODEV; ++ } ++ ++ mtd_info = &nandubi->mtd_info[mtdnum]; ++ ++ /* ++ * Search for volume with the same name ++ */ ++ ubivol = mtd_info->ubi_partitions.lh_first; ++ for(ubivol = mtd_info->ubi_partitions.lh_first; ++ ubivol != NULL; ++ ubivol = ubivol->next.le_next) { ++ if (strcmp(ubivol->vol_info.name, cfg->volname) == 0) { ++ break; ++ } ++ } ++ ++ if (ubivol) { ++ unsigned int requested_lebs, allocated_lebs; ++ ++ /* This should never happen, the fields are filled by scan_ubi */ ++ if (!mtd_info->dev_info.leb_size) { ++ return -EFAULT; ++ } ++ ++ /* Check if size is changed */ ++ requested_lebs = size / mtd_info->dev_info.leb_size + ++ ((size % mtd_info->dev_info.leb_size) ? 1 : 0); ++ allocated_lebs = ubivol->vol_info.rsvd_bytes / mtd_info->dev_info.leb_size; ++ ++ if (requested_lebs == allocated_lebs && ++ req_vol_type == ubivol->vol_info.type && ++ !check_ubi_alwaysremove(cfg)) { ++ TRACE("skipping volume %s (same size and type)", ++ ubivol->vol_info.name); ++ return 0; ++ } ++ ++ snprintf(node, sizeof(node), "/dev/ubi%d", ubivol->vol_info.dev_num); ++ err = ubi_rmvol(nandubi->libubi, node, ubivol->vol_info.vol_id); ++ if (err) { ++ ERROR("Volume %s cannot be dropped", ubivol->vol_info.name); ++ return -1; ++ } ++ TRACE("Removed UBI Volume %s", ubivol->vol_info.name); ++ ++ LIST_REMOVE(ubivol, next); ++ free(ubivol); ++ } ++ ++ if (size) { ++ /* We do not need a volume to get the right node */ ++ snprintf(node, sizeof(node), "/dev/ubi%d", mtd_info->dev_info.dev_num); ++ ++ /* ++ * Creates all other partitions as specified in the description file ++ * Volumes are empty, and they are filled later by the update procedure ++ */ ++ memset(&req, 0, sizeof(req)); ++ req.vol_type = req_vol_type; ++ req.vol_id = UBI_VOL_NUM_AUTO; ++ req.alignment = 1; ++ req.bytes = size; ++ req.name = cfg->volname; ++ err = ubi_mkvol(nandubi->libubi, node, &req); ++ if (err < 0) { ++ ERROR("cannot create %s UBI volume %s of %lld bytes", ++ (req_vol_type == UBI_DYNAMIC_VOLUME) ? "dynamic" : "static", ++ req.name, req.bytes); ++ return err; ++ } ++ ++ ubivol = (struct ubi_part *)calloc(1, sizeof(struct ubi_part)); ++ if (!ubivol) { ++ ERROR("No memory: malloc failed"); ++ return -ENOMEM; ++ } ++ err = ubi_get_vol_info1(nandubi->libubi, ++ mtd_info->dev_info.dev_num, req.vol_id, ++ &ubivol->vol_info); ++ if (err) { ++ ERROR("cannot get information about " ++ "newly created UBI volume"); ++ return err; ++ } ++ LIST_INSERT_HEAD(&mtd_info->ubi_partitions, ubivol, next); ++ TRACE("Created %s UBI volume %s of %lld bytes (old size %lld)", ++ (req_vol_type == UBI_DYNAMIC_VOLUME) ? "dynamic" : "static", ++ req.name, req.bytes, ubivol->vol_info.rsvd_bytes); ++ } ++ ++ return 0; ++} ++ ++/** ++ * check_auto_resize - check the property auto-resize for this image ++ * @img: image information ++ * ++ * Return: 1 if the property auto-resize is true, otherwise 0. ++ */ ++static bool check_ubi_autoresize(struct img_type *img) ++{ ++ return strtobool(dict_get_value(&img->properties, "auto-resize")); ++} ++ ++static int wait_volume(struct img_type *img) ++{ ++ int ret = -1, num = 0, dev_num, vol_id; ++ struct ubi_part *ubivol; ++ struct stat buf; ++ char node[64]; ++ ++ ubivol = search_volume_global(img->volname); ++ if (!ubivol) { ++ ERROR("can't found volume %s", img->volname); ++ return -1; ++ } ++ ++ dev_num = ubivol->vol_info.dev_num; ++ vol_id = ubivol->vol_info.vol_id; ++ ++ snprintf(node, sizeof(node), "/dev/ubi%d_%d", ++ dev_num, ++ vol_id); ++ ++ while (num++ < 5) ++ { ++ ret = stat(node, &buf); ++ if (!ret) ++ break; ++ ++ sleep(1); ++ } ++ ++ return ret; ++} ++ ++static int apply_rdiff_chunk_cb(void *out, const void *buf, unsigned int len) ++{ ++ struct rdiff_t *rdiff_state = (struct rdiff_t *)out; ++ rs_buffers_t *buffers = &rdiff_state->buffers; ++ unsigned int inbytesleft = len; ++ rs_result result = RS_RUNNING; ++ rs_result drain_run_result = RS_RUNNING; ++ ++ if (buffers->next_out == NULL) { ++ TEST_OR_FAIL(buffers->avail_out == 0, -1); ++ buffers->next_out = rdiff_state->outbuf; ++ buffers->avail_out = RDIFF_BUFFER_SIZE; ++ } ++ ++ while (inbytesleft > 0 || buffers->avail_in > 0) { ++ rdiff_stats("[pre] ", rdiff_state, result); ++ result = fill_inbuffer(rdiff_state, buf, &inbytesleft); ++ if (result != RS_DONE && result != RS_BLOCKED) { ++ return -1; ++ } ++ result = rs_job_iter(rdiff_state->job, buffers); ++ if (result != RS_DONE && result != RS_BLOCKED) { ++ ERROR("Error processing rdiff chunk: %s", rs_strerror(result)); ++ return -1; ++ } ++ drain_run_result = drain_outbuffer(rdiff_state); ++ if (drain_run_result != RS_DONE) { ++ ERROR("drain_outbuffer return error"); ++ return -1; ++ } ++ rdiff_stats("[post]", rdiff_state, result); ++ ++ if (result == RS_DONE) { ++ TRACE("rdiff processing done."); ++ break; ++ } ++ } ++ rdiff_stats("[ret] ", rdiff_state, result); ++ return 0; ++} ++ ++static int apply_rdiff_patch(struct img_type *img, ++ void __attribute__((__unused__)) * data) ++{ ++ int ret = 0; ++ long long bytes; ++ char node[64]; ++ int err; ++ char sbuf[128]; ++ ++ struct rdiff_t rdiff_state = {}; ++ rdiff_state.type = IMAGE_HANDLER; ++ ++ struct flash_description *flash = get_flash_info(); ++ libubi_t libubi = flash->libubi; ++ ++ char *base_file_filename = NULL; ++ char *output_size_str = NULL; ++ struct ubi_part *ubivol; ++ struct ubi_vol_info *vol; ++ ++ if (img->seek) { ++ /* ++ * img->seek mandates copyfile()'s out parameter to be a fd, it ++ * isn't. So, the seek option is invalid for the rdiff handler. ++ * */ ++ ERROR("Option 'seek' is not supported for rdiff."); ++ return -1; ++ } ++ ++ base_file_filename = dict_get_value(&img->properties, "rdiffbase"); ++ if (base_file_filename == NULL) { ++ ERROR("Property 'rdiffbase' is missing in sw-description."); ++ return -1; ++ } ++ ++ output_size_str = dict_get_value(&img->properties, "rdiffnewsize"); ++ if (!output_size_str) { ++ ERROR("Property 'rdiffnewsize' is missing in sw-description."); ++ return -1; ++ } ++ ++ bytes = ustrtoull(output_size_str, NULL, 0); ++ if (errno || bytes <= 0) { ++ ERROR("rdiffnewsize argument %s: ustrtoull failed", ++ output_size_str); ++ return -1; ++ } ++ TRACE("The size after applying patch would be %lld bytes", bytes); ++ ++ if (check_ubi_autoresize(img)) { ++ ret = resize_volume(img, bytes); ++ if (ret < 0) { ++ ERROR("Can't resize ubi volume %s", img->volname); ++ return -1; ++ } ++ ++ ret = wait_volume(img); ++ if (ret < 0) { ++ ERROR("can't found ubi volume %s", img->volname); ++ return -1; ++ } ++ } ++ ++ if (!libubi) { ++ ERROR("Request to write into UBI, but no UBI on system"); ++ return -1; ++ } ++ ++ /* find the volume to be updated */ ++ ubivol = search_volume_global(img->volname); ++ ++ if (!ubivol) { ++ ERROR("Image %s should be stored in volume " ++ "%s, but no volume found", ++ img->fname, ++ img->volname); ++ return -1; ++ } ++ ++ vol = &ubivol->vol_info; ++ ++ if (bytes > vol->rsvd_bytes) { ++ ERROR("\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)", ++ img->fname, bytes, img->volname, vol->rsvd_bytes); ++ return -1; ++ } ++ ++ snprintf(node, sizeof(node), "/dev/ubi%d_%d", ++ vol->dev_num, ++ vol->vol_id); ++ ++ err = ubi_probe_node(libubi, node); ++ ++ if (err == 1) { ++ ERROR("\"%s\" is an UBI device node, not an UBI volume node", ++ node); ++ return -1; ++ } ++ if (err < 0) { ++ if (errno == ENODEV) ++ ERROR("%s is not an UBI volume node", node); ++ else ++ ERROR("error while probing %s", node); ++ return -1; ++ } ++ ++ rdiff_state.dest_file_fd = open(node, O_RDWR); ++ if (rdiff_state.dest_file_fd < 0) { ++ ERROR("cannot open UBI volume \"%s\"", node); ++ return -1; ++ } ++ ++ if ((rdiff_state.base_file = fopen(base_file_filename, "rb+")) == NULL) { ++ ERROR("%s cannot be opened for reading: %s", base_file_filename, strerror(errno)); ++ ret = -1; ++ goto cleanup; ++ } ++ ++ if (!(rdiff_state.inbuf = malloc(RDIFF_BUFFER_SIZE))) { ++ ERROR("Cannot allocate memory for rdiff input buffer."); ++ ret = -1; ++ goto cleanup; ++ } ++ ++ if (!(rdiff_state.outbuf = malloc(RDIFF_BUFFER_SIZE))) { ++ ERROR("Cannot allocate memory for rdiff output buffer."); ++ ret = -1; ++ goto cleanup; ++ } ++ ++ err = ubi_update_start(libubi, rdiff_state.dest_file_fd, bytes); ++ if (err) { ++ ERROR("cannot start volume \"%s\" update", node); ++ ret = -1; ++ goto cleanup; ++ } ++ ++ snprintf(sbuf, sizeof(sbuf), "Installing image %s into volume %s(%s)", ++ img->fname, node, img->volname); ++ notify(RUN, RECOVERY_NO_ERROR, INFOLEVEL, sbuf); ++ ++ int loglevelmap[] = ++ { ++ [OFF] = RS_LOG_ERR, ++ [ERRORLEVEL] = RS_LOG_ERR, ++ [WARNLEVEL] = RS_LOG_WARNING, ++ [INFOLEVEL] = RS_LOG_INFO, ++ [DEBUGLEVEL] = RS_LOG_DEBUG, ++ [TRACELEVEL] = RS_LOG_DEBUG, ++ }; ++ rs_trace_set_level(loglevelmap[loglevel]); ++ rs_trace_to(rdiff_log); ++ ++ rdiff_state.job = rs_patch_begin(base_file_read_cb, rdiff_state.base_file); ++ ret = copyfile(img->fdin, ++ &rdiff_state, ++ img->size, ++ (unsigned long *)&img->offset, ++ img->seek, ++ 0, /* no skip */ ++ img->compressed, ++ &img->checksum, ++ img->sha256, ++ img->is_encrypted, ++ img->ivt_ascii, ++ apply_rdiff_chunk_cb); ++ if (ret != 0) { ++ ERROR("Error %d running rdiff job, aborting.", ret); ++ goto cleanup; ++ } ++ ++cleanup: ++ free(rdiff_state.inbuf); ++ free(rdiff_state.outbuf); ++ if (rdiff_state.job != NULL) { ++ (void)rs_job_free(rdiff_state.job); ++ } ++ if (rdiff_state.base_file != NULL) { ++ if (fclose(rdiff_state.base_file) == EOF) { ++ ERROR("Error while closing rdiff base: %s", strerror(errno)); ++ } ++ } ++ close(rdiff_state.dest_file_fd); ++ return ret; ++} ++ ++__attribute__((constructor)) ++void ubivol_rdiff_image_handler(void) ++{ ++ register_handler("ubivol_rdiff_image", apply_rdiff_patch, IMAGE_HANDLER, NULL); ++} diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/mtd.cfg b/meta-digi-dey/recipes-support/swupdate/swupdate/mtd.cfg index 9808999d4..787b48bfc 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/mtd.cfg +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/mtd.cfg @@ -6,3 +6,5 @@ CONFIG_UBIATTACH=y CONFIG_UBIBLACKLIST="" CONFIG_UBIWHITELIST="" CONFIG_UBIVIDOFFSET=0 +# Add UBIVOL_RDIFFHANDLER support +CONFIG_UBIVOL_RDIFFHANDLER=y diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend b/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend index 77f54716a..de0feed77 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend +++ b/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend @@ -8,6 +8,7 @@ RDEPENDS:${PN} += "libgcc" SRC_URI += " \ file://0001-Makefile-change-Makefile-to-build-swupdate-library-s.patch \ file://0002-config-add-on-the-fly-build-configuration-variable.patch \ + file://0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch \ ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'file://systemd.cfg', '', d)} \ ${@bb.utils.contains('STORAGE_MEDIA', 'mtd', 'file://mtd.cfg', '', d)} \ ${@oe.utils.conditional('TRUSTFENCE_SIGN', '1', 'file://signed_images.cfg', '', d)} \