source: baculafs/trunk/baculafs.py@ 781

Last change on this file since 781 was 781, checked in by joergs, on Jul 25, 2009 at 3:10:17 AM

getaddr checks for existing directories

  • Property svn:executable set to *
File size: 7.1 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'
18#LOG_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 def __init__(self, client=BACULA_CLIENT):
36 #logging.debug('BC init')
37 self.bconsole = pexpect.spawn( BACULA_CMD, logfile=file(LOG_BCONSOLE_DUMP, 'w'), timeout=10 )
38 self.bconsole.setecho( False )
39 self.bconsole.expect( BCONSOLE_CMD_PROMPT )
40 self.bconsole.sendline( 'restore' )
41 #self.bconsole.expect( BCONSOLE_SELECT_PROMPT )
42 self.bconsole.sendline( "5" )
43 #self.bconsole.expect( BCONSOLE_SELECT_PROMPT )
44 self.bconsole.sendline( BACULA_CLIENT )
45 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
46 #logging.debug( "BC alive: " + str(self.bconsole.isalive()) )
47 #logging.debug('BC init done')
48
49 def cd(self, path):
50 path = path + "/"
51 logging.debug( "(" + path + ")" )
52
53 self.bconsole.sendline( 'cd ' + path )
54 #self.bconsole.expect( BCONSOLE_RESTORE_PROMPT, timeout=10 )
55 #self.bconsole.sendline( 'pwd' )
56
57 index = self.bconsole.expect( ["cwd is: " + path + "[/]?", BCONSOLE_RESTORE_PROMPT, pexpect.EOF, pexpect.TIMEOUT ] )
58 logging.debug( "cd result: " + str(index) )
59
60 if index == 0:
61 # path ok, now wait for prompt
62 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
63 return True
64 elif index == 1:
65 #print "wrong path"
66 return False
67 elif index == 2:
68 logging.error( "EOF bconsole" )
69 #raise?
70 return False
71 elif index == 3:
72 logging.error( "TIMEOUT bconsole" )
73 return False
74
75 def ls(self, path):
76 logging.debug( "(" + path + ")" )
77
78 if self.cd( path ):
79 self.bconsole.sendline( 'ls' )
80 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
81 lines = self.bconsole.before.splitlines()
82 #logging.debug( str(lines) )
83 return lines
84 else:
85 return
86
87###############
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.debug('init')
99 #self.console = Bconsole()
100 fuse.Fuse.__init__(self, *args, **kw)
101 #logging.debug('init finished')
102
103
104 def _getattr(self,path):
105 # TODO: may cause problems with filenames that ends with "/"
106 path = path.rstrip( '/' )
107 logging.debug( '"' + path + '"' )
108
109 if (path in self.files):
110 #logging.debug( "(" + path + ")=" + str(self.files[path]) )
111 return self.files[path]
112
113 if Bconsole().cd(path):
114 # don't define files, because these have not been checked
115 self.files[path] = { 'type': self.TYPE_DIR, 'dirs': [ ".", ".." ] }
116
117 return self.files[path]
118
119
120
121
122 def _getdir(self, path):
123
124 # TODO: may cause problems with filenames that ends with "/"
125 path = path.rstrip( '/' )
126 logging.debug( '"' + path + '"' )
127
128 if (path in self.files):
129 #logging.debug( "(" + path + ")=" + str(self.files[path]) )
130 if self.files[path]['type'] == self.TYPE_NONE:
131 logging.info( '"' + path + '" does not exist (cached)' )
132 return self.files[path]
133 elif self.files[path]['type'] == self.TYPE_FILE:
134 logging.info( '"' + path + '"=file (cached)' )
135 return self.files[path]
136 elif ((self.files[path]['type'] == self.TYPE_DIR) and ('files' in self.files[path])):
137 logging.info( '"' + path + '"=dir (cached)' )
138 return self.files[path]
139
140 try:
141 files = Bconsole().ls(path)
142 logging.debug( " files: " + str( files ) )
143
144 # setting initial empty directory. Add entires later in this function
145 self.files[path] = { 'type': self.TYPE_DIR, 'dirs': [ ".", ".." ], 'files': [] }
146 for i in files:
147 if i.endswith('/'):
148 # we expect a directory
149 # TODO: error with filesnames, that ends with '/'
150 i = i.rstrip( '/' )
151 self.files[path]['dirs'].append(i)
152 if not (i in self.files):
153 self.files[path + "/" + i] = { 'type': self.TYPE_DIR }
154 else:
155 self.files[path]['files'].append(i)
156 self.files[path + "/" + i] = { 'type': self.TYPE_FILE }
157
158 except Exception as e:
159 logging.exception(e)
160 logging.error( "no access to path " + path )
161 self.files[path] = { 'type': TYPE_NONE }
162 logging.debug( '"' + path + '"=' + str( self.files[path] ) )
163 return self.files[path]
164
165
166
167 # TODO: only works after readdir for the directory (eg. ls)
168 def getattr(self, path):
169
170 # TODO: may cause problems with filenames that ends with "/"
171 path = path.rstrip( '/' )
172 logging.debug( '"' + path + '"' )
173
174 st = fuse.Stat()
175
176 if not (path in self.files):
177 self._getattr(path)
178
179 if not (path in self.files):
180 return -errno.ENOENT
181
182 file = self.files[path]
183
184 if file['type'] == self.TYPE_FILE:
185 st.st_mode = stat.S_IFREG | 0444
186 st.st_nlink = 1
187 st.st_size = 0
188 return st
189 elif file['type'] == self.TYPE_DIR:
190 st.st_mode = stat.S_IFDIR | 0755
191 if 'dirs' in file:
192 st.st_nlink = len(file['dirs'])
193 else:
194 st.st_nlink = 2
195 return st
196
197 # TODO: check for existens
198 return -errno.ENOENT
199
200
201
202
203 def readdir(self, path, offset):
204 logging.debug( '"' + path + '", offset=' + str(offset) + ')' )
205
206 dir = self._getdir( path )
207
208 #logging.debug( " readdir: type: " + str( dir['type'] ) )
209 #logging.debug( " readdir: dirs: " + str( dir['dirs'] ) )
210 #logging.debug( " readdir: file: " + str( dir['files'] ) )
211
212 if dir['type'] != self.TYPE_DIR:
213 return -errno.ENOENT
214 else:
215 return [fuse.Direntry(f) for f in dir['files'] + dir['dirs']]
216
217 #def open( self, path, flags ):
218 #logging.debug( "open " + path )
219 #return -errno.ENOENT
220
221 #def read( self, path, length, offset):
222 #logging.debug( "read " + path )
223 #return -errno.ENOENT
224
225if __name__ == "__main__":
226 # initialize logging
227 logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,format="%(asctime)s %(process)5d(%(threadName)s) %(levelname)-7s %(funcName)s( %(message)s )")
228
229 fs = BaculaFS()
230 fs.parse()
231 fs.main()
Note: See TracBrowser for help on using the repository browser.