jpayne@0
|
1 #! /usr/bin/env python3
|
jpayne@0
|
2
|
jpayne@0
|
3 from fuse import FUSE, FuseOSError, Operations, LoggingMixIn
|
jpayne@0
|
4 from multiprocessing import Process
|
jpayne@0
|
5
|
jpayne@0
|
6 import argparse
|
jpayne@0
|
7 import logging
|
jpayne@0
|
8 import os, os.path, sys
|
jpayne@0
|
9 import subprocess
|
jpayne@0
|
10 import tarfile
|
jpayne@0
|
11
|
jpayne@0
|
12
|
jpayne@0
|
13 class ArchiveDir(LoggingMixIn, Operations):
|
jpayne@0
|
14 "FUSE object to open a tar.bz file and expose it as a read-only directory"
|
jpayne@0
|
15 def __init__(self, archive):
|
jpayne@0
|
16 self.archive = archive
|
jpayne@0
|
17 self.openfiles = {}
|
jpayne@0
|
18
|
jpayne@0
|
19 def readdir(self, path, fh):
|
jpayne@0
|
20 for symbol in ['.','..']:
|
jpayne@0
|
21 yield symbol
|
jpayne@0
|
22 for name in self.archive.getnames():
|
jpayne@0
|
23 yield name
|
jpayne@0
|
24
|
jpayne@0
|
25 # def statfs(self, fh):
|
jpayne@0
|
26 # return dict(f_bavail=0,
|
jpayne@0
|
27 # f_bfree=0,
|
jpayne@0
|
28 # f_blocks=0,
|
jpayne@0
|
29 # f_bsize=0,
|
jpayne@0
|
30 # f_favail=0,
|
jpayne@0
|
31 # f_ffree=0,
|
jpayne@0
|
32 # f_files=0,
|
jpayne@0
|
33 # f_flag=0,
|
jpayne@0
|
34 # f_frsize=0,
|
jpayne@0
|
35 # f_namemax=0)
|
jpayne@0
|
36
|
jpayne@0
|
37 def getattr(self, path, fh=None):
|
jpayne@0
|
38 name = os.path.basename(path)
|
jpayne@0
|
39 info = self.archive.getmember(name)
|
jpayne@0
|
40 return dict(st_atime=info.mtime,
|
jpayne@0
|
41 st_ctime=info.mtime,
|
jpayne@0
|
42 st_gid=info.gid,
|
jpayne@0
|
43 st_mode=info.mode,
|
jpayne@0
|
44 st_nlink=2,
|
jpayne@0
|
45 st_size=info.size,
|
jpayne@0
|
46 st_mtime=info.mtime)
|
jpayne@0
|
47
|
jpayne@0
|
48 def open(self, path, flags):
|
jpayne@0
|
49 name = os.path.basename(path)
|
jpayne@0
|
50 self.openfiles[name] = self.archive.extractfile(name)
|
jpayne@0
|
51
|
jpayne@0
|
52 def release(self, path, fh):
|
jpayne@0
|
53 name = os.path.basename(path)
|
jpayne@0
|
54 self.openfiles[name].close()
|
jpayne@0
|
55 del self.openfiles[name]
|
jpayne@0
|
56
|
jpayne@0
|
57 def read(self, path, length, offset, fh):
|
jpayne@0
|
58 name = os.path.basename(path)
|
jpayne@0
|
59 fh = self.openfiles[name]
|
jpayne@0
|
60 fh.seek(offset)
|
jpayne@0
|
61 return fh.read(length=length)
|
jpayne@0
|
62
|
jpayne@0
|
63
|
jpayne@0
|
64 def start_fs(arch, mount_point):
|
jpayne@0
|
65 FUSE(ArchiveDir(arch),
|
jpayne@0
|
66 mount_point,
|
jpayne@0
|
67 nothreads=True,
|
jpayne@0
|
68 foreground=False,
|
jpayne@0
|
69 rdonly=True,
|
jpayne@0
|
70 volname="snp-fuse") #does this block?
|
jpayne@0
|
71
|
jpayne@0
|
72
|
jpayne@0
|
73 def main(archive, mount_point, command):
|
jpayne@0
|
74 with tarfile.open(archive, 'r:bz2') as arch:
|
jpayne@0
|
75 #t = Process(target=start_fs, args=(arch, mount_point), daemon=True)
|
jpayne@0
|
76 #t.start()
|
jpayne@0
|
77 start_fs(arch, mount_point)
|
jpayne@0
|
78 subprocess.check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr)
|
jpayne@0
|
79 #t.terminate()
|
jpayne@0
|
80 #t.join()
|
jpayne@0
|
81
|
jpayne@0
|
82
|
jpayne@0
|
83 if __name__ == '__main__':
|
jpayne@0
|
84 # create the default logger used by the logging mixin
|
jpayne@0
|
85 logger = logging.getLogger('fuse.log-mixin')
|
jpayne@0
|
86 logger.setLevel(logging.DEBUG)
|
jpayne@0
|
87 # create console handler with a higher log level
|
jpayne@0
|
88 ch = logging.StreamHandler()
|
jpayne@0
|
89 ch.setLevel(logging.DEBUG)
|
jpayne@0
|
90 # add the handlers to the logger
|
jpayne@0
|
91 logger.addHandler(ch)
|
jpayne@0
|
92 parser = argparse.ArgumentParser(description="mount a bzip2 archive for reading")
|
jpayne@0
|
93 parser.add_argument('archive')
|
jpayne@0
|
94 parser.add_argument('mount_point')
|
jpayne@0
|
95 parser.add_argument('command')
|
jpayne@0
|
96 args = parser.parse_args()
|
jpayne@0
|
97 main(**vars(args))
|