Skip to content
Newer
Older
100644 225 lines (179 sloc) 5.6 KB
cf5c395 @rep initial commit, adding the experimental files
authored
1 #!/usr/bin/python
2 # -*- coding: utf8 -*-
3
4 import os
5 import sys
6 import errno
7 import time
8 import stat
9 import struct
10 import logging
11 logging.basicConfig(level=logging.DEBUG)
12
13 from pwrcall import loop, unloop, Node, expose, Promise
14 from pwrcall.util import NodeException
15 from evnet import later, listenplain
16
17 PORT = 0x10f5
18 SDIR = './share/'
19
20 statproperties = ('st_atime', 'st_ctime', 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid')
21
22 def p(*args):
23 path = os.path.normpath(os.path.join(SDIR, *args))
24 if '..' in path: raise NodeException(errno.EPERM)
25 return path
26
27 def stat2dict(st):
28 return dict((key, getattr(st, key)) for key in statproperties)
29
30 def stat2dict2(st):
31 return dict((key, getattr(st, key)) for key in ('st_mode', 'st_ino',))
32
33 def rand64():
34 return struct.unpack('Q', os.urandom(8))[0]
35
36 class FSException(Exception):
37 pass
38
39 class Fileserver(object):
40 def __init__(self):
41 self.ino = 1
42 self.pathcache = {1:p('')}
43 self.filehandles = {}
44 later(20.0, self.outputstats)
45
46 def outputstats(self):
47 print 'STATS'
48 print ' -> PATHCACHE', self.pathcache
49 print ' -> FILEHANDLES', self.filehandles
50 later(20.0, self.outputstats)
51
52 @expose
53 def getattr(self, ino, fi):
54 print 'getattr:', ino
55 path = self.pathcache.get(ino, None)
56 if path == None: raise NodeException(errno.ENOENT)
57 else: return stat2dict(os.lstat(path))
58
59 @expose
60 def lookup(self, parent, name):
61 print 'lookup:', parent, name
62 fp = self.get_fullpath(parent, name)
63 if not os.path.exists(fp): raise NodeException(errno.ENOENT)
64 return self.get_entry(fp)
65
66 @expose
67 def open(self, ino, fi):
68 fp = self.get_fullpath(ino)
69 print 'open:', ino, fi, fp
70 #if not os.path.exists(fp): raise NodeException(errno.ENOENT)
71 fh = rand64()
72 #self.filehandles[fh] = open(fp, 'rwb')
73 self.filehandles[fh] = os.open(fp, os.O_RDWR)
74 return fh
75
76 def get_fullpath(self, ino, name=None):
77 path = self.pathcache.get(ino, None)
78 if path == None: raise NodeException(errno.ENOENT)
79 cp = os.path.join(path)
80 if name != None: cp = os.path.join(cp, name)
81 return cp
82
83 def get_entry(self, path):
84 stat = os.lstat(path)
85 self.pathcache[stat.st_ino] = path
86
87 entry = {'ino': stat.st_ino, 'attr': stat2dict(stat), 'attr_timeout': 5.0, 'entry_timeout': 5.0}
88 return entry
89
90 @expose
91 def mkdir(self, ctx, parent, name, mode):
92 print 'mkdir:', parent, name
93 cp = self.get_fullpath(parent, name)
94 if os.path.exists(cp): raise NodeException(errno.EEXIST)
95
96 os.mkdir(cp, mode)
97 return self.get_entry(cp)
98
99 @expose
100 def read(self, ino, size, off, fi):
101 print 'read', size, off, fi
102 buf = os.read(self.filehandles[fi['fh']], size)
103 return buf
104
105 @expose
106 def readdir(self, ino, size, off, fi):
107 fp = self.get_fullpath(ino)
108 print 'readdir', ino, fp
109 if not os.path.exists(fp) or not os.path.isdir(fp): raise NodeException(errno.ENOENT)
110
111 ppath, dirname = os.path.split(fp.rstrip('/'))
112 print 'readdir:', ino, 'fp', fp, 'ppath', ppath, 'dirname', dirname
113 if ppath == '': ppath = os.path.join(fp, '../')
114
115 pstat = os.lstat(ppath)
116 stat = os.lstat(fp)
117 self.pathcache[stat.st_ino] = fp
118 self.pathcache[pstat.st_ino] = ppath
119
120 entries = [('.', stat2dict2(stat)),
121 ('..', stat2dict2(pstat))]
122
123 for elem in os.listdir(fp):
124 stat = os.lstat(os.path.join(fp,elem))
125 self.pathcache[stat.st_ino] = os.path.join(fp,elem)
126 entries.append((elem, stat2dict2(stat)))
127
128 return entries
129
130 @expose
131 def rename(self, parent, name, newparent, newname):
132 print 'rename:', parent, name, newparent, newname
133 fp1 = self.get_fullpath(parent, name)
134 if not os.path.exists(fp1): raise NodeException(errno.ENOENT)
135 fp2 = self.get_fullpath(newparent, newname)
136
137 os.rename(fp1, fp2)
138 return 0
139
140 @expose
141 def unlink(self, parent, name):
142 print 'unlink:', parent, name
143 fp1 = self.get_fullpath(parent, name)
144 if not os.path.exists(fp1): raise NodeException(errno.ENOENT)
145
146 os.unlink(fp1)
147 return 0
148
149 @expose
150 def setattr(self, ino, attr, to_set, fi):
151 print 'setattr:', ino, attr, to_set
152 fp = self.get_fullpath(ino)
153 print ' -> file:', fp
154 if not os.path.exists(fp): raise NodeException(errno.ENOENT)
155
156 e = self.get_entry(fp)
157
158 for key in to_set:
159 if key == 'st_mode':
160 newmode = stat.S_IFMT(attr['st_mode']) | stat.S_IMODE(e['attr']['st_mode'])
161 os.chmod(fp, newmode)
162 e['attr']['st_mode'] = newmode
163 elif key == 'st_size':
164 fd = os.open(fp, os.O_RDWR | os.O_CREAT)
165 os.ftruncate(fd, attr['st_size'])
166 os.close(fd)
167 e['attr']['st_size'] = attr['st_size']
168 return e['attr']
169
170 @expose
171 def write(self, ino, buf, off, fi):
172 print 'write:', ino, off, fi
173 os.write(self.filehandles[fi['fh']], buf)
174 return len(buf)
175
176 @expose
177 def create(self, ctx, parent, name, mode, fi):
178 print 'create:', parent, name
179 fp = self.get_fullpath(parent)
180 if not os.path.exists(fp) or not os.path.isdir(fp): raise NodeException(errno.ENOENT)
181 filepath = os.path.join(fp, name)
182 fd = os.open(filepath, os.O_CREAT | os.O_RDWR, mode)
183
184 e = self.get_entry(filepath)
185 fh = rand64()
186 self.filehandles[fh] = fd
187 return (e, fh)
188
189 @expose
190 def forget(self, ino, nlookup):
191 #print 'forget:', ino, nlookup
192 #fp = self.pathcache.pop(ino, None)
193 #self.reply_none(req)
194 return None
195
196 @expose
197 def release(self, ino, fi):
198 print 'release:', ino, fi
199 fd = self.filehandles.pop(fi['fh'], None)
200 if fd != None: os.close(fd)
201 #self.reply_err(req, 0)
202 return 0
203
204
205 def main():
206 global SDIR
207 SDIR = sys.argv[1]
208 secret = sys.argv[2]
209
210 if not (os.path.exists(SDIR) and os.path.isdir(SDIR)):
211 os.mkdir(SDIR)
212
213 n = Node(cert=None)
214 n.listen(port=PORT)
215 gs = Fileserver()
216 ref = n.register(gs, cap=secret)
217 logging.info('gs at {0}'.format(n.refurl(ref)))
218
219 loop()
220 return 0
221
222 if __name__ == '__main__':
223 sys.exit(main())
224
Something went wrong with that request. Please try again.