1324145Smm/*- 2324145Smm * Copyright (c) 2009-2011 Sean Purcell 3324145Smm * All rights reserved. 4324145Smm * 5324145Smm * Redistribution and use in source and binary forms, with or without 6324145Smm * modification, are permitted provided that the following conditions 7324145Smm * are met: 8324145Smm * 1. Redistributions of source code must retain the above copyright 9324145Smm * notice, this list of conditions and the following disclaimer. 10324145Smm * 2. Redistributions in binary form must reproduce the above copyright 11324145Smm * notice, this list of conditions and the following disclaimer in the 12324145Smm * documentation and/or other materials provided with the distribution. 13324145Smm * 14324145Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15324145Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16324145Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17324145Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18324145Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19324145Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20324145Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21324145Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22324145Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23324145Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24324145Smm */ 25324145Smm 26324145Smm#include "archive_platform.h" 27324145Smm 28324145Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_read_support_filter_zstd.c 362134 2020-06-12 23:02:34Z mm $"); 29324145Smm 30324145Smm#ifdef HAVE_ERRNO_H 31324145Smm#include <errno.h> 32324145Smm#endif 33324145Smm 34324145Smm#ifdef HAVE_ERRNO_H 35324145Smm#include <errno.h> 36324145Smm#endif 37324145Smm#include <stdio.h> 38324145Smm#ifdef HAVE_STDLIB_H 39324145Smm#include <stdlib.h> 40324145Smm#endif 41324145Smm#ifdef HAVE_STRING_H 42324145Smm#include <string.h> 43324145Smm#endif 44324145Smm#ifdef HAVE_UNISTD_H 45324145Smm#include <unistd.h> 46324145Smm#endif 47324145Smm#if HAVE_ZSTD_H 48324145Smm#include <zstd.h> 49324145Smm#endif 50324145Smm 51324145Smm#include "archive.h" 52324145Smm#include "archive_endian.h" 53324145Smm#include "archive_private.h" 54324145Smm#include "archive_read_private.h" 55324145Smm 56324145Smm#if HAVE_ZSTD_H && HAVE_LIBZSTD 57324145Smm 58324145Smmstruct private_data { 59324145Smm ZSTD_DStream *dstream; 60324145Smm unsigned char *out_block; 61324145Smm size_t out_block_size; 62324145Smm int64_t total_out; 63324145Smm char in_frame; /* True = in the middle of a zstd frame. */ 64324145Smm char eof; /* True = found end of compressed data. */ 65324145Smm}; 66324145Smm 67324145Smm/* Zstd Filter. */ 68324145Smmstatic ssize_t zstd_filter_read(struct archive_read_filter *, const void**); 69324145Smmstatic int zstd_filter_close(struct archive_read_filter *); 70324145Smm#endif 71324145Smm 72324145Smm/* 73324145Smm * Note that we can detect zstd compressed files even if we can't decompress 74324145Smm * them. (In fact, we like detecting them because we can give better error 75324145Smm * messages.) So the bid framework here gets compiled even if no zstd library 76324145Smm * is available. 77324145Smm */ 78324145Smmstatic int zstd_bidder_bid(struct archive_read_filter_bidder *, 79324145Smm struct archive_read_filter *); 80324145Smmstatic int zstd_bidder_init(struct archive_read_filter *); 81324145Smm 82324145Smmint 83324145Smmarchive_read_support_filter_zstd(struct archive *_a) 84324145Smm{ 85324145Smm struct archive_read *a = (struct archive_read *)_a; 86324145Smm struct archive_read_filter_bidder *bidder; 87324145Smm 88324145Smm archive_check_magic(_a, ARCHIVE_READ_MAGIC, 89324145Smm ARCHIVE_STATE_NEW, "archive_read_support_filter_zstd"); 90324145Smm 91324145Smm if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) 92324145Smm return (ARCHIVE_FATAL); 93324145Smm 94324145Smm bidder->data = NULL; 95324145Smm bidder->name = "zstd"; 96324145Smm bidder->bid = zstd_bidder_bid; 97324145Smm bidder->init = zstd_bidder_init; 98324145Smm bidder->options = NULL; 99324145Smm bidder->free = NULL; 100324145Smm#if HAVE_ZSTD_H && HAVE_LIBZSTD 101324145Smm return (ARCHIVE_OK); 102324145Smm#else 103324145Smm archive_set_error(_a, ARCHIVE_ERRNO_MISC, 104324145Smm "Using external zstd program for zstd decompression"); 105324145Smm return (ARCHIVE_WARN); 106324145Smm#endif 107324145Smm} 108324145Smm 109324145Smm/* 110324145Smm * Test whether we can handle this data. 111324145Smm */ 112324145Smmstatic int 113324145Smmzstd_bidder_bid(struct archive_read_filter_bidder *self, 114324145Smm struct archive_read_filter *filter) 115324145Smm{ 116324145Smm const unsigned char *buffer; 117324145Smm ssize_t avail; 118324145Smm unsigned prefix; 119324145Smm 120324145Smm /* Zstd frame magic values */ 121324145Smm const unsigned zstd_magic = 0xFD2FB528U; 122362134Smm const unsigned zstd_magic_skippable_start = 0x184D2A50U; 123362134Smm const unsigned zstd_magic_skippable_mask = 0xFFFFFFF0; 124324145Smm 125324145Smm (void) self; /* UNUSED */ 126324145Smm 127324145Smm buffer = __archive_read_filter_ahead(filter, 4, &avail); 128324145Smm if (buffer == NULL) 129324145Smm return (0); 130324145Smm 131324145Smm prefix = archive_le32dec(buffer); 132324145Smm if (prefix == zstd_magic) 133324145Smm return (32); 134362134Smm if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start) 135362134Smm return (32); 136324145Smm 137324145Smm return (0); 138324145Smm} 139324145Smm 140324145Smm#if !(HAVE_ZSTD_H && HAVE_LIBZSTD) 141324145Smm 142324145Smm/* 143324145Smm * If we don't have the library on this system, we can't do the 144324145Smm * decompression directly. We can, however, try to run "zstd -d" 145324145Smm * in case that's available. 146324145Smm */ 147324145Smmstatic int 148324145Smmzstd_bidder_init(struct archive_read_filter *self) 149324145Smm{ 150324145Smm int r; 151324145Smm 152324145Smm r = __archive_read_program(self, "zstd -d -qq"); 153324145Smm /* Note: We set the format here even if __archive_read_program() 154324145Smm * above fails. We do, after all, know what the format is 155324145Smm * even if we weren't able to read it. */ 156324145Smm self->code = ARCHIVE_FILTER_ZSTD; 157324145Smm self->name = "zstd"; 158324145Smm return (r); 159324145Smm} 160324145Smm 161324145Smm#else 162324145Smm 163324145Smm/* 164324145Smm * Initialize the filter object 165324145Smm */ 166324145Smmstatic int 167324145Smmzstd_bidder_init(struct archive_read_filter *self) 168324145Smm{ 169324145Smm struct private_data *state; 170324145Smm const size_t out_block_size = ZSTD_DStreamOutSize(); 171324145Smm void *out_block; 172324145Smm ZSTD_DStream *dstream; 173324145Smm 174324145Smm self->code = ARCHIVE_FILTER_ZSTD; 175324145Smm self->name = "zstd"; 176324145Smm 177324145Smm state = (struct private_data *)calloc(sizeof(*state), 1); 178324145Smm out_block = (unsigned char *)malloc(out_block_size); 179324145Smm dstream = ZSTD_createDStream(); 180324145Smm 181324145Smm if (state == NULL || out_block == NULL || dstream == NULL) { 182324145Smm free(out_block); 183324145Smm free(state); 184324145Smm ZSTD_freeDStream(dstream); /* supports free on NULL */ 185324145Smm archive_set_error(&self->archive->archive, ENOMEM, 186324145Smm "Can't allocate data for zstd decompression"); 187324145Smm return (ARCHIVE_FATAL); 188324145Smm } 189324145Smm 190324145Smm self->data = state; 191324145Smm 192324145Smm state->out_block_size = out_block_size; 193324145Smm state->out_block = out_block; 194324145Smm state->dstream = dstream; 195324145Smm self->read = zstd_filter_read; 196324145Smm self->skip = NULL; /* not supported */ 197324145Smm self->close = zstd_filter_close; 198324145Smm 199324145Smm state->eof = 0; 200324145Smm state->in_frame = 0; 201324145Smm 202324145Smm return (ARCHIVE_OK); 203324145Smm} 204324145Smm 205324145Smmstatic ssize_t 206324145Smmzstd_filter_read(struct archive_read_filter *self, const void **p) 207324145Smm{ 208324145Smm struct private_data *state; 209324145Smm size_t decompressed; 210324145Smm ssize_t avail_in; 211324145Smm ZSTD_outBuffer out; 212324145Smm ZSTD_inBuffer in; 213324145Smm 214324145Smm state = (struct private_data *)self->data; 215324145Smm 216324145Smm out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 }; 217324145Smm 218324145Smm /* Try to fill the output buffer. */ 219324145Smm while (out.pos < out.size && !state->eof) { 220324145Smm if (!state->in_frame) { 221324145Smm const size_t ret = ZSTD_initDStream(state->dstream); 222324145Smm if (ZSTD_isError(ret)) { 223324145Smm archive_set_error(&self->archive->archive, 224324145Smm ARCHIVE_ERRNO_MISC, 225324145Smm "Error initializing zstd decompressor: %s", 226324145Smm ZSTD_getErrorName(ret)); 227324145Smm return (ARCHIVE_FATAL); 228324145Smm } 229324145Smm } 230324145Smm in.src = __archive_read_filter_ahead(self->upstream, 1, 231324145Smm &avail_in); 232324145Smm if (avail_in < 0) { 233324145Smm return avail_in; 234324145Smm } 235324145Smm if (in.src == NULL && avail_in == 0) { 236324145Smm if (!state->in_frame) { 237324145Smm /* end of stream */ 238324145Smm state->eof = 1; 239324145Smm break; 240324145Smm } else { 241324145Smm archive_set_error(&self->archive->archive, 242324145Smm ARCHIVE_ERRNO_MISC, 243324145Smm "Truncated zstd input"); 244324145Smm return (ARCHIVE_FATAL); 245324145Smm } 246324145Smm } 247324145Smm in.size = avail_in; 248324145Smm in.pos = 0; 249324145Smm 250324145Smm { 251324145Smm const size_t ret = 252324145Smm ZSTD_decompressStream(state->dstream, &out, &in); 253324145Smm 254324145Smm if (ZSTD_isError(ret)) { 255324145Smm archive_set_error(&self->archive->archive, 256324145Smm ARCHIVE_ERRNO_MISC, 257324145Smm "Zstd decompression failed: %s", 258324145Smm ZSTD_getErrorName(ret)); 259324145Smm return (ARCHIVE_FATAL); 260324145Smm } 261324145Smm 262324145Smm /* Decompressor made some progress */ 263324145Smm __archive_read_filter_consume(self->upstream, in.pos); 264324145Smm 265324145Smm /* ret guaranteed to be > 0 if frame isn't done yet */ 266324145Smm state->in_frame = (ret != 0); 267324145Smm } 268324145Smm } 269324145Smm 270324145Smm decompressed = out.pos; 271324145Smm state->total_out += decompressed; 272324145Smm if (decompressed == 0) 273324145Smm *p = NULL; 274324145Smm else 275324145Smm *p = state->out_block; 276324145Smm return (decompressed); 277324145Smm} 278324145Smm 279324145Smm/* 280324145Smm * Clean up the decompressor. 281324145Smm */ 282324145Smmstatic int 283324145Smmzstd_filter_close(struct archive_read_filter *self) 284324145Smm{ 285324145Smm struct private_data *state; 286324145Smm 287324145Smm state = (struct private_data *)self->data; 288324145Smm 289324145Smm ZSTD_freeDStream(state->dstream); 290324145Smm free(state->out_block); 291324145Smm free(state); 292324145Smm 293324145Smm return (ARCHIVE_OK); 294324145Smm} 295324145Smm 296324145Smm#endif /* HAVE_ZLIB_H && HAVE_LIBZSTD */ 297