]> arthur.barton.de Git - bup.git/blob - cmd/fuse-cmd.py
df9bf56fa399739cf9a70c3fe6216e1197ba9448
[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 from bup import options, git, vfs, xstat
11 from bup.helpers import log
12
13 try:
14     import fuse
15 except ImportError:
16     log('error: cannot find the python "fuse" module; please install it\n')
17     sys.exit(1)
18
19
20 class Stat(fuse.Stat):
21     def __init__(self):
22         self.st_mode = 0
23         self.st_ino = 0
24         self.st_dev = 0
25         self.st_nlink = 0
26         self.st_uid = 0
27         self.st_gid = 0
28         self.st_size = 0
29         self.st_atime = 0
30         self.st_mtime = 0
31         self.st_ctime = 0
32         self.st_blocks = 0
33         self.st_blksize = 0
34         self.st_rdev = 0
35
36
37 cache = {}
38 def cache_get(top, path):
39     parts = path.split('/')
40     cache[('',)] = top
41     c = None
42     max = len(parts)
43     #log('cache: %r\n' % cache.keys())
44     for i in range(max):
45         pre = parts[:max-i]
46         #log('cache trying: %r\n' % pre)
47         c = cache.get(tuple(pre))
48         if c:
49             rest = parts[max-i:]
50             for r in rest:
51                 #log('resolving %r from %r\n' % (r, c.fullname()))
52                 c = c.lresolve(r)
53                 key = tuple(pre + [r])
54                 #log('saving: %r\n' % (key,))
55                 cache[key] = c
56             break
57     assert(c)
58     return c
59         
60     
61
62 class BupFs(fuse.Fuse):
63     def __init__(self, top, meta=False):
64         fuse.Fuse.__init__(self)
65         self.top = top
66         self.meta = meta
67     
68     def getattr(self, path):
69         log('--getattr(%r)\n' % path)
70         try:
71             node = cache_get(self.top, path)
72             st = Stat()
73             st.st_mode = node.mode
74             st.st_nlink = node.nlinks()
75             st.st_size = node.size()  # Until/unless we store the size in m.
76             if self.meta:
77                 m = node.metadata()
78                 if m:
79                     st.st_mode = m.mode
80                     st.st_uid = m.uid
81                     st.st_gid = m.gid
82                     st.st_atime = max(0, xstat.fstime_floor_secs(m.atime))
83                     st.st_mtime = max(0, xstat.fstime_floor_secs(m.mtime))
84                     st.st_ctime = max(0, xstat.fstime_floor_secs(m.ctime))
85             return st
86         except vfs.NoSuchFile:
87             return -errno.ENOENT
88
89     def readdir(self, path, offset):
90         log('--readdir(%r)\n' % path)
91         node = cache_get(self.top, path)
92         yield fuse.Direntry('.')
93         yield fuse.Direntry('..')
94         for sub in node.subs():
95             yield fuse.Direntry(sub.name)
96
97     def readlink(self, path):
98         log('--readlink(%r)\n' % path)
99         node = cache_get(self.top, path)
100         return node.readlink()
101
102     def open(self, path, flags):
103         log('--open(%r)\n' % path)
104         node = cache_get(self.top, path)
105         accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
106         if (flags & accmode) != os.O_RDONLY:
107             return -errno.EACCES
108         node.open()
109
110     def release(self, path, flags):
111         log('--release(%r)\n' % path)
112
113     def read(self, path, size, offset):
114         log('--read(%r)\n' % path)
115         n = cache_get(self.top, path)
116         o = n.open()
117         o.seek(offset)
118         return o.read(size)
119
120
121 if not hasattr(fuse, '__version__'):
122     raise RuntimeError, "your fuse module is too old for fuse.__version__"
123 fuse.fuse_python_api = (0, 2)
124
125
126 optspec = """
127 bup fuse [-d] [-f] <mountpoint>
128 --
129 d,debug   increase debug level
130 f,foreground  run in foreground
131 o,allow-other allow other users to access the filesystem
132 meta          report original metadata for paths when available
133 """
134 o = options.Options(optspec)
135 (opt, flags, extra) = o.parse(sys.argv[1:])
136
137 if len(extra) != 1:
138     o.fatal("exactly one argument expected")
139
140 git.check_repo_or_die()
141 top = vfs.RefList(None)
142 f = BupFs(top, meta=opt.meta)
143 f.fuse_args.mountpoint = extra[0]
144 if opt.debug:
145     f.fuse_args.add('debug')
146 if opt.foreground:
147     f.fuse_args.setmod('foreground')
148 print f.multithreaded
149 f.multithreaded = False
150 if opt.allow_other:
151     f.fuse_args.add('allow_other')
152
153 f.main()