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
6969 qids = []
7070 try:
7171 for element in msg.wname:
72− path += element
72+ path += "/" + element
7373 qid = store.make_qid(path)
7474 qids.append(qid)
7575
@@ -90,8 +90,29 @@ class StyxFSServer: · 14 unmodified lines
9090 # The fid must have an existing qid.
9191 qid, path = store.get_qid_path(msg.fid)
9292
93+ if not store.open(msg.fid, msg.mode):
94+ return styx.Rerror(msg.tag, "Cannot open file.")
95+
9396 return styx.Ropen(msg.tag, qid, self.MAX_MSG_SIZE)
9497
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+
95116 def Tread(self, conn, client, msg):
96117
97118 store = self.clients[client]
@@ -101,6 +122,15 @@ class StyxFSServer: · 3 unmodified lines
101122
102123 return styx.Rread(msg.tag, data)
103124
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+
104134 def Tclunk(self, conn, client, msg):
105135
106136 store = self.clients[client]
@@ -120,7 +150,9 @@ class StyxFSServer: · 13 unmodified lines
120150 styx.Tstat.code: Tstat,
121151 styx.Twalk.code: Twalk,
122152 styx.Topen.code: Topen,
153+ styx.Tcreate.code: Tcreate,
123154 styx.Tread.code: Tread,
155+ styx.Twrite.code: Twrite,
124156 styx.Tclunk.code: Tclunk
125157 }
126158
@@ -137,6 +169,7 @@ class FileStore: · 10 unmodified lines
137169 self.dir = os.path.abspath(directory)
138170 self.qids = {}
139171 self.paths = {}
172+ self.opened = {}
140173
141174 def get_root_qid(self, fid, afid, uname, aname):
142175
@@ -150,6 +183,8 @@ class FileStore: · 7 unmodified lines
150183
151184 def set_qid_path(self, fid, qid, path):
152185
186+ path = path.lstrip("/")
187+
153188 self.qids[fid] = qid
154189 self.paths[fid] = path
155190
@@ -157,14 +192,16 @@ class FileStore: · 1 unmodified line
157192
158193 path = path.lstrip("/")
159194
160− file_path = os.path.join(self.dir, path)
161− s = os.stat(file_path)
162− if os.path.isdir(file_path):
195+ real_path = os.path.join(self.dir, path)
196+ s = os.stat(real_path)
197+ if os.path.isdir(real_path):
163198 qtype = 0x80
164199 else:
165200 qtype = 0
166201
167202 qversion = 0
203+
204+ # Use the inode number to uniquely refer to the object at this location.
168205 qpath = s.st_ino
169206
170207 return (qtype, qversion, qpath)
@@ -173,6 +210,9 @@ class FileStore: · 2 unmodified lines
173210
174211 del self.qids[fid]
175212 del self.paths[fid]
213+
214+ if fid in self.opened:
215+ del self.opened[fid]
176216
177217 def stat(self, fid):
178218
@@ -182,6 +222,8 @@ class FileStore: · 3 unmodified lines
182222
183223 def _stat(self, qid, path):
184224
225+ path = path.lstrip("/")
226+
185227 name = os.path.split(path)[1]
186228 real_path = os.path.join(self.dir, path)
187229 s = os.stat(real_path)
@@ -198,6 +240,64 @@ class FileStore: · 10 unmodified lines
198240 return styx.Stat(0, 0, qid, mode, s.st_atime, s.st_mtime, size,
199241 name, "styxfs", "styxfs", "")
200242
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+
201301 def read(self, fid, offset, count):
202302
203303 path = self.paths[fid]
@@ -205,12 +305,15 @@ class FileStore: · 1 unmodified line
205305 data = ""
206306
207307 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.
208311 files = os.listdir(real_path)
209312 files.sort()
210313
211314 for file_name in files:
212315 qid = self.make_qid(path + "/" + file_name)
213− data += self._stat(qid, file_name).encode()
316+ data += self._stat(qid, path + "/" + file_name).encode()
214317
215318 return data[offset:offset + count]
216319 else:
@@ -220,6 +323,21 @@ class FileStore: · 3 unmodified lines
220323 f.close()
221324
222325 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)
223341
224342
225343 if __name__ == "__main__":