Commit c16ca78e7fa836ca8cbd3f23e6896edb1763f1c9
1 parent
b460e8e2
oletimes: added optparse and xglob to process multiple files and zips (issue #141)
Showing
1 changed file
with
63 additions
and
28 deletions
oletools/oletimes.py
| ... | ... | @@ -49,19 +49,19 @@ http://www.decalage.info/python/oletools |
| 49 | 49 | # 2016-07-20 v0.50 SL: - added Python 3 support |
| 50 | 50 | # 2016-09-05 PL: - added main entry point for setup.py |
| 51 | 51 | # 2017-05-03 v0.51 PL: - fixed absolute imports (issue #141) |
| 52 | +# 2017-05-04 PL: - added optparse and xglob | |
| 52 | 53 | |
| 53 | 54 | __version__ = '0.51dev7' |
| 54 | 55 | |
| 55 | 56 | #------------------------------------------------------------------------------ |
| 56 | 57 | # TODO: |
| 57 | -# + optparse | |
| 58 | 58 | # + nicer output: table with fixed columns, datetime, etc |
| 59 | 59 | # + CSV output |
| 60 | 60 | # + option to only show available timestamps (by default?) |
| 61 | 61 | |
| 62 | 62 | #=== IMPORTS ================================================================= |
| 63 | 63 | |
| 64 | -import sys, os, datetime | |
| 64 | +import sys, os, optparse | |
| 65 | 65 | |
| 66 | 66 | # IMPORTANT: it should be possible to run oletools directly as scripts |
| 67 | 67 | # in any directory without installing them with pip or setup.py. |
| ... | ... | @@ -76,47 +76,82 @@ if not _parent_dir in sys.path: |
| 76 | 76 | sys.path.insert(0, _parent_dir) |
| 77 | 77 | |
| 78 | 78 | from oletools.thirdparty import olefile |
| 79 | +from oletools.thirdparty import xglob | |
| 79 | 80 | from oletools.thirdparty.prettytable import prettytable |
| 80 | 81 | |
| 81 | 82 | |
| 82 | -# === MAIN =================================================================== | |
| 83 | +# === FUNCTIONS ============================================================== | |
| 83 | 84 | |
| 84 | -def main(): | |
| 85 | - # print banner with version | |
| 86 | - print('oletimes %s - http://decalage.info/python/oletools' % __version__) | |
| 85 | +def dt2str(dt): | |
| 86 | + """ | |
| 87 | + Convert a datetime object to a string for display, without microseconds | |
| 87 | 88 | |
| 88 | - try: | |
| 89 | - ole = olefile.OleFileIO(sys.argv[1]) | |
| 90 | - except IndexError: | |
| 91 | - sys.exit(__doc__) | |
| 89 | + :param dt: datetime.datetime object, or None | |
| 90 | + :return: str, or None | |
| 91 | + """ | |
| 92 | + if dt is None: | |
| 93 | + return None | |
| 94 | + dt = dt.replace(microsecond=0) | |
| 95 | + return str(dt) | |
| 92 | 96 | |
| 93 | - def dt2str (dt): | |
| 94 | - """ | |
| 95 | - Convert a datetime object to a string for display, without microseconds | |
| 96 | - | |
| 97 | - :param dt: datetime.datetime object, or None | |
| 98 | - :return: str, or None | |
| 99 | - """ | |
| 100 | - if dt is None: | |
| 101 | - return None | |
| 102 | - dt = dt.replace(microsecond = 0) | |
| 103 | - return str(dt) | |
| 104 | 97 | |
| 98 | +def process_ole(ole): | |
| 105 | 99 | t = prettytable.PrettyTable(['Stream/Storage name', 'Modification Time', 'Creation Time']) |
| 106 | 100 | t.align = 'l' |
| 107 | 101 | t.max_width = 26 |
| 108 | - #t.border = False | |
| 109 | - | |
| 110 | - #print'- Root mtime=%s ctime=%s' % (ole.root.getmtime(), ole.root.getctime()) | |
| 111 | 102 | t.add_row(('Root', dt2str(ole.root.getmtime()), dt2str(ole.root.getctime()))) |
| 112 | - | |
| 113 | 103 | for obj in ole.listdir(streams=True, storages=True): |
| 114 | - #print '- %s: mtime=%s ctime=%s' % (repr('/'.join(obj)), ole.getmtime(obj), ole.getctime(obj)) | |
| 115 | 104 | t.add_row((repr('/'.join(obj)), dt2str(ole.getmtime(obj)), dt2str(ole.getctime(obj)))) |
| 116 | - | |
| 117 | 105 | print(t) |
| 118 | 106 | |
| 119 | - ole.close() | |
| 107 | + | |
| 108 | +# === MAIN =================================================================== | |
| 109 | + | |
| 110 | +def main(): | |
| 111 | + # print banner with version | |
| 112 | + print('oletimes %s - http://decalage.info/python/oletools' % __version__) | |
| 113 | + print ('THIS IS WORK IN PROGRESS - Check updates regularly!') | |
| 114 | + print ('Please report any issue at https://github.com/decalage2/oletools/issues') | |
| 115 | + print ('') | |
| 116 | + | |
| 117 | + usage = 'usage: oletimes [options] <filename> [filename2 ...]' | |
| 118 | + parser = optparse.OptionParser(usage=usage) | |
| 119 | + parser.add_option("-r", action="store_true", dest="recursive", | |
| 120 | + help='find files recursively in subdirectories.') | |
| 121 | + parser.add_option("-z", "--zip", dest='zip_password', type='str', default=None, | |
| 122 | + help='if the file is a zip archive, open all files from it, using the provided password (requires Python 2.6+)') | |
| 123 | + parser.add_option("-f", "--zipfname", dest='zip_fname', type='str', default='*', | |
| 124 | + help='if the file is a zip archive, file(s) to be opened within the zip. Wildcards * and ? are supported. (default:*)') | |
| 125 | + | |
| 126 | + # TODO: add logfile option | |
| 127 | + # parser.add_option('-l', '--loglevel', dest="loglevel", action="store", default=DEFAULT_LOG_LEVEL, | |
| 128 | + # help="logging level debug/info/warning/error/critical (default=%default)") | |
| 129 | + | |
| 130 | + (options, args) = parser.parse_args() | |
| 131 | + | |
| 132 | + # Print help if no arguments are passed | |
| 133 | + if len(args) == 0: | |
| 134 | + print(__doc__) | |
| 135 | + parser.print_help() | |
| 136 | + sys.exit() | |
| 137 | + | |
| 138 | + for container, filename, data in xglob.iter_files(args, recursive=options.recursive, | |
| 139 | + zip_password=options.zip_password, zip_fname=options.zip_fname): | |
| 140 | + # TODO: handle xglob errors | |
| 141 | + # ignore directory names stored in zip files: | |
| 142 | + if container and filename.endswith('/'): | |
| 143 | + continue | |
| 144 | + full_name = '%s in %s' % (filename, container) if container else filename | |
| 145 | + print("=" * 79) | |
| 146 | + print('FILE: %s\n' % full_name) | |
| 147 | + if data is not None: | |
| 148 | + # data extracted from zip file | |
| 149 | + ole = olefile.OleFileIO(data) | |
| 150 | + else: | |
| 151 | + # normal filename | |
| 152 | + ole = olefile.OleFileIO(filename) | |
| 153 | + process_ole(ole) | |
| 154 | + ole.close() | |
| 120 | 155 | |
| 121 | 156 | if __name__ == '__main__': |
| 122 | 157 | main() | ... | ... |