]> arthur.barton.de Git - bup.git/commitdiff
Port fuse to vfs2
authorRob Browning <rlb@defaultvalue.org>
Sat, 2 Dec 2017 19:31:13 +0000 (13:31 -0600)
committerRob Browning <rlb@defaultvalue.org>
Sun, 24 Dec 2017 20:30:05 +0000 (14:30 -0600)
The test adjustment was necessary because fuse now notices new saves.

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
cmd/fuse-cmd.py
t/test-fuse.sh

index 66e2b87acdde63142b96a4431b7af0e316b1ab99..14ae50815e9088af81925412b70a5dd8c0cd32e2 100755 (executable)
@@ -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] <mountpoint>
@@ -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()
index 4603e80f79e3b3a57a3073c440fd38d41302ed94..5a7365ad547b63924114de340f2d4cf5527a89a4 100755 (executable)
@@ -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