]> arthur.barton.de Git - bup.git/blob - cmd/fuse-cmd.py
8e57ab6f937dab330f4f7fd6e5c4618e1812dfe6
[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 from __future__ import absolute_import
9 import sys, os, errno
10
11 try:
12     import fuse
13 except ImportError:
14     log('error: cannot find the python "fuse" module; please install it\n')
15     sys.exit(1)
16 if not hasattr(fuse, '__version__'):
17     raise RuntimeError('your fuse module is too old for fuse.__version__')
18 fuse.fuse_python_api = (0, 2)
19
20 from bup import options, git, vfs, xstat
21 from bup.helpers import log
22 from bup.repo import LocalRepo
23
24 # FIXME: self.meta and want_meta?
25
26 class BupFs(fuse.Fuse):
27     def __init__(self, repo, verbose=0, fake_metadata=False):
28         fuse.Fuse.__init__(self)
29         self.repo = repo
30         self.verbose = verbose
31         self.fake_metadata = fake_metadata
32     
33     def getattr(self, path):
34         global opt
35         if self.verbose > 0:
36             log('--getattr(%r)\n' % path)
37         res = vfs.resolve(self.repo, path, want_meta=(not self.fake_metadata),
38                           follow=False)
39         name, item = res[-1]
40         if not item:
41             return -errno.ENOENT
42         if self.fake_metadata:
43             item = vfs.augment_item_meta(self.repo, item, include_size=True)
44         else:
45             item = vfs.ensure_item_has_metadata(self.repo, item,
46                                                 include_size=True)
47         meta = item.meta
48         # FIXME: do we want/need to do anything more with nlink?
49         st = fuse.Stat(st_mode=meta.mode, st_nlink=1, st_size=meta.size)
50         st.st_mode = meta.mode
51         st.st_uid = meta.uid
52         st.st_gid = meta.gid
53         st.st_atime = max(0, xstat.fstime_floor_secs(meta.atime))
54         st.st_mtime = max(0, xstat.fstime_floor_secs(meta.mtime))
55         st.st_ctime = max(0, xstat.fstime_floor_secs(meta.ctime))
56         return st
57
58     def readdir(self, path, offset):
59         assert not offset  # We don't return offsets, so offset should be unused
60         res = vfs.resolve(self.repo, path, follow=False)
61         dir_name, dir_item = res[-1]
62         if not dir_item:
63             yield -errno.ENOENT
64         yield fuse.Direntry('..')
65         # FIXME: make sure want_meta=False is being completely respected
66         for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False):
67             yield fuse.Direntry(ent_name.replace('/', '-'))
68
69     def readlink(self, path):
70         if self.verbose > 0:
71             log('--readlink(%r)\n' % path)
72         res = vfs.resolve(self.repo, path, follow=False)
73         name, item = res[-1]
74         if not item:
75             return -errno.ENOENT
76         return vfs.readlink(repo, item)
77
78     def open(self, path, flags):
79         if self.verbose > 0:
80             log('--open(%r)\n' % path)
81         res = vfs.resolve(self.repo, path, follow=False)
82         name, item = res[-1]
83         if not item:
84             return -errno.ENOENT
85         accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
86         if (flags & accmode) != os.O_RDONLY:
87             return -errno.EACCES
88         # Return None since read doesn't need the file atm...
89         # If we *do* return the file, it'll show up as the last argument
90         #return vfs.fopen(repo, item)
91
92     def read(self, path, size, offset):
93         if self.verbose > 0:
94             log('--read(%r)\n' % path)
95         res = vfs.resolve(self.repo, path, follow=False)
96         name, item = res[-1]
97         if not item:
98             return -errno.ENOENT
99         with vfs.fopen(repo, item) as f:
100             f.seek(offset)
101             return f.read(size)
102
103 optspec = """
104 bup fuse [-d] [-f] <mountpoint>
105 --
106 f,foreground  run in foreground
107 d,debug       run in the foreground and display FUSE debug information
108 o,allow-other allow other users to access the filesystem
109 meta          report original metadata for paths when available
110 v,verbose     increase log output (can be used more than once)
111 """
112 o = options.Options(optspec)
113 opt, flags, extra = o.parse(sys.argv[1:])
114
115 if len(extra) != 1:
116     o.fatal('only one mount point argument expected')
117
118 git.check_repo_or_die()
119 repo = LocalRepo()
120 f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta))
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 f.multithreaded = False
127 if opt.allow_other:
128     f.fuse_args.add('allow_other')
129 f.main()