jpayne@0: #! /usr/bin/env python3 jpayne@0: jpayne@0: from fuse import FUSE, FuseOSError, Operations, LoggingMixIn jpayne@0: from multiprocessing import Process jpayne@0: jpayne@0: import argparse jpayne@0: import logging jpayne@0: import os, os.path, sys jpayne@0: import subprocess jpayne@0: import tarfile jpayne@0: jpayne@0: jpayne@0: class ArchiveDir(LoggingMixIn, Operations): jpayne@0: "FUSE object to open a tar.bz file and expose it as a read-only directory" jpayne@0: def __init__(self, archive): jpayne@0: self.archive = archive jpayne@0: self.openfiles = {} jpayne@0: jpayne@0: def readdir(self, path, fh): jpayne@0: for symbol in ['.','..']: jpayne@0: yield symbol jpayne@0: for name in self.archive.getnames(): jpayne@0: yield name jpayne@0: jpayne@0: # def statfs(self, fh): jpayne@0: # return dict(f_bavail=0, jpayne@0: # f_bfree=0, jpayne@0: # f_blocks=0, jpayne@0: # f_bsize=0, jpayne@0: # f_favail=0, jpayne@0: # f_ffree=0, jpayne@0: # f_files=0, jpayne@0: # f_flag=0, jpayne@0: # f_frsize=0, jpayne@0: # f_namemax=0) jpayne@0: jpayne@0: def getattr(self, path, fh=None): jpayne@0: name = os.path.basename(path) jpayne@0: info = self.archive.getmember(name) jpayne@0: return dict(st_atime=info.mtime, jpayne@0: st_ctime=info.mtime, jpayne@0: st_gid=info.gid, jpayne@0: st_mode=info.mode, jpayne@0: st_nlink=2, jpayne@0: st_size=info.size, jpayne@0: st_mtime=info.mtime) jpayne@0: jpayne@0: def open(self, path, flags): jpayne@0: name = os.path.basename(path) jpayne@0: self.openfiles[name] = self.archive.extractfile(name) jpayne@0: jpayne@0: def release(self, path, fh): jpayne@0: name = os.path.basename(path) jpayne@0: self.openfiles[name].close() jpayne@0: del self.openfiles[name] jpayne@0: jpayne@0: def read(self, path, length, offset, fh): jpayne@0: name = os.path.basename(path) jpayne@0: fh = self.openfiles[name] jpayne@0: fh.seek(offset) jpayne@0: return fh.read(length=length) jpayne@0: jpayne@0: jpayne@0: def start_fs(arch, mount_point): jpayne@0: FUSE(ArchiveDir(arch), jpayne@0: mount_point, jpayne@0: nothreads=True, jpayne@0: foreground=False, jpayne@0: rdonly=True, jpayne@0: volname="snp-fuse") #does this block? jpayne@0: jpayne@0: jpayne@0: def main(archive, mount_point, command): jpayne@0: with tarfile.open(archive, 'r:bz2') as arch: jpayne@0: #t = Process(target=start_fs, args=(arch, mount_point), daemon=True) jpayne@0: #t.start() jpayne@0: start_fs(arch, mount_point) jpayne@0: subprocess.check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr) jpayne@0: #t.terminate() jpayne@0: #t.join() jpayne@0: jpayne@0: jpayne@0: if __name__ == '__main__': jpayne@0: # create the default logger used by the logging mixin jpayne@0: logger = logging.getLogger('fuse.log-mixin') jpayne@0: logger.setLevel(logging.DEBUG) jpayne@0: # create console handler with a higher log level jpayne@0: ch = logging.StreamHandler() jpayne@0: ch.setLevel(logging.DEBUG) jpayne@0: # add the handlers to the logger jpayne@0: logger.addHandler(ch) jpayne@0: parser = argparse.ArgumentParser(description="mount a bzip2 archive for reading") jpayne@0: parser.add_argument('archive') jpayne@0: parser.add_argument('mount_point') jpayne@0: parser.add_argument('command') jpayne@0: args = parser.parse_args() jpayne@0: main(**vars(args))