Commit 1665aeea56540af9923a5dae996327d9d0ae8b5a
1 parent
7680eb11
oleobj: vary shell status code if dumped or not / error occurred
Tell caller of script roughly what happened in call. Also: check whether given file arguments exist and return non-zero exit and remove print of non-existent __doc__
Showing
1 changed file
with
45 additions
and
10 deletions
oletools/oleobj.py
| @@ -165,6 +165,13 @@ STR_MAX_LEN = 1024 | @@ -165,6 +165,13 @@ STR_MAX_LEN = 1024 | ||
| 165 | # size of chunks to copy from ole stream to file | 165 | # size of chunks to copy from ole stream to file |
| 166 | DUMP_CHUNK_SIZE = 4096 | 166 | DUMP_CHUNK_SIZE = 4096 |
| 167 | 167 | ||
| 168 | +# return values from main; can be added | ||
| 169 | +# (e.g.: did dump but had err parsing and dumping --> return 1+4+8 = 13) | ||
| 170 | +RETURN_NO_DUMP = 0 # nothing found to dump/extract | ||
| 171 | +RETURN_DID_DUMP = 1 # did dump/extract successfully | ||
| 172 | +RETURN_ERR_ARGS = 2 # reserve for OptionParser.parse_args | ||
| 173 | +RETURN_ERR_STREAM = 4 # error opening/parsing a stream | ||
| 174 | +RETURN_ERR_DUMP = 8 # error dumping data from stream to file | ||
| 168 | 175 | ||
| 169 | # === FUNCTIONS ============================================================== | 176 | # === FUNCTIONS ============================================================== |
| 170 | 177 | ||
| @@ -527,12 +534,14 @@ def process_file(container, filename, data, output_dir=None): | @@ -527,12 +534,14 @@ def process_file(container, filename, data, output_dir=None): | ||
| 527 | print ('File: %r' % filename) | 534 | print ('File: %r' % filename) |
| 528 | index = 1 | 535 | index = 1 |
| 529 | 536 | ||
| 537 | + # do not throw errors but remember them and try continue with other streams | ||
| 538 | + err_stream = False | ||
| 539 | + err_dumping = False | ||
| 540 | + did_dump = False | ||
| 541 | + | ||
| 530 | # look for ole files inside file (e.g. unzip docx) | 542 | # look for ole files inside file (e.g. unzip docx) |
| 531 | - flag_no_ole = False | ||
| 532 | - flag_stream_error = False | ||
| 533 | for ole in find_ole(filename, data): | 543 | for ole in find_ole(filename, data): |
| 534 | if ole is None: # no ole file found | 544 | if ole is None: # no ole file found |
| 535 | - flag_no_ole = True | ||
| 536 | continue | 545 | continue |
| 537 | 546 | ||
| 538 | for path_parts in ole.listdir(): | 547 | for path_parts in ole.listdir(): |
| @@ -542,13 +551,14 @@ def process_file(container, filename, data, output_dir=None): | @@ -542,13 +551,14 @@ def process_file(container, filename, data, output_dir=None): | ||
| 542 | stream = None | 551 | stream = None |
| 543 | try: | 552 | try: |
| 544 | stream = ole.openstream(path_parts) | 553 | stream = ole.openstream(path_parts) |
| 545 | - print('extract file embedded in OLE object from stream %r:' % stream_path) | 554 | + print('extract file embedded in OLE object from stream %r:' |
| 555 | + % stream_path) | ||
| 546 | print ('Parsing OLE Package') | 556 | print ('Parsing OLE Package') |
| 547 | opkg = OleNativeStream(stream) | 557 | opkg = OleNativeStream(stream) |
| 548 | # leave stream open until dumping is finished | 558 | # leave stream open until dumping is finished |
| 549 | except Exception: | 559 | except Exception: |
| 550 | log.warning('*** Not an OLE 1.0 Object ({0})'.format(exc)) | 560 | log.warning('*** Not an OLE 1.0 Object ({0})'.format(exc)) |
| 551 | - flag_stream_error = True | 561 | + err_stream = True |
| 552 | if stream is not None: | 562 | if stream is not None: |
| 553 | stream.close() | 563 | stream.close() |
| 554 | continue | 564 | continue |
| @@ -583,18 +593,22 @@ def process_file(container, filename, data, output_dir=None): | @@ -583,18 +593,22 @@ def process_file(container, filename, data, output_dir=None): | ||
| 583 | break | 593 | break |
| 584 | next_size = min(DUMP_CHUNK_SIZE, | 594 | next_size = min(DUMP_CHUNK_SIZE, |
| 585 | opkg.actual_size - n_dumped) | 595 | opkg.actual_size - n_dumped) |
| 596 | + did_dump = True | ||
| 586 | except Exception as exc: | 597 | except Exception as exc: |
| 587 | log.warning('error dumping to {0} ({1})' | 598 | log.warning('error dumping to {0} ({1})' |
| 588 | .format(fname, exc)) | 599 | .format(fname, exc)) |
| 600 | + err_dumping = True | ||
| 589 | finally: | 601 | finally: |
| 590 | stream.close() | 602 | stream.close() |
| 591 | 603 | ||
| 592 | index += 1 | 604 | index += 1 |
| 605 | + return err_stream, err_dumping, did_dump | ||
| 593 | 606 | ||
| 594 | 607 | ||
| 595 | #=== MAIN ================================================================= | 608 | #=== MAIN ================================================================= |
| 596 | 609 | ||
| 597 | def main(): | 610 | def main(): |
| 611 | + """ main function, called when running this as script """ | ||
| 598 | # print banner with version | 612 | # print banner with version |
| 599 | print ('oleobj %s - http://decalage.info/oletools' % __version__) | 613 | print ('oleobj %s - http://decalage.info/oletools' % __version__) |
| 600 | print ('THIS IS WORK IN PROGRESS - Check updates regularly!') | 614 | print ('THIS IS WORK IN PROGRESS - Check updates regularly!') |
| @@ -640,9 +654,12 @@ def main(): | @@ -640,9 +654,12 @@ def main(): | ||
| 640 | 654 | ||
| 641 | # Print help if no arguments are passed | 655 | # Print help if no arguments are passed |
| 642 | if len(args) == 0: | 656 | if len(args) == 0: |
| 643 | - print (__doc__) | ||
| 644 | parser.print_help() | 657 | parser.print_help() |
| 645 | - sys.exit() | 658 | + return RETURN_ERR_ARGS |
| 659 | + for filename in args: | ||
| 660 | + if not os.path.isfile(filename): | ||
| 661 | + print('File does not exist: ' + filename) | ||
| 662 | + return RETURN_ERR_ARGS | ||
| 646 | 663 | ||
| 647 | # Setup logging to the console: | 664 | # Setup logging to the console: |
| 648 | # here we use stdout instead of stderr by default, so that the output | 665 | # here we use stdout instead of stderr by default, so that the output |
| @@ -652,14 +669,32 @@ def main(): | @@ -652,14 +669,32 @@ def main(): | ||
| 652 | # enable logging in the modules: | 669 | # enable logging in the modules: |
| 653 | log.setLevel(logging.NOTSET) | 670 | log.setLevel(logging.NOTSET) |
| 654 | 671 | ||
| 672 | + # remember if there was a problem and continue with other data | ||
| 673 | + any_err_stream = False | ||
| 674 | + any_err_dumping = False | ||
| 675 | + any_did_dump = False | ||
| 655 | 676 | ||
| 656 | for container, filename, data in xglob.iter_files(args, recursive=options.recursive, | 677 | for container, filename, data in xglob.iter_files(args, recursive=options.recursive, |
| 657 | zip_password=options.zip_password, zip_fname=options.zip_fname): | 678 | zip_password=options.zip_password, zip_fname=options.zip_fname): |
| 658 | # ignore directory names stored in zip files: | 679 | # ignore directory names stored in zip files: |
| 659 | if container and filename.endswith('/'): | 680 | if container and filename.endswith('/'): |
| 660 | continue | 681 | continue |
| 661 | - process_file(container, filename, data, options.output_dir) | 682 | + err_stream, err_dumping, did_dump = \ |
| 683 | + process_file(container, filename, data, options.output_dir) | ||
| 684 | + any_err_stream |= err_stream | ||
| 685 | + any_err_dumping |= err_dumping | ||
| 686 | + any_did_dump |= did_dump | ||
| 687 | + | ||
| 688 | + # assemble return value | ||
| 689 | + return_val = RETURN_NO_DUMP | ||
| 690 | + if any_did_dump: | ||
| 691 | + return_val += RETURN_DID_DUMP | ||
| 692 | + if any_err_stream: | ||
| 693 | + return_val += RETURN_ERR_STREAM | ||
| 694 | + if any_err_dumping: | ||
| 695 | + return_val += RETURN_ERR_DUMP | ||
| 696 | + return return_val | ||
| 662 | 697 | ||
| 663 | -if __name__ == '__main__': | ||
| 664 | - main() | ||
| 665 | 698 | ||
| 699 | +if __name__ == '__main__': | ||
| 700 | + sys.exit(main()) |