]> arthur.barton.de Git - bup.git/blobdiff - cmd/fuse-cmd.py
README: add 0.30.x to CI status table
[bup.git] / cmd / fuse-cmd.py
index ab0ec7e28df273161f74e823c82a39b7bec97eb0..2eb28fbcf8c0293844456c51cf9b4c2bdde09182 100755 (executable)
@@ -5,23 +5,44 @@ exec "$bup_python" "$0" ${1+"$@"}
 """
 # end of bup preamble
 
+from __future__ import absolute_import, print_function
 import sys, os, errno
 
 try:
     import fuse
 except ImportError:
-    log('error: cannot find the python "fuse" module; please install it\n')
-    sys.exit(1)
+    print('error: cannot find the python "fuse" module; please install it',
+          file=sys.stderr)
+    sys.exit(2)
 if not hasattr(fuse, '__version__'):
-    raise RuntimeError, "your fuse module is too old for fuse.__version__"
+    print('error: fuse module is too old for fuse.__version__', file=sys.stderr)
+    sys.exit(2)
 fuse.fuse_python_api = (0, 2)
 
+if sys.version_info[0] > 2:
+    try:
+        fuse_ver = fuse.__version__.split('.')
+        fuse_ver_maj = int(fuse_ver[0])
+    except:
+        log('error: cannot determine the fuse major version; please report',
+            file=sys.stderr)
+        sys.exit(2)
+    if len(fuse_ver) < 3 or fuse_ver_maj < 1:
+        print("error: fuse module can't handle binary data; please upgrade to 1.0+\n",
+              file=sys.stderr)
+        sys.exit(2)
+
 from bup import options, git, vfs, xstat
+from bup.compat import argv_bytes, fsdecode, py_maj
 from bup.helpers import log
 from bup.repo import LocalRepo
 
+
 # FIXME: self.meta and want_meta?
 
+# The path handling is just wrong, but the current fuse module can't
+# handle bytes paths.
+
 class BupFs(fuse.Fuse):
     def __init__(self, repo, verbose=0, fake_metadata=False):
         fuse.Fuse.__init__(self)
@@ -30,11 +51,12 @@ class BupFs(fuse.Fuse):
         self.fake_metadata = fake_metadata
     
     def getattr(self, path):
+        path = argv_bytes(path)
         global opt
         if self.verbose > 0:
             log('--getattr(%r)\n' % path)
-        res = vfs.lresolve(self.repo, path, want_meta=(not self.fake_metadata))
-        log('res: %r\n' % (res,))
+        res = vfs.resolve(self.repo, path, want_meta=(not self.fake_metadata),
+                          follow=False)
         name, item = res[-1]
         if not item:
             return -errno.ENOENT
@@ -47,37 +69,41 @@ class BupFs(fuse.Fuse):
         # 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_uid = meta.uid or 0
+        st.st_gid = meta.gid or 0
         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):
+        path = argv_bytes(path)
         assert not offset  # We don't return offsets, so offset should be unused
-        res = vfs.lresolve(self.repo, path)
+        res = vfs.resolve(self.repo, path, follow=False)
         dir_name, dir_item = res[-1]
         if not dir_item:
             yield -errno.ENOENT
         yield fuse.Direntry('..')
         # 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('/', '-'))
+            fusename = fsdecode(ent_name.replace(b'/', b'-'))
+            yield fuse.Direntry(fusename)
 
     def readlink(self, path):
+        path = argv_bytes(path)
         if self.verbose > 0:
             log('--readlink(%r)\n' % path)
-        res = vfs.lresolve(self.repo, path)
+        res = vfs.resolve(self.repo, path, follow=False)
         name, item = res[-1]
         if not item:
             return -errno.ENOENT
-        return vfs.readlink(repo, item)
+        return fsdecode(vfs.readlink(repo, item))
 
     def open(self, path, flags):
+        path = argv_bytes(path)
         if self.verbose > 0:
             log('--open(%r)\n' % path)
-        res = vfs.lresolve(self.repo, path)
+        res = vfs.resolve(self.repo, path, follow=False)
         name, item = res[-1]
         if not item:
             return -errno.ENOENT
@@ -89,9 +115,10 @@ class BupFs(fuse.Fuse):
         #return vfs.fopen(repo, item)
 
     def read(self, path, size, offset):
+        path = argv_bytes(path)
         if self.verbose > 0:
             log('--read(%r)\n' % path)
-        res = vfs.lresolve(self.repo, path)
+        res = vfs.resolve(self.repo, path, follow=False)
         name, item = res[-1]
         if not item:
             return -errno.ENOENT
@@ -99,6 +126,7 @@ class BupFs(fuse.Fuse):
             f.seek(offset)
             return f.read(size)
 
+
 optspec = """
 bup fuse [-d] [-f] <mountpoint>
 --
@@ -110,6 +138,14 @@ v,verbose     increase log output (can be used more than once)
 """
 o = options.Options(optspec)
 opt, flags, extra = o.parse(sys.argv[1:])
+if not opt.verbose:
+    opt.verbose = 0
+
+# Set stderr to be line buffered, even if it's not connected to the console
+# so that we'll be able to see diagnostics in a timely fashion.
+errfd = sys.stderr.fileno()
+sys.stderr.flush()
+sys.stderr = os.fdopen(errfd, 'w', 1)
 
 if len(extra) != 1:
     o.fatal('only one mount point argument expected')
@@ -117,7 +153,10 @@ if len(extra) != 1:
 git.check_repo_or_die()
 repo = LocalRepo()
 f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta))
+
+# This is likely wrong, but the fuse module doesn't currently accept bytes
 f.fuse_args.mountpoint = extra[0]
+
 if opt.debug:
     f.fuse_args.add('debug')
 if opt.foreground: