History

Improved handling of strings, converting to and from Unicode strings where needed and using byte strings when sending socket data and interacting with the operating system. Tried to make the modules compatible with both Python 2 and Python 3.

David Boddie committed 8 years ago

Commit 20f573c1 parent c2476e84 files · +66 −51Browse files

Unified · Split

4 files
  1. dictserver.py +21 −19
  2. localfileserver.py +36 −28
  3. styx.py +5 −3
  4. styxserver.py +4 −1
dictserver.py+21−19
@@ -1,4 +1,5 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2# -*- encoding: utf8 -*-
2 3
3# dictserver.py - Serves the contents of a Python dictionary.4# dictserver.py - Serves the contents of a Python dictionary.
4#5#
@@ -38,8 +39,8 @@ class DictStore: · 33 unmodified lines
38 39
39 def get_root_qid(self, fid, afid, uname, aname):40 def get_root_qid(self, fid, afid, uname, aname):
40 41
41 qid = self.make_qid("")42 qid = self.make_qid(u"/")
42 self.set_qid_path(fid, qid, "")43 self.set_qid_path(fid, qid, u"/")
43 self.root_fid = fid44 self.root_fid = fid
44 return qid45 return qid
45 46
@@ -49,14 +50,14 @@ class DictStore: · 3 unmodified lines
49 50
50 def set_qid_path(self, fid, qid, path):51 def set_qid_path(self, fid, qid, path):
51 52
52 path = path.lstrip("/")53 path = path.lstrip(u"/")
53 54
54 self.qids[fid] = qid55 self.qids[fid] = qid
55 self.paths[fid] = path56 self.paths[fid] = path
56 57
57 def make_qid(self, path):58 def make_qid(self, path):
58 59
59 path = path.lstrip("/")60 path = path.lstrip(u"/")
60 obj = self.traverse(path)61 obj = self.traverse(path)
61 62
62 if obj == None:63 if obj == None:
@@ -90,7 +91,7 @@ class DictStore: · 27 unmodified lines
90 91
91 def _stat(self, qid, path):92 def _stat(self, qid, path):
92 93
93 path = path.lstrip("/")94 path = path.lstrip(u"/")
94 95
95 obj = self.traverse(path)96 obj = self.traverse(path)
96 97
@@ -100,16 +101,16 @@ class DictStore: · 3 unmodified lines
100 if type(obj) == dict:101 if type(obj) == dict:
101 mode = 0x80000000102 mode = 0x80000000
102 size = 0103 size = 0
103 mode |= 0555104 mode |= 0o555
104 else:105 else:
105 mode = 0106 mode = 0
106 size = len(obj)107 size = len(obj)
107 mode |= 0444108 mode |= 0o444
108 109
109 name = path.split("/")[-1]110 name = path.split(u"/")[-1]
110 111
111 return styx.Stat(0, 0, qid, mode, self.now, self.now, size, name,112 return styx.Stat(0, 0, qid, mode, self.now, self.now, size, name,
112 "inferno", "inferno", "")113 u"inferno", u"inferno", u"")
113 114
114 def create(self, fid, name, perm):115 def create(self, fid, name, perm):
115 return False116 return False
@@ -137,7 +138,7 @@ class DictStore: · 21 unmodified lines
137 if obj == None:138 if obj == None:
138 return None139 return None
139 140
140 data = ""141 data = b""
141 142
142 if type(obj) == dict:143 if type(obj) == dict:
143 144
@@ -147,12 +148,12 @@ class DictStore: · 3 unmodified lines
147 files.sort()148 files.sort()
148 149
149 for file_name in files:150 for file_name in files:
150 qid = self.make_qid(path + "/" + file_name)151 qid = self.make_qid(path + u"/" + file_name)
151 data += self._stat(qid, path + "/" + file_name).encode()152 data += self._stat(qid, path + u"/" + file_name).encode()
152 153
153 return data[offset:offset + count]154 return data[offset:offset + count]
154 else:155 else:
155 return obj[offset:offset + count]156 return obj[offset:offset + count].encode("utf8")
156 157
157 def write(self, fid, offset, data):158 def write(self, fid, offset, data):
158 159
@@ -160,19 +161,19 @@ class DictStore: · 1 unmodified line
160 return -2161 return -2
161 162
162 def remove(self, fid):163 def remove(self, fid):
163 return False164 return u"Cannot remove dictionary entries."
164 165
165 def wstat(self, fid, st):166 def wstat(self, fid, st):
166 pass167 pass
167 168
168 def traverse(self, path):169 def traverse(self, path):
169 170
170 if path == "":171 if path == u"":
171 return self.d172 return self.d
172 173
173 obj = self.d174 obj = self.d
174 175
175 for element in path.split("/"):176 for element in path.split(u"/"):
176 177
177 try:178 try:
178 obj = obj[element]179 obj = obj[element]
@@ -191,11 +192,12 @@ if __name__ == "__main__": · 12 unmodified lines
191 port = int(sys.argv[1])192 port = int(sys.argv[1])
192 193
193 dictionary = {194 dictionary = {
194 "dir": {195 u"dir": {
195 "hello.txt": "Hello world!\n"196 u"hello.txt": u"Hello world!\n",
197 u"\u263a": u"Forståelse"
196 }198 }
197 }199 }
198 200
199 store = DictStore(dictionary)201 store = DictStore(dictionary)
200 server = styxserver.StyxServer(store)202 server = styxserver.StyxServer(store)
201 server.serve("", port)203 server.serve(b"", port)
localfileserver.py+36−28
@@ -17,7 +17,7 @@ · 16 unmodified lines
17# You should have received a copy of the GNU General Public License17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20import os, stat, sys20import locale, os, stat, sys
21import styx, styxserver21import styx, styxserver
22 22
23class FileStore:23class FileStore:
@@ -34,11 +34,12 @@ class FileStore: · 10 unmodified lines
34 self.paths = {}34 self.paths = {}
35 self.opened = {}35 self.opened = {}
36 self.root_fid = None36 self.root_fid = None
37 self.encoding = sys.getfilesystemencoding()
37 38
38 def get_root_qid(self, fid, afid, uname, aname):39 def get_root_qid(self, fid, afid, uname, aname):
39 40
40 qid = self.make_qid("")41 qid = self.make_qid(u"/")
41 self.set_qid_path(fid, qid, "")42 self.set_qid_path(fid, qid, u"/")
42 self.root_fid = fid43 self.root_fid = fid
43 return qid44 return qid
44 45
@@ -48,16 +49,16 @@ class FileStore: · 3 unmodified lines
48 49
49 def set_qid_path(self, fid, qid, path):50 def set_qid_path(self, fid, qid, path):
50 51
51 path = path.lstrip("/")52 path = path.lstrip(u"/")
52 53
53 self.qids[fid] = qid54 self.qids[fid] = qid
54 self.paths[fid] = path55 self.paths[fid] = path
55 56
56 def make_qid(self, path):57 def make_qid(self, path):
57 58
58 path = path.lstrip("/")59 path = path.lstrip(u"/")
59 60
60 real_path = os.path.join(self.dir, path)61 real_path = os.path.join(self.dir, path).encode(self.encoding)
61 62
62 try:63 try:
63 s = os.stat(real_path)64 s = os.stat(real_path)
@@ -93,10 +94,10 @@ class FileStore: · 29 unmodified lines
93 94
94 def _stat(self, qid, path):95 def _stat(self, qid, path):
95 96
96 path = path.lstrip("/")97 path = path.lstrip(u"/")
97 98
98 name = os.path.split(path)[1]99 name = os.path.split(path)[1]
99 real_path = os.path.join(self.dir, path)100 real_path = os.path.join(self.dir, path).encode(self.encoding)
100 101
101 try:102 try:
102 s = os.stat(real_path)103 s = os.stat(real_path)
@@ -110,14 +111,14 @@ class FileStore: · 7 unmodified lines
110 mode = 0111 mode = 0
111 size = s.st_size112 size = s.st_size
112 113
113 mode |= (s.st_mode & 0777)114 mode |= (s.st_mode & 0o777)
114 115
115 return styx.Stat(0, 0, qid, mode, s.st_atime, s.st_mtime, size,116 return styx.Stat(0, 0, qid, mode, s.st_atime, s.st_mtime, size,
116 name, "styxfs", "styxfs", "")117 name, u"styxfs", u"styxfs", u"")
117 118
118 def create(self, fid, name, perm):119 def create(self, fid, name, perm):
119 120
120 if name in (".", ".."):121 if name in (u".", u".."):
121 return False122 return False
122 123
123 elif fid in self.opened:124 elif fid in self.opened:
@@ -125,7 +126,7 @@ class FileStore: · 1 unmodified line
125 else:126 else:
126 # Obtain the real path of the directory.127 # Obtain the real path of the directory.
127 path = self.paths[fid]128 path = self.paths[fid]
128 real_path = os.path.join(self.dir, path)129 real_path = os.path.join(self.dir, path).encode(self.encoding)
129 130
130 if not os.path.isdir(real_path):131 if not os.path.isdir(real_path):
131 return False132 return False
@@ -133,7 +134,7 @@ class FileStore: · 1 unmodified line
133 # Read the directory permissions.134 # Read the directory permissions.
134 dir_perm = os.stat(real_path).st_mode135 dir_perm = os.stat(real_path).st_mode
135 136
136 new_real_path = os.path.join(real_path, name)137 new_real_path = os.path.join(self.dir, path, name).encode(self.encoding)
137 138
138 if os.path.exists(new_real_path):139 if os.path.exists(new_real_path):
139 return False140 return False
@@ -143,18 +144,18 @@ class FileStore: · 3 unmodified lines
143 if perm & styx.Stat.DMDIR:144 if perm & styx.Stat.DMDIR:
144 # Only pass the lowest permission bits through to the145 # Only pass the lowest permission bits through to the
145 # underlying filing system.146 # underlying filing system.
146 mode = dir_perm & 0777147 mode = dir_perm & 0o777
147 os.mkdir(new_real_path, mode)148 os.mkdir(new_real_path, mode)
148 else:149 else:
149 mode = dir_perm & 0666150 mode = dir_perm & 0o666
150 os.mknod(new_real_path, mode, stat.S_IFREG)151 os.mknod(new_real_path, mode, stat.S_IFREG)
151 152
152 except OSError:153 except OSError:
153 return False154 return False
154 155
155 # Update the fid to refer to the new object.156 # Update the fid to refer to the new object.
156 qid = self.make_qid(path + "/" + name)157 qid = self.make_qid(path + u"/" + name)
157 self.set_qid_path(fid, qid, path + "/" + name)158 self.set_qid_path(fid, qid, path + u"/" + name)
158 159
159 return qid160 return qid
160 161
@@ -177,7 +178,7 @@ class FileStore: · 16 unmodified lines
177 178
178 path = self.paths[fid]179 path = self.paths[fid]
179 real_path = os.path.join(self.dir, path)180 real_path = os.path.join(self.dir, path)
180 data = ""181 data = b""
181 182
182 if os.path.isdir(real_path):183 if os.path.isdir(real_path):
183 184
@@ -187,8 +188,8 @@ class FileStore: · 3 unmodified lines
187 files.sort()188 files.sort()
188 189
189 for file_name in files:190 for file_name in files:
190 qid = self.make_qid(path + "/" + file_name)191 qid = self.make_qid(path + u"/" + file_name)
191 data += self._stat(qid, path + "/" + file_name).encode()192 data += self._stat(qid, path + u"/" + file_name).encode()
192 193
193 return data[offset:offset + count]194 return data[offset:offset + count]
194 else:195 else:
@@ -207,7 +208,7 @@ class FileStore: · 12 unmodified lines
207 if os.path.isdir(real_path):208 if os.path.isdir(real_path):
208 return -1209 return -1
209 210
210 f = open(real_path, "r+wb")211 f = open(real_path, "r+b")
211 f.seek(offset)212 f.seek(offset)
212 f.write(data)213 f.write(data)
213 f.close()214 f.close()
@@ -225,7 +226,7 @@ class FileStore: · 11 unmodified lines
225 else:226 else:
226 os.remove(real_path)227 os.remove(real_path)
227 228
228 except OSError, e:229 except OSError as e:
229 return str(e)230 return str(e)
230 231
231 return True232 return True
@@ -233,18 +234,25 @@ class FileStore: · 1 unmodified line
233 def wstat(self, fid, st):234 def wstat(self, fid, st):
234 235
235 path = self.paths[fid]236 path = self.paths[fid]
236 real_path = os.path.join(self.dir, path)237 real_path = os.path.join(self.dir, path).encode(self.encoding)
238
239 pieces = path.split(u"/")
240 old_name = pieces[-1]
237 241
238 old_name = path.split("/")[-1]242 # Only update the name if the specified name is not empty and differs
239 if st.name != "" and st.name != old_name:243 # from the existing path.
240 new_path = os.path.join(os.path.split(real_path)[0], st.name)244 if st.name != u"" and st.name != old_name:
245 # Rename the file and use the new path for any further operations.
246 new_path = os.path.join(os.path.split(real_path)[0], st.name).encode(self.encoding)
241 os.rename(real_path, new_path)247 os.rename(real_path, new_path)
242 real_path = new_path248 real_path = new_path
249 # Update the path dictionary to contain the new path.
250 self.paths[fid] = pieces + [u"/" + st.name]
243 251
244 s = os.stat(real_path)252 s = os.stat(real_path)
245 253
246 if st.mode != 0xffffffff:254 if st.mode != 0xffffffff:
247 os.chmod(real_path, st.mode & 0777)255 os.chmod(real_path, st.mode & 0o777)
248 256
249 if st.mtime != 0xffffffff or st.atime != 0xffffffff:257 if st.mtime != 0xffffffff or st.atime != 0xffffffff:
250 if st.mtime == 0xffffffff:258 if st.mtime == 0xffffffff:
@@ -271,4 +279,4 @@ if __name__ == "__main__": · 20 unmodified lines
271 279
272 store = FileStore(directory)280 store = FileStore(directory)
273 server = styxserver.StyxServer(store)281 server = styxserver.StyxServer(store)
274 server.serve("", port)282 server.serve(b"", port)
styx.py+5−3
@@ -38,7 +38,7 @@ class SocketReceiver: · 37 unmodified lines
38 self.sock = sock38 self.sock = sock
39 39
40 def recv(self, n):40 def recv(self, n):
41 data = ""41 data = b""
42 while len(data) < n:42 while len(data) < n:
43 data += self.sock.recv(n - len(data))43 data += self.sock.recv(n - len(data))
44 44
@@ -108,7 +108,7 @@ def decode_format(stream, obj): · 63 unmodified lines
108 108
109def encode_format(stream, obj):109def encode_format(stream, obj):
110 110
111 data = ""111 data = b""
112 112
113 for name, length in obj.format:113 for name, length in obj.format:
114 114
@@ -624,7 +624,9 @@ class Stat: · 509 unmodified lines
624 624
625 def encode(self):625 def encode(self):
626 626
627 args = (self.type, self.dev) + self.qid + (self.mode, self.atime, self.mtime, self.length)627 args = (self.type, self.dev) + self.qid + \
628 (self.mode, int(self.atime), int(self.mtime), self.length)
629
628 data = struct.pack("<HIBIQIIIQ", *args)630 data = struct.pack("<HIBIQIIIQ", *args)
629 data += encode_string(self.name)631 data += encode_string(self.name)
630 data += encode_string(self.uid)632 data += encode_string(self.uid)
styxserver.py+4−1
@@ -50,7 +50,7 @@ class StyxServer: · 49 unmodified lines
50 reply = handler(self, conn, client, message)50 reply = handler(self, conn, client, message)
51 except KeyError:51 except KeyError:
52 reply = styx.Rerror(message.tag, "Unsupported message.")52 reply = styx.Rerror(message.tag, "Unsupported message.")
53 except StyxServerError, e:53 except StyxServerError as e:
54 reply = styx.Rerror(message.tag, e.message)54 reply = styx.Rerror(message.tag, e.message)
55 except socket.error:55 except socket.error:
56 # The connection was probably closed by the client.56 # The connection was probably closed by the client.
@@ -67,6 +67,9 @@ class StyxServer: · 10 unmodified lines
67 store = self.clients[client]67 store = self.clients[client]
68 68
69 qid = store.get_root_qid(msg.fid, msg.afid, msg.uname, msg.aname)69 qid = store.get_root_qid(msg.fid, msg.afid, msg.uname, msg.aname)
70 if qid == None:
71 return styx.Rerror(msg.tag, "Root not found.")
72
70 return styx.Rattach(msg.tag, qid)73 return styx.Rattach(msg.tag, qid)
71 74
72 def Tstat(self, conn, client, msg):75 def Tstat(self, conn, client, msg):