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