]> arthur.barton.de Git - bup.git/blob - cmd/fuse-cmd.py
ab0ec7e28df273161f74e823c82a39b7bec97eb0
[bup.git] / cmd / fuse-cmd.py
1 #!/bin/sh
2 """": # -*-python-*-
3 bup_python="$(dirname "$0")/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
5 """
6 # end of bup preamble
7
8 import sys, os, errno
9
10 try:
11     import fuse
12 except ImportError:
13     log('error: cannot find the python "fuse" module; please install it\n')
14     sys.exit(1)
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)
18
19 from bup import options, git, vfs, xstat
20 from bup.helpers import log
21 from bup.repo import LocalRepo
22
23 # FIXME: self.meta and want_meta?
24
25 class BupFs(fuse.Fuse):
26     def __init__(self, repo, verbose=0, fake_metadata=False):
27         fuse.Fuse.__init__(self)
28         self.repo = repo
29         self.verbose = verbose
30         self.fake_metadata = fake_metadata
31     
32     def getattr(self, path):
33         global opt
34         if self.verbose > 0:
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,))
38         name, item = res[-1]
39         if not item:
40             return -errno.ENOENT
41         if self.fake_metadata:
42             item = vfs.augment_item_meta(self.repo, item, include_size=True)
43         else:
44             item = vfs.ensure_item_has_metadata(self.repo, item,
45                                                 include_size=True)
46         meta = item.meta
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
50         st.st_uid = meta.uid
51         st.st_gid = meta.gid
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))
55         return st
56
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]
61         if not dir_item:
62             yield -errno.ENOENT
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('/', '-'))
67
68     def readlink(self, path):
69         if self.verbose > 0:
70             log('--readlink(%r)\n' % path)
71         res = vfs.lresolve(self.repo, path)
72         name, item = res[-1]
73         if not item:
74             return -errno.ENOENT
75         return vfs.readlink(repo, item)
76
77     def open(self, path, flags):
78         if self.verbose > 0:
79             log('--open(%r)\n' % path)
80         res = vfs.lresolve(self.repo, path)
81         name, item = res[-1]
82         if not item:
83             return -errno.ENOENT
84         accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
85         if (flags & accmode) != os.O_RDONLY:
86             return -errno.EACCES
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)
90
91     def read(self, path, size, offset):
92         if self.verbose > 0:
93             log('--read(%r)\n' % path)
94         res = vfs.lresolve(self.repo, path)
95         name, item = res[-1]
96         if not item:
97             return -errno.ENOENT
98         with vfs.fopen(repo, item) as f:
99             f.seek(offset)
100             return f.read(size)
101
102 optspec = """
103 bup fuse [-d] [-f] <mountpoint>
104 --
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)
110 """
111 o = options.Options(optspec)
112 opt, flags, extra = o.parse(sys.argv[1:])
113
114 if len(extra) != 1:
115     o.fatal('only one mount point argument expected')
116
117 git.check_repo_or_die()
118 repo = LocalRepo()
119 f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta))
120 f.fuse_args.mountpoint = extra[0]
121 if opt.debug:
122     f.fuse_args.add('debug')
123 if opt.foreground:
124     f.fuse_args.setmod('foreground')
125 f.multithreaded = False
126 if opt.allow_other:
127     f.fuse_args.add('allow_other')
128 f.main()