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