#!/usr/bin/python from __future__ import with_statement import os import sys import errno import os.path import fuse import db_mod import repo_mod #mport python2x3 import backshift_file_mod import compressed_file_mod import saveset_summary_mod class Backshift_fuse(fuse.LoggingMixIn, fuse.Operations): def __init__(self, backup_id): self.backup_id = backup_id self.canonical_hostname = saveset_summary_mod.canonicalize_hostname() self.repo = repo_mod.Repo(save_directory='.', canonical_hostname=self.canonical_hostname, subset=None) self.repo.to_established_backup_id(self.backup_id) def __call__(self, op, path, *args): return super(Backshift_fuse, self).__call__(op, path, *args) def access(self, path, mode): if not os.access(path, mode): raise fuse.FuseOSError(errno.EACCES) def chmod(self, path, mode): raise fuse.FuseOSError(errno.EROFS) def chown(self, path, uid, gid): raise fuse.FuseOSError(errno.EROFS) def create(self, path, mode): raise fuse.FuseOSError(errno.EROFS) def flush(self, path, fh): raise fuse.FuseOSError(errno.EROFS) def fsync(self, path, datasync, fh): raise fuse.FuseOSError(errno.EROFS) def getattr(self, path, fh=None): print('in getattr!') basename = os.path.basename(path) dirname = os.path.dirname(path) print('basename: %s, dirname: %s' % (basename, dirname)) directory = repo_mod.prepare_initial_directory(self.backup_id, dirname) print('directory: %s' % directory) plus_entries = os.path.join(directory, 'entries') directory_content = db_mod.open(plus_entries, 'rb', backend_open=compressed_file_mod.Compressed_file) print('directory_content: %s' % str(directory_content.items())) try: if basename in directory_content: self.backshift_file = backshift_file_mod.Backshift_file(self.repo, directory_content[basename], directory_content) keys = ('st_ctime', 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid') result = dict((key, getattr(self.backshift_file, key)) for key in keys) return result else: print('basename was not in keys(): %s' % basename) print('directory_content.keys)): %s' % str(directory_content.keys())) raise fuse.FuseOSError(errno.ENOENT) finally: directory_content.close() # DRS: Clearly, this needs to look in the repo instead of the filesystem def getxattr(self, *args, **kwargs): raise fuse.FuseOSError(errno.ENOTSUP) def link(self, target, source): raise fuse.FuseOSError(errno.EROFS) def listxattr(self, *args, **kwargs): raise fuse.FuseOSError(errno.ENOTSUP) def mkdir(self, path, mode=None): raise fuse.FuseOSError(errno.EROFS) def mknod(self, filename, node=None, device=None): raise fuse.FuseOSError(errno.EROFS) def open(self, full_path, flag, mode=None): # DRS: Still need to make this read a backshift file if mode is not None and ('w' in mode or '+' in mode): raise fuse.FuseOSError(errno.EROFS) directory = os.path.dirname(full_path) filename = os.path.basename(full_path) directory_content = db_mod.open(directory, 'rb', backend_open=compressed_file_mod.Compressed_file) self.backshift_file = backshift_file_mod.Backshift_file(self.repo, directory_content[filename], full_path) def read(self, full_path, size, offset, fh): left = offset right = left + size - 1 try: return repo_mod.give_block(self.backshift_file, left, right) except repo_mod.Not_regular_file: raise fuse.FuseOSError(errno.ENOTSUP) def readdir(self, full_path, fh): directory = repo_mod.prepare_initial_directory(self.backup_id, full_path) entries_filename = os.path.join(directory, 'entries') directory_content = db_mod.open(entries_filename, 'rb', backend_open=compressed_file_mod.Compressed_file) list_ = list(directory_content) directory_content.close() yield '.' yield '..' for element in list_: # FIXME: Why do we get back null strings sometimes? if element != '': yield element # DRS: Still need to respect the appropriate file readlink = os.readlink def release(self, path, fh): return os.close(fh) def rename(self, old, new): raise fuse.FuseOSError(errno.EROFS) def rmdir(self, path): raise fuse.FuseOSError(errno.EROFS) def statfs(self, path): raise fuse.FuseOSError(errno.ENODATA) def symlink(self, target, source): raise fuse.FuseOSError(errno.EROFS) def truncate(self, path, length, fh=None): raise fuse.FuseOSError(errno.EROFS) def unlink(self, path): raise fuse.FuseOSError(errno.EROFS) def utimens(self, path, other=None): raise fuse.FuseOSError(errno.EROFS) def write(self, path, data, offset, fh): raise fuse.FuseOSError(errno.EROFS) def usage(retval): sys.stderr.write('%s --save-directory /save/dir --backup-id backup_id --help\n' % sys.argv[0]) sys.exit(retval) def main(): save_directory = None backup_id = None mount_point = None while sys.argv[1:]: if sys.argv[1] == '--save-directory': save_directory = sys.argv[2] del sys.argv[1] elif sys.argv[1] == '--backup-id': backup_id = sys.argv[2] del sys.argv[1] elif sys.argv[1] == '--mount-point': mount_point = sys.argv[2] del sys.argv[1] elif sys.argv[1] in [ '-h', '--help' ]: usage(0) else: sys.stderr.write('%s: Unrecognized option: %s\n' % (sys.argv[0], sys.argv[1])) usage(1) del sys.argv[1] if save_directory is None: sys.stderr.write('%s: --save-directory is a required option\n' % sys.argv[0]) usage(1) if backup_id is None: sys.stderr.write('%s: --backup-id is a required option\n' % sys.argv[0]) usage(1) if mount_point is None: sys.stderr.write('%s: --mount-point is a required option\n' % sys.argv[0]) usage(1) os.chdir(save_directory) _filesystem = fuse.FUSE(Backshift_fuse(backup_id=backup_id), mount_point, foreground=True) if __name__ == "__main__": main() #!/usr/bin/python from __future__ import with_statement import os import sys import errno import os.path import fuse import db_mod import repo_mod #mport python2x3 import backshift_file_mod import compressed_file_mod import saveset_summary_mod class Backshift_fuse(fuse.LoggingMixIn, fuse.Operations): def __init__(self, backup_id): self.backup_id = backup_id self.canonical_hostname = saveset_summary_mod.canonicalize_hostname() self.repo = repo_mod.Repo(save_directory='.', canonical_hostname=self.canonical_hostname, subset=None) self.repo.to_established_backup_id(self.backup_id) def __call__(self, op, path, *args): return super(Backshift_fuse, self).__call__(op, path, *args) def access(self, path, mode): if not os.access(path, mode): raise fuse.FuseOSError(errno.EACCES) def chmod(self, path, mode): raise fuse.FuseOSError(errno.EROFS) def chown(self, path, uid, gid): raise fuse.FuseOSError(errno.EROFS) def create(self, path, mode): raise fuse.FuseOSError(errno.EROFS) def flush(self, path, fh): raise fuse.FuseOSError(errno.EROFS) def fsync(self, path, datasync, fh): raise fuse.FuseOSError(errno.EROFS) def getattr(self, path, fh=None): print('in getattr!') basename = os.path.basename(path) dirname = os.path.dirname(path) print('basename: %s, dirname: %s' % (basename, dirname)) directory = repo_mod.prepare_initial_directory(self.backup_id, dirname) print('directory: %s' % directory) plus_entries = os.path.join(directory, 'entries') directory_content = db_mod.open(plus_entries, 'rb', backend_open=compressed_file_mod.Compressed_file) print('directory_content: %s' % str(directory_content.items())) try: if basename in directory_content: self.backshift_file = backshift_file_mod.Backshift_file(self.repo, directory_content[basename], directory_content) keys = ('st_ctime', 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid') result = dict((key, getattr(self.backshift_file, key)) for key in keys) return result else: print('basename was not in keys(): %s' % basename) print('directory_content.keys)): %s' % str(directory_content.keys())) raise fuse.FuseOSError(errno.ENOENT) finally: directory_content.close() # DRS: Clearly, this needs to look in the repo instead of the filesystem def getxattr(self, *args, **kwargs): raise fuse.FuseOSError(errno.ENOTSUP) def link(self, target, source): raise fuse.FuseOSError(errno.EROFS) def listxattr(self, *args, **kwargs): raise fuse.FuseOSError(errno.ENOTSUP) def mkdir(self, path, mode=None): raise fuse.FuseOSError(errno.EROFS) def mknod(self, filename, node=None, device=None): raise fuse.FuseOSError(errno.EROFS) def open(self, full_path, flag, mode=None): # DRS: Still need to make this read a backshift file if mode is not None and ('w' in mode or '+' in mode): raise fuse.FuseOSError(errno.EROFS) directory = os.path.dirname(full_path) filename = os.path.basename(full_path) directory_content = db_mod.open(directory, 'rb', backend_open=compressed_file_mod.Compressed_file) self.backshift_file = backshift_file_mod.Backshift_file(self.repo, directory_content[filename], full_path) def read(self, full_path, size, offset, fh): left = offset right = left + size - 1 try: return repo_mod.give_block(self.backshift_file, left, right) except repo_mod.Not_regular_file: raise fuse.FuseOSError(errno.ENOTSUP) def readdir(self, full_path, fh): directory = repo_mod.prepare_initial_directory(self.backup_id, full_path) entries_filename = os.path.join(directory, 'entries') directory_content = db_mod.open(entries_filename, 'rb', backend_open=compressed_file_mod.Compressed_file) list_ = list(directory_content) directory_content.close() yield '.' yield '..' for element in list_: # FIXME: Why do we get back null strings sometimes? if element != '': yield element # DRS: Still need to respect the appropriate file readlink = os.readlink def release(self, path, fh): return os.close(fh) def rename(self, old, new): raise fuse.FuseOSError(errno.EROFS) def rmdir(self, path): raise fuse.FuseOSError(errno.EROFS) def statfs(self, path): raise fuse.FuseOSError(errno.ENODATA) def symlink(self, target, source): raise fuse.FuseOSError(errno.EROFS) def truncate(self, path, length, fh=None): raise fuse.FuseOSError(errno.EROFS) def unlink(self, path): raise fuse.FuseOSError(errno.EROFS) def utimens(self, path, other=None): raise fuse.FuseOSError(errno.EROFS) def write(self, path, data, offset, fh): raise fuse.FuseOSError(errno.EROFS) def usage(retval): sys.stderr.write('%s --save-directory /save/dir --backup-id backup_id --help\n' % sys.argv[0]) sys.exit(retval) def main(): save_directory = None backup_id = None mount_point = None while sys.argv[1:]: if sys.argv[1] == '--save-directory': save_directory = sys.argv[2] del sys.argv[1] elif sys.argv[1] == '--backup-id': backup_id = sys.argv[2] del sys.argv[1] elif sys.argv[1] == '--mount-point': mount_point = sys.argv[2] del sys.argv[1] elif sys.argv[1] in [ '-h', '--help' ]: usage(0) else: sys.stderr.write('%s: Unrecognized option: %s\n' % (sys.argv[0], sys.argv[1])) usage(1) del sys.argv[1] if save_directory is None: sys.stderr.write('%s: --save-directory is a required option\n' % sys.argv[0]) usage(1) if backup_id is None: sys.stderr.write('%s: --backup-id is a required option\n' % sys.argv[0]) usage(1) if mount_point is None: sys.stderr.write('%s: --mount-point is a required option\n' % sys.argv[0]) usage(1) os.chdir(save_directory) _filesystem = fuse.FUSE(Backshift_fuse(backup_id=backup_id), mount_point, foreground=True) if __name__ == "__main__": main()