X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=cmd%2Ffuse-cmd.py;h=8e57ab6f937dab330f4f7fd6e5c4618e1812dfe6;hb=6b6559e405d264d4127211b935b21a3dda93ad93;hp=64880975d861eb71be80ce34e15a6ea8b853a718;hpb=0e3565afb1cc11683eae5107d80d7d7ef66ed34c;p=bup.git diff --git a/cmd/fuse-cmd.py b/cmd/fuse-cmd.py index 6488097..8e57ab6 100755 --- a/cmd/fuse-cmd.py +++ b/cmd/fuse-cmd.py @@ -1,130 +1,129 @@ -#!/usr/bin/env python -import sys, os, stat, errno, fuse, re, time, tempfile -from bup import options, git, vfs -from bup.helpers import * +#!/bin/sh +"""": # -*-python-*- +bup_python="$(dirname "$0")/bup-python" || exit $? +exec "$bup_python" "$0" ${1+"$@"} +""" +# end of bup preamble +from __future__ import absolute_import +import sys, os, errno -class Stat(fuse.Stat): - def __init__(self): - self.st_mode = 0 - self.st_ino = 0 - self.st_dev = 0 - self.st_nlink = 0 - self.st_uid = 0 - self.st_gid = 0 - self.st_size = 0 - self.st_atime = 0 - self.st_mtime = 0 - self.st_ctime = 0 - self.st_blocks = 0 - self.st_blksize = 0 - self.st_rdev = 0 +try: + import fuse +except ImportError: + log('error: cannot find the python "fuse" module; please install it\n') + sys.exit(1) +if not hasattr(fuse, '__version__'): + raise RuntimeError('your fuse module is too old for fuse.__version__') +fuse.fuse_python_api = (0, 2) +from bup import options, git, vfs, xstat +from bup.helpers import log +from bup.repo import LocalRepo -cache = {} -def cache_get(top, path): - parts = path.split('/') - cache[('',)] = top - c = None - max = len(parts) - #log('cache: %r\n' % cache.keys()) - for i in range(max): - pre = parts[:max-i] - #log('cache trying: %r\n' % pre) - c = cache.get(tuple(pre)) - if c: - rest = parts[max-i:] - for r in rest: - #log('resolving %r from %r\n' % (r, c.fullname())) - c = c.lresolve(r) - key = tuple(pre + [r]) - #log('saving: %r\n' % (key,)) - cache[key] = c - break - assert(c) - return c - - +# FIXME: self.meta and want_meta? class BupFs(fuse.Fuse): - def __init__(self, top): + def __init__(self, repo, verbose=0, fake_metadata=False): fuse.Fuse.__init__(self) - self.top = top + self.repo = repo + self.verbose = verbose + self.fake_metadata = fake_metadata def getattr(self, path): - log('--getattr(%r)\n' % path) - try: - node = cache_get(self.top, path) - st = Stat() - st.st_mode = node.mode - st.st_nlink = node.nlinks() - st.st_size = node.size() - st.st_mtime = node.mtime - st.st_ctime = node.ctime - st.st_atime = node.atime - return st - except vfs.NoSuchFile: + global opt + if self.verbose > 0: + log('--getattr(%r)\n' % path) + res = vfs.resolve(self.repo, path, want_meta=(not self.fake_metadata), + follow=False) + name, item = res[-1] + if not item: return -errno.ENOENT + if self.fake_metadata: + item = vfs.augment_item_meta(self.repo, item, include_size=True) + else: + item = vfs.ensure_item_has_metadata(self.repo, item, + include_size=True) + meta = item.meta + # FIXME: do we want/need to do anything more with nlink? + st = fuse.Stat(st_mode=meta.mode, st_nlink=1, st_size=meta.size) + st.st_mode = meta.mode + st.st_uid = meta.uid + st.st_gid = meta.gid + st.st_atime = max(0, xstat.fstime_floor_secs(meta.atime)) + st.st_mtime = max(0, xstat.fstime_floor_secs(meta.mtime)) + st.st_ctime = max(0, xstat.fstime_floor_secs(meta.ctime)) + return st def readdir(self, path, offset): - log('--readdir(%r)\n' % path) - node = cache_get(self.top, path) - yield fuse.Direntry('.') + assert not offset # We don't return offsets, so offset should be unused + res = vfs.resolve(self.repo, path, follow=False) + dir_name, dir_item = res[-1] + if not dir_item: + yield -errno.ENOENT yield fuse.Direntry('..') - for sub in node.subs(): - yield fuse.Direntry(sub.name) + # FIXME: make sure want_meta=False is being completely respected + for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False): + yield fuse.Direntry(ent_name.replace('/', '-')) def readlink(self, path): - log('--readlink(%r)\n' % path) - node = cache_get(self.top, path) - return node.readlink() + if self.verbose > 0: + log('--readlink(%r)\n' % path) + res = vfs.resolve(self.repo, path, follow=False) + name, item = res[-1] + if not item: + return -errno.ENOENT + return vfs.readlink(repo, item) def open(self, path, flags): - log('--open(%r)\n' % path) - node = cache_get(self.top, path) + if self.verbose > 0: + log('--open(%r)\n' % path) + res = vfs.resolve(self.repo, path, follow=False) + name, item = res[-1] + if not item: + return -errno.ENOENT accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR if (flags & accmode) != os.O_RDONLY: return -errno.EACCES - node.open() - - def release(self, path, flags): - log('--release(%r)\n' % path) + # Return None since read doesn't need the file atm... + # If we *do* return the file, it'll show up as the last argument + #return vfs.fopen(repo, item) def read(self, path, size, offset): - log('--read(%r)\n' % path) - n = cache_get(self.top, path) - o = n.open() - o.seek(offset) - return o.read(size) - - -if not hasattr(fuse, '__version__'): - raise RuntimeError, "your fuse module is too old for fuse.__version__" -fuse.fuse_python_api = (0, 2) - + if self.verbose > 0: + log('--read(%r)\n' % path) + res = vfs.resolve(self.repo, path, follow=False) + name, item = res[-1] + if not item: + return -errno.ENOENT + with vfs.fopen(repo, item) as f: + f.seek(offset) + return f.read(size) optspec = """ bup fuse [-d] [-f] -- -d,debug increase debug level f,foreground run in foreground +d,debug run in the foreground and display FUSE debug information +o,allow-other allow other users to access the filesystem +meta report original metadata for paths when available +v,verbose increase log output (can be used more than once) """ -o = options.Options('bup fuse', optspec) -(opt, flags, extra) = o.parse(sys.argv[1:]) +o = options.Options(optspec) +opt, flags, extra = o.parse(sys.argv[1:]) if len(extra) != 1: - o.fatal("exactly one argument expected") + o.fatal('only one mount point argument expected') git.check_repo_or_die() -top = vfs.RefList(None) -f = BupFs(top) +repo = LocalRepo() +f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta)) f.fuse_args.mountpoint = extra[0] if opt.debug: f.fuse_args.add('debug') if opt.foreground: f.fuse_args.setmod('foreground') -print f.multithreaded f.multithreaded = False -f.fuse_args.add('allow_other') - +if opt.allow_other: + f.fuse_args.add('allow_other') f.main()