From: Rob Browning Date: Sat, 2 Dec 2017 19:31:13 +0000 (-0600) Subject: Port fuse to vfs2 X-Git-Tag: 0.30~130 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=bup.git;a=commitdiff_plain;h=268cd08083e33c630a99dfa108cfdb2f0b5c5482 Port fuse to vfs2 The test adjustment was necessary because fuse now notices new saves. Signed-off-by: Rob Browning Tested-by: Rob Browning --- diff --git a/cmd/fuse-cmd.py b/cmd/fuse-cmd.py index 66e2b87..14ae508 100755 --- a/cmd/fuse-cmd.py +++ b/cmd/fuse-cmd.py @@ -7,114 +7,97 @@ exec "$bup_python" "$0" ${1+"$@"} import sys, os, errno -from bup import options, git, vfs, xstat -from bup.helpers import buglvl, log - 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, vfs2 as 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) - if buglvl >= 1: - log('cache: %r\n' % cache.keys()) - for i in range(max): - pre = parts[:max-i] - if buglvl >= 1: - log('cache trying: %r\n' % pre) - c = cache.get(tuple(pre)) - if c: - rest = parts[max-i:] - for r in rest: - if buglvl >= 1: - log('resolving %r from %r\n' % (r, c.fullname())) - c = c.lresolve(r) - key = tuple(pre + [r]) - if buglvl >= 1: - 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, meta=False, verbose=0): + def __init__(self, repo, verbose=0, fake_metadata=False): fuse.Fuse.__init__(self) - self.top = top - self.meta = meta + self.repo = repo self.verbose = verbose + self.fake_metadata = fake_metadata def getattr(self, path): + global opt if self.verbose > 0: log('--getattr(%r)\n' % path) - try: - node = cache_get(self.top, path) - st = fuse.Stat(st_mode=node.mode, - st_nlink=node.nlinks(), - # Until/unless we store the size in m. - st_size=node.size()) - if self.meta: - m = node.metadata() - if m: - st.st_mode = m.mode - st.st_uid = m.uid - st.st_gid = m.gid - st.st_atime = max(0, xstat.fstime_floor_secs(m.atime)) - st.st_mtime = max(0, xstat.fstime_floor_secs(m.mtime)) - st.st_ctime = max(0, xstat.fstime_floor_secs(m.ctime)) - return st - except vfs.NoSuchFile: + res = vfs.lresolve(self.repo, path, want_meta=(not self.fake_metadata)) + log('res: %r\n' % (res,)) + 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): - if self.verbose > 0: - 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.lresolve(self.repo, path) + 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): if self.verbose > 0: log('--readlink(%r)\n' % path) - node = cache_get(self.top, path) - return node.readlink() + res = vfs.lresolve(self.repo, path) + name, item = res[-1] + if not item: + return -errno.ENOENT + return vfs.readlink(repo, item) def open(self, path, flags): if self.verbose > 0: log('--open(%r)\n' % path) - node = cache_get(self.top, path) + res = vfs.lresolve(self.repo, path) + 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): - if self.verbose > 0: - 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): if self.verbose > 0: 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) - + res = vfs.lresolve(self.repo, path) + 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] @@ -126,22 +109,20 @@ meta report original metadata for paths when available v,verbose increase log output (can be used more than once) """ o = options.Options(optspec) -(opt, flags, extra) = o.parse(sys.argv[1:]) +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, meta=opt.meta, verbose=opt.verbose) +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 if opt.allow_other: f.fuse_args.add('allow_other') - f.main() diff --git a/t/test-fuse.sh b/t/test-fuse.sh index 4603e80..5a7365a 100755 --- a/t/test-fuse.sh +++ b/t/test-fuse.sh @@ -83,10 +83,10 @@ pre-epoch" result=$(WVPASS cat mnt/src/latest/foo) || exit $? WVPASSEQ "$result" "content" -# Right now we don't detect new saves. WVPASS bup save -n src -d "$savestamp2" --strip src result=$(WVPASS ls mnt/src) || exit $? WVPASSEQ "$result" "$savename1 +$savename2 latest" WVPASS fusermount -uz mnt