-
Notifications
You must be signed in to change notification settings - Fork 0
/
simplefs.b
201 lines (156 loc) · 3.69 KB
/
simplefs.b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
implement SimpleFS;
include "sys.m";
sys: Sys;
sprint, print, fildes: import sys;
OTRUNC, ORCLOSE, OREAD, OWRITE: import Sys;
include "draw.m";
include "arg.m";
include "styx.m";
styx: Styx;
Tmsg, Rmsg: import Styx;
include "styxservers.m";
styxservers: Styxservers;
Styxserver, Fid, Navigator,
Navop, Enotfound, Enotdir: import styxservers;
SimpleFS: module {
init: fn(nil: ref Draw->Context, argv: list of string);
};
# FS file index
Qroot, Qctl, Qlog, Qmax: con iota;
tab := array[] of {
(Qroot, ".", Sys->DMDIR|8r555),
(Qctl, "ctl", 8r222),
(Qlog, "log", 8r444),
};
user: string = "none"; # User owning the fs
chatty: int = 0; # Debug log toggle -- triggers styx(2) tracing
log: list of string; # Written log history
# Serves a simple read-write filesystem
init(nil: ref Draw->Context, argv: list of string) {
sys = load Sys Sys->PATH;
arg := load Arg Arg->PATH;
if(arg == nil)
raise "could not load arg";
styx = load Styx Styx->PATH;
if(styx == nil)
raise "could not load styx";
styxservers = load Styxservers Styxservers->PATH;
if(styxservers == nil)
raise "could not load styxservers";
chatty = 0;
arg->init(argv);
arg->setusage("simplefs [-D] [-u user]");
while((c := arg->opt()) != 0)
case c {
'D' =>
chatty++;
'u' =>
user = arg->earg();
* =>
arg->usage();
}
argv = arg->argv();
# Start 9p infrastructure
styx->init();
styxservers->init(styx);
styxservers->traceset(chatty);
# Start FS navigator on /
navch := chan of ref Navop;
spawn navigator(navch);
nav := Navigator.new(navch);
(tc, srv) := Styxserver.new(fildes(0), nav, big Qroot);
# Primary server loop
loop:
while((tmsg := <-tc) != nil) {
# Switch on operations being performed on a given Fid
pick msg := tmsg {
Open =>
srv.default(msg);
Read =>
fid := srv.getfid(msg.fid);
if(fid.qtype & Sys->QTDIR) {
# This is a directory read
srv.default(msg);
continue loop;
}
case int fid.path {
Qlog =>
# A read on our log file, tell them what they've already said ☺
s := "";
for(l := log; l != nil; l = tl l)
s = hd l + s;
srv.reply(styxservers->readstr(msg, s));
* =>
srv.default(msg);
}
Write =>
fid := srv.getfid(msg.fid);
case int fid.path {
Qctl =>
# Don't care about offset
cmd := string msg.data;
reply: ref Rmsg = ref Rmsg.Write(msg.tag, len msg.data);
case cmd {
* =>
# Ignore empty writes
if(cmd != nil)
log = cmd :: log;
else
reply = ref Rmsg.Error(msg.tag, "empty write!");
}
srv.reply(reply);
* =>
srv.default(msg);
}
* =>
srv.default(msg);
}
}
exit;
}
# Navigator function for moving around under /
navigator(c: chan of ref Navop) {
loop:
for(;;) {
navop := <-c;
pick op := navop {
Stat =>
op.reply <-= (dir(int op.path), nil);
Walk =>
if(op.name == "..") {
op.reply <-= (dir(Qroot), nil);
continue loop;
}
case int op.path&16rff {
Qroot =>
for(i := 1; i < Qmax; i++)
if(tab[i].t1 == op.name) {
op.reply <-= (dir(i), nil);
continue loop;
}
op.reply <-= (nil, Enotfound);
* =>
op.reply <-= (nil, Enotdir);
}
Readdir =>
for(i := 0; i < op.count && i + op.offset < (len tab) - 1; i++)
op.reply <-= (dir(Qroot+1+i+op.offset), nil);
op.reply <-= (nil, nil);
}
}
}
# Given a path inside the table, this returns a Sys->Dir representing that path.
dir(path: int): ref Sys->Dir {
(nil, name, perm) := tab[path&16rff];
d := ref sys->zerodir;
d.name = name;
d.uid = d.gid = user;
d.qid.path = big path;
if(perm & Sys->DMDIR)
d.qid.qtype = Sys->QTDIR;
else
d.qid.qtype = Sys->QTFILE;
d.mtime = d.atime = 0;
d.mode = perm;
return d;
}