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 @@
11 #!/usr/bin/env python
2+# -*- encoding: utf8 -*-
23
34 # dictserver.py - Serves the contents of a Python dictionary.
45 #
@@ -38,8 +39,8 @@ class DictStore: · 33 unmodified lines
3839
3940 def get_root_qid(self, fid, afid, uname, aname):
4041
41− qid = self.make_qid("")
42− self.set_qid_path(fid, qid, "")
42+ qid = self.make_qid(u"/")
43+ self.set_qid_path(fid, qid, u"/")
4344 self.root_fid = fid
4445 return qid
4546
@@ -49,14 +50,14 @@ class DictStore: · 3 unmodified lines
4950
5051 def set_qid_path(self, fid, qid, path):
5152
52− path = path.lstrip("/")
53+ path = path.lstrip(u"/")
5354
5455 self.qids[fid] = qid
5556 self.paths[fid] = path
5657
5758 def make_qid(self, path):
5859
59− path = path.lstrip("/")
60+ path = path.lstrip(u"/")
6061 obj = self.traverse(path)
6162
6263 if obj == None:
@@ -90,7 +91,7 @@ class DictStore: · 27 unmodified lines
9091
9192 def _stat(self, qid, path):
9293
93− path = path.lstrip("/")
94+ path = path.lstrip(u"/")
9495
9596 obj = self.traverse(path)
9697
@@ -100,16 +101,16 @@ class DictStore: · 3 unmodified lines
100101 if type(obj) == dict:
101102 mode = 0x80000000
102103 size = 0
103− mode |= 0555
104+ mode |= 0o555
104105 else:
105106 mode = 0
106107 size = len(obj)
107− mode |= 0444
108+ mode |= 0o444
108109
109− name = path.split("/")[-1]
110+ name = path.split(u"/")[-1]
110111
111112 return styx.Stat(0, 0, qid, mode, self.now, self.now, size, name,
112− "inferno", "inferno", "")
113+ u"inferno", u"inferno", u"")
113114
114115 def create(self, fid, name, perm):
115116 return False
@@ -137,7 +138,7 @@ class DictStore: · 21 unmodified lines
137138 if obj == None:
138139 return None
139140
140− data = ""
141+ data = b""
141142
142143 if type(obj) == dict:
143144
@@ -147,12 +148,12 @@ class DictStore: · 3 unmodified lines
147148 files.sort()
148149
149150 for file_name in files:
150− qid = self.make_qid(path + "/" + file_name)
151− data += self._stat(qid, path + "/" + file_name).encode()
151+ qid = self.make_qid(path + u"/" + file_name)
152+ data += self._stat(qid, path + u"/" + file_name).encode()
152153
153154 return data[offset:offset + count]
154155 else:
155− return obj[offset:offset + count]
156+ return obj[offset:offset + count].encode("utf8")
156157
157158 def write(self, fid, offset, data):
158159
@@ -160,19 +161,19 @@ class DictStore: · 1 unmodified line
160161 return -2
161162
162163 def remove(self, fid):
163− return False
164+ return u"Cannot remove dictionary entries."
164165
165166 def wstat(self, fid, st):
166167 pass
167168
168169 def traverse(self, path):
169170
170− if path == "":
171+ if path == u"":
171172 return self.d
172173
173174 obj = self.d
174175
175− for element in path.split("/"):
176+ for element in path.split(u"/"):
176177
177178 try:
178179 obj = obj[element]
@@ -191,11 +192,12 @@ if __name__ == "__main__": · 12 unmodified lines
191192 port = int(sys.argv[1])
192193
193194 dictionary = {
194− "dir": {
195− "hello.txt": "Hello world!\n"
195+ u"dir": {
196+ u"hello.txt": u"Hello world!\n",
197+ u"\u263a": u"Forståelse"
196198 }
197199 }
198200
199201 store = DictStore(dictionary)
200202 server = styxserver.StyxServer(store)
201− server.serve("", port)
203+ server.serve(b"", port)
localfileserver.py+36−28
@@ -17,7 +17,7 @@ · 16 unmodified lines
1717 # You should have received a copy of the GNU General Public License
1818 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1919
20−import os, stat, sys
20+import locale, os, stat, sys
2121 import styx, styxserver
2222
2323 class FileStore:
@@ -34,11 +34,12 @@ class FileStore: · 10 unmodified lines
3434 self.paths = {}
3535 self.opened = {}
3636 self.root_fid = None
37+ self.encoding = sys.getfilesystemencoding()
3738
3839 def get_root_qid(self, fid, afid, uname, aname):
3940
40− qid = self.make_qid("")
41− self.set_qid_path(fid, qid, "")
41+ qid = self.make_qid(u"/")
42+ self.set_qid_path(fid, qid, u"/")
4243 self.root_fid = fid
4344 return qid
4445
@@ -48,16 +49,16 @@ class FileStore: · 3 unmodified lines
4849
4950 def set_qid_path(self, fid, qid, path):
5051
51− path = path.lstrip("/")
52+ path = path.lstrip(u"/")
5253
5354 self.qids[fid] = qid
5455 self.paths[fid] = path
5556
5657 def make_qid(self, path):
5758
58− path = path.lstrip("/")
59+ path = path.lstrip(u"/")
5960
60− real_path = os.path.join(self.dir, path)
61+ real_path = os.path.join(self.dir, path).encode(self.encoding)
6162
6263 try:
6364 s = os.stat(real_path)
@@ -93,10 +94,10 @@ class FileStore: · 29 unmodified lines
9394
9495 def _stat(self, qid, path):
9596
96− path = path.lstrip("/")
97+ path = path.lstrip(u"/")
9798
9899 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)
100101
101102 try:
102103 s = os.stat(real_path)
@@ -110,14 +111,14 @@ class FileStore: · 7 unmodified lines
110111 mode = 0
111112 size = s.st_size
112113
113− mode |= (s.st_mode & 0777)
114+ mode |= (s.st_mode & 0o777)
114115
115116 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"")
117118
118119 def create(self, fid, name, perm):
119120
120− if name in (".", ".."):
121+ if name in (u".", u".."):
121122 return False
122123
123124 elif fid in self.opened:
@@ -125,7 +126,7 @@ class FileStore: · 1 unmodified line
125126 else:
126127 # Obtain the real path of the directory.
127128 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)
129130
130131 if not os.path.isdir(real_path):
131132 return False
@@ -133,7 +134,7 @@ class FileStore: · 1 unmodified line
133134 # Read the directory permissions.
134135 dir_perm = os.stat(real_path).st_mode
135136
136− new_real_path = os.path.join(real_path, name)
137+ new_real_path = os.path.join(self.dir, path, name).encode(self.encoding)
137138
138139 if os.path.exists(new_real_path):
139140 return False
@@ -143,18 +144,18 @@ class FileStore: · 3 unmodified lines
143144 if perm & styx.Stat.DMDIR:
144145 # Only pass the lowest permission bits through to the
145146 # underlying filing system.
146− mode = dir_perm & 0777
147+ mode = dir_perm & 0o777
147148 os.mkdir(new_real_path, mode)
148149 else:
149− mode = dir_perm & 0666
150+ mode = dir_perm & 0o666
150151 os.mknod(new_real_path, mode, stat.S_IFREG)
151152
152153 except OSError:
153154 return False
154155
155156 # Update the fid to refer to the new object.
156− qid = self.make_qid(path + "/" + name)
157− self.set_qid_path(fid, qid, path + "/" + name)
157+ qid = self.make_qid(path + u"/" + name)
158+ self.set_qid_path(fid, qid, path + u"/" + name)
158159
159160 return qid
160161
@@ -177,7 +178,7 @@ class FileStore: · 16 unmodified lines
177178
178179 path = self.paths[fid]
179180 real_path = os.path.join(self.dir, path)
180− data = ""
181+ data = b""
181182
182183 if os.path.isdir(real_path):
183184
@@ -187,8 +188,8 @@ class FileStore: · 3 unmodified lines
187188 files.sort()
188189
189190 for file_name in files:
190− qid = self.make_qid(path + "/" + file_name)
191− data += self._stat(qid, path + "/" + file_name).encode()
191+ qid = self.make_qid(path + u"/" + file_name)
192+ data += self._stat(qid, path + u"/" + file_name).encode()
192193
193194 return data[offset:offset + count]
194195 else:
@@ -207,7 +208,7 @@ class FileStore: · 12 unmodified lines
207208 if os.path.isdir(real_path):
208209 return -1
209210
210− f = open(real_path, "r+wb")
211+ f = open(real_path, "r+b")
211212 f.seek(offset)
212213 f.write(data)
213214 f.close()
@@ -225,7 +226,7 @@ class FileStore: · 11 unmodified lines
225226 else:
226227 os.remove(real_path)
227228
228− except OSError, e:
229+ except OSError as e:
229230 return str(e)
230231
231232 return True
@@ -233,18 +234,25 @@ class FileStore: · 1 unmodified line
233234 def wstat(self, fid, st):
234235
235236 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]
237241
238− old_name = path.split("/")[-1]
239− if st.name != "" and st.name != old_name:
240− new_path = os.path.join(os.path.split(real_path)[0], st.name)
242+ # Only update the name if the specified name is not empty and differs
243+ # from the existing path.
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)
241247 os.rename(real_path, new_path)
242248 real_path = new_path
249+ # Update the path dictionary to contain the new path.
250+ self.paths[fid] = pieces + [u"/" + st.name]
243251
244252 s = os.stat(real_path)
245253
246254 if st.mode != 0xffffffff:
247− os.chmod(real_path, st.mode & 0777)
255+ os.chmod(real_path, st.mode & 0o777)
248256
249257 if st.mtime != 0xffffffff or st.atime != 0xffffffff:
250258 if st.mtime == 0xffffffff:
@@ -271,4 +279,4 @@ if __name__ == "__main__": · 20 unmodified lines
271279
272280 store = FileStore(directory)
273281 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
3838 self.sock = sock
3939
4040 def recv(self, n):
41− data = ""
41+ data = b""
4242 while len(data) < n:
4343 data += self.sock.recv(n - len(data))
4444
@@ -108,7 +108,7 @@ def decode_format(stream, obj): · 63 unmodified lines
108108
109109 def encode_format(stream, obj):
110110
111− data = ""
111+ data = b""
112112
113113 for name, length in obj.format:
114114
@@ -624,7 +624,9 @@ class Stat: · 509 unmodified lines
624624
625625 def encode(self):
626626
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+
628630 data = struct.pack("<HIBIQIIIQ", *args)
629631 data += encode_string(self.name)
630632 data += encode_string(self.uid)
styxserver.py+4−1
@@ -50,7 +50,7 @@ class StyxServer: · 49 unmodified lines
5050 reply = handler(self, conn, client, message)
5151 except KeyError:
5252 reply = styx.Rerror(message.tag, "Unsupported message.")
53− except StyxServerError, e:
53+ except StyxServerError as e:
5454 reply = styx.Rerror(message.tag, e.message)
5555 except socket.error:
5656 # The connection was probably closed by the client.
@@ -67,6 +67,9 @@ class StyxServer: · 10 unmodified lines
6767 store = self.clients[client]
6868
6969 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+
7073 return styx.Rattach(msg.tag, qid)
7174
7275 def Tstat(self, conn, client, msg):