A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 875 lines 21 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2021 by James Buren 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "zip.h" 23#include "string-extra.h" 24#include "file.h" 25#include "dir.h" 26#include "system.h" 27#include "errno.h" 28#include "core_alloc.h" 29#include "timefuncs.h" 30#include "pathfuncs.h" 31#include "crc32.h" 32#include "rbendian.h" 33 34#define zip_core_alloc(N) core_alloc_ex((N),&buflib_ops_locked) 35 36enum { 37 ZIP_SIG_ED = 0x06054b50, 38 ZIP_SIG_CD = 0x02014b50, 39 ZIP_SIG_LF = 0x04034b50, 40 ZIP_BIT_DD = 0x0008, 41 ZIP_METHOD_STORE = 0x0000, 42 ZIP_MAX_LENGTH = 0xffff, 43 ZIP_BUFFER_SIZE = 4096, 44}; 45 46enum { 47 ZIP_STATE_INITIAL, 48 ZIP_STATE_ED_ENTER, 49 ZIP_STATE_ED_EXIT, 50 ZIP_STATE_CD_ENTER, 51 ZIP_STATE_CD_EXIT, 52 ZIP_STATE_LF_ENTER, 53 ZIP_STATE_LF_EXIT, 54}; 55 56struct zip_ed_disk { 57 uint32_t signature; 58 uint16_t disk_number; 59 uint16_t disk_number_cd; 60 uint16_t disk_entries_cd; 61 uint16_t cd_entries; 62 uint32_t cd_size; 63 uint32_t cd_offset; 64 uint16_t comment_length; 65 // comment block (variable length) 66} __attribute__((packed)); 67 68struct zip_ed { 69 uint32_t cd_size; 70 uint32_t cd_offset; 71 uint16_t cd_entries; 72}; 73 74struct zip_cd_disk { 75 uint32_t signature; 76 uint16_t version_madeby; 77 uint16_t version_needed; 78 uint16_t flags; 79 uint16_t method; 80 uint16_t time; 81 uint16_t date; 82 uint32_t crc; 83 uint32_t compressed_size; 84 uint32_t uncompressed_size; 85 uint16_t name_length; 86 uint16_t extra_length; 87 uint16_t comment_length; 88 uint16_t disk_number; 89 uint16_t internal_attributes; 90 uint32_t external_attributes; 91 uint32_t lf_offset; 92 // name block (variable length) 93 // extra block (variable length) 94 // comment block (variable length) 95} __attribute__((packed)); 96 97struct zip_cd { 98 uint32_t crc; 99 uint32_t compressed_size; 100 uint32_t uncompressed_size; 101 uint32_t lf_offset; 102}; 103 104struct zip_lf_disk { 105 uint32_t signature; 106 uint16_t version_needed; 107 uint16_t flags; 108 uint16_t method; 109 uint16_t time; 110 uint16_t date; 111 uint32_t crc; 112 uint32_t compressed_size; 113 uint32_t uncompressed_size; 114 uint16_t name_length; 115 uint16_t extra_length; 116 // name block (variable length) 117 // extra block (variable length) 118} __attribute__((packed)); 119 120struct zip_lf { 121 uint16_t flags; 122 uint16_t method; 123 uint16_t time; 124 uint16_t date; 125 uint32_t crc; 126 uint32_t compressed_size; 127 uint32_t uncompressed_size; 128 uint16_t name_length; 129 char name[MAX_PATH]; 130}; 131 132struct zip { 133 ssize_t (*read) (struct zip*, void*, size_t); 134 off_t (*seek) (struct zip*, off_t, int); 135 off_t (*size) (struct zip*); 136 void (*close) (struct zip*); 137 int zip_handle; 138 int state; 139 zip_callback cb; 140 struct zip_args args; 141 void* ctx; 142 struct zip_ed ed; 143 int cds_handle; 144 struct zip_cd* cds; 145 struct zip_lf lf; 146}; 147 148struct zip_file { 149 struct zip base; 150 int file; 151}; 152 153struct zip_mem { 154 struct zip base; 155 int mem_handle; 156 const uint8_t* mem; 157 off_t mem_offset; 158 off_t mem_size; 159}; 160 161struct zip_extract { 162 zip_callback cb; 163 void* ctx; 164 size_t name_offset; 165 size_t name_size; 166 char* name; 167 int file; 168 char path[MAX_PATH]; 169}; 170 171static int zip_read_ed(struct zip* z) { 172 const off_t file_size = z->size(z); 173 const off_t max_size = sizeof(struct zip_ed_disk) + ZIP_MAX_LENGTH; 174 const off_t read_size = MIN(file_size, max_size); 175 const uint32_t sig = htole32(ZIP_SIG_ED); 176 int mem_handle = -1; 177 uint8_t* mem; 178 off_t i = read_size - sizeof(struct zip_ed_disk); 179 const struct zip_ed_disk* edd; 180 uint16_t disk_number; 181 uint16_t disk_number_cd; 182 uint16_t disk_entries_cd; 183 uint16_t cd_entries; 184 struct zip_ed* ed = &z->ed; 185 int rv; 186 187 z->state = ZIP_STATE_ED_ENTER; 188 189 if (file_size < (off_t) sizeof(struct zip_ed_disk)) { 190 rv = -2; 191 goto bail; 192 } 193 194 if ((mem_handle = zip_core_alloc(read_size)) < 0) { 195 rv = -3; 196 goto bail; 197 } 198 199 mem = core_get_data(mem_handle); 200 201 if (z->seek(z, -read_size, SEEK_END) < 0) { 202 rv = -4; 203 goto bail; 204 } 205 206 if (z->read(z, mem, read_size) != read_size) { 207 rv = -5; 208 goto bail; 209 } 210 211 for (; i >= 0; i--) 212 if (memcmp(mem + i, &sig, sizeof(uint32_t)) == 0) 213 break; 214 215 if (i < 0) { 216 rv = -6; 217 goto bail; 218 } 219 220 edd = (struct zip_ed_disk*) (mem + i); 221 disk_number = letoh16(edd->disk_number); 222 disk_number_cd = letoh16(edd->disk_number_cd); 223 disk_entries_cd = letoh16(edd->disk_entries_cd); 224 cd_entries = letoh16(edd->cd_entries); 225 226 if (disk_number != 0 || disk_number_cd != 0 || disk_entries_cd != cd_entries) { 227 rv = -7; 228 goto bail; 229 } 230 231 ed->cd_size = letoh32(edd->cd_size); 232 ed->cd_offset = letoh32(edd->cd_offset); 233 ed->cd_entries = cd_entries; 234 235 z->state = ZIP_STATE_ED_EXIT; 236 rv = 0; 237 238bail: 239 core_free(mem_handle); 240 return rv; 241} 242 243static int zip_read_cd(struct zip* z, bool use_cb) { 244 const struct zip_ed* ed = &z->ed; 245 const uint32_t cd_size = ed->cd_size; 246 const uint32_t cd_offset = ed->cd_offset; 247 const uint16_t cd_entries = ed->cd_entries; 248 const uint32_t sig = htole32(ZIP_SIG_CD); 249 int cds_handle = -1; 250 int mem_handle = -1; 251 struct zip_cd* cds; 252 uint8_t* mem; 253 struct zip_lf* lf = &z->lf; 254 struct zip_args* args = &z->args; 255 struct zip_cd_disk* cdd; 256 struct zip_cd* cd; 257 uint16_t name_length; 258 int rv; 259 260 z->state = ZIP_STATE_CD_ENTER; 261 262 if ((cds_handle = zip_core_alloc(sizeof(struct zip_cd) * cd_entries)) < 0) { 263 rv = -7; 264 goto bail; 265 } 266 267 if ((mem_handle = zip_core_alloc(cd_size)) < 0) { 268 rv = -8; 269 goto bail; 270 } 271 272 cds = core_get_data(cds_handle); 273 mem = core_get_data(mem_handle); 274 275 if (z->seek(z, cd_offset, SEEK_SET) < 0) { 276 rv = -9; 277 goto bail; 278 } 279 280 if (z->read(z, mem, cd_size) != (ssize_t) cd_size) { 281 rv = -10; 282 goto bail; 283 } 284 285 if (use_cb) { 286 args->entries = cd_entries; 287 args->name = lf->name; 288 args->block = NULL; 289 args->block_size = 0; 290 args->read_size = 0; 291 } 292 293 cdd = (struct zip_cd_disk*) mem; 294 295 for (uint16_t i = 0; i < cd_entries; i++) { 296 if (cdd->signature != sig) { 297 rv = -11; 298 goto bail; 299 } 300 301 cd = &cds[i]; 302 303 cd->crc = letoh32(cdd->crc); 304 cd->compressed_size = letoh32(cdd->compressed_size); 305 cd->uncompressed_size = letoh32(cdd->uncompressed_size); 306 cd->lf_offset = letoh32(cdd->lf_offset); 307 308 mem += sizeof(struct zip_cd_disk); 309 name_length = letoh16(cdd->name_length); 310 if (use_cb) { 311 if (name_length >= sizeof(lf->name)) { 312 rv = -12; 313 goto bail; 314 } 315 316 args->entry = i + 1; 317 args->file_size = cd->uncompressed_size; 318 args->mtime = dostime_mktime(letoh16(cdd->date), letoh16(cdd->time)); 319 320 memcpy(lf->name, mem, name_length); 321 lf->name[name_length] = '\0'; 322 323 if ((rv = z->cb(args, ZIP_PASS_SHALLOW, z->ctx)) > 0) 324 goto bail; 325 } 326 mem += name_length; 327 mem += letoh16(cdd->extra_length); 328 mem += letoh16(cdd->comment_length); 329 cdd = (struct zip_cd_disk*) mem; 330 } 331 332 z->cds_handle = cds_handle; 333 z->cds = cds; 334 z->state = ZIP_STATE_CD_EXIT; 335 rv = 0; 336 337bail: 338 if (rv != 0) 339 core_free(cds_handle); 340 core_free(mem_handle); 341 return rv; 342} 343 344static int zip_read_lf(struct zip* z, uint16_t i) { 345 const uint32_t sig = htole32(ZIP_SIG_LF); 346 const struct zip_cd* cd = &z->cds[i]; 347 struct zip_lf* lf = &z->lf; 348 struct zip_lf_disk lfd; 349 uint16_t name_length; 350 351 if (z->seek(z, cd->lf_offset, SEEK_SET) < 0) 352 return -14; 353 354 if (z->read(z, &lfd, sizeof(struct zip_lf_disk)) != sizeof(struct zip_lf_disk)) 355 return -15; 356 357 if (lfd.signature != sig) 358 return -16; 359 360 name_length = letoh16(lfd.name_length); 361 362 if (name_length >= sizeof(lf->name)) 363 return -17; 364 365 if (z->read(z, lf->name, name_length) != name_length) 366 return -18; 367 368 if (z->seek(z, letoh16(lfd.extra_length), SEEK_CUR) < 0) 369 return -19; 370 371 lf->flags = letoh16(lfd.flags); 372 lf->method = letoh16(lfd.method); 373 lf->time = letoh16(lfd.time); 374 lf->date = letoh16(lfd.date); 375 lf->crc = letoh32(lfd.crc); 376 lf->compressed_size = letoh32(lfd.compressed_size); 377 lf->uncompressed_size = letoh32(lfd.uncompressed_size); 378 lf->name_length = name_length; 379 lf->name[name_length] = '\0'; 380 381 if ((lf->flags & ZIP_BIT_DD) == ZIP_BIT_DD) { 382 lf->crc = cd->crc; 383 lf->compressed_size = cd->compressed_size; 384 lf->uncompressed_size = cd->uncompressed_size; 385 } 386 387 return 0; 388} 389 390static int zip_read_store(struct zip* z, void* mem, uint32_t mem_size) { 391 const struct zip_lf* lf = &z->lf; 392 struct zip_args* args = &z->args; 393 uint32_t file_size = lf->uncompressed_size; 394 uint32_t block_size = mem_size; 395 uint32_t crc = 0xffffffff; 396 int rv; 397 398 if (lf->compressed_size != lf->uncompressed_size) 399 return -21; 400 401 args->block = mem; 402 args->block_size = block_size; 403 args->read_size = 0; 404 405 do { 406 if (block_size > file_size) { 407 args->block_size = block_size = file_size; 408 } 409 410 if (z->read(z, mem, block_size) != (off_t) block_size) 411 return -22; 412 413 args->read_size += block_size; 414 crc = crc_32r(mem, block_size, crc); 415 416 if ((rv = z->cb(args, ZIP_PASS_DATA, z->ctx)) != 0) 417 return (rv < 0) ? 0 : rv; 418 419 file_size -= block_size; 420 } while (file_size > 0); 421 422 if (~crc != lf->crc) 423 return -24; 424 425 return 0; 426} 427 428static int zip_read_entry(struct zip* z, uint16_t i, void* mem, uint32_t mem_size) { 429 const struct zip_lf* lf = &z->lf; 430 struct zip_args* args = &z->args; 431 int rv; 432 433 if ((rv = zip_read_lf(z, i)) != 0) 434 return rv; 435 436 args->entry = i + 1; 437 args->file_size = lf->uncompressed_size; 438 args->mtime = dostime_mktime(lf->date, lf->time); 439 args->block = NULL; 440 args->block_size = 0; 441 args->read_size = 0; 442 443 if ((rv = z->cb(&z->args, ZIP_PASS_START, z->ctx)) != 0) 444 return (rv < 0) ? 0 : rv; 445 446 if (lf->uncompressed_size == 0) 447 goto skip_data; 448 449 if (lf->method == ZIP_METHOD_STORE) { 450 if ((rv = zip_read_store(z, mem, mem_size)) != 0) 451 return rv; 452 } else { 453 return -20; 454 } 455 456skip_data: 457 args->block = NULL; 458 args->block_size = 0; 459 args->read_size = 0; 460 461 if ((rv = z->cb(args, ZIP_PASS_END, z->ctx)) != 0) 462 return (rv < 0) ? 0 : rv; 463 464 return 0; 465} 466 467static int zip_read_entries(struct zip* z) { 468 const struct zip_ed* ed = &z->ed; 469 const uint16_t cd_entries = ed->cd_entries; 470 struct zip_lf* lf = &z->lf; 471 struct zip_args* args = &z->args; 472 uint32_t mem_size = ZIP_BUFFER_SIZE; 473 int mem_handle; 474 void* mem; 475 int rv; 476 477 z->state = ZIP_STATE_LF_ENTER; 478 479 if ((mem_handle = zip_core_alloc(mem_size)) < 0) { 480 rv = -13; 481 goto bail; 482 } 483 484 mem = core_get_data(mem_handle); 485 486 args->entries = cd_entries; 487 args->name = lf->name; 488 489 for (uint16_t i = 0; i < cd_entries; i++) 490 if ((rv = zip_read_entry(z, i, mem, mem_size)) > 0) 491 goto bail; 492 493 z->state = ZIP_STATE_LF_EXIT; 494 rv = 0; 495 496bail: 497 core_free(mem_handle); 498 return rv; 499} 500 501static void zip_init(struct zip* z, int zip_handle) { 502 z->zip_handle = zip_handle; 503 z->state = ZIP_STATE_INITIAL; 504 z->cb = NULL; 505 memset(&z->args, 0, sizeof(struct zip_args)); 506 z->ctx = NULL; 507 memset(&z->ed, 0, sizeof(struct zip_ed)); 508 z->cds_handle = -1; 509 z->cds = NULL; 510 memset(&z->lf, 0, sizeof(struct zip_lf)); 511} 512 513static ssize_t zip_file_read(struct zip* zh, void* mem, size_t mem_size) { 514 struct zip_file* z = (struct zip_file*) zh; 515 516 return read(z->file, mem, mem_size); 517} 518 519static off_t zip_file_seek(struct zip* zh, off_t offset, int whence) { 520 struct zip_file* z = (struct zip_file*) zh; 521 522 return lseek(z->file, offset, whence); 523} 524 525static off_t zip_file_size(struct zip* zh) { 526 struct zip_file* z = (struct zip_file*) zh; 527 528 return filesize(z->file); 529} 530 531static void zip_file_close(struct zip* zh) { 532 struct zip_file* z = (struct zip_file*) zh; 533 534 close(z->file); 535} 536 537static void zip_file_init(struct zip_file* z, int zip_handle, int file) { 538 struct zip* zh = &z->base; 539 540 zh->read = zip_file_read; 541 zh->seek = zip_file_seek; 542 zh->size = zip_file_size; 543 zh->close = zip_file_close; 544 zip_init(zh, zip_handle); 545 546 z->file = file; 547} 548 549static ssize_t zip_mem_read(struct zip* zh, void* mem, size_t mem_size) { 550 struct zip_mem* z = (struct zip_mem*) zh; 551 off_t bytes = z->mem_size - z->mem_offset; 552 off_t read_size = MIN(bytes, (off_t) mem_size); 553 554 memcpy(mem, z->mem + z->mem_offset, read_size); 555 z->mem_offset += read_size; 556 557 return read_size; 558} 559 560static off_t zip_mem_seek(struct zip* zh, off_t offset, int whence) { 561 struct zip_mem* z = (struct zip_mem*) zh; 562 off_t new_offset; 563 564 switch (whence) { 565 case SEEK_SET: 566 new_offset = offset; 567 break; 568 569 case SEEK_CUR: 570 new_offset = z->mem_offset + offset; 571 break; 572 573 case SEEK_END: 574 new_offset = z->mem_size + offset; 575 break; 576 577 default: 578 new_offset = -1; 579 break; 580 } 581 582 if (new_offset < 0 || new_offset > z->mem_size) 583 return -1; 584 585 z->mem_offset = new_offset; 586 587 return new_offset; 588} 589 590static off_t zip_mem_size(struct zip* zh) { 591 struct zip_mem* z = (struct zip_mem*) zh; 592 593 return z->mem_size; 594} 595 596static void zip_mem_close(struct zip* zh) { 597 struct zip_mem* z = (struct zip_mem*) zh; 598 599 core_free(z->mem_handle); 600} 601 602static void zip_mem_init(struct zip_mem* z, int zip_handle, int mem_handle, const void* mem, off_t mem_size) { 603 struct zip* zh = &z->base; 604 605 zh->read = zip_mem_read; 606 zh->seek = zip_mem_seek; 607 zh->size = zip_mem_size; 608 zh->close = zip_mem_close; 609 zip_init(zh, zip_handle); 610 611 z->mem_handle = mem_handle; 612 z->mem = mem; 613 z->mem_offset = 0; 614 z->mem_size = mem_size; 615} 616 617static int zip_extract_start(const struct zip_args* args, struct zip_extract* ze) { 618 size_t name_length; 619 const char* dir; 620 size_t dir_length; 621 622 if ((name_length = strlcpy(ze->name, args->name, ze->name_size)) >= ze->name_size) 623 return 5; 624 625 if ((dir_length = path_dirname(ze->name, &dir)) > 0) { 626 char c = ze->name[dir_length]; 627 628 ze->name[dir_length] = '\0'; 629 630 if (!dir_exists(ze->path)) { 631 const char* path = ze->name; 632 const char* name; 633 634 while (parse_path_component(&path, &name) > 0) { 635 size_t offset = path - ze->name; 636 char c = ze->name[offset]; 637 638 ze->name[offset] = '\0'; 639 640 if (mkdir(ze->path) < 0 && errno != EEXIST) 641 return 6; 642 643 ze->name[offset] = c; 644 } 645 } 646 647 ze->name[dir_length] = c; 648 } 649 650 if (ze->name[name_length - 1] == PATH_SEPCH) { 651 if (mkdir(ze->path) < 0 && errno != EEXIST) 652 return 7; 653 654 return 0; 655 } 656 657 if ((ze->file = creat(ze->path, 0666)) < 0) 658 return 8; 659 660 return 0; 661} 662 663static int zip_extract_data(const struct zip_args* args, struct zip_extract* ze) { 664 if (write(ze->file, args->block, args->block_size) != (ssize_t) args->block_size) { 665 return 9; 666 } 667 668 return 0; 669} 670 671static int zip_extract_end(const struct zip_args* args, struct zip_extract* ze) { 672 int rv; 673 674 if (ze->file >= 0) { 675 rv = close(ze->file); 676 677 ze->file = -1; 678 679 if (rv < 0) 680 return 10; 681 } 682 683 if (modtime(ze->path, args->mtime) < 0) 684 return 11; 685 686 return 0; 687} 688 689static int zip_extract_callback(const struct zip_args* args, int pass, void* ctx) { 690 struct zip_extract* ze = ctx; 691 int rv; 692 693 if (ze->cb != NULL && (rv = ze->cb(args, pass, ze->ctx)) != 0) 694 return rv; 695 696 switch (pass) { 697 case ZIP_PASS_START: 698 return zip_extract_start(args, ze); 699 700 case ZIP_PASS_DATA: 701 return zip_extract_data(args, ze); 702 703 case ZIP_PASS_END: 704 return zip_extract_end(args, ze); 705 706 default: 707 return 1; 708 } 709} 710 711struct zip* zip_open(const char* name, bool try_mem) { 712 int file = -1; 713 int mem_handle = -1; 714 int zip_handle = -1; 715 off_t mem_size; 716 void* mem; 717 void* zip; 718 719 if (name == NULL || name[0] == '\0') 720 goto bail; 721 722 if ((file = open(name, O_RDONLY)) < 0) 723 goto bail; 724 725 if (try_mem && (mem_handle = zip_core_alloc(mem_size = filesize(file))) >= 0) { 726 if ((zip_handle = zip_core_alloc(sizeof(struct zip_mem))) < 0) 727 goto bail; 728 729 mem = core_get_data(mem_handle); 730 731 if (read(file, mem, mem_size) != mem_size) 732 goto bail; 733 734 close(file); 735 736 zip = core_get_data(zip_handle); 737 738 zip_mem_init(zip, zip_handle, mem_handle, mem, mem_size); 739 } else { 740 if ((zip_handle = zip_core_alloc(sizeof(struct zip_file))) < 0) 741 goto bail; 742 743 zip = core_get_data(zip_handle); 744 745 zip_file_init(zip, zip_handle, file); 746 } 747 748 return zip; 749 750bail: 751 if (file >= 0) 752 close(file); 753 core_free(mem_handle); 754 core_free(zip_handle); 755 return NULL; 756} 757 758int zip_read_shallow(struct zip* z, zip_callback cb, void* ctx) { 759 int rv; 760 761 if (z == NULL || z->state != ZIP_STATE_INITIAL || cb == NULL) 762 return -1; 763 764 z->cb = cb; 765 z->ctx = ctx; 766 767 if ((rv = zip_read_ed(z)) != 0) 768 return rv; 769 770 return zip_read_cd(z, true); 771} 772 773int zip_read_deep(struct zip* z, zip_callback cb, void* ctx) { 774 int rv; 775 776 if (z == NULL || (z->state != ZIP_STATE_INITIAL && z->state != ZIP_STATE_CD_EXIT) || cb == NULL) 777 return -1; 778 779 z->cb = cb; 780 z->ctx = ctx; 781 782 if (z->state == ZIP_STATE_CD_EXIT) 783 goto read_entries; 784 785 if ((rv = zip_read_ed(z)) != 0) 786 return rv; 787 788 if ((rv = zip_read_cd(z, false)) != 0) 789 return rv; 790 791read_entries: 792 return zip_read_entries(z); 793} 794 795int zip_extract(struct zip* z, const char* root, zip_callback cb, void* ctx) { 796 int rv; 797 int ze_handle = -1; 798 struct zip_extract* ze; 799 char* path; 800 size_t size; 801 size_t length; 802 803 if (root == NULL || root[0] == '\0') 804 root = PATH_ROOTSTR; 805 806 if (root[0] != PATH_SEPCH) { 807 rv = -1; 808 goto bail; 809 } 810 811 if (!dir_exists(root)) { 812 rv = 1; 813 goto bail; 814 } 815 816 if ((ze_handle = zip_core_alloc(sizeof(struct zip_extract))) < 0) { 817 rv = 2; 818 goto bail; 819 } 820 821 ze = core_get_data(ze_handle); 822 ze->cb = cb; 823 ze->ctx = ctx; 824 ze->file = -1; 825 826 path = ze->path; 827 size = sizeof(ze->path); 828 length = strlcpy(path, root, size); 829 830 if (length >= size) { 831 rv = 3; 832 goto bail; 833 } 834 835 path += length; 836 size -= length; 837 838 if (path[-1] != PATH_SEPCH) { 839 length = strlcpy(path, PATH_SEPSTR, size); 840 841 if (length >= size) { 842 rv = 4; 843 goto bail; 844 } 845 846 path += length; 847 size -= length; 848 } 849 850 ze->name_offset = path - ze->path; 851 ze->name_size = size; 852 ze->name = path; 853 854 rv = zip_read_deep(z, zip_extract_callback, ze); 855 856bail: 857 if (ze_handle >= 0) { 858 if (ze->file >= 0) 859 close(ze->file); 860 861 core_free(ze_handle); 862 } 863 return rv; 864} 865 866void zip_close(struct zip* z) { 867 if (z == NULL) 868 return; 869 870 z->close(z); 871 872 core_free(z->cds_handle); 873 874 core_free(z->zip_handle); 875}