History

Fixed invalid concatenation of path elements to include directory separators. Ensured that leading separators are removed in methods are called with paths constructed in this way. Added support for create and write operations.

David Boddie committed 8 years ago

Commit 2c133ab1 parent a087d721 file · +123 −5Browse files

Unified · Split

styxfs.py+123−5
@@ -69,7 +69,7 @@ class StyxFSServer: · 68 unmodified lines
69 qids = []69 qids = []
70 try:70 try:
71 for element in msg.wname:71 for element in msg.wname:
72 path += element72 path += "/" + element
73 qid = store.make_qid(path)73 qid = store.make_qid(path)
74 qids.append(qid)74 qids.append(qid)
75 75
@@ -90,8 +90,29 @@ class StyxFSServer: · 14 unmodified lines
90 # The fid must have an existing qid.90 # The fid must have an existing qid.
91 qid, path = store.get_qid_path(msg.fid)91 qid, path = store.get_qid_path(msg.fid)
92 92
93 if not store.open(msg.fid, msg.mode):
94 return styx.Rerror(msg.tag, "Cannot open file.")
95
93 return styx.Ropen(msg.tag, qid, self.MAX_MSG_SIZE)96 return styx.Ropen(msg.tag, qid, self.MAX_MSG_SIZE)
94 97
98 def Tcreate(self, conn, client, msg):
99
100 store = self.clients[client]
101
102 # The fid must have an existing qid that corresponds to a directory
103 # and cannot be itself in use.
104 qid, path = store.get_qid_path(msg.fid)
105
106 new_qid = store.create(msg.fid, msg.name, msg.perm)
107 if new_qid == False:
108 return styx.Rerror(msg.tag, "Cannot create file.")
109
110 # The fid now refers to the newly open file or directory.
111 if not store.open(msg.fid, msg.mode):
112 return styx.Rerror(msg.tag, "Cannot open file.")
113
114 return styx.Rcreate(msg.tag, new_qid, self.MAX_MSG_SIZE)
115
95 def Tread(self, conn, client, msg):116 def Tread(self, conn, client, msg):
96 117
97 store = self.clients[client]118 store = self.clients[client]
@@ -101,6 +122,15 @@ class StyxFSServer: · 3 unmodified lines
101 122
102 return styx.Rread(msg.tag, data)123 return styx.Rread(msg.tag, data)
103 124
125 def Twrite(self, conn, client, msg):
126
127 store = self.clients[client]
128
129 # The fid must have an existing qid.
130 count = store.write(msg.fid, msg.offset, msg.data)
131
132 return styx.Rwrite(msg.tag, count)
133
104 def Tclunk(self, conn, client, msg):134 def Tclunk(self, conn, client, msg):
105 135
106 store = self.clients[client]136 store = self.clients[client]
@@ -120,7 +150,9 @@ class StyxFSServer: · 13 unmodified lines
120 styx.Tstat.code: Tstat,150 styx.Tstat.code: Tstat,
121 styx.Twalk.code: Twalk,151 styx.Twalk.code: Twalk,
122 styx.Topen.code: Topen,152 styx.Topen.code: Topen,
153 styx.Tcreate.code: Tcreate,
123 styx.Tread.code: Tread,154 styx.Tread.code: Tread,
155 styx.Twrite.code: Twrite,
124 styx.Tclunk.code: Tclunk156 styx.Tclunk.code: Tclunk
125 }157 }
126 158
@@ -137,6 +169,7 @@ class FileStore: · 10 unmodified lines
137 self.dir = os.path.abspath(directory)169 self.dir = os.path.abspath(directory)
138 self.qids = {}170 self.qids = {}
139 self.paths = {}171 self.paths = {}
172 self.opened = {}
140 173
141 def get_root_qid(self, fid, afid, uname, aname):174 def get_root_qid(self, fid, afid, uname, aname):
142 175
@@ -150,6 +183,8 @@ class FileStore: · 7 unmodified lines
150 183
151 def set_qid_path(self, fid, qid, path):184 def set_qid_path(self, fid, qid, path):
152 185
186 path = path.lstrip("/")
187
153 self.qids[fid] = qid188 self.qids[fid] = qid
154 self.paths[fid] = path189 self.paths[fid] = path
155 190
@@ -157,14 +192,16 @@ class FileStore: · 1 unmodified line
157 192
158 path = path.lstrip("/")193 path = path.lstrip("/")
159 194
160 file_path = os.path.join(self.dir, path)195 real_path = os.path.join(self.dir, path)
161 s = os.stat(file_path)196 s = os.stat(real_path)
162 if os.path.isdir(file_path):197 if os.path.isdir(real_path):
163 qtype = 0x80198 qtype = 0x80
164 else:199 else:
165 qtype = 0200 qtype = 0
166 201
167 qversion = 0202 qversion = 0
203
204 # Use the inode number to uniquely refer to the object at this location.
168 qpath = s.st_ino205 qpath = s.st_ino
169 206
170 return (qtype, qversion, qpath)207 return (qtype, qversion, qpath)
@@ -173,6 +210,9 @@ class FileStore: · 2 unmodified lines
173 210
174 del self.qids[fid]211 del self.qids[fid]
175 del self.paths[fid]212 del self.paths[fid]
213
214 if fid in self.opened:
215 del self.opened[fid]
176 216
177 def stat(self, fid):217 def stat(self, fid):
178 218
@@ -182,6 +222,8 @@ class FileStore: · 3 unmodified lines
182 222
183 def _stat(self, qid, path):223 def _stat(self, qid, path):
184 224
225 path = path.lstrip("/")
226
185 name = os.path.split(path)[1]227 name = os.path.split(path)[1]
186 real_path = os.path.join(self.dir, path)228 real_path = os.path.join(self.dir, path)
187 s = os.stat(real_path)229 s = os.stat(real_path)
@@ -198,6 +240,64 @@ class FileStore: · 10 unmodified lines
198 return styx.Stat(0, 0, qid, mode, s.st_atime, s.st_mtime, size,240 return styx.Stat(0, 0, qid, mode, s.st_atime, s.st_mtime, size,
199 name, "styxfs", "styxfs", "")241 name, "styxfs", "styxfs", "")
200 242
243 def create(self, fid, name, perm):
244
245 if name in (".", ".."):
246 return False
247
248 elif fid in self.opened:
249 return False
250 else:
251 # Obtain the real path of the directory.
252 path = self.paths[fid]
253 real_path = os.path.join(self.dir, path)
254
255 if not os.path.isdir(real_path):
256 return False
257
258 # Read the directory permissions.
259 dir_perm = os.stat(real_path).st_mode
260
261 new_real_path = os.path.join(real_path, name)
262
263 if os.path.exists(new_real_path):
264 return False
265
266 # Create the file or directory with suitable permissions.
267 try:
268 if perm & styx.Stat.DMDIR:
269 # Only pass the lowest permission bits through to the
270 # underlying filing system.
271 mode = dir_perm & 0777
272 os.mkdir(new_real_path, mode)
273 else:
274 mode = dir_perm & 0666
275 os.mknod(new_real_path, mode, stat.S_IFREG)
276
277 except OSError:
278 return False
279
280 # Update the fid to refer to the new object.
281 qid = self.make_qid(path + "/" + name)
282 self.set_qid_path(fid, qid, path + "/" + name)
283
284 return qid
285
286 def open(self, fid, mode):
287
288 if fid in self.opened:
289 self.opened[fid] = mode
290 if mode & styx.Stat.DMEXCL:
291 return False
292 else:
293 self.opened[fid] = mode
294
295 return True
296
297 def is_opened(self, fid):
298
299 return fid in self.opened
300
201 def read(self, fid, offset, count):301 def read(self, fid, offset, count):
202 302
203 path = self.paths[fid]303 path = self.paths[fid]
@@ -205,12 +305,15 @@ class FileStore: · 1 unmodified line
205 data = ""305 data = ""
206 306
207 if os.path.isdir(real_path):307 if os.path.isdir(real_path):
308
309 # Iterate over a sorted list of files in the directory, constructing
310 # a byte string of information about them that can be sent in chunks.
208 files = os.listdir(real_path)311 files = os.listdir(real_path)
209 files.sort()312 files.sort()
210 313
211 for file_name in files:314 for file_name in files:
212 qid = self.make_qid(path + "/" + file_name)315 qid = self.make_qid(path + "/" + file_name)
213 data += self._stat(qid, file_name).encode()316 data += self._stat(qid, path + "/" + file_name).encode()
214 317
215 return data[offset:offset + count]318 return data[offset:offset + count]
216 else:319 else:
@@ -220,6 +323,21 @@ class FileStore: · 3 unmodified lines
220 f.close()323 f.close()
221 324
222 return data325 return data
326
327 def write(self, fid, offset, data):
328
329 path = self.paths[fid]
330 real_path = os.path.join(self.dir, path)
331
332 if os.path.isdir(real_path):
333 return styx.Rerror(msg.tag, "Not a file.")
334
335 f = open(real_path, "r+wb")
336 f.seek(offset)
337 f.write(data)
338 f.close()
339
340 return len(data)
223 341
224 342
225if __name__ == "__main__":343if __name__ == "__main__":