/
niceSOFT
/
createrepo_c
Обзор
Документация
Войти
/
niceSOFT
/
createrepo_c
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/compression_wrapper.c
1 722 строки
60 KB
Pietro Cerutti
Include unistd.h for STDOUT_FILENO
24 апр 2025, 13:18
24 апр 2025, 13:18
70e92f6
Код
Авторство
О чём код?
/* createrepo_c - Library of routines for manipulation with repodata * Copyright (C) 2012 Tomas Mlcoch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ #include <glib.h> #include <glib/gstdio.h> #include <stdio.h> #include <assert.h> #include <errno.h> #include <string.h> #include <stdio.h> #include <ctype.h> #include <stdbool.h> #include <zlib.h> #include <bzlib.h> #include <lzma.h> #ifdef WITH_ZCHUNK #include <zck.h> #include <unistd.h> #endif // WITH_ZCHUNK #include "error.h" #include "compression_wrapper.h" #include <zstd.h> #define ERR_DOMAIN CREATEREPO_C_ERROR /* #define Z_CR_CW_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) */ #define CR_CW_GZ_COMPRESSION_LEVEL Z_DEFAULT_COMPRESSION /* #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 */ #define GZ_STRATEGY Z_DEFAULT_STRATEGY #define GZ_BUFFER_SIZE (1024*128) #define BZ2_VERBOSITY 0 #define BZ2_BLOCKSIZE100K 5 // Higher gives better compression but takes // more memory #define BZ2_WORK_FACTOR 0 // 0 == default == 30 (available 0-250) #define BZ2_USE_LESS_MEMORY 0 #define BZ2_SKIP_FFLUSH 0 /* number 0..9 or LZMA_PRESET_DEFAULT default preset LZMA_PRESET_EXTREME significantly slower, improving the compression ratio marginally */ #define CR_CW_XZ_COMPRESSION_LEVEL 5 /* LZMA_CHECK_NONE LZMA_CHECK_CRC32 LZMA_CHECK_CRC64 LZMA_CHECK_SHA256 */ #define XZ_CHECK LZMA_CHECK_CRC32 /* UINT64_MAX effectively disable the limiter */ #define XZ_MEMORY_USAGE_LIMIT UINT64_MAX #define XZ_DECODER_FLAGS 0 #define XZ_BUFFER_SIZE (1024*32) cr_ContentStat * cr_contentstat_new(cr_ChecksumType type, GError **err) { cr_ContentStat *cstat; assert(!err || *err == NULL); cstat = g_malloc0(sizeof(cr_ContentStat)); cstat->checksum_type = type; return cstat; } void cr_contentstat_free(cr_ContentStat *cstat, GError **err) { assert(!err || *err == NULL); if (!cstat) return; g_free(cstat->hdr_checksum); g_free(cstat->checksum); g_free(cstat); } typedef struct { lzma_stream stream; FILE *file; unsigned char buffer[XZ_BUFFER_SIZE]; } XzFile; /** level 10 or 11 are good choices for the XML files that we generate. * level 10 requires ~ 18% more time with 1% saving over level 9 * level 11 requires ~ 50% more time with 1.5% saving over level 9 * level 12 requires ~ 65% more time with 1.5% saving over level 9 * level 13 requires ~ 260% more time with 1.55% saving over level 9 */ #define CR_CW_ZSTD_COMPRESSION_LEVEL 10 typedef struct { void *buffer; size_t buffer_size; ZSTD_inBuffer zib; ZSTD_outBuffer zob; void * context; //ZSTD_{C,D}Ctx } ZstdFile; cr_CompressionType cr_detect_compression(const char *filename, GError **err) { assert(filename); assert(!err || *err == NULL); if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { g_debug("%s: File %s doesn't exist or not a regular file", __func__, filename); g_set_error(err, ERR_DOMAIN, CRE_NOFILE, "File %s doesn't exist or not a regular file", filename); return CR_CW_UNKNOWN_COMPRESSION; } // Try determine compression type via filename suffix if (g_str_has_suffix(filename, ".gz") || g_str_has_suffix(filename, ".gzip") || g_str_has_suffix(filename, ".gunzip")) { return CR_CW_GZ_COMPRESSION; } else if (g_str_has_suffix(filename, ".bz2") || g_str_has_suffix(filename, ".bzip2")) { return CR_CW_BZ2_COMPRESSION; } else if (g_str_has_suffix(filename, ".xz")) { return CR_CW_XZ_COMPRESSION; } else if (g_str_has_suffix(filename, ".zck")) { return CR_CW_ZCK_COMPRESSION; } else if (g_str_has_suffix(filename, ".zst")) { return CR_CW_ZSTD_COMPRESSION; } else if (g_str_has_suffix(filename, ".xml") || g_str_has_suffix(filename, ".tar") || g_str_has_suffix(filename, ".yaml") || g_str_has_suffix(filename, ".sqlite") || g_str_has_suffix(filename, ".txt")) { return CR_CW_NO_COMPRESSION; } // No success? Let's get hardcore... (Use magic bytes) g_debug("%s: File has no recognizable extension, checking magic bytes (%s)", __func__, filename); unsigned char magic[5]; FILE* file = fopen(filename, "rb"); if (file == NULL) { g_debug("%s: Unable to open file! (%s)", __func__, filename); g_set_error(err, ERR_DOMAIN, CRE_IO, "fopen(): %s", g_strerror(errno)); return CR_CW_UNKNOWN_COMPRESSION; } size_t bytesRead = fread(magic, 1, sizeof(magic), file); fclose(file); if (bytesRead != sizeof(magic)) { // Assume that if there's less than 5 bytes in the file, it's uncompressed g_debug("%s: Unable to read bytes from file for magic number detection, assuming uncompressed (%s)", __func__, filename); return CR_CW_NO_COMPRESSION; } if (!memcmp(magic, "\x1F\x8B", 2)) { return CR_CW_GZ_COMPRESSION; } else if (!memcmp(magic, "\x28\xB5\x2F\xFD", 4)) { return CR_CW_ZSTD_COMPRESSION; } else if (!memcmp(magic, "\x42\x5A", 2)) { return CR_CW_BZ2_COMPRESSION; } else if (!memcmp(magic, "\xFD\x37\x7A\x58\x5A", 5)) { return CR_CW_XZ_COMPRESSION; } else if (!memcmp(magic, "\0ZCK1", 5)) { return CR_CW_ZCK_COMPRESSION; } // Still no luck? Heuristic: if the filename has >1 stacked file extension, and we don't // recognize the last one, then return CR_CW_UNKNOWN_COMPRESSION. If it has only a single // file extension and we don't recognize it, then we return CR_CW_NO_COMPRESSION. g_debug("%s: Unable to detect compression from magic bytes (%s)", __func__, filename); gchar *basename = g_path_get_basename(filename); gchar **parts = g_strsplit(basename, ".", -1); bool more_than_one_extension = g_strv_length(parts) >= 3; g_strfreev(parts); g_free(basename); if (more_than_one_extension) { g_debug("%s: File has more than one extension, returning unknown compression (%s)", __func__, filename); return CR_CW_UNKNOWN_COMPRESSION; } else { g_debug("%s: File has one or no extension, assuming uncompressed (%s)", __func__, filename); return CR_CW_NO_COMPRESSION; } } cr_CompressionType cr_compression_type(const char *name) { if (!name) return CR_CW_UNKNOWN_COMPRESSION; int type = CR_CW_UNKNOWN_COMPRESSION; gchar *name_lower = g_strdup(name); for (gchar *c = name_lower; *c; c++) *c = tolower(*c); if (!g_strcmp0(name_lower, "gz") || !g_strcmp0(name_lower, "gzip")) type = CR_CW_GZ_COMPRESSION; if (!g_strcmp0(name_lower, "bz2") || !g_strcmp0(name_lower, "bzip2")) type = CR_CW_BZ2_COMPRESSION; if (!g_strcmp0(name_lower, "xz")) type = CR_CW_XZ_COMPRESSION; if (!g_strcmp0(name_lower, "zck")) type = CR_CW_ZCK_COMPRESSION; if (!g_strcmp0(name_lower, "zstd")) type = CR_CW_ZSTD_COMPRESSION; g_free(name_lower); return type; } const char * cr_compression_suffix(cr_CompressionType comtype) { switch (comtype) { case CR_CW_GZ_COMPRESSION: return ".gz"; case CR_CW_BZ2_COMPRESSION: return ".bz2"; case CR_CW_XZ_COMPRESSION: return ".xz"; case CR_CW_ZCK_COMPRESSION: return ".zck"; case CR_CW_ZSTD_COMPRESSION: return ".zst"; default: return NULL; } } static const char * cr_gz_strerror(gzFile f) { int errnum; const char *msg = gzerror(f, &errnum); if (errnum == Z_ERRNO) msg = g_strerror(errno); return msg; } #ifdef WITH_ZCHUNK cr_ChecksumType cr_cktype_from_zck(zckCtx *zck, GError **err) { int cktype = zck_get_full_hash_type(zck); if (cktype < 0) { g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Unable to read hash from zchunk file"); return CR_CHECKSUM_UNKNOWN; } if (cktype == ZCK_HASH_SHA256) return CR_CHECKSUM_SHA256; #ifdef WITH_LEGACY_HASHES else if (cktype == ZCK_HASH_SHA1) return CR_CHECKSUM_SHA1; #endif else { const char *ckname = zck_hash_name_from_type(cktype); if (ckname == NULL) ckname = "Unknown"; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Unknown zchunk checksum type: %s", ckname); return CR_CHECKSUM_UNKNOWN; } } #endif // WITH_ZCHUNK CR_FILE * cr_sopen(const char *filename, cr_OpenMode mode, cr_CompressionType comtype, cr_ContentStat *stat, GError **err) { CR_FILE *file = NULL; cr_CompressionType type = comtype; GError *tmp_err = NULL; assert(filename); assert(mode == CR_CW_MODE_READ || mode == CR_CW_MODE_WRITE); assert(mode < CR_CW_MODE_SENTINEL); assert(comtype < CR_CW_COMPRESSION_SENTINEL); assert(!err || *err == NULL); if (mode == CR_CW_MODE_WRITE) { if (comtype == CR_CW_AUTO_DETECT_COMPRESSION) { g_debug("%s: CR_CW_AUTO_DETECT_COMPRESSION cannot be used if " "mode is CR_CW_MODE_WRITE", __func__); assert(0); g_set_error(err, ERR_DOMAIN, CRE_ASSERT, "CR_CW_AUTO_DETECT_COMPRESSION cannot be used if " "mode is CR_CW_MODE_WRITE"); return NULL; } if (comtype == CR_CW_UNKNOWN_COMPRESSION) { g_debug("%s: CR_CW_UNKNOWN_COMPRESSION cannot be used if mode" " is CR_CW_MODE_WRITE", __func__); assert(0); g_set_error(err, ERR_DOMAIN, CRE_ASSERT, "CR_CW_UNKNOWN_COMPRESSION cannot be used if mode " "is CR_CW_MODE_WRITE"); return NULL; } } if (comtype == CR_CW_AUTO_DETECT_COMPRESSION) { // Try to detect type of compression type = cr_detect_compression(filename, &tmp_err); if (tmp_err) { // Error while detection g_propagate_error(err, tmp_err); return NULL; } } if (type == CR_CW_UNKNOWN_COMPRESSION) { // Detection without error but compression type is unknown g_debug("%s: Cannot detect compression type", __func__); g_set_error(err, ERR_DOMAIN, CRE_UNKNOWNCOMPRESSION, "Cannot detect compression type"); return NULL; } // Open file const char *mode_str = (mode == CR_CW_MODE_WRITE) ? "wb" : "rb"; file = g_malloc0(sizeof(CR_FILE)); file->mode = mode; file->type = type; file->INNERFILE = NULL; switch (type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- mode_str = (mode == CR_CW_MODE_WRITE) ? "w" : "r"; file->FILE = (void *) fopen(filename, mode_str); if (!file->FILE) g_set_error(err, ERR_DOMAIN, CRE_IO, "fopen(): %s", g_strerror(errno)); break; case (CR_CW_GZ_COMPRESSION): // --------------------------------------- file->FILE = (void *) gzopen(filename, mode_str); if (!file->FILE) { g_set_error(err, ERR_DOMAIN, CRE_GZ, "gzopen(): %s", g_strerror(errno)); break; } if (mode == CR_CW_MODE_WRITE) gzsetparams((gzFile) file->FILE, CR_CW_GZ_COMPRESSION_LEVEL, GZ_STRATEGY); if (gzbuffer((gzFile) file->FILE, GZ_BUFFER_SIZE) == -1) { g_debug("%s: gzbuffer() call failed", __func__); g_set_error(err, ERR_DOMAIN, CRE_GZ, "gzbuffer() call failed"); } break; case (CR_CW_ZSTD_COMPRESSION): { // ------------------------------------ FILE *f = fopen(filename, mode_str); if (!f) { g_set_error(err, ERR_DOMAIN, CRE_IO, "fopen(): %s", g_strerror(errno)); break; } file->INNERFILE = f; ZstdFile *zstd_file = g_malloc0(sizeof(ZstdFile)); if (mode == CR_CW_MODE_WRITE) { if ((zstd_file->context = (void *) ZSTD_createCCtx()) == NULL) { g_set_error(err, ERR_DOMAIN, CRE_ZSTD, "%s", "Failed to create ZSTD context."); g_free(zstd_file); fclose(f); break; } size_t ret = ZSTD_CCtx_setParameter(zstd_file->context, ZSTD_c_compressionLevel, CR_CW_ZSTD_COMPRESSION_LEVEL); if (ZSTD_isError(ret)) { g_set_error(err, ERR_DOMAIN, CRE_ZSTD, "%s", ZSTD_getErrorName(ret)); g_free(zstd_file); fclose(f); break; } zstd_file->buffer_size = ZSTD_CStreamOutSize(); } else { if ((zstd_file->context = (void *) ZSTD_createDCtx()) == NULL) { g_free(zstd_file); fclose(f); g_set_error(err, ERR_DOMAIN, CRE_IO, "%s", "Failed to create ZSTD context."); break; } zstd_file->buffer_size = ZSTD_DStreamInSize(); } zstd_file->buffer = g_malloc(zstd_file->buffer_size); file->FILE = (void *) zstd_file; break; } case (CR_CW_BZ2_COMPRESSION): { // ------------------------------------ FILE *f = fopen(filename, mode_str); file->INNERFILE = f; int bzerror; if (!f) { g_set_error(err, ERR_DOMAIN, CRE_IO, "fopen(): %s", g_strerror(errno)); break; } if (mode == CR_CW_MODE_WRITE) { file->FILE = (void *) BZ2_bzWriteOpen(&bzerror, f, BZ2_BLOCKSIZE100K, BZ2_VERBOSITY, BZ2_WORK_FACTOR); } else { file->FILE = (void *) BZ2_bzReadOpen(&bzerror, f, BZ2_VERBOSITY, BZ2_USE_LESS_MEMORY, NULL, 0); } if (bzerror != BZ_OK) { const char *err_msg; fclose(f); switch (bzerror) { case BZ_CONFIG_ERROR: err_msg = "library has been mis-compiled"; break; case BZ_PARAM_ERROR: err_msg = "bad function params"; break; case BZ_IO_ERROR: err_msg = "ferror(f) is nonzero"; break; case BZ_MEM_ERROR: err_msg = "insufficient memory is available"; break; default: err_msg = "other error"; } g_set_error(err, ERR_DOMAIN, CRE_BZ2, "Bz2 error: %s", err_msg); } break; } case (CR_CW_XZ_COMPRESSION): { // ------------------------------------- int ret; XzFile *xz_file = g_malloc(sizeof(XzFile)); lzma_stream *stream = &(xz_file->stream); memset(stream, 0, sizeof(lzma_stream)); /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XXX: This part is a little tricky. Because in the default initializer LZMA_STREAM_INIT are some items NULL and (according to C standard) NULL may have different internal representation than zero. This should not be a problem nowadays. */ // Prepare coder/decoder if (mode == CR_CW_MODE_WRITE) { #ifdef ENABLE_THREADED_XZ_ENCODER // The threaded encoder takes the options as pointer to // a lzma_mt structure. lzma_mt mt = { // No flags are needed. .flags = 0, // Let liblzma determine a sane block size. .block_size = 0, // Use no timeout for lzma_code() calls by setting timeout // to zero. That is, sometimes lzma_code() might block for // a long time (from several seconds to even minutes). // If this is not OK, for example due to progress indicator // needing updates, specify a timeout in milliseconds here. // See the documentation of lzma_mt in lzma/container.h for // information how to choose a reasonable timeout. .timeout = 0, // Use the default preset (6) for LZMA2. // To use a preset, filters must be set to NULL. .preset = LZMA_PRESET_DEFAULT, .filters = NULL, // Integrity checking. .check = XZ_CHECK, }; // Detect how many threads the CPU supports. mt.threads = lzma_cputhreads(); // If the number of CPU cores/threads cannot be detected, // use one thread. if (mt.threads == 0) mt.threads = 1; // If the number of CPU cores/threads exceeds threads_max, // limit the number of threads to keep memory usage lower. const uint32_t threads_max = 2; if (mt.threads > threads_max) mt.threads = threads_max; if (mt.threads > 1) // Initialize the threaded encoder ret = lzma_stream_encoder_mt(stream, &mt); else #endif // Initialize the single-threaded encoder ret = lzma_easy_encoder(stream, CR_CW_XZ_COMPRESSION_LEVEL, XZ_CHECK); } else { ret = lzma_auto_decoder(stream, XZ_MEMORY_USAGE_LIMIT, XZ_DECODER_FLAGS); } if (ret != LZMA_OK) { const char *err_msg; switch (ret) { case LZMA_MEM_ERROR: err_msg = "Cannot allocate memory"; break; case LZMA_OPTIONS_ERROR: err_msg = "Unsupported flags (options)"; break; case LZMA_PROG_ERROR: err_msg = "One or more of the parameters " "have values that will never be valid. " "(Possibly a bug)"; break; case LZMA_UNSUPPORTED_CHECK: err_msg = "Specified integrity check is not supported"; break; default: err_msg = "Unknown error"; } g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ error (%d): %s", ret, err_msg); g_free((void *) xz_file); break; } // Open input/output file FILE *f = fopen(filename, mode_str); if (!f) { g_set_error(err, ERR_DOMAIN, CRE_XZ, "fopen(): %s", g_strerror(errno)); lzma_end(&(xz_file->stream)); g_free((void *) xz_file); break; } xz_file->file = f; file->FILE = (void *) xz_file; break; } case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------- #ifdef WITH_ZCHUNK FILE *f = fopen(filename, mode_str); if (!f) { g_set_error(err, ERR_DOMAIN, CRE_IO, "fopen(): %s", g_strerror(errno)); break; } file->INNERFILE = f; int fd = fileno(f); file->FILE = (void *) zck_create(); zckCtx *zck = file->FILE; if (mode == CR_CW_MODE_WRITE) { if (!file->FILE || !zck_init_write(zck, fd) || !zck_set_ioption(zck, ZCK_MANUAL_CHUNK, 1) || !zck_set_ioption(zck, ZCK_COMP_TYPE, ZCK_COMP_ZSTD) || !zck_set_ioption(zck, ZCK_ZSTD_COMP_LEVEL, CR_CW_ZSTD_COMPRESSION_LEVEL)) { zck_set_log_fd(STDOUT_FILENO); g_set_error(err, ERR_DOMAIN, CRE_IO, "%s", zck_get_error(zck)); break; } } else { if (!file->FILE || !zck_init_read(zck, fd)) { g_set_error(err, ERR_DOMAIN, CRE_IO, "%s", zck_get_error(zck)); break; } } break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: // ----------------------------------------------------------- break; } if (!file->FILE) { // File is not open -> cleanup if (err && *err == NULL) g_set_error(err, ERR_DOMAIN, CRE_XZ, "Unknown error while opening: %s", filename); g_free(file); return NULL; } if (stat) { file->stat = stat; if (stat->checksum_type == CR_CHECKSUM_UNKNOWN) { file->checksum_ctx = NULL; } else { file->checksum_ctx = cr_checksum_new(stat->checksum_type, &tmp_err); if (tmp_err) { g_propagate_error(err, tmp_err); cr_close(file, NULL); return NULL; } } #ifdef WITH_ZCHUNK /* Fill zchunk header_stat with header information */ if (mode == CR_CW_MODE_READ && type == CR_CW_ZCK_COMPRESSION) { zckCtx *zck = (zckCtx *)file->FILE; cr_ChecksumType cktype = cr_cktype_from_zck(zck, err); if (cktype == CR_CHECKSUM_UNKNOWN) { /* Error is already set in cr_cktype_from_zck */ g_free(file); return NULL; } file->stat->hdr_checksum_type = cktype; file->stat->hdr_checksum = zck_get_header_digest(zck); file->stat->hdr_size = zck_get_header_length(zck); if (*err != NULL || file->stat->hdr_checksum == NULL || file->stat->hdr_size < 0) { g_free(file); return NULL; } } #endif // WITH_ZCHUNK } assert(!err || (!file && *err != NULL) || (file && *err == NULL)); return file; } int cr_set_dict(CR_FILE *cr_file, const void *dict, unsigned int len, GError **err) { int ret = CRE_OK; assert(!err || *err == NULL); if (len == 0) return CRE_OK; switch (cr_file->type) { case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------ #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *)cr_file->FILE; size_t wlen = (size_t)len; if (!zck_set_soption(zck, ZCK_COMP_DICT, dict, wlen)) { ret = CRE_ERROR; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Error setting dict"); break; } break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: { // --------------------------------------------------------- ret = CRE_ERROR; g_set_error(err, ERR_DOMAIN, CRE_ERROR, "Compression format doesn't support dict"); break; } } return ret; } int cr_close(CR_FILE *cr_file, GError **err) { int ret = CRE_ERROR; int rc; assert(!err || *err == NULL); if (!cr_file) return CRE_OK; switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- if (fclose((FILE *) cr_file->FILE) == 0) { ret = CRE_OK; } else { ret = CRE_IO; g_set_error(err, ERR_DOMAIN, CRE_IO, "fclose(): %s", g_strerror(errno)); } break; case (CR_CW_GZ_COMPRESSION): // --------------------------------------- rc = gzclose((gzFile) cr_file->FILE); if (rc == Z_OK) ret = CRE_OK; else { const char *err_msg; switch (rc) { case Z_STREAM_ERROR: err_msg = "file is not valid"; break; case Z_ERRNO: err_msg = "file operation error"; break; case Z_MEM_ERROR: err_msg = "if out of memory"; break; case Z_BUF_ERROR: err_msg = "last read ended in the middle of a stream"; break; default: err_msg = "error"; } ret = CRE_GZ; g_set_error(err, ERR_DOMAIN, CRE_GZ, "gzclose(): %s", err_msg); } break; case (CR_CW_ZSTD_COMPRESSION): { // -------------------------------------- ZstdFile * zstd = (ZstdFile *) cr_file->FILE; if (cr_file->mode == CR_CW_MODE_READ) { ZSTD_freeDCtx(zstd->context); } else { size_t remaining; // No more new input just finish flushing compression data ZSTD_inBuffer zip = { NULL, 0, 0 }; do { zstd->zob.dst = zstd->buffer; zstd->zob.size = zstd->buffer_size; zstd->zob.pos = 0; remaining = ZSTD_compressStream2(zstd->context, &zstd->zob , &zip, ZSTD_e_end); if (ZSTD_isError(remaining)) { g_set_error(err, ERR_DOMAIN, CRE_ZSTD, "%s", ZSTD_getErrorName(remaining)); break; } else if (zstd->zob.pos != fwrite(zstd->buffer, 1, zstd->zob.pos, cr_file->INNERFILE)) { g_set_error(err, ERR_DOMAIN, CRE_IO, "cr_close ZSTD fwrite failed"); break; } } while(remaining != 0); ZSTD_freeCCtx(zstd->context); } fclose(cr_file->INNERFILE); g_free(zstd->buffer); g_free(cr_file->FILE); ret = CRE_OK; break; } case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- if (cr_file->mode == CR_CW_MODE_READ) BZ2_bzReadClose(&rc, (BZFILE *) cr_file->FILE); else BZ2_bzWriteClose(&rc, (BZFILE *) cr_file->FILE, BZ2_SKIP_FFLUSH, NULL, NULL); fclose(cr_file->INNERFILE); if (rc == BZ_OK) { ret = CRE_OK; } else { const char *err_msg; switch (rc) { case BZ_SEQUENCE_ERROR: // This really should not happen err_msg = "file was opened with BZ2_bzReadOpen"; break; case BZ_IO_ERROR: err_msg = "error writing the compressed file"; break; default: err_msg = "other error"; } ret = CRE_BZ2; g_set_error(err, ERR_DOMAIN, CRE_BZ2, "Bz2 error: %s", err_msg); } break; case (CR_CW_XZ_COMPRESSION): { // ------------------------------------- XzFile *xz_file = (XzFile *) cr_file->FILE; lzma_stream *stream = &(xz_file->stream); if (cr_file->mode == CR_CW_MODE_WRITE) { // Write out rest of buffer while (1) { stream->next_out = (uint8_t*) xz_file->buffer; stream->avail_out = XZ_BUFFER_SIZE; rc = lzma_code(stream, LZMA_FINISH); if (rc != LZMA_OK && rc != LZMA_STREAM_END) { // Error while coding const char *err_msg; switch (rc) { case LZMA_MEM_ERROR: err_msg = "Memory allocation failed"; break; case LZMA_DATA_ERROR: // This error is returned if the compressed // or uncompressed size get near 8 EiB // (2^63 bytes) because that's where the .xz // file format size limits currently are. // That is, the possibility of this error // is mostly theoretical unless you are doing // something very unusual. // // Note that strm->total_in and strm->total_out // have nothing to do with this error. Changing // those variables won't increase or decrease // the chance of getting this error. err_msg = "File size limits exceeded"; break; default: // This is most likely LZMA_PROG_ERROR. err_msg = "Unknown error, possibly a bug"; break; } ret = CRE_XZ; g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ: lzma_code() error (%d): %s", rc, err_msg); break; } size_t olen = XZ_BUFFER_SIZE - stream->avail_out; if (fwrite(xz_file->buffer, 1, olen, xz_file->file) != olen) { // Error while writing ret = CRE_XZ; g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ: fwrite() error: %s", g_strerror(errno)); break; } if (rc == LZMA_STREAM_END) { // Everything all right ret = CRE_OK; break; } } } else { ret = CRE_OK; } fclose(xz_file->file); lzma_end(stream); g_free(stream); break; } case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------ #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *) cr_file->FILE; ret = CRE_OK; if (cr_file->mode == CR_CW_MODE_WRITE) { if (zck_end_chunk(zck) < 0) { ret = CRE_ZCK; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Unable to end final chunk: %s", zck_get_error(zck)); break; } } if (!zck_close(zck)) { ret = CRE_ZCK; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Unable to close zchunk file: %s", zck_get_error(zck)); break; } cr_ChecksumType cktype = cr_cktype_from_zck(zck, err); if (cktype == CR_CHECKSUM_UNKNOWN) { /* Error is already set in cr_cktype_from_zck */ break; } if (cr_file->stat) { cr_file->stat->hdr_checksum_type = cktype; cr_file->stat->hdr_checksum = zck_get_header_digest(zck); cr_file->stat->hdr_size = zck_get_header_length(zck); if ((err && *err) || cr_file->stat->hdr_checksum == NULL || cr_file->stat->hdr_size < 0) { ret = CRE_ZCK; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Unable to get zchunk header information: %s", zck_get_error(zck)); break; } } zck_free(&zck); fclose(cr_file->INNERFILE); break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: // ----------------------------------------------------------- ret = CRE_BADARG; g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); break; } if (cr_file->stat) { g_free(cr_file->stat->checksum); if (cr_file->checksum_ctx) cr_file->stat->checksum = cr_checksum_final(cr_file->checksum_ctx, NULL); else cr_file->stat->checksum = NULL; } g_free(cr_file); assert(!err || (ret != CRE_OK && *err != NULL) || (ret == CRE_OK && *err == NULL)); return ret; } int cr_read(CR_FILE *cr_file, void *buffer, unsigned int len, GError **err) { int bzerror; int ret = CR_CW_ERR; assert(cr_file); assert(buffer); assert(!err || *err == NULL); if (cr_file->mode != CR_CW_MODE_READ) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in read mode"); return CR_CW_ERR; } switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- ret = fread(buffer, 1, len, (FILE *) cr_file->FILE); if ((ret != (int) len) && !feof((FILE *) cr_file->FILE)) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_IO, "fread(): %s", g_strerror(errno)); } break; case (CR_CW_GZ_COMPRESSION): // --------------------------------------- ret = gzread((gzFile) cr_file->FILE, buffer, len); if (ret == -1) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_GZ, "fread(): %s", cr_gz_strerror((gzFile) cr_file->FILE)); } break; case (CR_CW_ZSTD_COMPRESSION): { // --------------------------------------- ZstdFile * zstd = (ZstdFile *) cr_file->FILE; ZSTD_outBuffer zob = {buffer, len, 0}; while (zob.pos < zob.size) { // Re-fill compressed data buffer if (zstd->zib.pos >= zstd->zib.size) { zstd->zib.size = fread(zstd->buffer, 1, zstd->buffer_size, cr_file->INNERFILE); if (zstd->zib.size == 0) { break; //EOF } zstd->zib.src = zstd->buffer; zstd->zib.pos = 0; } // Decompress chunk int decomp_ret = ZSTD_decompressStream(zstd->context, &zob, &zstd->zib); if (ZSTD_isError(decomp_ret)) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_ZSTD, "%s", ZSTD_getErrorName(decomp_ret)); break; } } if (!(err && *err)) { ret = zob.pos; } break; } case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- ret = BZ2_bzRead(&bzerror, (BZFILE *) cr_file->FILE, buffer, len); if (!ret && bzerror == BZ_SEQUENCE_ERROR) // Next read after BZ_STREAM_END (EOF) return 0; if (bzerror != BZ_OK && bzerror != BZ_STREAM_END) { const char *err_msg; ret = CR_CW_ERR; switch (bzerror) { case BZ_PARAM_ERROR: // This should not happend err_msg = "bad function params!"; break; case BZ_SEQUENCE_ERROR: // This should not happend err_msg = "file was opened with BZ2_bzWriteOpen"; break; case BZ_IO_ERROR: err_msg = "error while reading from the compressed file"; break; case BZ_UNEXPECTED_EOF: err_msg = "the compressed file ended before " "the logical end-of-stream was detected"; break; case BZ_DATA_ERROR: err_msg = "data integrity error was detected in " "the compressed stream"; break; case BZ_DATA_ERROR_MAGIC: err_msg = "the stream does not begin with " "the requisite header bytes (ie, is not " "a bzip2 data file)."; break; case BZ_MEM_ERROR: err_msg = "insufficient memory was available"; break; default: err_msg = "other error"; } g_set_error(err, ERR_DOMAIN, CRE_BZ2, "Bz2 error: %s", err_msg); } break; case (CR_CW_XZ_COMPRESSION): { // ------------------------------------- XzFile *xz_file = (XzFile *) cr_file->FILE; lzma_stream *stream = &(xz_file->stream); stream->next_out = buffer; stream->avail_out = len; while (stream->avail_out) { int lret; // Fill input buffer if (stream->avail_in == 0) { if ((lret = fread(xz_file->buffer, 1, XZ_BUFFER_SIZE, xz_file->file)) < 0) { g_debug("%s: XZ: Error while fread", __func__); g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ: fread(): %s", g_strerror(errno)); return CR_CW_ERR; // Error while reading input file } else if (lret == 0) { g_debug("%s: EOF", __func__); break; // EOF } stream->next_in = xz_file->buffer; stream->avail_in = lret; } // Decode lret = lzma_code(stream, LZMA_RUN); if (lret != LZMA_OK && lret != LZMA_STREAM_END) { const char *err_msg; switch (lret) { case LZMA_MEM_ERROR: err_msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: // .xz magic bytes weren't found. err_msg = "The input is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: // For example, the headers specify a filter // that isn't supported by this liblzma // version (or it hasn't been enabled when // building liblzma, but no-one sane does // that unless building liblzma for an // embedded system). Upgrading to a newer // liblzma might help. // // Note that it is unlikely that the file has // accidentally became corrupt if you get this // error. The integrity of the .xz headers is // always verified with a CRC32, so // unintentionally corrupt files can be // distinguished from unsupported files. err_msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: err_msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: // Typically this error means that a valid // file has got truncated, but it might also // be a damaged part in the file that makes // the decoder think the file is truncated. // If you prefer, you can use the same error // message for this as for LZMA_DATA_ERROR. err_msg = "Compressed file is truncated or " "otherwise corrupt"; break; default: // This is most likely LZMA_PROG_ERROR. err_msg = "Unknown error, possibly a bug"; break; } g_debug("%s: XZ: Error while decoding (%d): %s", __func__, lret, err_msg); g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ: Error while decoding (%d): %s", lret, err_msg); return CR_CW_ERR; // Error while decoding } if (lret == LZMA_STREAM_END) break; } ret = len - stream->avail_out; break; } case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------ #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *) cr_file->FILE; ssize_t rb = zck_read(zck, buffer, len); if (rb < 0) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "ZCK: Unable to read: %s", zck_get_error(zck)); break; } ret = rb; break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: // ----------------------------------------------------------- ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); break; } assert(!err || (ret == CR_CW_ERR && *err != NULL) || (ret != CR_CW_ERR && *err == NULL)); if (cr_file->stat && ret != CR_CW_ERR) { cr_file->stat->size += ret; if (cr_file->checksum_ctx) { GError *tmp_err = NULL; cr_checksum_update(cr_file->checksum_ctx, buffer, ret, &tmp_err); if (tmp_err) { g_propagate_error(err, tmp_err); return CR_CW_ERR; } } } return ret; } int cr_write(CR_FILE *cr_file, const void *buffer, unsigned int len, GError **err) { int bzerror; int ret = CR_CW_ERR; assert(cr_file); assert(buffer); assert(!err || *err == NULL); if (cr_file->mode != CR_CW_MODE_WRITE) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in read mode"); return ret; } if (cr_file->stat) { cr_file->stat->size += len; if (cr_file->checksum_ctx) { GError *tmp_err = NULL; cr_checksum_update(cr_file->checksum_ctx, buffer, len, &tmp_err); if (tmp_err) { g_propagate_error(err, tmp_err); return CR_CW_ERR; } } } switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- if ((ret = (int) fwrite(buffer, 1, len, (FILE *) cr_file->FILE)) != (int) len) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_IO, "fwrite(): %s", g_strerror(errno)); } break; case (CR_CW_GZ_COMPRESSION): // --------------------------------------- if (len == 0) { ret = 0; break; } if ((ret = gzwrite((gzFile) cr_file->FILE, buffer, len)) == 0) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_GZ, "gzwrite(): %s", cr_gz_strerror((gzFile) cr_file->FILE)); } break; case (CR_CW_ZSTD_COMPRESSION): { // --------------------------------------- ZstdFile * zstd = (ZstdFile *) cr_file->FILE; ZSTD_inBuffer zib = {buffer, len, 0}; while (zib.pos < zib.size) { zstd->zob.dst = zstd->buffer; zstd->zob.size = zstd->buffer_size; zstd->zob.pos = 0; // Compress chunk into buffer size_t remaining = ZSTD_compressStream2(zstd->context, &zstd->zob , &zib, ZSTD_e_continue); if (ZSTD_isError(remaining)) { g_set_error(err, ERR_DOMAIN, CRE_ZSTD, "%s", ZSTD_getErrorName(remaining)); break; } // Write compressed buffer if (zstd->zob.pos > 0) { size_t nw = fwrite(zstd->buffer, 1, zstd->zob.pos, cr_file->INNERFILE); if (nw != zstd->zob.pos) { g_set_error(err, ERR_DOMAIN, CRE_IO, "cr_write zstd write failed"); break; } } } if (!(err && *err)) { ret = zib.pos; } break; } case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- BZ2_bzWrite(&bzerror, (BZFILE *) cr_file->FILE, (void *) buffer, len); if (bzerror == BZ_OK) { ret = len; } else { const char *err_msg; ret = CR_CW_ERR; switch (bzerror) { case BZ_PARAM_ERROR: // This should not happend err_msg = "bad function params!"; break; case BZ_SEQUENCE_ERROR: // This should not happend err_msg = "file was opened with BZ2_bzReadOpen"; break; case BZ_IO_ERROR: err_msg = "error while reading from the compressed file"; break; default: err_msg = "other error"; } g_set_error(err, ERR_DOMAIN, CRE_BZ2, "Bz2 error: %s", err_msg); } break; case (CR_CW_XZ_COMPRESSION): { // ------------------------------------- XzFile *xz_file = (XzFile *) cr_file->FILE; lzma_stream *stream = &(xz_file->stream); ret = len; stream->next_in = buffer; stream->avail_in = len; while (stream->avail_in) { int lret; stream->next_out = xz_file->buffer; stream->avail_out = XZ_BUFFER_SIZE; lret = lzma_code(stream, LZMA_RUN); if (lret != LZMA_OK) { const char *err_msg; ret = CR_CW_ERR; switch (lret) { case LZMA_MEM_ERROR: err_msg = "Memory allocation failed"; break; case LZMA_DATA_ERROR: // This error is returned if the compressed // or uncompressed size get near 8 EiB // (2^63 bytes) because that's where the .xz // file format size limits currently are. // That is, the possibility of this error // is mostly theoretical unless you are doing // something very unusual. // // Note that strm->total_in and strm->total_out // have nothing to do with this error. Changing // those variables won't increase or decrease // the chance of getting this error. err_msg = "File size limits exceeded"; break; default: // This is most likely LZMA_PROG_ERROR. err_msg = "Unknown error, possibly a bug"; break; } g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ: lzma_code() error (%d): %s", lret, err_msg); break; // Error while coding } size_t out_len = XZ_BUFFER_SIZE - stream->avail_out; if ((fwrite(xz_file->buffer, 1, out_len, xz_file->file)) != out_len) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_XZ, "XZ: fwrite(): %s", g_strerror(errno)); break; // Error while writing } } break; } case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------ #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *) cr_file->FILE; ssize_t wb = zck_write(zck, buffer, len); if (wb < 0) { ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_ZCK, "ZCK: Unable to write: %s", zck_get_error(zck)); break; } ret = wb; break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: // ----------------------------------------------------------- g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); break; } assert(!err || (ret == CR_CW_ERR && *err != NULL) || (ret != CR_CW_ERR && *err == NULL)); return ret; } int cr_puts(CR_FILE *cr_file, const char *str, GError **err) { size_t len; int ret = CR_CW_ERR; assert(cr_file); assert(!err || *err == NULL); if (!str) return 0; if (cr_file->mode != CR_CW_MODE_WRITE) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in write mode"); return CR_CW_ERR; } switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- case (CR_CW_GZ_COMPRESSION): // --------------------------------------- case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- case (CR_CW_XZ_COMPRESSION): // --------------------------------------- case (CR_CW_ZCK_COMPRESSION): // -------------------------------------- case (CR_CW_ZSTD_COMPRESSION): // -------------------------------------- len = strlen(str); ret = cr_write(cr_file, str, len, err); if (ret != (int) len) ret = CR_CW_ERR; break; default: // ----------------------------------------------------------- g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); break; } assert(!err || (ret == CR_CW_ERR && *err != NULL) || (ret != CR_CW_ERR && *err == NULL)); return ret; } int cr_end_chunk(CR_FILE *cr_file, GError **err) { int ret = CRE_OK; assert(cr_file); assert(!err || *err == NULL); if (cr_file->mode != CR_CW_MODE_WRITE) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in write mode"); return CR_CW_ERR; } switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- case (CR_CW_GZ_COMPRESSION): // --------------------------------------- case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- case (CR_CW_XZ_COMPRESSION): // --------------------------------------- case (CR_CW_ZSTD_COMPRESSION): // --------------------------------------- break; case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------ #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *) cr_file->FILE; ssize_t wb = zck_end_chunk(zck); if (wb < 0) { g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Error ending chunk: %s", zck_get_error(zck)); return CR_CW_ERR; } ret = wb; break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: // ----------------------------------------------------------- g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); return CR_CW_ERR; break; } assert(!err || (ret == CR_CW_ERR && *err != NULL) || (ret != CR_CW_ERR && *err == NULL)); return ret; } int cr_set_autochunk(CR_FILE *cr_file, gboolean auto_chunk, GError **err) { int ret = CRE_OK; assert(cr_file); assert(!err || *err == NULL); if (cr_file->mode != CR_CW_MODE_WRITE) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in write mode"); return CR_CW_ERR; } switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- case (CR_CW_GZ_COMPRESSION): // --------------------------------------- case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- case (CR_CW_XZ_COMPRESSION): // --------------------------------------- case (CR_CW_ZSTD_COMPRESSION): // --------------------------------------- break; case (CR_CW_ZCK_COMPRESSION): { // ------------------------------------ #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *) cr_file->FILE; if (!zck_set_ioption(zck, ZCK_MANUAL_CHUNK, !auto_chunk)) { g_set_error(err, ERR_DOMAIN, CRE_ZCK, "Error setting auto_chunk: %s", zck_get_error(zck)); return CR_CW_ERR; } break; #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); break; #endif // WITH_ZCHUNK } default: // ----------------------------------------------------------- g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); return CR_CW_ERR; break; } assert(!err || (ret == CR_CW_ERR && *err != NULL) || (ret != CR_CW_ERR && *err == NULL)); return ret; } int cr_printf(GError **err, CR_FILE *cr_file, const char *format, ...) { va_list vl; int ret; gchar *buf = NULL; assert(cr_file); assert(!err || *err == NULL); if (!format) return 0; if (cr_file->mode != CR_CW_MODE_WRITE) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in write mode"); return CR_CW_ERR; } // Fill format string va_start(vl, format); ret = g_vasprintf(&buf, format, vl); va_end(vl); if (ret < 0) { g_debug("%s: vasprintf() call failed", __func__); g_set_error(err, ERR_DOMAIN, CRE_MEMORY, "vasprintf() call failed"); g_free(buf); return CR_CW_ERR; } assert(buf); int tmp_ret; switch (cr_file->type) { case (CR_CW_NO_COMPRESSION): // --------------------------------------- case (CR_CW_GZ_COMPRESSION): // --------------------------------------- case (CR_CW_BZ2_COMPRESSION): // -------------------------------------- case (CR_CW_XZ_COMPRESSION): // --------------------------------------- case (CR_CW_ZCK_COMPRESSION): // -------------------------------------- case (CR_CW_ZSTD_COMPRESSION): // -------------------------------------- tmp_ret = cr_write(cr_file, buf, ret, err); if (tmp_ret != (int) ret) ret = CR_CW_ERR; break; default: // ----------------------------------------------------------- ret = CR_CW_ERR; g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); break; } g_free(buf); assert(!err || (ret == CR_CW_ERR && *err != NULL) || (ret != CR_CW_ERR && *err == NULL)); return ret; } ssize_t cr_get_zchunk_with_index(CR_FILE *cr_file, ssize_t zchunk_index, char **copy_buf, GError **err) { assert(cr_file); assert(!err || *err == NULL); if (cr_file->mode != CR_CW_MODE_READ) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "File is not opened in read mode"); return 0; } if (cr_file->type != CR_CW_ZCK_COMPRESSION){ g_set_error(err, ERR_DOMAIN, CRE_BADARG, "Bad compressed file type"); return 0; } #ifdef WITH_ZCHUNK zckCtx *zck = (zckCtx *) cr_file->FILE; zckChunk *idx = zck_get_chunk(zck, zchunk_index); ssize_t chunk_size = zck_get_chunk_size(idx); if (chunk_size <= 0) return 0; *copy_buf = g_malloc(chunk_size); return zck_get_chunk_data(idx, *copy_buf, chunk_size); #else g_set_error(err, ERR_DOMAIN, CRE_IO, "createrepo_c wasn't compiled " "with zchunk support"); return 0; #endif // WITH_ZCHUNK }