#!/usr/bin/env python

import mobius.tsk
import mobius.config
import optparse
import sys

print '%s v%s' % (mobius.config.APP_NAME, mobius.config.APP_VERSION)
print 'Python API - TSK Example'
print 'by Eduardo Aguiar'
print

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief show entry metadata
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def show_entry_metadata (entry, stream, indent):
  filename = entry.name

  if stream:
    inode = '%d-%d-%d' % (entry.inode, stream.type, stream.id)

    if stream.name and stream.name != '$I30':
      filename += ':' + stream.name

  else:
    inode = str (entry.inode)

  print '%s%s (%s) -> %s (inode=%s%s, deleted=%s, size=%d, mode=%o, uid=%d, gid=%d, atime=%s, mtime=%s, ctime=%s, crtime=%s, dtime=%s)' % \
			(indent, filename, entry.short_name or '', entry.path or '', inode, '(realloc)' if entry.is_reallocated else '', entry.is_deleted, entry.size, entry.mode, entry.uid, entry.gid, entry.atime, entry.mtime, entry.ctime, entry.crtime, entry.dtime)
  
  if stream:

    if stream.size < 4096:
      data_4k = stream.read ()	# full read test

    else:
      data_4k = stream.read (4096)

    print indent, '  ', ' '.join (['%02x' % ord (c) for c in data_4k[:16]])
 
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief show entry
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def show_entry (entry, visited=set (), indent=''):

  if (entry.inode == 0 and entry.name != "$MFT") or entry.name in ('.', '..'):
    return

  if not entry.is_deleted:
    if entry.inode in visited:
      return
    else:
      visited.add (entry.inode)

  # show entry metadata
  for stream in entry.streams or [None]:
    show_entry_metadata (entry, stream, indent)
 
  # recurse into children
  if not entry.is_reallocated:
    for child in entry.children:
      try:
        show_entry (child, visited, indent + '  ')
      except Exception, e:
        print 'Warning:', e

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# process command line
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
parser = optparse.OptionParser ()
parser.add_option ("-o", "--offset", dest="offset", help="offset in sectors", default=0)

(option, args) = parser.parse_args ()

if not args:
  print 'You must enter a valid path to a disk image file'
  sys.exit (2)

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# show data
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
diskimage = mobius.tsk.DiskImage (args[0])
print 'imagefile'
print '    type:', diskimage.type
print '    size:', diskimage.size
print '    sector size:', diskimage.sector_size

filesystem = mobius.tsk.FileSystem (diskimage, int (option.offset) * 512)
print
print 'filesystem'
print '    offset:', filesystem.offset
print '    inode count:', filesystem.inode_count
print '    root inode:', filesystem.root_inode
print '    first inode:', filesystem.first_inode
print '    last inode:', filesystem.last_inode
print '    id:', filesystem.id

root = filesystem.root_entry
print
print 'root entry'
print '    size:', root.size
print '    inode:', root.inode
print '    name:', root.name
print '    short name:', root.short_name
print '    path:', root.path

show_entry (root)
