X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=cmd%2Ffuse-cmd.py;h=8e57ab6f937dab330f4f7fd6e5c4618e1812dfe6;hb=5fc56d8e45065211119c781de0546e83c8270479;hp=30776cb36b0013adf0bf49de831b5768baa349f6;hpb=ceacdc2cefcd74fafe568c81b633387bbd379605;p=bup.git diff --git a/cmd/fuse-cmd.py b/cmd/fuse-cmd.py index 30776cb..8e57ab6 100755 --- a/cmd/fuse-cmd.py +++ b/cmd/fuse-cmd.py @@ -1,145 +1,129 @@ -#!/usr/bin/env python +#!/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 -from bup import options, git, vfs, xstat -from bup.helpers import * + 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 -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 - - -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, meta=False): + 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): - 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() # Until/unless we store the size in m. - 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: + 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(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) +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()