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