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@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