summaryrefslogtreecommitdiff
path: root/appl/lib/nametree.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/nametree.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/nametree.b')
-rw-r--r--appl/lib/nametree.b278
1 files changed, 278 insertions, 0 deletions
diff --git a/appl/lib/nametree.b b/appl/lib/nametree.b
new file mode 100644
index 00000000..b9975567
--- /dev/null
+++ b/appl/lib/nametree.b
@@ -0,0 +1,278 @@
+implement Nametree;
+include "sys.m";
+ sys: Sys;
+include "styx.m";
+include "styxservers.m";
+ Navop: import Styxservers;
+ Enotfound, Eexists: import Styxservers;
+
+Fholder: adt {
+ parentqid: big;
+ d: Sys->Dir;
+ child: cyclic ref Fholder;
+ sibling: cyclic ref Fholder;
+ hash: cyclic ref Fholder;
+};
+
+init()
+{
+ sys = load Sys Sys->PATH;
+}
+
+start(): (ref Tree, chan of ref Styxservers->Navop)
+{
+ fs := ref Tree(chan of ref Treeop, chan of string);
+ c := chan of ref Styxservers->Navop;
+ spawn fsproc(c, fs.c);
+ return (fs, c);
+}
+
+Tree.quit(t: self ref Tree)
+{
+ t.c <-= nil;
+}
+
+Tree.create(t: self ref Tree, parentq: big, d: Sys->Dir): string
+{
+ t.c <-= ref Treeop.Create(t.reply, parentq, d);
+ return <-t.reply;
+}
+
+Tree.remove(t: self ref Tree, q: big): string
+{
+ t.c <-= ref Treeop.Remove(t.reply, q);
+ return <-t.reply;
+}
+
+Tree.wstat(t: self ref Tree, q: big, d: Sys->Dir): string
+{
+ t.c <-= ref Treeop.Wstat(t.reply, q, d);
+ return <-t.reply;
+}
+
+Tree.getpath(t: self ref Tree, q: big): string
+{
+ t. c <-= ref Treeop.Getpath(t.reply, q);
+ return <-t.reply;
+}
+
+fsproc(c: chan of ref Styxservers->Navop, fsc: chan of ref Treeop)
+{
+ tab := array[23] of ref Fholder;
+ starttime := 0;
+
+ for (;;) alt {
+ grq := <-c =>
+ if (grq == nil)
+ exit;
+ (q, reply) := (grq.path, grq.reply);
+ fh := findfile(tab, q);
+ if (fh == nil) {
+ reply <-= (nil, Enotfound);
+ continue;
+ }
+ pick rq := grq {
+ Stat =>
+ reply <-= (ref fh.d, nil);
+ Walk =>
+ d := fswalk(tab, fh, rq.name);
+ if (d == nil)
+ reply <-= (nil, Enotfound);
+ else
+ reply <-= (d, nil);
+ Readdir =>
+ (start, end) := (rq.offset, rq.offset + rq.count);
+ fh = fh.child;
+ for (i := 0; i < end && fh != nil; i++) {
+ if (i >= start)
+ reply <-= (ref fh.d, nil);
+ fh = fh.sibling;
+ }
+ reply <-= (nil, nil);
+ * =>
+ panic(sys->sprint("unknown op %d\n", tagof(grq)));
+ }
+ grq := <-fsc =>
+ if (grq == nil)
+ exit;
+ (q, reply) := (grq.q, grq.reply);
+ pick rq := grq {
+ Create =>
+ reply <-= fscreate(tab, q, rq.d);
+ Remove =>
+ reply <-= fsremove(tab, q);
+ Wstat =>
+ reply <-= fswstat(tab, q, rq.d);
+ Getpath =>
+ reply <-= fsgetpath(tab, q);
+ * =>
+ panic(sys->sprint("unknown fs op %d\n", tagof(grq)));
+ }
+ }
+}
+
+hashfn(q: big, n: int): int
+{
+ h := int (q % big n);
+ if (h < 0)
+ h += n;
+ return h;
+}
+
+findfile(tab: array of ref Fholder, q: big): ref Fholder
+{
+ for (fh := tab[hashfn(q, len tab)]; fh != nil; fh = fh.hash)
+ if (fh.d.qid.path == q)
+ return fh;
+ return nil;
+}
+
+fsgetpath(tab: array of ref Fholder, q: big): string
+{
+ fh := findfile(tab, q);
+ if (fh == nil)
+ return nil;
+ s := fh.d.name;
+ while (fh.parentqid != fh.d.qid.path) {
+ fh = findfile(tab, fh.parentqid);
+ if (fh == nil)
+ return nil;
+ s = fh.d.name + "/" + s;
+ }
+ return s;
+}
+
+fswalk(tab: array of ref Fholder, fh: ref Fholder, name: string): ref Sys->Dir
+{
+ if (name == "..")
+ return ref findfile(tab, fh.parentqid).d;
+ for (fh = fh.child; fh != nil; fh = fh.sibling)
+ if (fh.d.name == name)
+ return ref fh.d;
+ return nil;
+}
+
+fsremove(tab: array of ref Fholder, q: big): string
+{
+ prev: ref Fholder;
+
+ # remove from hash table
+ slot := hashfn(q, len tab);
+ for (fh := tab[slot]; fh != nil; fh = fh.hash) {
+ if (fh.d.qid.path == q)
+ break;
+ prev = fh;
+ }
+ if (fh == nil)
+ return Enotfound;
+ if (prev == nil)
+ tab[slot] = fh.hash;
+ else
+ prev.hash = fh.hash;
+ fh.hash = nil;
+
+ # remove from parent's children
+ parent := findfile(tab, fh.parentqid);
+ if (parent != nil) {
+ prev = nil;
+ for (sfh := parent.child; sfh != nil; sfh = sfh.sibling) {
+ if (sfh == fh)
+ break;
+ prev = sfh;
+ }
+ if (sfh == nil)
+ panic("child not found in parent");
+ if (prev == nil)
+ parent.child = fh.sibling;
+ else
+ prev.sibling = fh.sibling;
+ }
+ fh.sibling = nil;
+
+ # now remove any descendents
+ sibling: ref Fholder;
+ for (sfh := fh.child; sfh != nil; sfh = sibling) {
+ sibling = sfh.sibling;
+ sfh.parentqid = sfh.d.qid.path; # make sure it doesn't disrupt things.
+ fsremove(tab, sfh.d.qid.path);
+ }
+ return nil;
+}
+
+fscreate(tab: array of ref Fholder, q: big, d: Sys->Dir): string
+{
+ parent := findfile(tab, q);
+ if (findfile(tab, d.qid.path) != nil)
+ return Eexists;
+ # allow creation of a root directory only if its parent is itself
+ if (parent == nil && d.qid.path != q)
+ return Enotfound;
+ fh: ref Fholder;
+ if (parent == nil)
+ fh = ref Fholder(q, d, nil, nil, nil);
+ else {
+ if (fswalk(tab, parent, d.name) != nil)
+ return Eexists;
+ fh = ref Fholder(parent.d.qid.path, d, nil, nil, nil);
+ fh.sibling = parent.child;
+ parent.child = fh;
+ }
+ slot := hashfn(d.qid.path, len tab);
+ fh.hash = tab[slot];
+ tab[slot] = fh;
+ return nil;
+}
+
+fswstat(tab: array of ref Fholder, q: big, d: Sys->Dir): string
+{
+ fh := findfile(tab, q);
+ if (fh == nil)
+ return Enotfound;
+
+ d = applydir(d, fh.d);
+
+ # if renaming a file, check for duplicates
+ if (d.name != fh.d.name) {
+ parent := findfile(tab, fh.parentqid);
+ if (parent != nil && parent != fh && fswalk(tab, parent, d.name) != nil)
+ return Eexists;
+ }
+ fh.d = d;
+ fh.d.qid.path = q; # ensure the qid can't be changed
+ return nil;
+}
+
+applydir(d: Sys->Dir, onto: Sys->Dir): Sys->Dir
+{
+ if (d.name != nil)
+ onto.name = d.name;
+ if (d.uid != nil)
+ onto.uid = d.uid;
+ if (d.gid != nil)
+ onto.gid = d.gid;
+ if (d.muid != nil)
+ onto.muid = d.muid;
+ if (d.qid.vers != ~0)
+ onto.qid.vers = d.qid.vers;
+ if (d.qid.qtype != ~0)
+ onto.qid.qtype = d.qid.qtype;
+ if (d.mode != ~0)
+ onto.mode = d.mode;
+ if (d.atime != ~0)
+ onto.atime = d.atime;
+ if (d.mtime != ~0)
+ onto.mtime = d.mtime;
+ if (d.length != ~big 0)
+ onto.length = d.length;
+ if (d.dtype != ~0)
+ onto.dtype = d.dtype;
+ if (d.dev != ~0)
+ onto.dev = d.dev;
+ return onto;
+}
+
+panic(s: string)
+{
+ sys->fprint(sys->fildes(2), "panic: %s\n", s);
+ raise "panic";
+}