extractor_plugin_main.c (20877B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2012 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file main/extractor_plugin_main.c 22 * @brief main loop for an out-of-process plugin 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "extractor.h" 27 #include "extractor_common.h" 28 #include "extractor_datasource.h" 29 #include "extractor_plugins.h" 30 #include "extractor_ipc.h" 31 #include "extractor_logging.h" 32 #include "extractor_plugin_main.h" 33 #include <dirent.h> 34 #include <sys/types.h> 35 #if GNU_LINUX 36 #include <sys/wait.h> 37 #include <sys/shm.h> 38 #include <signal.h> 39 #endif 40 41 #if WINDOWS 42 #define SHM_ID HANDLE 43 #define INVALID_SHM_ID NULL 44 #else 45 #define SHM_ID int 46 #define INVALID_SHM_ID -1 47 #endif 48 49 /** 50 * Closure we use for processing requests inside the helper process. 51 */ 52 struct ProcessingContext 53 { 54 /** 55 * Our plugin handle. 56 */ 57 struct EXTRACTOR_PluginList *plugin; 58 59 /** 60 * Shared memory area. 61 */ 62 void *shm; 63 64 /** 65 * Overall size of the file. 66 */ 67 uint64_t file_size; 68 69 /** 70 * Current read offset when reading from the SHM. 71 */ 72 uint64_t read_position; 73 74 /** 75 * Current offset of the SHM in the file. 76 */ 77 uint64_t shm_off; 78 79 /** 80 * Handle to the shared memory. 81 */ 82 SHM_ID shm_id; 83 84 /** 85 * Size of the shared memory map. 86 */ 87 uint32_t shm_map_size; 88 89 /** 90 * Number of bytes ready in SHM. 91 */ 92 uint32_t shm_ready_bytes; 93 94 /** 95 * Input stream. 96 */ 97 int in; 98 99 /** 100 * Output stream. 101 */ 102 int out; 103 104 /** 105 * When we last sent a #MESSAGE_ALIVE, in milliseconds. 106 */ 107 uint64_t last_alive; 108 }; 109 110 111 /** 112 * Minimum time between two #MESSAGE_ALIVE, in milliseconds; well below 113 * the silence LE tolerates (500 ms). 114 */ 115 #define ALIVE_INTERVAL_MS 100 116 117 118 /** 119 * Get a monotonic time stamp. 120 * 121 * @return current time in milliseconds since some arbitrary epoch 122 */ 123 static uint64_t 124 now_ms (void) 125 { 126 #if WINDOWS 127 return (uint64_t) GetTickCount64 (); 128 #else 129 struct timespec ts; 130 131 if (0 != clock_gettime (CLOCK_MONOTONIC, 132 &ts)) 133 return 0; 134 return ((uint64_t) ts.tv_sec) * 1000 + ts.tv_nsec / 1000000; 135 #endif 136 } 137 138 139 /** 140 * Tell LE that we are still busy, unless we did so very recently. 141 * 142 * @param pc processing context 143 */ 144 static void 145 send_alive (struct ProcessingContext *pc) 146 { 147 unsigned char alive = MESSAGE_ALIVE; 148 uint64_t now = now_ms (); 149 150 if (now - pc->last_alive < ALIVE_INTERVAL_MS) 151 return; 152 pc->last_alive = now; 153 if (-1 == EXTRACTOR_write_all_ (pc->out, 154 &alive, 155 sizeof (alive))) 156 LOG ("Failed to send MESSAGE_ALIVE\n"); 157 } 158 159 160 /** 161 * Moves current absolute buffer position to 'pos' in 'whence' mode. 162 * Will move logical position without shifting the buffer, if possible. 163 * Will not move beyond the end of file. 164 * 165 * @param plugin plugin context 166 * @param pos position to move to 167 * @param whence seek mode (SEEK_CUR, SEEK_SET, SEEK_END) 168 * @return new absolute position, -1 on error 169 */ 170 static int64_t 171 plugin_env_seek (void *cls, 172 int64_t pos, 173 int whence) 174 { 175 struct ProcessingContext *pc = cls; 176 struct SeekRequestMessage srm = { 177 .opcode = MESSAGE_SEEK 178 }; 179 struct UpdateMessage um; 180 uint64_t npos; 181 unsigned char reply; 182 uint16_t wval; 183 184 if ( (SEEK_CUR == whence) && 185 (0 == pos) ) 186 { 187 /* a no-op seek is how a busy plugin keeps its channel open */ 188 send_alive (pc); 189 return (int64_t) pc->read_position; 190 } 191 switch (whence) 192 { 193 case SEEK_CUR: 194 if ( (pos < 0) && (pc->read_position < -pos) ) 195 { 196 LOG ("Invalid seek operation\n"); 197 return -1; 198 } 199 if ((pos > 0) && ((pc->read_position + pos < pc->read_position) || 200 (pc->read_position + pos > pc->file_size))) 201 { 202 LOG ("Invalid seek operation\n"); 203 return -1; 204 } 205 npos = (uint64_t) (pc->read_position + pos); 206 wval = 0; 207 break; 208 case SEEK_END: 209 if (pos > 0) 210 { 211 LOG ("Invalid seek operation\n"); 212 return -1; 213 } 214 if (UINT64_MAX == pc->file_size) 215 { 216 wval = 2; 217 npos = (uint64_t) -pos; 218 break; 219 } 220 pos = (int64_t) (pc->file_size + pos); 221 /* fall-through! */ 222 case SEEK_SET: 223 if ( (pos < 0) || (pc->file_size < pos) ) 224 { 225 LOG ("Invalid seek operation\n"); 226 return -1; 227 } 228 npos = (uint64_t) pos; 229 wval = 0; 230 break; 231 default: 232 LOG ("Invalid seek operation\n"); 233 return -1; 234 } 235 if ( (pc->shm_off <= npos) && 236 (pc->shm_off + pc->shm_ready_bytes > npos) && 237 (0 == wval) ) 238 { 239 pc->read_position = npos; 240 return (int64_t) npos; 241 } 242 /* need to seek */ 243 srm.opcode = MESSAGE_SEEK; 244 srm.reserved = 0; 245 srm.whence = wval; 246 srm.requested_bytes = pc->shm_map_size; 247 if (0 == wval) 248 { 249 if (srm.requested_bytes > pc->file_size - npos) 250 srm.requested_bytes = pc->file_size - npos; 251 } 252 else 253 { 254 srm.requested_bytes = npos; 255 } 256 srm.file_offset = npos; 257 if (-1 == EXTRACTOR_write_all_ (pc->out, &srm, sizeof (srm))) 258 { 259 LOG ("Failed to send MESSAGE_SEEK\n"); 260 return -1; 261 } 262 if (-1 == 263 EXTRACTOR_read_all_ (pc->in, 264 &reply, sizeof (reply))) 265 { 266 LOG ("Plugin `%s' failed to read response to MESSAGE_SEEK\n", 267 pc->plugin->short_libname); 268 return -1; 269 } 270 if (MESSAGE_UPDATED_SHM != reply) 271 { 272 LOG ("Unexpected reply %d to seek\n", reply); 273 return -1; /* was likely a MESSAGE_DISCARD_STATE */ 274 } 275 if (-1 == EXTRACTOR_read_all_ (pc->in, &um.reserved, sizeof (um) - 1)) 276 { 277 LOG ("Failed to read MESSAGE_UPDATED_SHM\n"); 278 return -1; 279 } 280 pc->shm_off = um.shm_off; 281 pc->shm_ready_bytes = um.shm_ready_bytes; 282 pc->file_size = um.file_size; 283 if (2 == wval) 284 { 285 /* convert offset to be absolute from beginning of the file */ 286 npos = pc->file_size - npos; 287 } 288 if ( (pc->shm_off <= npos) && 289 ((pc->shm_off + pc->shm_ready_bytes > npos) || 290 (pc->file_size == pc->shm_off)) ) 291 { 292 pc->read_position = npos; 293 return (int64_t) npos; 294 } 295 /* oops, serious missunderstanding, we asked to seek 296 and then were notified about a different position!? */ 297 LOG ( 298 "Plugin `%s' got invalid MESSAGE_UPDATED_SHM in response to my %d-seek (%llu not in %llu-%llu)\n", 299 pc->plugin->short_libname, 300 (int) wval, 301 (unsigned long long) npos, 302 (unsigned long long) pc->shm_off, 303 (unsigned long long) pc->shm_off + pc->shm_ready_bytes); 304 return -1; 305 } 306 307 308 /** 309 * Fills @a data with a pointer to the data buffer. 310 * 311 * @param plugin plugin context 312 * @param data location to store data pointer 313 * @param count number of bytes to read 314 * @return number of bytes (<= count) available in @a data, -1 on error 315 */ 316 static ssize_t 317 plugin_env_read (void *cls, 318 void **data, 319 size_t count) 320 { 321 struct ProcessingContext *pc = cls; 322 unsigned char *dp; 323 324 *data = NULL; 325 if ( (count + pc->read_position > pc->file_size) || 326 (count + pc->read_position < pc->read_position) ) 327 count = pc->file_size - pc->read_position; 328 if ( ( ( (pc->read_position >= pc->shm_off + pc->shm_ready_bytes) && 329 (pc->read_position < pc->file_size)) || 330 (pc->read_position < pc->shm_off) ) && 331 (-1 == plugin_env_seek (pc, pc->read_position, SEEK_SET) ) ) 332 { 333 LOG ("Failed to seek to satisfy read\n"); 334 return -1; 335 } 336 if (pc->read_position + count > pc->shm_off + pc->shm_ready_bytes) 337 count = pc->shm_off + pc->shm_ready_bytes - pc->read_position; 338 dp = pc->shm; 339 *data = &dp[pc->read_position - pc->shm_off]; 340 pc->read_position += count; 341 return count; 342 } 343 344 345 /** 346 * Provide the overall file size to plugins. 347 * 348 * @param cls the 'struct ProcessingContext' 349 * @return overall file size of the current file 350 */ 351 static uint64_t 352 plugin_env_get_size (void *cls) 353 { 354 struct ProcessingContext *pc = cls; 355 356 return pc->file_size; 357 } 358 359 360 /** 361 * Function called by a plugin in a child process. Transmits 362 * the meta data back to the parent process. 363 * 364 * @param cls closure, "struct ProcessingContext" with the FD for transmission 365 * @param plugin_name name of the plugin that produced this value; 366 * special values can be used (i.e. '<zlib>' for zlib being 367 * used in the main libextractor library and yielding 368 * meta data). 369 * @param type libextractor-type describing the meta data 370 * @param format basic format information about data 371 * @param data_mime_type mime-type of data (not of the original file); 372 * can be NULL (if mime-type is not known) 373 * @param data actual meta-data found 374 * @param data_len number of bytes in data 375 * @return 0 to continue extracting, 1 to abort (transmission error) 376 */ 377 static int 378 plugin_env_send_proc (void *cls, 379 const char *plugin_name, 380 enum EXTRACTOR_MetaType type, 381 enum EXTRACTOR_MetaFormat format, 382 const char *data_mime_type, 383 const char *data, 384 size_t data_len) 385 { 386 struct ProcessingContext *pc = cls; 387 struct MetaMessage mm; 388 size_t mime_len; 389 unsigned char reply; 390 391 if (data_len > MAX_META_DATA) 392 return 0; /* skip, too large */ 393 if (NULL == data_mime_type) 394 mime_len = 0; 395 else 396 mime_len = strlen (data_mime_type) + 1; 397 if (mime_len > UINT16_MAX) 398 mime_len = UINT16_MAX; 399 mm.opcode = MESSAGE_META; 400 mm.reserved = 0; 401 mm.meta_type = type; 402 mm.meta_format = (uint16_t) format; 403 mm.mime_length = (uint16_t) mime_len; 404 mm.value_size = (uint32_t) data_len; 405 if ( (sizeof (mm) != 406 EXTRACTOR_write_all_ (pc->out, 407 &mm, sizeof (mm))) || 408 (mime_len != 409 EXTRACTOR_write_all_ (pc->out, 410 data_mime_type, mime_len)) || 411 (data_len != 412 EXTRACTOR_write_all_ (pc->out, 413 data, data_len)) ) 414 { 415 LOG ("Failed to send meta message\n"); 416 return 1; 417 } 418 if (-1 == 419 EXTRACTOR_read_all_ (pc->in, 420 &reply, sizeof (reply))) 421 { 422 LOG ("Failed to read response to meta message\n"); 423 return 1; 424 } 425 if (MESSAGE_DISCARD_STATE == reply) 426 return 1; 427 if (MESSAGE_CONTINUE_EXTRACTING != reply) 428 { 429 LOG ("Received unexpected reply to meta data: %d\n", reply); 430 return 1; 431 } 432 return 0; 433 } 434 435 436 /** 437 * Handle an init message. The opcode itself has already been read. 438 * 439 * @param pc processing context 440 * @return 0 on success, -1 on error 441 */ 442 static int 443 handle_init_message (struct ProcessingContext *pc) 444 { 445 struct InitMessage init = { 446 .opcode = MESSAGE_INIT_STATE 447 }; 448 449 if (NULL != pc->shm) 450 { 451 LOG ("Cannot handle 'init' message, have already been initialized\n"); 452 return -1; 453 } 454 if (sizeof (struct InitMessage) - 1 455 != EXTRACTOR_read_all_ (pc->in, 456 &init.reserved, 457 sizeof (struct InitMessage) - 1)) 458 { 459 LOG ("Failed to read 'init' message\n"); 460 return -1; 461 } 462 if (init.shm_name_length > MAX_SHM_NAME) 463 { 464 LOG ("Invalid 'init' message\n"); 465 return -1; 466 } 467 { 468 char shm_name[init.shm_name_length + 1]; 469 470 if (init.shm_name_length 471 != EXTRACTOR_read_all_ (pc->in, 472 shm_name, 473 init.shm_name_length)) 474 { 475 LOG ("Failed to read 'init' message\n"); 476 return -1; 477 } 478 shm_name[init.shm_name_length] = '\0'; 479 480 pc->shm_map_size = init.shm_map_size; 481 #if WINDOWS 482 /* FIXME: storing pointer in an int */ 483 pc->shm_id = OpenFileMapping (FILE_MAP_READ, FALSE, shm_name); 484 if (NULL == pc->shm_id) 485 return -1; 486 pc->shm = MapViewOfFile (pc->shm_id, FILE_MAP_READ, 0, 0, 0); 487 if (NULL == pc->shm) 488 { 489 CloseHandle (pc->shm_id); 490 return -1; 491 } 492 #else 493 pc->shm_id = shm_open (shm_name, O_RDONLY, 0); 494 if (-1 == pc->shm_id) 495 { 496 LOG_STRERROR_FILE ("open", shm_name); 497 return -1; 498 } 499 pc->shm = mmap (NULL, 500 pc->shm_map_size, 501 PROT_READ, 502 MAP_SHARED, 503 pc->shm_id, 0); 504 if ( ((void*) -1) == pc->shm) 505 { 506 LOG_STRERROR_FILE ("mmap", shm_name); 507 return -1; 508 } 509 #endif 510 } 511 return 0; 512 } 513 514 515 /** 516 * Handle a start message. The opcode itself has already been read. 517 * 518 * @param pc processing context 519 * @return 0 on success, -1 on error 520 */ 521 static int 522 handle_start_message (struct ProcessingContext *pc) 523 { 524 struct StartMessage start = { 525 .opcode = MESSAGE_EXTRACT_START 526 }; 527 struct EXTRACTOR_ExtractContext ec; 528 char done; 529 530 if (sizeof (struct StartMessage) - 1 531 != EXTRACTOR_read_all_ (pc->in, 532 &start.reserved, 533 sizeof (struct StartMessage) - 1)) 534 { 535 LOG ("Failed to read 'start' message\n"); 536 return -1; 537 } 538 pc->shm_ready_bytes = start.shm_ready_bytes; 539 pc->file_size = start.file_size; 540 pc->read_position = 0; 541 pc->shm_off = 0; 542 ec.cls = pc; 543 ec.config = pc->plugin->plugin_options; 544 ec.read = &plugin_env_read; 545 ec.seek = &plugin_env_seek; 546 ec.get_size = &plugin_env_get_size; 547 ec.proc = &plugin_env_send_proc; 548 pc->plugin->extract_method (&ec); 549 done = MESSAGE_DONE; 550 if (-1 == EXTRACTOR_write_all_ (pc->out, &done, sizeof (done))) 551 { 552 LOG ("Failed to write 'done' message\n"); 553 return -1; 554 } 555 if ( (NULL != pc->plugin->specials) && 556 (NULL != strstr (pc->plugin->specials, "force-kill")) ) 557 { 558 /* we're required to die after each file since this 559 plugin only supports a single file at a time */ 560 #if ! WINDOWS 561 fsync (pc->out); 562 #else 563 _commit (pc->out); 564 #endif 565 _exit (0); 566 } 567 return 0; 568 } 569 570 571 /** 572 * Main loop function for plugins. Reads a message from the plugin 573 * input pipe and acts on it. 574 * 575 * @param pc processing context 576 */ 577 static void 578 process_requests (struct ProcessingContext *pc) 579 { 580 while (1) 581 { 582 unsigned char code; 583 584 if (1 != EXTRACTOR_read_all_ (pc->in, &code, 1)) 585 { 586 LOG ("Failed to read next request\n"); 587 break; 588 } 589 switch (code) 590 { 591 case MESSAGE_INIT_STATE: 592 if (0 != handle_init_message (pc)) 593 { 594 LOG ("Failure to handle INIT\n"); 595 return; 596 } 597 break; 598 case MESSAGE_EXTRACT_START: 599 if (0 != handle_start_message (pc)) 600 { 601 LOG ("Failure to handle START\n"); 602 return; 603 } 604 break; 605 case MESSAGE_UPDATED_SHM: 606 LOG ("Illegal message\n"); 607 /* not allowed here, we're not waiting for SHM to move! */ 608 return; 609 case MESSAGE_DISCARD_STATE: 610 /* odd, we're already in the start state... */ 611 continue; 612 default: 613 LOG ("Received invalid message %d\n", (int) code); 614 /* error, unexpected message */ 615 return; 616 } 617 } 618 } 619 620 621 /** 622 * Open '/dev/null' and make the result the given 623 * file descriptor. 624 * 625 * @param target_fd desired FD to point to /dev/null 626 * @param flags open flags (O_RDONLY, O_WRONLY) 627 */ 628 static void 629 open_dev_null (int target_fd, 630 int flags) 631 { 632 int fd; 633 634 #ifndef WINDOWS 635 fd = open ("/dev/null", flags); 636 #else 637 fd = open ("\\\\?\\NUL", flags); 638 #endif 639 if (-1 == fd) 640 { 641 LOG_STRERROR_FILE ("open", "/dev/null"); 642 return; /* good luck */ 643 } 644 if (fd == target_fd) 645 return; /* already done */ 646 if (-1 == dup2 (fd, target_fd)) 647 { 648 LOG_STRERROR ("dup2"); 649 (void) close (fd); 650 return; /* good luck */ 651 } 652 /* close original result from 'open' */ 653 if (0 != close (fd)) 654 LOG_STRERROR ("close"); 655 } 656 657 658 /** 659 * 'main' function of the child process. Loads the plugin, 660 * sets up its in and out pipes, then runs the request serving function. 661 * 662 * @param plugin extractor plugin to use 663 * @param in stream to read from 664 * @param out stream to write to 665 */ 666 void 667 EXTRACTOR_plugin_main_ (struct EXTRACTOR_PluginList *plugin, 668 int in, int out) 669 { 670 struct ProcessingContext pc; 671 672 if (0 != EXTRACTOR_plugin_load_ (plugin)) 673 { 674 #if DEBUG 675 fprintf (stderr, "Plugin `%s' failed to load!\n", 676 plugin->short_libname); 677 #endif 678 return; 679 } 680 if ( (NULL != plugin->specials) && 681 (NULL != strstr (plugin->specials, "close-stderr"))) 682 { 683 if (0 != close (2)) 684 LOG_STRERROR ("close"); 685 open_dev_null (2, O_WRONLY); 686 } 687 if ( (NULL != plugin->specials) && 688 (NULL != strstr (plugin->specials, "close-stdout"))) 689 { 690 if (0 != close (1)) 691 LOG_STRERROR ("close"); 692 open_dev_null (1, O_WRONLY); 693 } 694 pc.plugin = plugin; 695 pc.in = in; 696 pc.out = out; 697 pc.shm_id = INVALID_SHM_ID; 698 pc.shm = NULL; 699 pc.shm_map_size = 0; 700 process_requests (&pc); 701 LOG ("IPC error; plugin `%s' terminates!\n", 702 plugin->short_libname); 703 #if WINDOWS 704 if (NULL != pc.shm) 705 UnmapViewOfFile (pc.shm); 706 if (NULL != pc.shm_id) 707 CloseHandle (pc.shm_id); 708 #else 709 if ( (NULL != pc.shm) && 710 (MAP_FAILED != pc.shm) ) 711 munmap (pc.shm, 712 pc.shm_map_size); 713 if (-1 != pc.shm_id) 714 { 715 if (0 != close (pc.shm_id)) 716 LOG_STRERROR ("close"); 717 } 718 #endif 719 } 720 721 722 #if WINDOWS 723 /** 724 * Reads plugin data from the LE server process. 725 * Also initializes allocation granularity (duh...). 726 * 727 * @param fd the pipe to read from 728 * @return newly allocated plugin context 729 */ 730 static struct EXTRACTOR_PluginList * 731 read_plugin_data (int fd) 732 { 733 struct EXTRACTOR_PluginList *ret; 734 SYSTEM_INFO si; 735 size_t i; 736 737 if (NULL == (ret = malloc (sizeof (struct EXTRACTOR_PluginList)))) 738 { 739 LOG_STRERROR ("malloc"); 740 return NULL; 741 } 742 memset (ret, 743 0, 744 sizeof (struct EXTRACTOR_PluginList)); 745 /*GetSystemInfo (&si); 746 ret->allocation_granularity = si.dwAllocationGranularity;*/ 747 if (-1 == EXTRACTOR_read_all_ (fd, &i, sizeof (size_t))) 748 { 749 free (ret); 750 return NULL; 751 } 752 if ( (0 == i) || 753 (NULL == (ret->libname = malloc (i))) ) 754 { 755 free (ret); 756 return NULL; 757 } 758 EXTRACTOR_read_all_ (fd, ret->libname, i); 759 ret->libname[i - 1] = '\0'; 760 if (-1 == EXTRACTOR_read_all_ (fd, &i, sizeof (size_t))) 761 { 762 free (ret->libname); 763 free (ret); 764 return NULL; 765 } 766 if ( (0 == i) || 767 (NULL == (ret->short_libname = malloc (i))) ) 768 { 769 free (ret->libname); 770 free (ret); 771 return NULL; 772 } 773 if (-1 == EXTRACTOR_read_all_ (fd, ret->short_libname, i)) 774 { 775 free (ret->short_libname); 776 free (ret->libname); 777 free (ret); 778 return NULL; 779 } 780 ret->short_libname[i - 1] = '\0'; 781 if (-1 == EXTRACTOR_read_all_ (fd, &i, sizeof (size_t))) 782 { 783 free (ret->short_libname); 784 free (ret->libname); 785 free (ret); 786 return NULL; 787 } 788 if (0 == i) 789 { 790 /* no options, that's OK, too! */ 791 return ret; 792 } 793 if (NULL == (ret->plugin_options = malloc (i))) 794 { 795 free (ret->short_libname); 796 free (ret->libname); 797 free (ret); 798 return NULL; 799 } 800 if (-1 == EXTRACTOR_read_all_ (fd, ret->plugin_options, i)) 801 { 802 free (ret->plugin_options); 803 free (ret->short_libname); 804 free (ret->libname); 805 free (ret); 806 return NULL; 807 } 808 ret->plugin_options[i - 1] = '\0'; 809 return ret; 810 } 811 812 813 /** 814 * FIXME: document. 815 */ 816 void CALLBACK 817 RundllEntryPoint (HWND hwnd, 818 HINSTANCE hinst, 819 LPSTR lpszCmdLine, 820 int nCmdShow) 821 { 822 struct EXTRACTOR_PluginList *plugin; 823 intptr_t in_h; 824 intptr_t out_h; 825 int in; 826 int out; 827 828 sscanf (lpszCmdLine, "%lu %lu", &in_h, &out_h); 829 in = _open_osfhandle (in_h, _O_RDONLY); 830 out = _open_osfhandle (out_h, 0); 831 setmode (in, _O_BINARY); 832 setmode (out, _O_BINARY); 833 if (NULL == (plugin = read_plugin_data (in))) 834 { 835 close (in); 836 close (out); 837 return; 838 } 839 EXTRACTOR_plugin_main_ (plugin, in, out); 840 close (in); 841 close (out); 842 /* libgobject may crash us hard if we LoadLibrary() it directly or 843 * indirectly, and then exit normally (causing FreeLibrary() to be 844 * called by the OS) or call FreeLibrary() on it directly or 845 * indirectly. 846 * By terminating here we alleviate that problem. 847 */TerminateProcess (GetCurrentProcess (), 0); 848 } 849 850 851 /** 852 * FIXME: document. 853 */ 854 void CALLBACK 855 RundllEntryPointA (HWND hwnd, 856 HINSTANCE hinst, 857 LPSTR lpszCmdLine, 858 int nCmdShow) 859 { 860 return RundllEntryPoint (hwnd, hinst, lpszCmdLine, nCmdShow); 861 } 862 863 864 #endif