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