A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.
1 /******************************************************************************\ 2 * * 3 * UNIPKG (c) iSteve <isteve@bofh.cz>, 2005 * 4 * * 5 * Universal PacKaGer. * 6 * Licensed under GNU/GPL - if you don't like the software, fix it! * 7 * * 8 \******************************************************************************/ 9 10 /////////////////////////////////////////////////////////////////////////////// 11 // // 12 // B A S E I N C L U S I O N S A N D D E F I N I T I O N S // 13 // // 14 /////////////////////////////////////////////////////////////////////////////// 15 #define _GNU_SOURCE 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <fcntl.h> 21 #include <sys/types.h> 22 #include <sys/mman.h> 23 #include <sys/stat.h> 24 25 #ifdef HAVE_SYSMACROS_H 26 #include <sys/sysmacros.h> 27 #endif 28 29 #include <errno.h> 30 #include <zlib.h> 31 32 #include "../archive.h" 33 #include "../common.h" 34 #include "../compression.h" 35 36 #define DEBCTLRBUFS 512 37 #define DEB_MAGIC "!<arch>\ndebian-binary" 38 #define DEB_MAGICSIZE 21 39 40 #define ARMAGIC "!<arch>\n" 41 #define ARMAGICLEN 8 42 43 #define ADMINMEMBER "control.tar.gz " 44 #define ADMINMEMBER_COMPAT "control.tar.gz/ " 45 #define DATAMEMBER_GZ "data.tar.gz " 46 #define DATAMEMBER_COMPAT_GZ "data.tar.gz/ " 47 #define DATAMEMBER_BZ2 "data.tar.bz2 " 48 #define DATAMEMBER_COMPAT_BZ2 "data.tar.bz2/ " 49 #define DATAMEMBER_CAT "data.tar " 50 #define DATAMEMBER_COMPAT_CAT "data.tar/ " 51 52 /////////////////////////////////////////////////////////////////////////////// 53 // // 54 // B A S E F U N C T I O N S // 55 // // 56 /////////////////////////////////////////////////////////////////////////////// 57 58 // GETCTRLHDR() 59 // 60 // Gets a value from debian's control file 61 // 62 // Parameters: 63 // the whole control file 64 // the header we look for 65 // the size of the control file 66 // 67 // Return value: 68 // malloced string 69 static char *getctrlhdr(char *fullfile, char *hdr, off_t size) { 70 char *start, *end, *tar; 71 72 if ((start = pstrnstr(fullfile, hdr, size, 0)) == NULL) { 73 return NULL; 74 } 75 if (start != fullfile) { // Is it at the start of the file? 76 if (*(start-1) != '\n') { // No? And is it on a new line? 77 return NULL; // No? Baibai. 78 } 79 } 80 start = start + strlen(hdr); 81 82 while ((*start == ' ') && (start < fullfile+size)) { start++; } // Skip all spaces after the start, since there may be issues. 83 84 if ((end = pstrnstr(start, "\n", size, 0)) == NULL) { 85 return NULL; 86 } 87 tar = malloc((int)end - (int)start + 1); 88 strncpy(tar, start, (int)end - (int)start); 89 tar[(int)end - (int)start] = 0x0; 90 return tar; 91 } 92 93 // SWITCH_CONTROL_NAMES() 94 // 95 // Identifies the filename as member of control archive. 96 // 97 // Parameters: 98 // the filename 99 // 100 // Return value: 101 // 0 if control 102 // 1 if preinst script 103 // 2 if postinst script 104 // 3 if prerm script 105 // 4 if postrm script 106 // -1 if none of above (eg. md5sum) 107 static int switch_control_names(char *fn) { 108 char *bn; 109 110 bn = basename(fn); 111 if (!strcmp(bn, "control")) { return 0; } 112 if (!strcmp(bn, "preinst")) { return 1; } 113 if (!strcmp(bn, "postinst")) { return 2; } 114 if (!strcmp(bn, "prerm")) { return 3; } 115 if (!strcmp(bn, "postrm")) { return 4; } 116 117 return -1; 118 } 119 120 // SWITCH_DEB_NAMES() 121 // 122 // Switches names of members or ar archive in debian package. 123 // 124 // Parameters: 125 // the filename we are checking 126 // 127 // Return value: 128 // 0 if control 129 // 1 if gzipped data 130 // 2 if bzip2ed data 131 // 3 if uncompressed data 132 static int switch_deb_names(char *fn) { 133 if ((!strcmp(fn, ADMINMEMBER)) || (!strcmp(fn, ADMINMEMBER_COMPAT))) { return 0; } 134 if ((!strcmp(fn, DATAMEMBER_GZ)) || (!strcmp(fn, DATAMEMBER_COMPAT_GZ))) { return 1; } 135 if ((!strcmp(fn, DATAMEMBER_BZ2)) || (!strcmp(fn, DATAMEMBER_COMPAT_BZ2))) { return 2; } 136 if ((!strcmp(fn, DATAMEMBER_CAT)) || (!strcmp(fn, DATAMEMBER_COMPAT_CAT))) { return 3; } 137 138 return -1; 139 } 140 141 /////////////////////////////////////////////////////////////////////////////// 142 // // 143 // A P I F U N C T I O N S // 144 // // 145 /////////////////////////////////////////////////////////////////////////////// 146 147 int identify(packdef pdef) { 148 char buf[DEB_MAGICSIZE]; 149 off_t curpos; 150 151 if ((curpos = ftell(pdef.filepointer)) == -1) { 152 return 2; 153 } 154 if (fseek(pdef.filepointer, 0, SEEK_SET)) { 155 return 2; 156 } 157 158 if (!fread(buf, DEB_MAGICSIZE, 1, pdef.filepointer)) { 159 return 2; 160 } 161 162 if (fseek(pdef.filepointer, curpos, SEEK_SET)) { 163 return 2; 164 } 165 166 if (memcmp(buf, DEB_MAGIC, DEB_MAGICSIZE) == 0) { 167 return 0; 168 } 169 else { 170 return 1; 171 } 172 } 173 174 int pkgdetails(packdef pdef, pkginfo *pinfo) { 175 int err; 176 177 void *filemap; 178 off_t offset; 179 180 off_t fsize; 181 struct stat statbuf; 182 183 char *fullfile; 184 185 char *obuf; 186 unsigned long obuflen; 187 188 int archive_file; 189 c_compdata cstream; 190 comarchive *tar_archive, *ar_archive; 191 192 fstat(fileno(pdef.filepointer), &statbuf); 193 fsize = statbuf.st_size; 194 195 filemap = mmap(0, fsize, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0); 196 if (filemap == MAP_FAILED) { return 1; } 197 198 offset = 0; 199 if (memcmp(filemap + offset, ARMAGIC, ARMAGICLEN)) { return 1; } 200 offset += ARMAGICLEN; 201 202 pinfo->files=NULL; 203 pinfo->filecount = 0; 204 205 ar_archive = init_archive(AT_AR); 206 do { 207 if (*((char*)filemap + offset) == '\n') { offset++; } 208 update_nextblock(ar_archive); 209 if (ar_archive->stage == AS_HEADER) 210 clear_archive_member(ar_archive); 211 212 err = parse_block(ar_archive, filemap + offset); 213 214 if (err) 215 break; 216 217 offset += ar_archive -> nextblock; 218 219 // We are "unpacking" them right away, because we mmap it... 220 update_upfilesize(ar_archive); 221 222 archive_file = switch_deb_names(ar_archive->name); 223 switch (archive_file) { 224 /*****************************************************************************\ 225 * Control -- GZIP * 226 \*****************************************************************************/ 227 case 0: 228 obuflen = 512; 229 obuf = malloc(obuflen); 230 231 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_GZIP); 232 fullfile = NULL; 233 234 if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) { 235 // A corrupted control archive. 236 decompression_cleanup(&cstream); 237 munmap(filemap, fsize); 238 free(obuf); 239 return 1; 240 } 241 242 tar_archive = init_archive(AT_TAR); 243 do { 244 if (tar_archive->stage == AS_NEWFILE) { 245 if (switch_control_names(tar_archive->name) != -1) 246 fullfile = malloc(tar_archive->filesize); 247 } 248 249 update_nextblock(tar_archive); 250 if (tar_archive->nextblock > obuflen) { 251 obuflen = tar_archive->nextblock; 252 obuf = realloc(obuf, obuflen); 253 } 254 255 if (decompression_decompress(&cstream, tar_archive->nextblock, obuf) != CE_OK) 256 break; 257 258 if (decompression_ammount_not_processed(&cstream) > 0) 259 break; 260 261 update_stage(tar_archive); 262 263 switch (tar_archive->stage) { 264 case AS_DATA: 265 if (fullfile != NULL) { 266 memcpy(fullfile + tar_archive->upfilesize, obuf, ((tar_archive->filesize - tar_archive->upfilesize) > tar_archive->nextblock) ? tar_archive->nextblock : tar_archive->filesize - tar_archive->upfilesize); 267 } 268 269 update_upfilesize(tar_archive); 270 break; 271 case AS_HEADER: 272 if (fullfile != NULL) { 273 switch (switch_control_names(tar_archive->name)) { 274 case 0: 275 pinfo->name = getctrlhdr(fullfile, "Package:", tar_archive->filesize); 276 pinfo->version = getctrlhdr(fullfile, "Version:", tar_archive->filesize); 277 pinfo->description = getctrlhdr(fullfile, "Description:", tar_archive->filesize); 278 break; 279 case 1: 280 pinfo->preinst.data = malloc(tar_archive->filesize); 281 pinfo->preinst.len = tar_archive->filesize; 282 memcpy(pinfo->preinst.data, fullfile, tar_archive->filesize); 283 break; 284 case 2: 285 pinfo->postinst.data = malloc(tar_archive->filesize); 286 pinfo->postinst.len = tar_archive->filesize; 287 memcpy(pinfo->postinst.data, fullfile, tar_archive->filesize); 288 break; 289 case 3: 290 pinfo->prerm.data = malloc(tar_archive->filesize); 291 pinfo->prerm.len = tar_archive->filesize; 292 memcpy(pinfo->prerm.data, fullfile, tar_archive->filesize); 293 break; 294 case 4: 295 pinfo->postrm.data = malloc(tar_archive->filesize); 296 pinfo->postrm.len = tar_archive->filesize; 297 memcpy(pinfo->postrm.data, fullfile, tar_archive->filesize); 298 break; 299 } 300 301 free(fullfile); 302 fullfile = NULL; 303 } 304 305 clear_archive_member(tar_archive); 306 break; 307 } 308 309 err = parse_block(tar_archive, obuf); 310 311 if (err) 312 break; 313 } while (decompression_ammount_left(&cstream, 0) > 0); 314 315 deinit_archive(tar_archive); 316 decompression_cleanup(&cstream); 317 318 free(obuf); 319 break; 320 321 /*****************************************************************************\ 322 * Data -- GZIP, BZIP2, UNCOMPRESSED * 323 \*****************************************************************************/ 324 case 1: 325 case 2: 326 case 3: 327 obuflen = 512; 328 obuf = malloc(obuflen); 329 330 err = CE_OK; 331 332 switch (archive_file) { 333 case 1: 334 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_GZIP); 335 break; 336 case 2: 337 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_BZIP2); 338 break; 339 case 3: 340 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_NONE); 341 break; 342 } 343 344 if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) { 345 // A corrupted file archive. 346 decompression_cleanup(&cstream); 347 munmap(filemap, fsize); 348 free(obuf); 349 deinit_archive(ar_archive); 350 return 1; 351 } 352 353 tar_archive = init_archive(AT_TAR); 354 do { 355 if (tar_archive->stage == AS_NEWFILE) { 356 addfile(pinfo, absolutizestr(tar_archive->name, "/"), (tar_archive->ftype == AF_DIRECTORY) ? F_DIRECTORY : F_REGULAR); 357 pinfo->pkgsize += tar_archive->filesize; 358 } 359 360 update_nextblock(tar_archive); 361 if (tar_archive->nextblock > obuflen) { 362 obuflen = tar_archive->nextblock; 363 obuf = realloc(obuf, obuflen); 364 } 365 366 if (decompression_decompress(&cstream, tar_archive->nextblock, obuf) != CE_OK) 367 break; 368 369 if (decompression_ammount_not_processed(&cstream) > 0) 370 break; 371 372 update_stage(tar_archive); 373 374 switch (tar_archive->stage) { 375 case AS_DATA: 376 update_upfilesize(tar_archive); 377 // Perform data handling when actually unpacking stuff 378 break; 379 case AS_HEADER: 380 clear_archive_member(tar_archive); 381 break; 382 } 383 384 err = parse_block(tar_archive, obuf); 385 386 if (err) 387 break; 388 } while (decompression_ammount_left(&cstream, 0) > 0); 389 390 deinit_archive(tar_archive); 391 decompression_cleanup(&cstream); 392 393 free(obuf); 394 break; 395 } 396 397 offset += ar_archive->filesize; 398 } while (offset < fsize - 1); 399 deinit_archive(ar_archive); 400 401 munmap(filemap, fsize); 402 403 if (pinfo->description == NULL) { pinfo->description = strdup("Debian package, no description."); } 404 if (pinfo->version == NULL) { pinfo->version = strdup("unknown"); } 405 if (pinfo->name == NULL) { return 1; } 406 407 // These are various parameters to be used in various cases with the handling scripts. 408 // They are only given if the script exists. 409 if (pinfo->preinst.data != NULL) { 410 pinfo->preinst.parameters[A_IRRELEVANT] = strdup("configure"); 411 pinfo->preinst.parameters[A_UPGRADE] = strdup("upgrade"); 412 pinfo->preinst.parameters[A_DOWNGRADE] = strdup("upgrade"); 413 pinfo->preinst.parameters[A_REINSTALL] = strdup("upgrade"); 414 } 415 416 if (pinfo->postinst.data != NULL) { 417 pinfo->postinst.parameters[A_IRRELEVANT] = strdup("configure"); 418 pinfo->postinst.parameters[A_UPGRADE] = strdup("upgrade"); 419 pinfo->postinst.parameters[A_DOWNGRADE] = strdup("upgrade"); 420 pinfo->postinst.parameters[A_REINSTALL] = strdup("upgrade"); 421 } 422 423 if (pinfo->prerm.data != NULL) { 424 pinfo->prerm.parameters[A_IRRELEVANT] = strdup("remove"); 425 pinfo->prerm.parameters[A_REMOVE] = strdup("remove"); 426 pinfo->prerm.parameters[A_UPGRADE] = strdup("upgrade"); 427 pinfo->prerm.parameters[A_DOWNGRADE] = strdup("upgrade"); 428 pinfo->prerm.parameters[A_REINSTALL] = strdup("upgrade"); 429 } 430 431 if (pinfo->postrm.data != NULL) { 432 pinfo->postrm.parameters[A_IRRELEVANT] = strdup("remove"); 433 pinfo->postrm.parameters[A_REMOVE] = strdup("remove"); 434 pinfo->postrm.parameters[A_UPGRADE] = strdup("upgrade"); 435 pinfo->postrm.parameters[A_DOWNGRADE] = strdup("upgrade"); 436 pinfo->postrm.parameters[A_REINSTALL] = strdup("upgrade"); 437 } 438 439 return 0; 440 } 441 442 int pkginstall(packdef pdef) { 443 FILE *fpout; 444 int err; 445 void *filemap; 446 off_t fsize; 447 struct stat statbuf; 448 449 char *curpath; 450 char *obuf; 451 unsigned long obuflen; 452 453 off_t offset; 454 int archive_file; 455 456 c_compdata cstream; 457 comarchive *tar_archive, *ar_archive; 458 459 fstat(fileno(pdef.filepointer), &statbuf); 460 fsize = statbuf.st_size; 461 462 curpath = NULL; 463 fpout = NULL; 464 filemap = NULL; 465 filemap = mmap(0, fsize, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0); 466 if (filemap == MAP_FAILED) { return 1; } 467 468 offset = 0; 469 if (memcmp(filemap + offset, ARMAGIC, ARMAGICLEN)) { return 1; } 470 offset += ARMAGICLEN; 471 472 ar_archive = init_archive(AT_AR); 473 do { 474 if (*((char*)filemap + offset) == '\n') { offset++; } 475 476 update_nextblock(ar_archive); 477 update_stage(ar_archive); 478 if (ar_archive->stage == AS_HEADER) 479 clear_archive_member(ar_archive); 480 481 err = parse_block(ar_archive, filemap + offset); 482 483 if (err) 484 break; 485 486 offset += ar_archive -> nextblock; 487 488 // We are "unpacking" them right away, because we mmap it... 489 ar_archive -> upfilesize = ar_archive -> filesize; 490 491 archive_file = switch_deb_names(ar_archive->name); 492 switch (archive_file) { 493 /*****************************************************************************\ 494 * Control -- GZIP * 495 \*****************************************************************************/ 496 case 0: 497 // We don't care. 498 break; 499 500 /*****************************************************************************\ 501 * Data -- GZIP, BZIP2, UNCOMPRESSED * 502 \*****************************************************************************/ 503 case 1: 504 case 2: 505 case 3: 506 obuflen = 512; 507 obuf = malloc(obuflen); 508 509 err = CE_OK; 510 511 switch (archive_file) { 512 case 1: 513 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_GZIP); 514 break; 515 case 2: 516 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_BZIP2); 517 break; 518 case 3: 519 err = decompression_setup(&cstream, filemap, offset, ar_archive->filesize, obuf, obuflen, C_NONE); 520 break; 521 } 522 523 if ((err != CE_OK) || (decompression_init(&cstream))) { 524 // A corrupted file archive. 525 decompression_cleanup(&cstream); 526 munmap(filemap, fsize); 527 free(obuf); 528 deinit_archive(ar_archive); 529 return 1; 530 } 531 532 tar_archive = init_archive(AT_TAR); 533 do { 534 if (tar_archive->stage == AS_NEWFILE) { 535 free(curpath); 536 curpath = absolutizestr(tar_archive->name, pdef.destdir); 537 // Create relevant files 538 switch (tar_archive->ftype) { 539 case AF_REGULAR: 540 if (fpout != NULL) { 541 fclose(fpout); 542 } 543 if ((fpout = fopen(curpath, "w")) == NULL) { 544 free(curpath); 545 free(obuf); 546 decompression_cleanup(&cstream); 547 munmap(filemap, fsize); 548 deinit_archive(tar_archive); 549 deinit_archive(ar_archive); 550 return 2; 551 } 552 553 FCHOWNMOD(fileno(fpout), tar_archive->mode, tar_archive->uid, tar_archive->gid); 554 555 if (tar_archive->filesize == 0) { 556 // Nothing to write. We just created it. 557 fclose(fpout); 558 fpout = NULL; 559 560 // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored 561 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid); 562 } 563 break; 564 case AF_SYMLINK: 565 symlink(tar_archive->linktarget, curpath); 566 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid); 567 break; 568 case AF_DEVNODE: 569 mknod(curpath, tar_archive->mode, makedev(tar_archive->dmajor, tar_archive->dminor)); 570 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid); 571 break; 572 case AF_FIFOBUF: 573 mkfifo(curpath, tar_archive->mode); 574 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid); 575 break; 576 case AF_DIRECTORY: 577 if (stat(curpath, &statbuf)) { 578 mkdir(curpath, tar_archive->mode); 579 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid); 580 } 581 break; 582 } 583 } 584 585 update_nextblock(tar_archive); 586 if (tar_archive->nextblock > obuflen) { 587 obuflen = tar_archive->nextblock; 588 obuf = realloc(obuf, obuflen); 589 } 590 591 if (decompression_decompress(&cstream, tar_archive->nextblock, obuf) != CE_OK) 592 break; 593 594 if (decompression_ammount_not_processed(&cstream) > 0) 595 break; 596 597 update_stage(tar_archive); 598 599 switch (tar_archive->stage) { 600 case AS_DATA: 601 // Feed data... 602 if (tar_archive->ftype == AF_REGULAR) { 603 if (fpout != NULL) { 604 fwrite(obuf, ((tar_archive->filesize - tar_archive->upfilesize) > tar_archive->nextblock) ? tar_archive->nextblock : tar_archive->filesize - tar_archive->upfilesize, 1, fpout); 605 } 606 } 607 608 update_upfilesize(tar_archive); 609 break; 610 case AS_HEADER: 611 // Clear up... 612 if (tar_archive->ftype == AF_REGULAR) { 613 if (fpout != NULL) { 614 fsync(fileno(fpout)); 615 fclose(fpout); 616 fpout = NULL; 617 618 // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored 619 CHOWNMOD(curpath, tar_archive->mode, tar_archive->uid, tar_archive->gid); 620 } 621 } 622 clear_archive_member(tar_archive); 623 break; 624 } 625 626 err = parse_block(tar_archive, obuf); 627 628 if (err) 629 break; 630 } while (decompression_ammount_left(&cstream, 0)); 631 deinit_archive(tar_archive); 632 633 decompression_cleanup(&cstream); 634 free(curpath); 635 free(obuf); 636 break; 637 } 638 639 offset += ar_archive->filesize; 640 } while (offset < fsize - 1); 641 deinit_archive(ar_archive); 642 munmap(filemap, fsize); 643 644 return 0; 645 }