PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/samples/tskfuse.py

https://code.google.com/p/pytsk/
Python | 281 lines | 190 code | 62 blank | 29 comment | 20 complexity | d2006dee3bcaf6620198fb915d6992a0 MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/env python
  2. import images
  3. import pytsk3
  4. import stat
  5. from errno import *
  6. import pdb
  7. import os, sys, re
  8. # pull in some spaghetti to make this stuff work without fuse-py being installed
  9. try:
  10. import _find_fuse_parts
  11. except ImportError:
  12. pass
  13. import fuse
  14. from fuse import Fuse
  15. if not hasattr(fuse, '__version__'):
  16. raise RuntimeError, \
  17. "your fuse-py doesn't know of fuse.__version__, probably it's too old."
  18. fuse.fuse_python_api = (0, 2)
  19. fuse.feature_assert('stateful_files', 'has_init')
  20. int_re = re.compile("^(\d+)([kKmMgGs]?)$")
  21. def parse_int(string):
  22. """ Parses an integer from a string. Supports suffixes """
  23. try:
  24. m = int_re.match(string)
  25. except TypeError:
  26. return int(string)
  27. if not m: raise ValueError("%r is not an integer" % string)
  28. base = int(m.group(1))
  29. suffix = m.group(2).lower()
  30. if not suffix:
  31. return base
  32. if suffix == 's':
  33. return base * 512
  34. if suffix == 'k':
  35. return base * 1024
  36. if suffix == 'm':
  37. return base * 1024 * 1024
  38. if suffix == 'g':
  39. return base * 1024 * 1024 * 1024
  40. raise ValueError("Unknown suffix '%r'" % suffix)
  41. ## A stub to allow for overriding later
  42. Img_Info = pytsk3.Img_Info
  43. def make_stat(meta):
  44. """ Return a stat structure from TSK metadata struct """
  45. meta_type_dispatcher = {
  46. pytsk3.TSK_FS_META_TYPE_DIR: stat.S_IFDIR,
  47. pytsk3.TSK_FS_META_TYPE_REG: stat.S_IFREG,
  48. pytsk3.TSK_FS_META_TYPE_FIFO: stat.S_IFIFO,
  49. pytsk3.TSK_FS_META_TYPE_CHR: stat.S_IFCHR,
  50. pytsk3.TSK_FS_META_TYPE_LNK: stat.S_IFLNK,
  51. pytsk3.TSK_FS_META_TYPE_BLK: stat.S_IFBLK,
  52. }
  53. s = fuse.Stat()
  54. s.st_ino = meta.addr
  55. s.st_dev = 0
  56. s.st_nlink = meta.nlink
  57. s.st_uid = meta.uid
  58. s.st_gid = meta.gid
  59. s.st_size = meta.size
  60. s.st_atime = meta.atime
  61. s.st_mtime = meta.mtime
  62. s.st_ctime = meta.crtime
  63. s.st_blocks = 2
  64. s.st_rdev = 0
  65. s.st_mode = meta_type_dispatcher.get(int(meta.type), 0)
  66. s.st_mode |= int(meta.mode)
  67. return s
  68. class TSKFuse(Fuse):
  69. """ A class that makes a filesystem appear in a fuse
  70. filesystem. This is kind of like mounting it, but it uses the
  71. sleuthkit.
  72. """
  73. offset = '0'
  74. def __init__(self, *args, **kw):
  75. Fuse.__init__(self, *args, **kw)
  76. def main(self):
  77. options, args = self.parser.parse_args()
  78. self.img = images.SelectImage(options.type, args)
  79. self.offset = parse_int(options.offset)
  80. self.fs = pytsk3.FS_Info(self.img, offset = self.offset)
  81. ## Prepare the file class - this will be used to read specific
  82. ## files:
  83. self.file_class = self.TSKFuseFile
  84. self.file_class.fs = self.fs
  85. return Fuse.main(self)
  86. def getattr(self, path):
  87. try:
  88. f = self.fs.open(path)
  89. except RuntimeError: return None
  90. s = make_stat(f.info.meta)
  91. s.st_blksize = self.fs.info.block_size
  92. return s
  93. def readdir(self, path, offset):
  94. for f in self.fs.open_dir(path):
  95. try:
  96. result = fuse.Direntry(f.info.name.name)
  97. if f.info.meta.type == pytsk3.TSK_FS_META_TYPE_DIR:
  98. result.type = stat.S_IFDIR
  99. else:
  100. result.type = stat.S_IFREG
  101. except AttributeError: pass
  102. yield result
  103. def unlink(self, path):
  104. pass
  105. def rmdir(self, path):
  106. pass
  107. def symlink(self, path, path1):
  108. pass
  109. def rename(self, path, path1):
  110. pass
  111. def link(self, path, path1):
  112. pass
  113. def chmod(self, path, mode):
  114. pass
  115. def chown(self, path, user, group):
  116. pass
  117. def truncate(self, path, len):
  118. pass
  119. def mknod(self, path, mode, dev):
  120. pass
  121. def mkdir(self, path, mode):
  122. pass
  123. def utime(self, path, times):
  124. pass
  125. def access(self, path, mode):
  126. pass
  127. def statfs(self):
  128. """
  129. Should return an object with statvfs attributes (f_bsize, f_frsize...).
  130. Eg., the return value of os.statvfs() is such a thing (since py 2.2).
  131. If you are not reusing an existing statvfs object, start with
  132. fuse.StatVFS(), and define the attributes.
  133. To provide usable information (ie., you want sensible df(1)
  134. output, you are suggested to specify the following attributes:
  135. - f_bsize - preferred size of file blocks, in bytes
  136. - f_frsize - fundamental size of file blcoks, in bytes
  137. [if you have no idea, use the same as blocksize]
  138. - f_blocks - total number of blocks in the filesystem
  139. - f_bfree - number of free blocks
  140. - f_files - total number of file inodes
  141. - f_ffree - nunber of free file inodes
  142. """
  143. s=fuse.StatVfs()
  144. info = self.fs.info
  145. s.f_bsize = info.dev_bsize
  146. s.f_frsize = 0
  147. s.f_blocks = info.block_count
  148. s.f_bfree = 0
  149. s.f_files = info.inum_count
  150. s.f_ffree = 0
  151. return s
  152. def fsinit(self):
  153. pass
  154. class TSKFuseFile(object):
  155. """ This is a file created on the AFF4 universe """
  156. direct_io = False
  157. keep_cache = True
  158. def __init__(self, path, flags, *mode):
  159. self.path = path
  160. try:
  161. self.fd = self.fs.open(path = path)
  162. except RuntimeError:
  163. raise IOError("unable to open %s" % path)
  164. def read(self, length, offset):
  165. return self.fd.read_random(offset, length)
  166. def _fflush(self):
  167. pass
  168. def fsync(self, isfsyncfile):
  169. pass
  170. def flush(self):
  171. pass
  172. def fgetattr(self):
  173. s = make_stat(self.fd.info.meta)
  174. s.st_blksize = self.fs.info.block_size
  175. return s
  176. def ftruncate(self, len):
  177. pass
  178. def write(self, *args, **kwargs):
  179. return -EOPNOTSUPP
  180. def lock(self, cmd, owner, **kw):
  181. return -EOPNOTSUPP
  182. def close(self):
  183. self.fd.close()
  184. def main():
  185. global server
  186. usage = """
  187. Userspace tsk-fuse: mount a filesystem through fuse.
  188. %prog [options] image_name mount_point
  189. """
  190. server = TSKFuse(version="%prog " + fuse.__version__,
  191. usage=usage,
  192. dash_s_do='setsingle')
  193. # Disable multithreading: if you want to use it, protect all method of
  194. # XmlFile class with locks, in order to prevent race conditions
  195. server.multithreaded = False
  196. server.parser.add_option("-O", "--offset", default="0",
  197. help="Offset of filesystem [default: %default]")
  198. server.parser.add_option("-t", "--type", default="raw",
  199. help="Type of image. Currently supported options 'raw', "
  200. "'ewf'")
  201. server.parse(values = server, errex=1)
  202. ## Try to fix up the mount point if it was given relative to the
  203. ## CWD
  204. if server.fuse_args.mountpoint and not os.access(os.path.join("/",server.fuse_args.mountpoint), os.W_OK):
  205. server.fuse_args.mountpoint = os.path.join(os.getcwd(), server.fuse_args.mountpoint)
  206. server.main()
  207. if __name__ == '__main__':
  208. main()