Home | History | Annotate | Line # | Download | only in common
      1 // SPDX-License-Identifier: 0BSD
      2 
      3 ///////////////////////////////////////////////////////////////////////////////
      4 //
      5 /// \file       common.c
      6 /// \brief      Common functions needed in many places in liblzma
      7 //
      8 //  Author:     Lasse Collin
      9 //
     10 ///////////////////////////////////////////////////////////////////////////////
     11 
     12 #include "common.h"
     13 
     14 
     15 /////////////
     16 // Version //
     17 /////////////
     18 
     19 extern LZMA_API(uint32_t)
     20 lzma_version_number(void)
     21 {
     22 	return LZMA_VERSION;
     23 }
     24 
     25 
     26 extern LZMA_API(const char *)
     27 lzma_version_string(void)
     28 {
     29 	return LZMA_VERSION_STRING;
     30 }
     31 
     32 
     33 ///////////////////////
     34 // Memory allocation //
     35 ///////////////////////
     36 
     37 lzma_attr_alloc_size(1)
     38 extern void *
     39 lzma_alloc(size_t size, const lzma_allocator *allocator)
     40 {
     41 	// Some malloc() variants return NULL if called with size == 0.
     42 	if (size == 0)
     43 		size = 1;
     44 
     45 	void *ptr;
     46 
     47 	if (allocator != NULL && allocator->alloc != NULL)
     48 		ptr = allocator->alloc(allocator->opaque, 1, size);
     49 	else
     50 		ptr = malloc(size);
     51 
     52 	return ptr;
     53 }
     54 
     55 
     56 lzma_attr_alloc_size(1)
     57 extern void *
     58 lzma_alloc_zero(size_t size, const lzma_allocator *allocator)
     59 {
     60 	// Some calloc() variants return NULL if called with size == 0.
     61 	if (size == 0)
     62 		size = 1;
     63 
     64 	void *ptr;
     65 
     66 	if (allocator != NULL && allocator->alloc != NULL) {
     67 		ptr = allocator->alloc(allocator->opaque, 1, size);
     68 		if (ptr != NULL)
     69 			memzero(ptr, size);
     70 	} else {
     71 		ptr = calloc(1, size);
     72 	}
     73 
     74 	return ptr;
     75 }
     76 
     77 
     78 extern void
     79 lzma_free(void *ptr, const lzma_allocator *allocator)
     80 {
     81 	if (allocator != NULL && allocator->free != NULL)
     82 		allocator->free(allocator->opaque, ptr);
     83 	else
     84 		free(ptr);
     85 
     86 	return;
     87 }
     88 
     89 
     90 //////////
     91 // Misc //
     92 //////////
     93 
     94 extern size_t
     95 lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
     96 		size_t in_size, uint8_t *restrict out,
     97 		size_t *restrict out_pos, size_t out_size)
     98 {
     99 	assert(in != NULL || *in_pos == in_size);
    100 	assert(out != NULL || *out_pos == out_size);
    101 
    102 	assert(*in_pos <= in_size);
    103 	assert(*out_pos <= out_size);
    104 
    105 	const size_t in_avail = in_size - *in_pos;
    106 	const size_t out_avail = out_size - *out_pos;
    107 	const size_t copy_size = my_min(in_avail, out_avail);
    108 
    109 	// Call memcpy() only if there is something to copy. If there is
    110 	// nothing to copy, in or out might be NULL and then the memcpy()
    111 	// call would trigger undefined behavior.
    112 	if (copy_size > 0)
    113 		memcpy(out + *out_pos, in + *in_pos, copy_size);
    114 
    115 	*in_pos += copy_size;
    116 	*out_pos += copy_size;
    117 
    118 	return copy_size;
    119 }
    120 
    121 
    122 extern lzma_ret
    123 lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator,
    124 		const lzma_filter_info *filters)
    125 {
    126 	lzma_next_coder_init(filters[0].init, next, allocator);
    127 	next->id = filters[0].id;
    128 	return filters[0].init == NULL
    129 			? LZMA_OK : filters[0].init(next, allocator, filters);
    130 }
    131 
    132 
    133 extern lzma_ret
    134 lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator,
    135 		const lzma_filter *reversed_filters)
    136 {
    137 	// Check that the application isn't trying to change the Filter ID.
    138 	// End of filters is indicated with LZMA_VLI_UNKNOWN in both
    139 	// reversed_filters[0].id and next->id.
    140 	if (reversed_filters[0].id != next->id)
    141 		return LZMA_PROG_ERROR;
    142 
    143 	if (reversed_filters[0].id == LZMA_VLI_UNKNOWN)
    144 		return LZMA_OK;
    145 
    146 	assert(next->update != NULL);
    147 	return next->update(next->coder, allocator, NULL, reversed_filters);
    148 }
    149 
    150 
    151 extern void
    152 lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
    153 {
    154 	if (next->init != (uintptr_t)(NULL)) {
    155 		// To avoid tiny end functions that simply call
    156 		// lzma_free(coder, allocator), we allow leaving next->end
    157 		// NULL and call lzma_free() here.
    158 		if (next->end != NULL)
    159 			next->end(next->coder, allocator);
    160 		else
    161 			lzma_free(next->coder, allocator);
    162 
    163 		// Reset the variables so the we don't accidentally think
    164 		// that it is an already initialized coder.
    165 		*next = LZMA_NEXT_CODER_INIT;
    166 	}
    167 
    168 	return;
    169 }
    170 
    171 
    172 //////////////////////////////////////
    173 // External to internal API wrapper //
    174 //////////////////////////////////////
    175 
    176 extern lzma_ret
    177 lzma_strm_init(lzma_stream *strm)
    178 {
    179 	if (strm == NULL)
    180 		return LZMA_PROG_ERROR;
    181 
    182 	if (strm->internal == NULL) {
    183 		strm->internal = lzma_alloc(sizeof(lzma_internal),
    184 				strm->allocator);
    185 		if (strm->internal == NULL)
    186 			return LZMA_MEM_ERROR;
    187 
    188 		strm->internal->next = LZMA_NEXT_CODER_INIT;
    189 	}
    190 
    191 	memzero(strm->internal->supported_actions,
    192 			sizeof(strm->internal->supported_actions));
    193 	strm->internal->sequence = ISEQ_RUN;
    194 	strm->internal->allow_buf_error = false;
    195 
    196 	strm->total_in = 0;
    197 	strm->total_out = 0;
    198 
    199 	return LZMA_OK;
    200 }
    201 
    202 
    203 extern LZMA_API(lzma_ret)
    204 lzma_code(lzma_stream *strm, lzma_action action)
    205 {
    206 	// Sanity checks
    207 	if ((strm->next_in == NULL && strm->avail_in != 0)
    208 			|| (strm->next_out == NULL && strm->avail_out != 0)
    209 			|| strm->internal == NULL
    210 			|| strm->internal->next.code == NULL
    211 			|| (unsigned int)(action) > LZMA_ACTION_MAX
    212 			|| !strm->internal->supported_actions[action])
    213 		return LZMA_PROG_ERROR;
    214 
    215 	// Check if unsupported members have been set to non-zero or non-NULL,
    216 	// which would indicate that some new feature is wanted.
    217 	if (strm->reserved_ptr1 != NULL
    218 			|| strm->reserved_ptr2 != NULL
    219 			|| strm->reserved_ptr3 != NULL
    220 			|| strm->reserved_ptr4 != NULL
    221 			|| strm->reserved_int2 != 0
    222 			|| strm->reserved_int3 != 0
    223 			|| strm->reserved_int4 != 0
    224 			|| strm->reserved_enum1 != LZMA_RESERVED_ENUM
    225 			|| strm->reserved_enum2 != LZMA_RESERVED_ENUM)
    226 		return LZMA_OPTIONS_ERROR;
    227 
    228 	switch (strm->internal->sequence) {
    229 	case ISEQ_RUN:
    230 		switch (action) {
    231 		case LZMA_RUN:
    232 			break;
    233 
    234 		case LZMA_SYNC_FLUSH:
    235 			strm->internal->sequence = ISEQ_SYNC_FLUSH;
    236 			break;
    237 
    238 		case LZMA_FULL_FLUSH:
    239 			strm->internal->sequence = ISEQ_FULL_FLUSH;
    240 			break;
    241 
    242 		case LZMA_FINISH:
    243 			strm->internal->sequence = ISEQ_FINISH;
    244 			break;
    245 
    246 		case LZMA_FULL_BARRIER:
    247 			strm->internal->sequence = ISEQ_FULL_BARRIER;
    248 			break;
    249 		}
    250 
    251 		break;
    252 
    253 	case ISEQ_SYNC_FLUSH:
    254 		// The same action must be used until we return
    255 		// LZMA_STREAM_END, and the amount of input must not change.
    256 		if (action != LZMA_SYNC_FLUSH
    257 				|| strm->internal->avail_in != strm->avail_in)
    258 			return LZMA_PROG_ERROR;
    259 
    260 		break;
    261 
    262 	case ISEQ_FULL_FLUSH:
    263 		if (action != LZMA_FULL_FLUSH
    264 				|| strm->internal->avail_in != strm->avail_in)
    265 			return LZMA_PROG_ERROR;
    266 
    267 		break;
    268 
    269 	case ISEQ_FINISH:
    270 		if (action != LZMA_FINISH
    271 				|| strm->internal->avail_in != strm->avail_in)
    272 			return LZMA_PROG_ERROR;
    273 
    274 		break;
    275 
    276 	case ISEQ_FULL_BARRIER:
    277 		if (action != LZMA_FULL_BARRIER
    278 				|| strm->internal->avail_in != strm->avail_in)
    279 			return LZMA_PROG_ERROR;
    280 
    281 		break;
    282 
    283 	case ISEQ_END:
    284 		return LZMA_STREAM_END;
    285 
    286 	case ISEQ_ERROR:
    287 	default:
    288 		return LZMA_PROG_ERROR;
    289 	}
    290 
    291 	size_t in_pos = 0;
    292 	size_t out_pos = 0;
    293 	lzma_ret ret = strm->internal->next.code(
    294 			strm->internal->next.coder, strm->allocator,
    295 			strm->next_in, &in_pos, strm->avail_in,
    296 			strm->next_out, &out_pos, strm->avail_out, action);
    297 
    298 	// Updating next_in and next_out has to be skipped when they are NULL
    299 	// to avoid null pointer + 0 (undefined behavior). Do this by checking
    300 	// in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug)
    301 	// will get caught one way or other.
    302 	if (in_pos > 0) {
    303 		strm->next_in += in_pos;
    304 		strm->avail_in -= in_pos;
    305 		strm->total_in += in_pos;
    306 	}
    307 
    308 	if (out_pos > 0) {
    309 		strm->next_out += out_pos;
    310 		strm->avail_out -= out_pos;
    311 		strm->total_out += out_pos;
    312 	}
    313 
    314 	strm->internal->avail_in = strm->avail_in;
    315 
    316 	switch (ret) {
    317 	case LZMA_OK:
    318 		// Don't return LZMA_BUF_ERROR when it happens the first time.
    319 		// This is to avoid returning LZMA_BUF_ERROR when avail_out
    320 		// was zero but still there was no more data left to written
    321 		// to next_out.
    322 		if (out_pos == 0 && in_pos == 0) {
    323 			if (strm->internal->allow_buf_error)
    324 				ret = LZMA_BUF_ERROR;
    325 			else
    326 				strm->internal->allow_buf_error = true;
    327 		} else {
    328 			strm->internal->allow_buf_error = false;
    329 		}
    330 		break;
    331 
    332 	case LZMA_TIMED_OUT:
    333 		strm->internal->allow_buf_error = false;
    334 		ret = LZMA_OK;
    335 		break;
    336 
    337 	case LZMA_SEEK_NEEDED:
    338 		strm->internal->allow_buf_error = false;
    339 
    340 		// If LZMA_FINISH was used, reset it back to the
    341 		// LZMA_RUN-based state so that new input can be supplied
    342 		// by the application.
    343 		if (strm->internal->sequence == ISEQ_FINISH)
    344 			strm->internal->sequence = ISEQ_RUN;
    345 
    346 		break;
    347 
    348 	case LZMA_STREAM_END:
    349 		if (strm->internal->sequence == ISEQ_SYNC_FLUSH
    350 				|| strm->internal->sequence == ISEQ_FULL_FLUSH
    351 				|| strm->internal->sequence
    352 					== ISEQ_FULL_BARRIER)
    353 			strm->internal->sequence = ISEQ_RUN;
    354 		else
    355 			strm->internal->sequence = ISEQ_END;
    356 
    357 		FALLTHROUGH;
    358 
    359 	case LZMA_NO_CHECK:
    360 	case LZMA_UNSUPPORTED_CHECK:
    361 	case LZMA_GET_CHECK:
    362 	case LZMA_MEMLIMIT_ERROR:
    363 		// Something else than LZMA_OK, but not a fatal error,
    364 		// that is, coding may be continued (except if ISEQ_END).
    365 		strm->internal->allow_buf_error = false;
    366 		break;
    367 
    368 	default:
    369 		// All the other errors are fatal; coding cannot be continued.
    370 		assert(ret != LZMA_BUF_ERROR);
    371 		strm->internal->sequence = ISEQ_ERROR;
    372 		break;
    373 	}
    374 
    375 	return ret;
    376 }
    377 
    378 
    379 extern LZMA_API(void)
    380 lzma_end(lzma_stream *strm)
    381 {
    382 	if (strm != NULL && strm->internal != NULL) {
    383 		lzma_next_end(&strm->internal->next, strm->allocator);
    384 		lzma_free(strm->internal, strm->allocator);
    385 		strm->internal = NULL;
    386 	}
    387 
    388 	return;
    389 }
    390 
    391 
    392 #ifdef HAVE_SYMBOL_VERSIONS_LINUX
    393 // This is for compatibility with binaries linked against liblzma that
    394 // has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
    395 LZMA_SYMVER_API("lzma_get_progress (at) XZ_5.2.2",
    396 	void, lzma_get_progress_522)(lzma_stream *strm,
    397 		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow
    398 		__attribute__((__alias__("lzma_get_progress_52")));
    399 
    400 LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2",
    401 	void, lzma_get_progress_52)(lzma_stream *strm,
    402 		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
    403 
    404 #define lzma_get_progress lzma_get_progress_52
    405 #endif
    406 extern LZMA_API(void)
    407 lzma_get_progress(lzma_stream *strm,
    408 		uint64_t *progress_in, uint64_t *progress_out)
    409 {
    410 	if (strm->internal->next.get_progress != NULL) {
    411 		strm->internal->next.get_progress(strm->internal->next.coder,
    412 				progress_in, progress_out);
    413 	} else {
    414 		*progress_in = strm->total_in;
    415 		*progress_out = strm->total_out;
    416 	}
    417 
    418 	return;
    419 }
    420 
    421 
    422 extern LZMA_API(lzma_check)
    423 lzma_get_check(const lzma_stream *strm)
    424 {
    425 	// Return LZMA_CHECK_NONE if we cannot know the check type.
    426 	// It's a bug in the application if this happens.
    427 	if (strm->internal->next.get_check == NULL)
    428 		return LZMA_CHECK_NONE;
    429 
    430 	return strm->internal->next.get_check(strm->internal->next.coder);
    431 }
    432 
    433 
    434 extern LZMA_API(uint64_t)
    435 lzma_memusage(const lzma_stream *strm)
    436 {
    437 	uint64_t memusage;
    438 	uint64_t old_memlimit;
    439 
    440 	if (strm == NULL || strm->internal == NULL
    441 			|| strm->internal->next.memconfig == NULL
    442 			|| strm->internal->next.memconfig(
    443 				strm->internal->next.coder,
    444 				&memusage, &old_memlimit, 0) != LZMA_OK)
    445 		return 0;
    446 
    447 	return memusage;
    448 }
    449 
    450 
    451 extern LZMA_API(uint64_t)
    452 lzma_memlimit_get(const lzma_stream *strm)
    453 {
    454 	uint64_t old_memlimit;
    455 	uint64_t memusage;
    456 
    457 	if (strm == NULL || strm->internal == NULL
    458 			|| strm->internal->next.memconfig == NULL
    459 			|| strm->internal->next.memconfig(
    460 				strm->internal->next.coder,
    461 				&memusage, &old_memlimit, 0) != LZMA_OK)
    462 		return 0;
    463 
    464 	return old_memlimit;
    465 }
    466 
    467 
    468 extern LZMA_API(lzma_ret)
    469 lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
    470 {
    471 	// Dummy variables to simplify memconfig functions
    472 	uint64_t old_memlimit;
    473 	uint64_t memusage;
    474 
    475 	if (strm == NULL || strm->internal == NULL
    476 			|| strm->internal->next.memconfig == NULL)
    477 		return LZMA_PROG_ERROR;
    478 
    479 	// Zero is a special value that cannot be used as an actual limit.
    480 	// If 0 was specified, use 1 instead.
    481 	if (new_memlimit == 0)
    482 		new_memlimit = 1;
    483 
    484 	return strm->internal->next.memconfig(strm->internal->next.coder,
    485 			&memusage, &old_memlimit, new_memlimit);
    486 }
    487