MODULE RfsFS;
IMPORT SYSTEM, Modules, Clock, Files, RfsClientProxy, KernelLog;
CONST
BufSize = RfsClientProxy.Payload;
MaxBufs = 2;
FnLength = 32;
EnumRegular = 0;
EnumDetail = 1;
Ok = RfsClientProxy.REPLYOK;
Trace = 0;
TYPE
DiskSector = RECORD END;
FileName = ARRAY FnLength OF CHAR;
DataSector = RECORD (DiskSector)
B: ARRAY BufSize OF CHAR
END;
Buffer* = POINTER TO RECORD (Files.Hint)
apos*, lim*: LONGINT;
mod: BOOLEAN;
next: Buffer;
data*: DataSector
END;
TYPE
FileSystem* = OBJECT (Files.FileSystem)
VAR stubs: RfsClientProxy.Proxy;
PROCEDURE New0*(name: ARRAY OF CHAR): Files.File;
VAR
res: LONGINT;
f: File;
buf: Buffer;
namebuf, nameTemp: FileName;
hashval, errorcode: LONGINT;
BEGIN {EXCLUSIVE}
f := NIL;
Check(name, namebuf, res);
IF res <= 0 THEN
FillBuf(nameTemp, 0X);
stubs.CreateTmp(nameTemp, hashval, errorcode);
IF errorcode = Ok THEN
NEW(buf);
buf.apos := 0;
buf.mod := TRUE;
buf.lim := 0;
buf.next := buf;
NEW(f);
f.fs := SELF;
f.key := hashval;
f.aleng := 0;
f.bleng := 0;
f.modH := TRUE;
f.firstbuf := buf;
f.nofbufs := 1;
f.name := namebuf;
f.nameTemp := nameTemp;
Clock.Get(f.time, f.date);
f.registered := (f.name[0] = 0X);
END;
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("New0->name:");
KernelLog.String(name);
KernelLog.String(", res:");
KernelLog.Int(res, 1);
KernelLog.Exit;
END;
RETURN f
END New0;
PROCEDURE Old0*(name: ARRAY OF CHAR): Files.File;
VAR
res: LONGINT;
f: File;
buf: Buffer;
namebuf: FileName;
hashval, errorcode, fileLen, time, date: LONGINT;
BEGIN {EXCLUSIVE}
f := NIL;
Check(name, namebuf, res);
IF res = 0 THEN
stubs.Lookup(namebuf, hashval, errorcode);
IF (errorcode = Ok) & (hashval # 0) THEN
NEW(buf);
NEW(f);
f.key := hashval;
f.fs := SELF;
stubs.GetAttr(hashval, fileLen, time, date, errorcode);
f.aleng := fileLen DIV BufSize;
f.bleng := fileLen MOD BufSize;
ReadBuf(f, buf, 0, errorcode);
IF errorcode # Ok THEN
RETURN NIL;
END;
buf.next := buf;
buf.mod := FALSE;
buf.apos := 0;
IF f.aleng = 0 THEN
buf.lim := f.bleng;
ELSE
buf.lim := BufSize;
END;
f.firstbuf := buf;
f.nofbufs := 1;
f.name := namebuf;
f.time := time;
f.date := date;
f.registered := TRUE;
END;
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Old0->name:");
KernelLog.String(name);
KernelLog.String(", res:");
KernelLog.Int(res, 1);
KernelLog.Exit;
END;
RETURN f
END Old0;
PROCEDURE Delete0*(name: ARRAY OF CHAR; VAR key, res: LONGINT);
VAR namebuf: FileName; errorcode: LONGINT;
BEGIN {EXCLUSIVE}
Check(name, namebuf, res);
IF res = 0 THEN
stubs.Remove(namebuf, errorcode);
IF errorcode = Ok THEN
res := 0;
ELSE
res := 2;
END;
key := 1;
ELSE
key := 0
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Delete0->name:");
KernelLog.String(name);
KernelLog.String(", key:");
KernelLog.Int(key, 1);
KernelLog.String(", res:");
KernelLog.Int(res, 1);
KernelLog.Exit;
END;
END Delete0;
PROCEDURE Rename0*(old, new: ARRAY OF CHAR; f: Files.File; VAR res: LONGINT);
VAR oldbuf, newbuf: FileName; errorcode: LONGINT;
BEGIN {EXCLUSIVE}
Check(old, oldbuf, res);
IF res = 0 THEN
Check(new, newbuf, res);
IF res = 0 THEN
IF f # NIL THEN
stubs.Rename(oldbuf, newbuf, errorcode);
IF errorcode # Ok THEN
res := 2;
END;
ELSE
res := 2;
END;
END;
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Rename0->old:");
KernelLog.String(old);
KernelLog.String(", new:");
KernelLog.String(new);
KernelLog.String(", res:");
KernelLog.Int(res, 1);
KernelLog.Exit;
END;
END Rename0;
PROCEDURE Enumerate0*(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
VAR fnTmp, fn: ARRAY Files.PrefixLength+FnLength OF CHAR; dir: RfsClientProxy.Dir;
errorcode, cookie, endOfDir, helper, time, date, size, detail: LONGINT;
BEGIN {EXCLUSIVE}
fn := ".";
cookie := 0;
helper := 0;
IF (Files.EnumTime IN flags) OR (Files.EnumSize IN flags) THEN
detail := EnumDetail;
ELSE
detail := EnumRegular;
END;
NEW(dir);
WHILE helper = 0 DO
stubs.ReadDir(fn, mask, detail, cookie, dir, endOfDir, errorcode);
IF errorcode = Ok THEN
WHILE (dir.nbrOfEntrys > 0) & (dir.first # NIL) DO
dir.Get(fnTmp, time, date, size);
Files.JoinName(prefix, fnTmp, fn);
enum.PutEntry(fn, {}, time, date, size);
END;
cookie := dir.nbrOfEntrys;
helper := endOfDir;
ELSE
helper := 1;
END;
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Enumerate0->mask:");
KernelLog.String(mask);
KernelLog.Exit;
END;
END Enumerate0;
PROCEDURE FileKey*(name: ARRAY OF CHAR): LONGINT;
VAR
res: LONGINT;
namebuf: FileName;
hashval, errorcode: LONGINT;
BEGIN {EXCLUSIVE}
hashval := 0;
Check(name, namebuf, res);
IF res = 0 THEN
stubs.Lookup(namebuf, hashval, errorcode);
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("FileKey->name:");
KernelLog.String(name);
KernelLog.String(", filekey:");
KernelLog.Int(hashval, 1);
KernelLog.Exit;
END;
RETURN hashval;
END FileKey;
PROCEDURE &RfsInit*(vol: RfsClientProxy.Proxy);
BEGIN
SELF.stubs := vol;
END RfsInit;
PROCEDURE Finalize;
VAR errorcode: LONGINT;
BEGIN {EXCLUSIVE}
stubs.Unmount(errorcode);
Finalize^;
END Finalize;
END FileSystem;
TYPE
File* = OBJECT (Files.File)
VAR
aleng, bleng: LONGINT;
nofbufs: LONGINT;
modH, registered: BOOLEAN;
firstbuf*: Buffer;
name*, nameTemp*: FileName;
time, date: LONGINT;
PROCEDURE Set*(VAR r: Files.Rider; pos: LONGINT);
VAR a, b: LONGINT;
BEGIN {EXCLUSIVE}
r.eof := FALSE;
r.res := 0;
r.file := SELF;
r.fs := fs;
IF pos < 0 THEN
a := 0; b := 0;
ELSIF pos < aleng*BufSize + bleng THEN
a := pos DIV BufSize;
b := pos MOD BufSize;
ELSE
a := aleng;
b := bleng;
END;
r.apos := a;
r.bpos := b;
r.hint := firstbuf;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Set->pos:");
KernelLog.Int(pos, 1);
KernelLog.Exit;
END;
END Set;
PROCEDURE Pos*(VAR r: Files.Rider): LONGINT;
BEGIN
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Pos->pos:");
KernelLog.Int(r.apos*BufSize + r.bpos, 1);
KernelLog.Exit;
END;
RETURN r.apos*BufSize + r.bpos;
END Pos;
PROCEDURE Read*(VAR r: Files.Rider; VAR x: CHAR);
VAR buf: Buffer; errorcode: LONGINT;
BEGIN {EXCLUSIVE}
buf := r.hint(Buffer);
IF r.apos # buf.apos THEN
buf := GetBuf(SELF, r.apos);
r.hint := buf;
END;
IF r.bpos < buf.lim THEN
x := buf.data.B[r.bpos];
INC(r.bpos);
ELSIF r.apos < aleng THEN
INC(r.apos);
buf := SearchBuf(SELF, r.apos);
IF buf = NIL THEN
buf := r.hint(Buffer);
IF buf.mod THEN
WriteBuf(SELF, buf, errorcode);
END ;
ReadBuf(SELF, buf, r.apos, errorcode);
ELSE
r.hint := buf;
END;
IF buf.lim > 0 THEN
x := buf.data.B[0];
r.bpos := 1;
ELSE
x := 0X;
r.eof := TRUE;
END;
ELSE
x := 0X; r.eof := TRUE
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Read->x:");
KernelLog.Char(x);
KernelLog.Exit;
END;
END Read;
PROCEDURE ReadBytes*(VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT);
VAR src, dst: SYSTEM.ADDRESS; m, errorcode: LONGINT; buf: Buffer;
BEGIN {EXCLUSIVE}
IF LEN(x)-ofs < len THEN
SYSTEM.HALT(19);
END;
IF len > 0 THEN
dst := SYSTEM.ADR(x[ofs]);
buf := r.hint(Buffer);
IF r.apos # buf.apos THEN
buf := GetBuf(SELF, r.apos); r.hint := buf;
END;
LOOP
IF len <= 0 THEN
EXIT;
END ;
src := SYSTEM.ADR(buf.data.B[0]) + r.bpos;
m := r.bpos + len;
IF m <= buf.lim THEN
SYSTEM.MOVE(src, dst, len);
r.bpos := m;
r.res := 0;
EXIT;
ELSIF buf.lim = BufSize THEN
m := buf.lim - r.bpos;
IF m > 0 THEN
SYSTEM.MOVE(src, dst, m);
INC(dst, m);
DEC(len, m)
END;
IF r.apos < aleng THEN
INC(r.apos);
r.bpos := 0;
buf := SearchBuf(SELF, r.apos);
IF buf = NIL THEN
buf := r.hint(Buffer);
IF buf.mod THEN
WriteBuf(SELF, buf, errorcode)
END;
ReadBuf(SELF, buf, r.apos, errorcode);
ELSE
r.hint := buf;
END;
ELSE
r.bpos := buf.lim;
r.res := len;
r.eof := TRUE;
EXIT;
END
ELSE
m := buf.lim - r.bpos;
IF m > 0 THEN
SYSTEM.MOVE(src, dst, m);
r.bpos := buf.lim;
END;
r.res := len - m; r.eof := TRUE; EXIT
END;
END;
ELSE
r.res := 0
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("ReadBytes->ofs:");
KernelLog.Int(ofs, 1);
KernelLog.String(", len:");
KernelLog.Int(len, 1);
KernelLog.Exit;
END;
END ReadBytes;
PROCEDURE Write*(VAR r: Files.Rider; x: CHAR);
VAR buf: Buffer; errorcode: LONGINT;
BEGIN {EXCLUSIVE}
buf := r.hint(Buffer);
IF r.apos # buf.apos THEN
buf := GetBuf(SELF, r.apos);
r.hint := buf
END;
IF r.bpos >= buf.lim THEN
IF r.bpos < BufSize THEN
INC(buf.lim);
INC(bleng);
modH := TRUE;
ELSE
WriteBuf(SELF, buf, errorcode);
INC(r.apos);
buf := SearchBuf(SELF, r.apos);
IF buf = NIL THEN
buf := r.hint(Buffer);
IF r.apos <= aleng THEN
ReadBuf(SELF, buf, r.apos, errorcode)
ELSE
buf.apos := r.apos;
buf.lim := 1;
INC(aleng);
bleng := 1;
modH := TRUE;
END
ELSE
r.hint := buf;
END;
r.bpos := 0
END
END;
buf.data.B[r.bpos] := x;
INC(r.bpos);
buf.mod := TRUE;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Write->x:");
KernelLog.Char(x);
KernelLog.Exit;
END;
END Write;
PROCEDURE WriteBytes*(VAR r: Files.Rider; CONST x: ARRAY OF CHAR; ofs, len: LONGINT);
VAR src, dst: SYSTEM.ADDRESS; m, errorcode: LONGINT; buf: Buffer;
BEGIN {EXCLUSIVE}
IF LEN(x)-ofs < len THEN
SYSTEM.HALT(19);
END;
IF len > 0 THEN
src := SYSTEM.ADR(x[ofs]);
buf := r.hint(Buffer);
IF r.apos # buf.apos THEN
buf := GetBuf(SELF, r.apos);
r.hint := buf
END;
LOOP
IF len <= 0 THEN
EXIT;
END;
buf.mod := TRUE;
dst := SYSTEM.ADR(buf.data.B[0]) + r.bpos;
m := r.bpos + len;
IF m <= buf.lim THEN
SYSTEM.MOVE(src, dst, len);
r.bpos := m;
EXIT;
ELSIF m <= BufSize THEN
SYSTEM.MOVE(src, dst, len);
r.bpos := m;
bleng := m;
buf.lim := m;
modH := TRUE;
EXIT
ELSE
m := BufSize - r.bpos;
IF m > 0 THEN
SYSTEM.MOVE(src, dst, m);
buf.lim := BufSize;
INC(src, m);
DEC(len, m);
END;
WriteBuf(SELF, buf, errorcode);
INC(r.apos);
r.bpos := 0;
buf := SearchBuf(SELF, r.apos);
IF buf = NIL THEN
buf := r.hint(Buffer);
IF r.apos <= aleng THEN
ReadBuf(SELF, buf, r.apos, errorcode)
ELSE
buf.apos := r.apos;
buf.lim := 0;
INC(aleng);
bleng := 0;
modH := TRUE;
END
ELSE
r.hint := buf
END
END
END
END;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("WriteBytes->ofs:");
KernelLog.Int(ofs, 1);
KernelLog.String(", len:");
KernelLog.Int(len, 1);
KernelLog.Exit;
END;
END WriteBytes;
PROCEDURE Length*(): LONGINT;
BEGIN {EXCLUSIVE}
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Length->size:");
KernelLog.Int(aleng*BufSize + bleng, 1);
KernelLog.Exit;
END;
RETURN aleng*BufSize + bleng;
END Length;
PROCEDURE GetDate*(VAR t, d: LONGINT);
BEGIN {EXCLUSIVE}
t := time;
d := date;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("GetDate->time:");
KernelLog.Int(time, 1);
KernelLog.String(", date:");
KernelLog.Int(date, 1);
KernelLog.Exit;
END;
END GetDate;
PROCEDURE SetDate*(t, d: LONGINT);
VAR errorcode: LONGINT; fsCasted: FileSystem;
BEGIN {EXCLUSIVE}
time := t;
date := d;
fsCasted := SELF.fs(FileSystem);
fsCasted.stubs.SetAttr(name, time, date, errorcode);
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("SetDate->time:");
KernelLog.Int(time, 1);
KernelLog.String(", date:");
KernelLog.Int(date, 1);
KernelLog.Exit;
END;
END SetDate;
PROCEDURE GetName*(VAR name: ARRAY OF CHAR);
BEGIN {EXCLUSIVE}
Files.JoinName(fs.prefix, SELF.name, name);
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("GetName->name:");
KernelLog.String(name);
KernelLog.Exit;
END;
END GetName;
PROCEDURE Register0*(VAR res: LONGINT);
VAR
buf: Buffer;
errorcode: LONGINT;
fsCasted : FileSystem;
BEGIN
IF ~registered & (name # "") THEN
fsCasted := SELF.fs(FileSystem);
fsCasted.stubs.Rename(nameTemp, name, errorcode);
IF errorcode = Ok THEN
registered := TRUE;
res := 0;
ELSE
res := 1;
END;
ELSE
res := 1;
END;
buf := firstbuf;
REPEAT
IF buf.mod THEN WriteBuf(SELF, buf, errorcode) END;
buf := buf.next;
UNTIL buf = firstbuf;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Register->res:");
KernelLog.Int(res, 1);
KernelLog.Exit;
END;
END Register0;
PROCEDURE Update*;
VAR buf: Buffer; errorcode: LONGINT;
BEGIN {EXCLUSIVE}
buf := firstbuf;
REPEAT
IF buf.mod THEN WriteBuf(SELF, buf, errorcode) END;
buf := buf.next;
UNTIL buf = firstbuf;
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("Update");
KernelLog.Exit;
END;
END Update;
END File;
VAR newfs*: FileSystem;
PROCEDURE Check(VAR s: ARRAY OF CHAR; VAR name: FileName; VAR res: LONGINT);
VAR i: LONGINT; ch: CHAR;
BEGIN
ch := s[0]; i := 0;
IF ch = "/" THEN
res := 3;
ELSIF ("A" <= CAP(ch)) & (CAP(ch) <= "Z") THEN
LOOP name[i] := ch; INC(i); ch := s[i];
IF (ch = ".") & (name[i-1] = ".") THEN
res := 3;
EXIT;
ELSIF ch = 0X THEN
WHILE i < FnLength DO name[i] := 0X; INC(i) END ;
res := 0; EXIT
END ;
IF ~(("A" <= CAP(ch)) & (CAP(ch) <= "Z")
OR ("0" <= ch) & (ch <= "9") OR (ch = ".")) THEN res := 3; EXIT
END ;
IF i = FnLength-1 THEN res := 4; EXIT END
END
ELSIF ch = 0X THEN name[0] := 0X; res := -1
ELSE res := 3
END
END Check;
PROCEDURE ReadBuf(f: File; buf: Buffer; pos: LONGINT; VAR errorcode: LONGINT);
VAR fsCasted: FileSystem; received: LONGINT;
BEGIN
fsCasted := f.fs(FileSystem);
fsCasted.stubs.Read(f.key, pos*BufSize, BufSize, buf.data.B, 0, received, errorcode);
IF errorcode = Ok THEN
IF pos < f.aleng THEN
buf.lim := received;
ELSE
buf.lim := f.bleng;
END;
buf.apos := pos;
buf.mod := FALSE;
ELSIF errorcode = RfsClientProxy.CACHEMISS THEN
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("ReadBuf->errorcode: ");
KernelLog.Int(errorcode, 1);
KernelLog.Exit;
END;
IF ~f.registered THEN
fsCasted.stubs.Lookup(f.nameTemp, f.key, errorcode);
ELSE
fsCasted.stubs.Lookup(f.name, f.key, errorcode);
END;
fsCasted.stubs.Read(f.key, pos*BufSize, BufSize, buf.data.B, 0, received, errorcode);
IF errorcode = Ok THEN
IF pos < f.aleng THEN
buf.lim := received;
ELSE
buf.lim := f.bleng;
END;
buf.apos := pos;
buf.mod := FALSE;
END;
END;
END ReadBuf;
PROCEDURE WriteBuf(f: File; buf: Buffer; VAR errorcode: LONGINT);
VAR fsCasted: FileSystem; written: LONGINT;
BEGIN
f.modH := TRUE;
fsCasted := f.fs(FileSystem);
fsCasted.stubs.Write(f.key, buf.apos*BufSize, buf.lim, buf.data.B, written, errorcode);
IF errorcode = Ok THEN
buf.mod := FALSE;
ELSIF errorcode = RfsClientProxy.CACHEMISS THEN
IF Trace = 1 THEN
KernelLog.Enter;
KernelLog.String("WriteBuf->errorcode: ");
KernelLog.Int(errorcode, 1);
KernelLog.Exit;
END;
IF ~f.registered THEN
fsCasted.stubs.Lookup(f.nameTemp, f.key, errorcode);
ELSE
fsCasted.stubs.Lookup(f.name, f.key, errorcode);
END;
fsCasted.stubs.Write(f.key, buf.apos*BufSize, buf.lim, buf.data.B, written, errorcode);
IF errorcode = Ok THEN
buf.mod := FALSE;
END;
END;
END WriteBuf;
PROCEDURE SearchBuf(f: File; pos: LONGINT): Buffer;
VAR buf: Buffer;
BEGIN
buf := f.firstbuf;
LOOP
IF buf.apos = pos THEN EXIT END;
buf := buf.next;
IF buf = f.firstbuf THEN buf := NIL; EXIT END
END;
RETURN buf
END SearchBuf;
PROCEDURE GetBuf(f: File; pos: LONGINT): Buffer;
VAR buf: Buffer; errorcode: LONGINT;
BEGIN
buf := f.firstbuf;
LOOP
IF buf.apos = pos THEN EXIT END;
IF buf.next = f.firstbuf THEN
IF f.nofbufs < MaxBufs THEN
NEW(buf); buf.next := f.firstbuf.next; f.firstbuf.next := buf;
INC(f.nofbufs)
ELSE
f.firstbuf := buf;
IF buf.mod THEN WriteBuf(f, buf, errorcode) END
END;
buf.apos := pos;
IF pos <= f.aleng THEN ReadBuf(f, buf, pos, errorcode) END;
EXIT
END;
buf := buf.next
END;
RETURN buf
END GetBuf;
PROCEDURE NewFS*(context : Files.Parameters);
VAR vol: RfsClientProxy.Proxy;
BEGIN
vol := context.vol(RfsClientProxy.Proxy);
IF vol # NIL THEN
NEW(newfs, vol);
newfs.desc := "Remote File System";
Files.Add(newfs, context.prefix);
context.out.String("FS->"); context.out.String(context.prefix); context.out.String(" added"); context.out.Ln
ELSE
context.error.String("FS"); context.error.String("RfsFS: Failure"); context.error.Ln
END;
END NewFS;
PROCEDURE FillBuf(VAR x: ARRAY OF CHAR; ch: CHAR);
VAR len, i: LONGINT;
BEGIN
len := LEN(x);
FOR i := 0 TO len-1 DO
x[i] := ch;
END;
END FillBuf;
PROCEDURE Cleanup;
VAR ft: Files.FileSystemTable; i: LONGINT;
BEGIN
IF Modules.shutdown = Modules.None THEN
Files.GetList(ft);
IF ft # NIL THEN
FOR i := 0 TO LEN(ft^)-1 DO
IF ft[i] IS FileSystem THEN Files.Remove(ft[i]) END
END
END
END
END Cleanup;
BEGIN
Modules.InstallTermHandler(Cleanup);
newfs := NIL;
END RfsFS.
(*
aleng * BufSize + bleng = length of File
apos * BufSize + bpos = current position
0 <= bpos <= lim <= BufSize
0 <= apos <= aleng
(apos < aleng) & (lim = BufSize) OR (apos = aleng)
Methods with {} notation are explicitly unprotected. They must be called only from a protected context.
*)