source: baculafs/trunk/baculafs.py@ 778

Last change on this file since 778 was 778, checked in by joergs, on Jul 24, 2009 at 10:57:28 PM

initial prototyp/proof of concept

  • Property svn:executable set to *
File size: 6.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import logging
5import fuse
6import stat
7import errno
8import os
9import pexpect
10import sys
11
12fuse.fuse_python_api = (0, 2)
13
14###### bconsole
15################
16
17LOG_FILENAME = '/tmp/baculafs.log'
18LOG_BCONSOLE = '/tmp/bconsole.log'
19LOG_BCONSOLE_DUMP = '/tmp/bconsole.out'
20
21
22#BACULA_CMD = 'strace -f -o /tmp/bconsole.strace /usr/sbin/bconsole -n'
23BACULA_CMD = '/usr/sbin/bconsole -n'
24# .clients
25# 5: ting-fd
26BACULA_CLIENT='5'
27
28BCONSOLE_CMD_PROMPT='\*'
29BCONSOLE_SELECT_PROMPT='Select item:.*'
30BCONSOLE_RESTORE_PROMPT='\$ '
31
32
33class Bconsole:
34
35 #bconsole = None
36
37 def __init__(self, client=BACULA_CLIENT):
38 #logging.basicConfig(filename=LOG_BCONSOLE,level=logging.DEBUG,)
39 logging.debug('BC init')
40 self.bconsole = pexpect.spawn( BACULA_CMD, logfile=file(LOG_BCONSOLE_DUMP, 'w'), timeout=10 )
41 self.bconsole.setecho( False )
42 self.bconsole.expect( BCONSOLE_CMD_PROMPT )
43 self.bconsole.sendline( 'restore' )
44 #self.bconsole.expect( BCONSOLE_SELECT_PROMPT )
45 self.bconsole.sendline( "5" )
46 #self.bconsole.expect( BCONSOLE_SELECT_PROMPT )
47 self.bconsole.sendline( BACULA_CLIENT )
48 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
49 logging.debug( "BC alive: " + str(self.bconsole.isalive()) )
50 logging.debug('BC init done')
51
52
53 def ls(self, path):
54
55 path = path + "/"
56 logging.debug( "BC ls(" + path + ")" )
57
58 self.bconsole.sendline( 'cd ' + path )
59 #self.bconsole.expect( BCONSOLE_RESTORE_PROMPT, timeout=10 )
60 #self.bconsole.sendline( 'pwd' )
61
62 index = self.bconsole.expect( ["cwd is: " + path + "[/]?", BCONSOLE_RESTORE_PROMPT, pexpect.EOF, pexpect.TIMEOUT ] )
63 logging.debug( "BC ls: cd result: " + str(index) )
64
65 if index == 0:
66 # path ok, now wait for prompt
67 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
68 elif index == 1:
69 #print "wrong path"
70 return
71 elif index == 2:
72 print "error EOF"
73 raise
74 elif index == 3:
75 print "error TIMEOUT"
76 return
77
78 self.bconsole.sendline( 'ls' )
79 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
80 lines = self.bconsole.before.splitlines()
81 logging.debug( "BC ls: " + str(lines) )
82 return lines
83
84###############
85
86hello_world_path = "/helloworld"
87hello_world = "Hello World!"
88
89class BaculaFS(fuse.Fuse):
90
91 TYPE_NONE = 0
92 TYPE_FILE = 1
93 TYPE_DIR = 2
94
95 files = { '': {'type': TYPE_DIR} }
96
97 def __init__(self, *args, **kw):
98 logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)
99 logging.debug('init')
100 #self.console = Bconsole()
101 fuse.Fuse.__init__(self, *args, **kw)
102 #logging.debug('init finished')
103
104 def _getdir(self, path):
105
106 # TODO: may cause problems with filenames that ends with "/"
107 path = path.rstrip( '/' )
108 logging.debug( "_getdir(" + path + ")" )
109
110 if (path in self.files):
111 logging.debug( " _getdir(" + path + ")=" + str(self.files[path]) )
112 if self.files[path]['type'] == self.TYPE_FILE:
113 logging.debug( " type: file" )
114 return self.files[path]
115 elif ((self.files[path]['type'] == self.TYPE_DIR) and ('files' in self.files[path])):
116 logging.debug( " type: dir (cached)" )
117 return self.files[path]
118
119 try:
120 files = Bconsole().ls(path)
121 logging.debug( " files: " + str( files ) )
122 self.files[path] = {}
123 self.files[path]['type'] = self.TYPE_DIR
124 self.files[path]['dirs'] = [ ".", ".." ]
125 self.files[path]['files'] = []
126 for i in files:
127 if i.endswith('/'):
128 # we expect a directory
129 # TODO: error with filesnames, that ends with '/'
130 i = i.rstrip( '/' )
131 self.files[path]['dirs'].append(i)
132 if not (i in self.files):
133 self.files[path + "/" + i] = { 'type': self.TYPE_DIR }
134 else:
135 self.files[path]['files'].append(i)
136 self.files[path + "/" + i] = { 'type': self.TYPE_FILE }
137
138 except:
139 logging.debug( "Unexpected error:" + sys.exc_info()[0] )
140 logging.error( "no access to path " + path )
141 self.files[path] = { 'type': TYPE_NONE }
142 logging.debug( " " + str( self.files[path] ) )
143 return self.files[path]
144
145
146
147 # TODO: only works after readdir for the directory (eg. ls)
148 def getattr(self, path):
149 logging.debug( "getattr " + path )
150
151 st = fuse.Stat()
152
153 #file = self._getdir( path )
154
155 # TODO: may cause problems with filenames that ends with "/"
156 path = path.rstrip( '/' )
157 file = self.files[path]
158
159 if file['type'] == self.TYPE_FILE:
160 st.st_mode = stat.S_IFREG | 0444
161 st.st_nlink = 1
162 st.st_size = 0
163 elif file['type'] == self.TYPE_DIR:
164 st.st_mode = stat.S_IFDIR | 0755
165 st.st_nlink = 2
166 else:
167 return -errno.ENOENT
168 return st
169
170
171
172 def readdir(self, path, offset):
173 logging.debug( "readdir " + path + "(offset: " + str(offset) + ")" )
174
175 dir = self._getdir( path )
176
177 #logging.debug( " readdir: type: " + str( dir['type'] ) )
178 #logging.debug( " readdir: dirs: " + str( dir['dirs'] ) )
179 #logging.debug( " readdir: file: " + str( dir['files'] ) )
180
181 if dir['type'] != self.TYPE_DIR:
182 return -errno.ENOENT
183 else:
184 return [fuse.Direntry(f) for f in dir['files'] + dir['dirs']]
185
186 #def open( self, path, flags ):
187 #logging.debug( "open " + path )
188 #return -errno.ENOENT
189
190 #def read( self, path, length, offset):
191 #logging.debug( "read " + path )
192 #return -errno.ENOENT
193
194if __name__ == "__main__":
195 fs = BaculaFS()
196 fs.parse()
197 fs.main()
Note: See TracBrowser for help on using the repository browser.