3 bup_python="$(dirname "$0")/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
13 log('error: cannot find the python "fuse" module; please install it\n')
15 if not hasattr(fuse, '__version__'):
16 raise RuntimeError, "your fuse module is too old for fuse.__version__"
17 fuse.fuse_python_api = (0, 2)
19 from bup import options, git, vfs, xstat
20 from bup.helpers import log
21 from bup.repo import LocalRepo
23 # FIXME: self.meta and want_meta?
25 class BupFs(fuse.Fuse):
26 def __init__(self, repo, verbose=0, fake_metadata=False):
27 fuse.Fuse.__init__(self)
29 self.verbose = verbose
30 self.fake_metadata = fake_metadata
32 def getattr(self, path):
35 log('--getattr(%r)\n' % path)
36 res = vfs.lresolve(self.repo, path, want_meta=(not self.fake_metadata))
37 log('res: %r\n' % (res,))
41 if self.fake_metadata:
42 item = vfs.augment_item_meta(self.repo, item, include_size=True)
44 item = vfs.ensure_item_has_metadata(self.repo, item,
47 # FIXME: do we want/need to do anything more with nlink?
48 st = fuse.Stat(st_mode=meta.mode, st_nlink=1, st_size=meta.size)
49 st.st_mode = meta.mode
52 st.st_atime = max(0, xstat.fstime_floor_secs(meta.atime))
53 st.st_mtime = max(0, xstat.fstime_floor_secs(meta.mtime))
54 st.st_ctime = max(0, xstat.fstime_floor_secs(meta.ctime))
57 def readdir(self, path, offset):
58 assert not offset # We don't return offsets, so offset should be unused
59 res = vfs.lresolve(self.repo, path)
60 dir_name, dir_item = res[-1]
63 yield fuse.Direntry('..')
64 # FIXME: make sure want_meta=False is being completely respected
65 for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False):
66 yield fuse.Direntry(ent_name.replace('/', '-'))
68 def readlink(self, path):
70 log('--readlink(%r)\n' % path)
71 res = vfs.lresolve(self.repo, path)
75 return vfs.readlink(repo, item)
77 def open(self, path, flags):
79 log('--open(%r)\n' % path)
80 res = vfs.lresolve(self.repo, path)
84 accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
85 if (flags & accmode) != os.O_RDONLY:
87 # Return None since read doesn't need the file atm...
88 # If we *do* return the file, it'll show up as the last argument
89 #return vfs.fopen(repo, item)
91 def read(self, path, size, offset):
93 log('--read(%r)\n' % path)
94 res = vfs.lresolve(self.repo, path)
98 with vfs.fopen(repo, item) as f:
103 bup fuse [-d] [-f] <mountpoint>
105 f,foreground run in foreground
106 d,debug run in the foreground and display FUSE debug information
107 o,allow-other allow other users to access the filesystem
108 meta report original metadata for paths when available
109 v,verbose increase log output (can be used more than once)
111 o = options.Options(optspec)
112 opt, flags, extra = o.parse(sys.argv[1:])
115 o.fatal('only one mount point argument expected')
117 git.check_repo_or_die()
119 f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta))
120 f.fuse_args.mountpoint = extra[0]
122 f.fuse_args.add('debug')
124 f.fuse_args.setmod('foreground')
125 f.multithreaded = False
127 f.fuse_args.add('allow_other')