From fcdbfe893873b610997b39943e4c0f9ae489c14f Mon Sep 17 00:00:00 2001 From: Matthew Almond Date: Sep 27 2021 23:47:51 +0000 Subject: Merge branch 'c8s' into c8s-sig-hyperscale-experimental --- diff --git a/SOURCES/0001-Fix-cr_compress_file_with_stat-Memory-leak.patch b/SOURCES/0001-Fix-cr_compress_file_with_stat-Memory-leak.patch new file mode 100644 index 0000000..126a489 --- /dev/null +++ b/SOURCES/0001-Fix-cr_compress_file_with_stat-Memory-leak.patch @@ -0,0 +1,25 @@ +From 1ec1e767e4a48bc2c1d09b52da9e749352f8d925 Mon Sep 17 00:00:00 2001 +From: Jaroslav Rohel +Date: Thu, 6 May 2021 19:09:19 +0200 +Subject: [PATCH] Fix: cr_compress_file_with_stat: Memory leak + +--- + src/misc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/misc.c b/src/misc.c +index e5350ac..59c04e6 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -503,6 +503,8 @@ cr_compress_file_with_stat(const char *src, + if (!orig) { + ret = tmp_err->code; + g_propagate_prefixed_error(err, tmp_err, "Cannot open %s: ", src); ++ if (dst != in_dst) ++ g_free(dst); + return ret; + } + +-- +libgit2 1.0.1 + diff --git a/SOURCES/0002-Preserve-changed-API-for-cr_compress_file_with_stat-RhBug1973588.patch b/SOURCES/0002-Preserve-changed-API-for-cr_compress_file_with_stat-RhBug1973588.patch new file mode 100644 index 0000000..d14a0ae --- /dev/null +++ b/SOURCES/0002-Preserve-changed-API-for-cr_compress_file_with_stat-RhBug1973588.patch @@ -0,0 +1,380 @@ +From a611bb0c3729713af28031cdf1d056823d663db1 Mon Sep 17 00:00:00 2001 +From: Aleš Matěj +Date: Thu, 9 Sep 2021 08:31:03 +0200 +Subject: [PATCH] Preserve changed API for cr_compress_file_with_stat (RhBug:1973588) + +In order to be compatible in rhel8 we want to preserve the old API and +behavior. + +Keep the fixed version as cr_compress_file_with_stat_v2 only for rhel8 + +https://bugzilla.redhat.com/show_bug.cgi?id=1973588 +--- + src/misc.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + src/misc.h | 42 ++++++++++++++++++++++++++++++++++++++++-- + src/modifyrepo_shared.c | 4 ++-- + src/python/misc-py.c | 2 +- + src/threads.c | 14 +++++++------- + tests/test_misc.c | 34 +++++++++++++++++----------------- + 6 files changed, 204 insertions(+), 30 deletions(-) + +diff --git a/src/misc.c b/src/misc.c +index 59c04e6..b3a218c 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -446,7 +446,7 @@ cr_copy_file(const char *src, const char *in_dst, GError **err) + + int + cr_compress_file_with_stat(const char *src, +- const char *in_dst, ++ char **in_dst, + cr_CompressionType compression, + cr_ContentStat *stat, + const char *zck_dict_dir, +@@ -458,6 +458,142 @@ cr_compress_file_with_stat(const char *src, + char buf[BUFFER_SIZE]; + CR_FILE *orig = NULL; + CR_FILE *new = NULL; ++ gchar *dst = (gchar *) *in_dst; ++ GError *tmp_err = NULL; ++ ++ assert(src); ++ assert(!err || *err == NULL); ++ ++ const char *c_suffix = cr_compression_suffix(compression); ++ ++ // Src must be a file NOT a directory ++ if (!g_file_test(src, G_FILE_TEST_IS_REGULAR)) { ++ g_debug("%s: Source (%s) must be a regular file!", __func__, src); ++ g_set_error(err, ERR_DOMAIN, CRE_NOFILE, ++ "Not a regular file: %s", src); ++ return CRE_NOFILE; ++ } ++ ++ if (!dst) { ++ // If destination is NULL, use src + compression suffix ++ *in_dst = g_strconcat(src, ++ c_suffix, ++ NULL); ++ } else if (g_str_has_suffix(dst, "/")) { ++ // If destination is dir use filename from src + compression suffix ++ *in_dst = g_strconcat(dst, ++ cr_get_filename(src), ++ c_suffix, ++ NULL); ++ } else if (c_suffix && !g_str_has_suffix(dst, c_suffix)) { ++ cr_CompressionType old_type = cr_detect_compression(src, &tmp_err); ++ if (tmp_err) { ++ g_debug("%s: Unable to detect compression type of %s", __func__, src); ++ g_clear_error(&tmp_err); ++ } else if (old_type != CR_CW_NO_COMPRESSION) { ++ _cleanup_free_ gchar *tmp_file = g_strndup(dst, strlen(dst) - strlen(cr_compression_suffix(old_type))); ++ *in_dst = g_strconcat(tmp_file, ++ c_suffix, ++ NULL); ++ } ++ } ++ if (dst != *in_dst && dst) ++ g_free(dst); ++ dst = (gchar *) *in_dst; ++ ++ int mode = CR_CW_AUTO_DETECT_COMPRESSION; ++ ++ orig = cr_open(src, ++ CR_CW_MODE_READ, ++ mode, ++ &tmp_err); ++ if (!orig) { ++ ret = tmp_err->code; ++ g_propagate_prefixed_error(err, tmp_err, "Cannot open %s: ", src); ++ return ret; ++ } ++ ++ _cleanup_free_ gchar *dict = NULL; ++ size_t dict_size = 0; ++ if (compression == CR_CW_ZCK_COMPRESSION && zck_dict_dir) { ++ /* Find zdict */ ++ _cleanup_free_ gchar *file_basename = NULL; ++ if (dst) { ++ _cleanup_free_ gchar *dict_base = NULL; ++ if (g_str_has_suffix(dst, ".zck")) ++ dict_base = g_strndup(dst, strlen(dst)-4); ++ else ++ dict_base = g_strdup(dst); ++ file_basename = g_path_get_basename(dict_base); ++ } else { ++ file_basename = g_path_get_basename(src); ++ } ++ _cleanup_free_ gchar *dict_file = cr_get_dict_file(zck_dict_dir, file_basename); ++ ++ /* Read dictionary from file */ ++ if (dict_file && !g_file_get_contents(dict_file, &dict, ++ &dict_size, &tmp_err)) { ++ g_set_error(err, ERR_DOMAIN, CRE_IO, ++ "Error reading zchunk dict %s: %s", ++ dict_file, tmp_err->message); ++ ret = CRE_IO; ++ goto compress_file_cleanup; ++ } ++ } ++ ++ new = cr_sopen(dst, CR_CW_MODE_WRITE, compression, stat, &tmp_err); ++ if (tmp_err) { ++ g_debug("%s: Cannot open destination file %s", __func__, dst); ++ g_propagate_prefixed_error(err, tmp_err, "Cannot open %s: ", dst); ++ ret = CRE_IO; ++ goto compress_file_cleanup; ++ } ++ if (compression == CR_CW_ZCK_COMPRESSION) { ++ if (dict && cr_set_dict(new, dict, dict_size, &tmp_err) != CRE_OK) { ++ ret = tmp_err->code; ++ g_propagate_prefixed_error(err, tmp_err, "Unable to set zdict for %s: ", dst); ++ goto compress_file_cleanup; ++ } ++ if (zck_auto_chunk && cr_set_autochunk(new, TRUE, &tmp_err) != CRE_OK) { ++ ret = tmp_err->code; ++ g_propagate_prefixed_error(err, tmp_err, "Unable to set auto-chunking for %s: ", dst); ++ goto compress_file_cleanup; ++ } ++ } ++ while ((readed = cr_read(orig, buf, BUFFER_SIZE, &tmp_err)) > 0) { ++ cr_write(new, buf, readed, &tmp_err); ++ if (tmp_err) { ++ ret = tmp_err->code; ++ g_propagate_prefixed_error(err, tmp_err, "Unable to write to %s: ", dst); ++ goto compress_file_cleanup; ++ } ++ } ++ ++compress_file_cleanup: ++ ++ if (orig) ++ cr_close(orig, NULL); ++ ++ if (new) ++ cr_close(new, NULL); ++ ++ return ret; ++} ++ ++int ++cr_compress_file_with_stat_v2(const char *src, ++ const char *in_dst, ++ cr_CompressionType compression, ++ cr_ContentStat *stat, ++ const char *zck_dict_dir, ++ gboolean zck_auto_chunk, ++ GError **err) ++{ ++ int ret = CRE_OK; ++ int readed; ++ char buf[BUFFER_SIZE]; ++ CR_FILE *orig = NULL; ++ CR_FILE *new = NULL; + gchar *dst = (gchar *) in_dst; + GError *tmp_err = NULL; + +diff --git a/src/misc.h b/src/misc.h +index 60f1a0f..528ccc3 100644 +--- a/src/misc.h ++++ b/src/misc.h +@@ -184,9 +184,24 @@ gboolean cr_copy_file(const char *src, + cr_compress_file_with_stat(SRC, DST, COMTYPE, NULL, ZCK_DICT_DIR, \ + ZCK_AUTO_CHUNK, ERR) + ++/** Compress file. This function is temporary and present ++ * only in rhel 8, it will be removed in future versions. ++ * @param SRC source filename ++ * @param DST destination (If dst is dir, filename of src + ++ * compression suffix is used. ++ * If dst is NULL, src + compression suffix is used) ++ * @param COMTYPE type of compression ++ * @param ZCK_DICT_DIR Location of zchunk zdicts (if zchunk is enabled) ++ * @param ZCK_AUTO_CHUNK Whether zchunk file should be auto-chunked ++ * @param ERR GError ** ++ * @return cr_Error return code ++ */ ++#define cr_compress_file_v2(SRC, DST, COMTYPE, ZCK_DICT_DIR, ZCK_AUTO_CHUNK, ERR) \ ++ cr_compress_file_with_stat_v2(SRC, DST, COMTYPE, NULL, ZCK_DICT_DIR, \ ++ ZCK_AUTO_CHUNK, ERR) + /** Compress file. + * @param src source filename +- * @param dst destination (If dst is dir, filename of src + ++ * @param dst pointer to destination (If dst is dir, filename of src + + * compression suffix is used. + * If dst is NULL, src + compression suffix is used) + * @param comtype type of compression +@@ -197,13 +212,36 @@ gboolean cr_copy_file(const char *src, + * @return cr_Error return code + */ + int cr_compress_file_with_stat(const char *src, +- const char *dst, ++ char **dst, + cr_CompressionType comtype, + cr_ContentStat *stat, + const char *zck_dict_dir, + gboolean zck_auto_chunk, + GError **err); + ++/** Compress file with stat versions 2. This function is temporary and present ++ * only in rhel 8, it will be removed in future versions. ++ * It is a compatibility function that preserves the API and behavior of ++ * cr_compress_file_with_stat from createrepo_c-0.12.0. ++ * @param src source filename ++ * @param dst destination (If dst is dir, filename of src + ++ * compression suffix is used. ++ * If dst is NULL, src + compression suffix is used) ++ * @param comtype type of compression ++ * @param stat pointer to cr_ContentStat or NULL ++ * @param zck_dict_dir Location of zchunk zdicts (if zchunk is enabled) ++ * @param zck_auto_chunk Whether zchunk file should be auto-chunked ++ * @param err GError ** ++ * @return cr_Error return code ++ */ ++int cr_compress_file_with_stat_v2(const char *src, ++ const char *dst, ++ cr_CompressionType comtype, ++ cr_ContentStat *stat, ++ const char *zck_dict_dir, ++ gboolean zck_auto_chunk, ++ GError **err); ++ + /** Decompress file. + * @param SRC source filename + * @param DST destination (If dst is dir, filename of src without +diff --git a/src/modifyrepo_shared.c b/src/modifyrepo_shared.c +index 4e59660..8cf246d 100644 +--- a/src/modifyrepo_shared.c ++++ b/src/modifyrepo_shared.c +@@ -120,8 +120,8 @@ cr_write_file(gchar *repopath, cr_ModifyRepoTask *task, + g_debug("%s: Copy & compress operation %s -> %s", + __func__, src_fn, dst_fn); + +- if (cr_compress_file(src_fn, dst_fn, compress_type, +- task->zck_dict_dir, TRUE, err) != CRE_OK) { ++ if (cr_compress_file_v2(src_fn, dst_fn, compress_type, ++ task->zck_dict_dir, TRUE, err) != CRE_OK) { + g_debug("%s: Copy & compress operation failed", __func__); + return NULL; + } +diff --git a/src/python/misc-py.c b/src/python/misc-py.c +index 6a7871e..cc28448 100644 +--- a/src/python/misc-py.c ++++ b/src/python/misc-py.c +@@ -49,7 +49,7 @@ py_compress_file_with_stat(G_GNUC_UNUSED PyObject *self, PyObject *args) + return NULL; + } + +- cr_compress_file_with_stat(src, dst, type, contentstat, NULL, FALSE, &tmp_err); ++ cr_compress_file_with_stat_v2(src, dst, type, contentstat, NULL, FALSE, &tmp_err); + if (tmp_err) { + nice_exception(&tmp_err, NULL); + return NULL; +diff --git a/src/threads.c b/src/threads.c +index 9ef839d..91b5430 100644 +--- a/src/threads.c ++++ b/src/threads.c +@@ -100,13 +100,13 @@ cr_compressing_thread(gpointer data, G_GNUC_UNUSED gpointer user_data) + cr_compression_suffix(task->type), + NULL); + +- cr_compress_file_with_stat(task->src, +- task->dst, +- task->type, +- task->stat, +- task->zck_dict_dir, +- task->zck_auto_chunk, +- &tmp_err); ++ cr_compress_file_with_stat_v2(task->src, ++ task->dst, ++ task->type, ++ task->stat, ++ task->zck_dict_dir, ++ task->zck_auto_chunk, ++ &tmp_err); + + if (tmp_err) { + // Error encountered +diff --git a/tests/test_misc.c b/tests/test_misc.c +index 6614809..1acccb7 100644 +--- a/tests/test_misc.c ++++ b/tests/test_misc.c +@@ -548,8 +548,8 @@ compressfile_test_text_file(Copyfiletest *copyfiletest, + GError *tmp_err = NULL; + + g_assert(!g_file_test(copyfiletest->dst_file, G_FILE_TEST_EXISTS)); +- ret = cr_compress_file(TEST_TEXT_FILE, copyfiletest->dst_file, +- CR_CW_GZ_COMPRESSION, NULL, FALSE, &tmp_err); ++ ret = cr_compress_file_v2(TEST_TEXT_FILE, copyfiletest->dst_file, ++ CR_CW_GZ_COMPRESSION, NULL, FALSE, &tmp_err); + g_assert(!tmp_err); + g_assert_cmpint(ret, ==, CRE_OK); + g_assert(g_file_test(copyfiletest->dst_file, G_FILE_TEST_IS_REGULAR)); +@@ -574,9 +574,9 @@ compressfile_with_stat_test_text_file(Copyfiletest *copyfiletest, + g_assert(!tmp_err); + + g_assert(!g_file_test(copyfiletest->dst_file, G_FILE_TEST_EXISTS)); +- ret = cr_compress_file_with_stat(TEST_TEXT_FILE, copyfiletest->dst_file, +- CR_CW_GZ_COMPRESSION, stat, NULL, FALSE, +- &tmp_err); ++ ret = cr_compress_file_with_stat_v2(TEST_TEXT_FILE, copyfiletest->dst_file, ++ CR_CW_GZ_COMPRESSION, stat, NULL, FALSE, ++ &tmp_err); + g_assert(!tmp_err); + g_assert_cmpint(ret, ==, CRE_OK); + g_assert(g_file_test(copyfiletest->dst_file, G_FILE_TEST_IS_REGULAR)); +@@ -603,9 +603,9 @@ compressfile_with_stat_test_gz_file_gz_output(Copyfiletest *copyfiletest, + char * dst_full_name = g_strconcat(copyfiletest->dst_file, ".gz", NULL); + + g_assert(!g_file_test(dst_full_name, G_FILE_TEST_EXISTS)); +- ret = cr_compress_file_with_stat(TEST_TEXT_FILE_GZ, dst_full_name, +- CR_CW_GZ_COMPRESSION, stat, NULL, FALSE, +- &tmp_err); ++ ret = cr_compress_file_with_stat_v2(TEST_TEXT_FILE_GZ, dst_full_name, ++ CR_CW_GZ_COMPRESSION, stat, NULL, FALSE, ++ &tmp_err); + g_assert(!tmp_err); + g_assert_cmpint(ret, ==, CRE_OK); + g_assert(g_file_test(dst_full_name, G_FILE_TEST_IS_REGULAR)); +@@ -633,9 +633,9 @@ compressfile_test_gz_file_xz_output(Copyfiletest *copyfiletest, + char * dst_full_name = g_strconcat(copyfiletest->dst_file, ".xz", NULL); + + g_assert(!g_file_test(dst_full_name, G_FILE_TEST_EXISTS)); +- ret = cr_compress_file(TEST_TEXT_FILE_GZ, dst_full_name, +- CR_CW_XZ_COMPRESSION, NULL, FALSE, +- &tmp_err); ++ ret = cr_compress_file_v2(TEST_TEXT_FILE_GZ, dst_full_name, ++ CR_CW_XZ_COMPRESSION, NULL, FALSE, ++ &tmp_err); + g_assert(!tmp_err); + g_assert_cmpint(ret, ==, CRE_OK); + g_assert(g_file_test(dst_full_name, G_FILE_TEST_IS_REGULAR)); +@@ -660,9 +660,9 @@ compressfile_test_xz_file_gz_output(Copyfiletest *copyfiletest, + char * dst_full_name = g_strconcat(copyfiletest->dst_file, ".gz", NULL); + + g_assert(!g_file_test(dst_full_name, G_FILE_TEST_EXISTS)); +- ret = cr_compress_file(TEST_TEXT_FILE_XZ, dst_full_name, +- CR_CW_GZ_COMPRESSION, NULL, FALSE, +- &tmp_err); ++ ret = cr_compress_file_v2(TEST_TEXT_FILE_XZ, dst_full_name, ++ CR_CW_GZ_COMPRESSION, NULL, FALSE, ++ &tmp_err); + g_assert(!tmp_err); + g_assert_cmpint(ret, ==, CRE_OK); + g_assert(g_file_test(dst_full_name, G_FILE_TEST_IS_REGULAR)); +@@ -687,9 +687,9 @@ compressfile_test_sqlite_file_gz_output(Copyfiletest *copyfiletest, + char * dst_full_name = g_strconcat(copyfiletest->dst_file, ".gz", NULL); + + g_assert(!g_file_test(dst_full_name, G_FILE_TEST_EXISTS)); +- ret = cr_compress_file(TEST_SQLITE_FILE, dst_full_name, +- CR_CW_GZ_COMPRESSION, NULL, FALSE, +- &tmp_err); ++ ret = cr_compress_file_v2(TEST_SQLITE_FILE, dst_full_name, ++ CR_CW_GZ_COMPRESSION, NULL, FALSE, ++ &tmp_err); + g_assert(!tmp_err); + g_assert_cmpint(ret, ==, CRE_OK); + g_assert(g_file_test(dst_full_name, G_FILE_TEST_EXISTS)); +-- +libgit2 1.0.1 + diff --git a/SPECS/createrepo_c.spec b/SPECS/createrepo_c.spec index fd89134..3a1f3b1 100644 --- a/SPECS/createrepo_c.spec +++ b/SPECS/createrepo_c.spec @@ -25,11 +25,13 @@ Summary: Creates a common metadata repository Name: createrepo_c Version: 0.17.2 -Release: 1.1%{?dist} +Release: 3.1%{?dist} License: GPLv2+ URL: https://github.com/rpm-software-management/createrepo_c Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz -Patch0: https://github.com/rpm-software-management/createrepo_c/pull/269.patch +Patch1: 0001-Fix-cr_compress_file_with_stat-Memory-leak.patch +Patch2: 0002-Preserve-changed-API-for-cr_compress_file_with_stat-RhBug1973588.patch +Patch3: https://github.com/rpm-software-management/createrepo_c/pull/269.patch Provides: createrepo_c(pr269) BuildRequires: cmake @@ -177,9 +179,18 @@ ln -sr %{buildroot}%{_bindir}/modifyrepo_c %{buildroot}%{_bindir}/modifyrepo %{python3_sitearch}/%{name}-%{version}-py%{python3_version}.egg-info %changelog +* Wed Sep 27 2021 Matthew Almond - 0.17.2-3.1 +- Update to 0.17.2-3 with PR269 + +* Wed Sep 15 2021 Pavla Kratochvilova - 0.17.2-3 +- Preserve changed API for cr_compress_file_with_stat (RhBug:1973588) + * Wed Aug 04 2021 Matthew Almond - 0.17.2-1.1 - Update to 0.17.2-1 with PR269 +* Tue Jul 27 2021 Pavla Kratochvilova - 0.17.2-2 +- Fix: cr_compress_file_with_stat: Memory leak + * Mon May 24 2021 Matthew Almond - 0.16.2-2.1 - PR269 for --skip-filelists