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