From a195efca406d816a06d08a1a74cb7d5307e1951c Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 20 Jan 2022 18:10:55 +0000 Subject: [PATCH] Issue #1859 - Part 3: Replace bzip2 handling in MAR files with xz. Since there really is no need to add file detection logic to the updater if updating through AUS is old->new only anyway, replacing bzip2 handling with xz handling is fine, instead of adding it. Considering the far superior compression of LZMA and MAR not being a common archive format anyway, let's just K.I.S.S. it :) --- modules/libmar/src/mar.h | 2 +- modules/libmar/src/mar_extract.c | 2 +- modules/libmar/src/mar_read.c | 2 +- toolkit/mozapps/update/common/errors.h | 2 +- .../mozapps/update/updater/archivereader.cpp | 92 ++++++++++++------- .../update/updater/updater-common.build | 1 + 6 files changed, 64 insertions(+), 37 deletions(-) diff --git a/modules/libmar/src/mar.h b/modules/libmar/src/mar.h index 776daf648d..e9c8d555e4 100644 --- a/modules/libmar/src/mar.h +++ b/modules/libmar/src/mar.h @@ -109,7 +109,7 @@ int mar_enum_items(MarFile *mar, MarItemCallback callback, void *data); * @return The number of bytes written or a negative value if an * error occurs. */ -int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, +int mar_read(MarFile *mar, const MarItem *item, int offset, uint8_t *buf, int bufsize); /** diff --git a/modules/libmar/src/mar_extract.c b/modules/libmar/src/mar_extract.c index ec1cd6c534..969697ee29 100644 --- a/modules/libmar/src/mar_extract.c +++ b/modules/libmar/src/mar_extract.c @@ -37,7 +37,7 @@ static int mar_ensure_parent_dir(const char *path) static int mar_test_callback(MarFile *mar, const MarItem *item, void *unused) { FILE *fp; - char buf[BLOCKSIZE]; + uint8_t buf[BLOCKSIZE]; int fd, len, offset = 0; if (mar_ensure_parent_dir(item->name)) diff --git a/modules/libmar/src/mar_read.c b/modules/libmar/src/mar_read.c index 241d0c08e4..89b9da27d6 100644 --- a/modules/libmar/src/mar_read.c +++ b/modules/libmar/src/mar_read.c @@ -530,7 +530,7 @@ int mar_enum_items(MarFile *mar, MarItemCallback callback, void *closure) { return 0; } -int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, +int mar_read(MarFile *mar, const MarItem *item, int offset, uint8_t *buf, int bufsize) { int nr; diff --git a/toolkit/mozapps/update/common/errors.h b/toolkit/mozapps/update/common/errors.h index 846118d55d..de1782b8e5 100644 --- a/toolkit/mozapps/update/common/errors.h +++ b/toolkit/mozapps/update/common/errors.h @@ -46,7 +46,7 @@ #define WRITE_ERROR_ACCESS_DENIED 35 // #define WRITE_ERROR_SHARING_VIOLATION 36 // Replaced with errors 46-48 #define WRITE_ERROR_CALLBACK_APP 37 -#define UNEXPECTED_BZIP_ERROR 39 +#define UNEXPECTED_XZ_ERROR 39 #define UNEXPECTED_MAR_ERROR 40 #define UNEXPECTED_BSPATCH_ERROR 41 #define UNEXPECTED_FILE_OPERATION_ERROR 42 diff --git a/toolkit/mozapps/update/updater/archivereader.cpp b/toolkit/mozapps/update/updater/archivereader.cpp index 90cf45c3db..72debbe82e 100644 --- a/toolkit/mozapps/update/updater/archivereader.cpp +++ b/toolkit/mozapps/update/updater/archivereader.cpp @@ -1,5 +1,4 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -15,6 +14,9 @@ #include "updatehelper.h" #endif +#define XZ_USE_CRC64 +#include "xz.h" + // These are generated at compile time based on the DER file for the channel // being used #ifdef MOZ_VERIFY_MAR_SIGNATURE @@ -36,10 +38,10 @@ # include #endif -static int inbuf_size = 262144; -static int outbuf_size = 262144; -static char *inbuf = nullptr; -static char *outbuf = nullptr; +static size_t inbuf_size = 262144; +static size_t outbuf_size = 262144; +static uint8_t *inbuf = nullptr; +static uint8_t *outbuf = nullptr; /** * Performs a verification on the opened MAR file with the passed in @@ -182,22 +184,22 @@ ArchiveReader::Open(const NS_tchar *path) Close(); if (!inbuf) { - inbuf = (char *)malloc(inbuf_size); + inbuf = (uint8_t *)malloc(inbuf_size); if (!inbuf) { // Try again with a smaller buffer. inbuf_size = 1024; - inbuf = (char *)malloc(inbuf_size); + inbuf = (uint8_t *)malloc(inbuf_size); if (!inbuf) return ARCHIVE_READER_MEM_ERROR; } } if (!outbuf) { - outbuf = (char *)malloc(outbuf_size); + outbuf = (uint8_t *)malloc(outbuf_size); if (!outbuf) { // Try again with a smaller buffer. outbuf_size = 1024; - outbuf = (char *)malloc(outbuf_size); + outbuf = (uint8_t *)malloc(outbuf_size); if (!outbuf) return ARCHIVE_READER_MEM_ERROR; } @@ -211,6 +213,9 @@ ArchiveReader::Open(const NS_tchar *path) if (!mArchive) return READ_ERROR; + xz_crc32_init(); + xz_crc64_init(); + return OK; } @@ -273,12 +278,21 @@ ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp) { /* decompress the data chunk by chunk */ - bz_stream strm; - int offset, inlen, outlen, ret = OK; + int offset, inlen, ret = OK; + struct xz_buf strm = { 0 }; + enum xz_ret xz_rv = XZ_OK; - memset(&strm, 0, sizeof(strm)); - if (BZ2_bzDecompressInit(&strm, 0, 0) != BZ_OK) - return UNEXPECTED_BZIP_ERROR; + struct xz_dec * dec = xz_dec_init(XZ_DYNALLOC, 64 * 1024 * 1024); + if (!dec) { + return UNEXPECTED_XZ_ERROR; + } + + strm.in = inbuf; + strm.in_pos = 0; + strm.in_size = 0; + strm.out = outbuf; + strm.out_pos = 0; + strm.out_size = outbuf_size; offset = 0; for (;;) { @@ -287,38 +301,50 @@ ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp) break; } - if (offset < (int) item->length && strm.avail_in == 0) { + if (offset < (int) item->length && strm.in_pos == strm.in_size) { inlen = mar_read(mArchive, item, offset, inbuf, inbuf_size); - if (inlen <= 0) - return READ_ERROR; + if (inlen <= 0) { + ret = READ_ERROR; + break; + } offset += inlen; - strm.next_in = inbuf; - strm.avail_in = inlen; + strm.in_size = inlen; + strm.in_pos = 0; } - strm.next_out = outbuf; - strm.avail_out = outbuf_size; + xz_rv = xz_dec_run(dec, &strm); - ret = BZ2_bzDecompress(&strm); - if (ret != BZ_OK && ret != BZ_STREAM_END) { - ret = UNEXPECTED_BZIP_ERROR; - break; - } - - outlen = outbuf_size - strm.avail_out; - if (outlen) { - if (fwrite(outbuf, outlen, 1, fp) != 1) { + if (strm.out_pos == outbuf_size) { + if (fwrite(outbuf, 1, strm.out_pos, fp) != strm.out_pos) { ret = WRITE_ERROR_EXTRACT; break; } + + strm.out_pos = 0; } - if (ret == BZ_STREAM_END) { - ret = OK; + if (xz_rv == XZ_OK) { + // There is still more data to decompress. + continue; + } + + // The return value of xz_dec_run is not XZ_OK and if it isn't XZ_STREAM_END + // an error has occured. + if (xz_rv != XZ_STREAM_END) { + ret = UNEXPECTED_XZ_ERROR; break; } + + // Write out the remainder of the decompressed data. In the case of + // strm.out_pos == 0 this is needed to create empty files included in the + // mar file. + if (fwrite(outbuf, 1, strm.out_pos, fp) != strm.out_pos) { + ret = WRITE_ERROR_EXTRACT; + } + + break; } - BZ2_bzDecompressEnd(&strm); + xz_dec_end(dec); return ret; } diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build index a46c1388cc..1ace8fcc71 100644 --- a/toolkit/mozapps/update/updater/updater-common.build +++ b/toolkit/mozapps/update/updater/updater-common.build @@ -57,6 +57,7 @@ else: USE_LIBS += [ 'mar', + 'xz-embedded', ] if CONFIG['MOZ_SYSTEM_BZ2']: