MODULE SambaClient;
IMPORT
SYSTEM, Machine, Streams, KernelLog, Dates, Strings, Locks, Files, DNS, IP, TCP;
CONST
PID = 9876;
NativeOS = "A2";
NativeLanMan = "STECIFS";
PrimaryDomain = "ETHZ";
Trace = FALSE;
SendBufferSize = 32000;
RWLimit = 2048;
TYPE
Connection = POINTER TO RECORD
out: Streams.Writer;
in: Streams.Reader;
ipaddr: ARRAY 16 OF CHAR;
path, mask, fnLast: ARRAY 256 OF CHAR;
user, pw: ARRAY 64 OF CHAR;
tid, uid, sid: INTEGER;
END;
FileSystem* = OBJECT(Files.FileSystem)
VAR
c: Connection;
connection: TCP.Connection;
lock: Locks.RecursiveLock;
PROCEDURE New0*(name: ARRAY OF CHAR): Files.File;
VAR
key: LONGINT;
f: File;
BEGIN
IF Trace THEN KernelLog.String("FileSystem.New - Name: "); KernelLog.String(name); KernelLog.Ln(); END;
lock.Acquire();
key := OpenAndX(c, name, 41H, TRUE);
lock.Release();
IF key # 0 THEN
NEW(f);
f.fs := SELF;
f.c := c;
f.key := key;
f.openRead := FALSE;
COPY(name, f.filename);
RETURN f;
ELSE
RETURN NIL;
END;
END New0;
PROCEDURE Old0*(name: ARRAY OF CHAR): Files.File;
VAR
f: File;
key: LONGINT;
BEGIN
IF Trace THEN KernelLog.String("FileSystem.Old - Name: "); KernelLog.String(name); KernelLog.Ln(); END;
key := FileKey(name);
IF key # 0 THEN
NEW(f);
f.c := c;
f.fs := SELF;
f.key := key;
f.openRead := TRUE;
COPY(name, f.filename);
RETURN f;
ELSE
RETURN NIL;
END;
END Old0;
PROCEDURE Delete0*(name: ARRAY OF CHAR; VAR key, res: LONGINT);
VAR
check : BOOLEAN;
closekey : LONGINT;
BEGIN
IF Trace THEN
KernelLog.String("FileSystem.Delete"); KernelLog.Ln();
KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
END;
lock.Acquire();
closekey := OpenAndX(c, name, 40H, FALSE);
CloseFile(c, closekey);
lock.Release();
Strings.TrimLeft(name, CHR(2FH));
lock.Acquire();
SendSMBHeader(SHORT(39 + Strings.Length(name)), 06X, c);
c.out.Net8(1);
c.out.RawInt(22);
c.out.RawInt(SHORT(2 + Strings.Length(name)));
c.out.Net8(4);
c.out.RawString(name);
c.out.Update();
check := RecieveResponse(06X, c);
lock.Release();
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on Delete"); KernelLog.Ln(); END;
res := -1;
ELSE
res := 0;
END;
END Delete0;
PROCEDURE Rename0*(old, new: ARRAY OF CHAR; f: Files.File; VAR res: LONGINT);
VAR
check : BOOLEAN;
closekey : LONGINT;
BEGIN
IF Trace THEN
KernelLog.String("FileSystem.Rename"); KernelLog.Ln();
KernelLog.String(" -- Old: "); KernelLog.String(old); KernelLog.Ln();
KernelLog.String(" -- New: "); KernelLog.String(new); KernelLog.Ln();
END;
lock.Acquire();
closekey := OpenAndX(c, old, 40H, FALSE);
CloseFile(c, closekey);
lock.Release();
ReplaceSlash(old);
ReplaceSlash(new);
lock.Acquire();
SendSMBHeader(SHORT(41 + Strings.Length(new) + Strings.Length(old)), 07X, c);
c.out.Net8(1);
c.out.RawInt(22);
c.out.RawInt(SHORT(4 + Strings.Length(new) + Strings.Length(old)));
c.out.Net8(4);
c.out.RawString(old);
c.out.Net8(4);
c.out.RawString(new);
c.out.Update();
check := RecieveResponse(07X, c);
lock.Release();
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on Rename"); KernelLog.Ln(); END;
res := -1;
ELSE
res := 0;
END;
END Rename0;
PROCEDURE Enumerate0*(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
VAR
check, endOfSearch, findFirst: BOOLEAN;
dirMask, filename: ARRAY 256 OF CHAR;
byteCount, dataOff, paraOff, eos: INTEGER;
fileFlags : SET;
attr, curPos, nextEntryOff, progress, maskLen: LONGINT;
t: ARRAY 2 OF LONGINT;
ch: ARRAY 2 OF CHAR;
dt: Dates.DateTime;
date, time, size: LONGINT;
BEGIN
endOfSearch := FALSE;
findFirst := TRUE;
maskLen := Strings.Length(mask);
COPY(mask, dirMask);
ReplaceSlash(mask);
IF Trace THEN
KernelLog.String("FileSystem.Enumerate"); KernelLog.Ln();
KernelLog.String(" -- Mask: "); KernelLog.String(mask); KernelLog.Ln();
END;
IF mask = "*" THEN
ch[0] := CHR(92); ch[1] := 0X;
Strings.Concat(ch, "*", c.mask);
dirMask := "/";
ELSIF Strings.EndsWith("\\*", mask) THEN
Strings.Truncate(mask, maskLen - 2);
Strings.Truncate(dirMask, maskLen - 2);
Strings.Concat(mask, "*", c.mask);
ELSIF Strings.EndsWith("\*", mask) THEN
Strings.Truncate(mask, maskLen - 1);
Strings.Truncate(dirMask, maskLen - 1);
Strings.Concat(mask, "*", c.mask);
ELSE
RETURN;
END;
WHILE ~endOfSearch DO
lock.Acquire();
IF findFirst THEN
check := Trans2Find(c, 1);
ELSE
check := Trans2Find(c, 2);
END;
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on Enumerate"); KernelLog.Ln(); END;
lock.Release();
RETURN;
END;
c.in.SkipBytes(1);
c.in.SkipBytes(2);
c.in.SkipBytes(2);
c.in.SkipBytes(2);
c.in.SkipBytes(2);
c.in.RawInt(paraOff);
c.in.SkipBytes(2);
c.in.RawInt(byteCount);
c.in.RawInt(dataOff);
c.in.SkipBytes(2);
c.in.SkipBytes(1);
c.in.SkipBytes(1);
c.in.SkipBytes(2);
c.in.SkipBytes(paraOff - 55);
IF findFirst THEN
c.in.RawInt(c.sid);
END;
c.in.SkipBytes(2);
c.in.RawInt(eos);
IF eos = 1 THEN
endOfSearch := TRUE;
END;
c.in.SkipBytes(2);
c.in.SkipBytes(2);
IF findFirst THEN
c.in.SkipBytes(dataOff - paraOff - 10);
ELSE
c.in.SkipBytes(dataOff - paraOff - 8);
END;
progress := 0;
check := TRUE;
WHILE progress < byteCount DO
curPos := c.in.Pos();
c.in.RawLInt(nextEntryOff);
IF nextEntryOff = 0 THEN
check := FALSE;
progress := byteCount;
ELSE
progress := progress + nextEntryOff;
curPos := curPos + nextEntryOff;
END;
c.in.SkipBytes(4);
c.in.SkipBytes(8);
c.in.SkipBytes(8);
c.in.RawLInt(t[0]);
c.in.RawLInt(t[1]);
GetDateTime(t, dt);
IF ~Dates.ValidDateTime(dt) THEN
dt := Dates.Now();
KernelLog.String("SambaClient: Replaced invalid date & time by current time"); KernelLog.Ln;
END;
Dates.DateTimeToOberon(dt, date, time);
c.in.SkipBytes(8);
c.in.RawLInt(size);
c.in.SkipBytes(4);
c.in.SkipBytes(8);
c.in.RawLInt(attr);
fileFlags := {};
IF (4 IN SYSTEM.VAL(SET, attr)) THEN INCL(fileFlags, Files.Directory); END;
IF (0 IN SYSTEM.VAL(SET, attr)) THEN INCL(fileFlags, Files.ReadOnly); END;
c.in.SkipBytes(4);
c.in.SkipBytes(4);
c.in.SkipBytes(1);
c.in.SkipBytes(1);
c.in.SkipBytes(24);
c.in.RawString(filename);
COPY(filename, c.fnLast);
Strings.Concat(dirMask, filename, filename);
Files.JoinName(prefix, filename, filename);
enum.PutEntry(filename, fileFlags, time, date, size);
WHILE (c.in.Pos() # curPos) & check DO
c.in.SkipBytes(1);
END;
END;
findFirst := FALSE;
lock.Release();
END;
END Enumerate0;
PROCEDURE FileKey*(name: ARRAY OF CHAR): LONGINT;
VAR key: LONGINT;
BEGIN
lock.Acquire();
key := OpenAndX(c, name, 40H, FALSE);
lock.Release();
RETURN key;
END FileKey;
PROCEDURE CreateDirectory0*(name: ARRAY OF CHAR; VAR res: LONGINT);
VAR check: BOOLEAN;
BEGIN
IF Trace THEN
KernelLog.String("FileSystem.CreateDirectory"); KernelLog.Ln();
KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
END;
lock.Acquire();
SendSMBHeader(SHORT(37+ Strings.Length(name)), 00X, c);
c.out.Net8(0);
c.out.RawInt(SHORT(2 + Strings.Length(name)));
c.out.Net8(4);
c.out.RawString(name);
c.out.Update();
check := RecieveResponse(00X, c);
lock.Release();
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on CreateDirectory"); KernelLog.Ln(); END;
res := -1;
ELSE
res := 0;
END;
END CreateDirectory0;
PROCEDURE RemoveDirectory0*(name: ARRAY OF CHAR; force: BOOLEAN; VAR key, res: LONGINT);
VAR check: BOOLEAN;
BEGIN
IF Trace THEN
KernelLog.String("FileSystem.DeleteDirectory"); KernelLog.Ln();
KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
END;
lock.Acquire();
SendSMBHeader(SHORT(37+ Strings.Length(name)), 01X, c);
c.out.Net8(0);
c.out.RawInt(SHORT(2 + Strings.Length(name)));
c.out.Net8(4);
c.out.RawString(name);
c.out.Update();
check := RecieveResponse(01X, c);
lock.Release();
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on DeleteDirectory"); KernelLog.Ln(); END;
res := -1;
ELSE
res := 0;
END;
END RemoveDirectory0;
PROCEDURE Finalize*;
BEGIN
Finalize^;
connection.Close();
END Finalize;
END FileSystem;
TYPE
File* = OBJECT(Files.File)
VAR
c: Connection;
filename: ARRAY 256 OF CHAR;
openRead: BOOLEAN;
PROCEDURE Set*(VAR r: Files.Rider; pos: LONGINT);
BEGIN
r.apos := pos;
r.file := SELF;
END Set;
PROCEDURE Pos*(VAR r: Files.Rider): LONGINT;
BEGIN
RETURN r.apos;
END Pos;
PROCEDURE Read*(VAR r: Files.Rider; VAR x: CHAR);
VAR a : ARRAY 1 OF CHAR;
BEGIN
a[0] := x;
ReadBytes(r,a,0,1);
END Read;
PROCEDURE ReadBytes*(VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT);
VAR
check: BOOLEAN;
dataOff, byteCount, padding: INTEGER;
i : LONGINT;
adjLen, adjOff: INTEGER;
localKey: INTEGER;
BEGIN
IF Trace THEN KernelLog.String("File.ReadBytes - Read AndX"); KernelLog.Ln(); END;
fs(FileSystem).lock.Acquire();
IF ~(openRead & (key # 0)) THEN
localKey := OpenAndX(c, filename, 40H, FALSE);
IF localKey # 0 THEN
key := localKey;
openRead := TRUE;
ELSE
r.res := len;
fs(FileSystem).lock.Release();
RETURN;
END;
END;
adjOff := 0;
WHILE len > 0 DO
IF len > RWLimit THEN
adjLen := RWLimit;
ELSE
adjLen := SHORT(len);
END;
SendSMBHeader(55, 2EX, c);
c.out.Net8(10);
c.out.Net8(255);
c.out.Net8(0);
c.out.RawInt(0);
c.out.RawInt(SHORT(key));
c.out.RawLInt(r.apos);
c.out.RawInt(adjLen);
c.out.RawInt(adjLen);
c.out.Net32(0);
c.out.RawInt(0);
c.out.RawInt(0);
c.out.Update();
check := RecieveResponse(2EX, c);
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on Read AndX"); KernelLog.Ln(); END;
r.res := len;
fs(FileSystem).lock.Release();
RETURN;
END;
c.in.SkipBytes(13);
c.in.RawInt(dataOff);
c.in.SkipBytes(10);
c.in.RawInt(byteCount);
IF (dataOff = 0) THEN
r.res := len;
fs(FileSystem).lock.Release();
RETURN;
END;
padding := dataOff - 59;
c.in.SkipBytes(padding);
byteCount := byteCount - padding;
IF Trace THEN KernelLog.String(" -- ByteCount: "); KernelLog.Int(byteCount, 0); KernelLog.Ln(); END;
i := adjOff;
c.in.Bytes(x, ofs, byteCount, i);
ofs := ofs + i;
r.apos := r.apos + i;
r.res := adjLen - i;
len := len - adjLen;
adjOff := adjOff + adjLen;
END;
fs(FileSystem).lock.Release();
END ReadBytes;
PROCEDURE Write*(VAR r: Files.Rider; x: CHAR);
VAR
a: ARRAY 1 OF CHAR;
BEGIN
a[0] := x;
WriteBytes(r,a,0,1);
END Write;
PROCEDURE WriteBytes*(VAR r: Files.Rider; CONST x: ARRAY OF CHAR; ofs, len: LONGINT);
VAR
check: BOOLEAN;
bytesWritten: INTEGER;
adjLen, adjOff: INTEGER;
localKey: INTEGER;
BEGIN
fs(FileSystem).lock.Acquire();
IF ~(~openRead & (key # 0)) THEN
localKey := OpenAndX(c, filename, 41H, FALSE);
IF localKey # 0 THEN
key := localKey;
openRead := FALSE;
ELSE
r.res := len;
fs(FileSystem).lock.Release();
RETURN;
END;
END;
IF Trace THEN
KernelLog.String("FileSystem.WriteBytes - Write AndX");
KernelLog.String(" ("); KernelLog.Int(len, 0); KernelLog.String(" bytes from offset ");
KernelLog.Int(ofs, 0); KernelLog.String(")");
KernelLog.Ln();
END;
fs(FileSystem).lock.Acquire();
adjOff := 0;
WHILE len > 0 DO
IF len > RWLimit THEN
adjLen := RWLimit;
ELSE
adjLen := SHORT(len);
END;
SendSMBHeader(59 + adjLen, 2FX, c);
c.out.Net8(12);
c.out.Net8(255);
c.out.Net8(0);
c.out.RawInt(0);
c.out.RawInt(SHORT(key));
c.out.RawLInt(r.apos);
c.out.RawLInt(0);
c.out.RawInt(0);
c.out.RawInt(0);
c.out.RawInt(0);
c.out.RawInt(adjLen);
c.out.RawInt(59);
c.out.RawInt(adjLen);
IF adjLen # 0 THEN
IF Trace THEN KernelLog.String(" -- Write bytes: "); KernelLog.Int(adjLen, 0); KernelLog.Ln(); END;
c.out.Bytes(x, adjOff, adjLen);
ELSE
IF Trace THEN KernelLog.String(" -- No bytes written!"); KernelLog.Ln(); END;
END;
c.out.Update();
check := RecieveResponse(2FX, c);
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on Write AndX"); KernelLog.Ln(); END;
fs(FileSystem).lock.Release();
RETURN;
END;
c.in.SkipBytes(5);
c.in.RawInt(bytesWritten);
IF Trace THEN
KernelLog.String(" -- Bytes written: "); KernelLog.Int(bytesWritten, 0); KernelLog.Ln();
END;
r.apos := r.apos + bytesWritten;
len := len - adjLen;
adjOff := adjOff + adjLen;
END;
fs(FileSystem).lock.Release();
END WriteBytes;
PROCEDURE Length*(): LONGINT;
VAR
filesize: LONGINT;
check: BOOLEAN;
BEGIN
fs(FileSystem).lock.Acquire();
IF Trace THEN
KernelLog.String("File.Length"); KernelLog.Ln();
KernelLog.String(" -- Name: "); KernelLog.String(filename); KernelLog.Ln();
END;
SendSMBHeader(37 + SHORT(Strings.Length(filename)), 08X, c);
c.out.Net8(0);
c.out.RawInt(SHORT(Strings.Length(filename)) + 1);
c.out.Net8(4);
c.out.RawString(filename);
c.out.Update();
IF Trace THEN KernelLog.String(" -- Query Information Request sent"); KernelLog.Ln(); END;
check := RecieveResponse(08X, c);
IF ~check THEN
IF Trace THEN
KernelLog.String(" -- ERROR on Query Information Request"); KernelLog.Ln();
END;
fs(FileSystem).lock.Release();
RETURN 0;
END;
c.in.SkipBytes(7);
c.in.RawLInt(filesize);
fs(FileSystem).lock.Release();
IF Trace THEN KernelLog.String(" -- File size: "); KernelLog.Int(filesize, 0); KernelLog.Ln(); END;
RETURN filesize;
END Length;
PROCEDURE GetDate*(VAR t, d: LONGINT);
BEGIN HALT(301) END GetDate;
PROCEDURE SetDate*(t, d: LONGINT);
BEGIN HALT(301) END SetDate;
PROCEDURE GetName*(VAR name: ARRAY OF CHAR);
BEGIN
Files.JoinName(fs.prefix, filename, name);
IF Trace THEN
KernelLog.String("File.GetName"); KernelLog.Ln();
KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
END;
END GetName;
PROCEDURE Register0*(VAR res: LONGINT);
BEGIN END Register0;
PROCEDURE Update*;
BEGIN END Update;
END File;
TYPE
TCPSender = OBJECT
VAR
connection: TCP.Connection;
PROCEDURE Connect(CONST host: ARRAY OF CHAR; port: LONGINT; VAR c: Connection);
VAR
fadr: IP.Adr;
res: LONGINT;
BEGIN {EXCLUSIVE}
res := 0;
DNS.HostByName(host, fadr, res);
IF res = DNS.Ok THEN
NEW(connection);
connection.Open(TCP.NilPort, fadr, port, res);
IF res = TCP.Ok THEN
IF Trace THEN KernelLog.String("Connection open!"); KernelLog.Ln(); END;
NEW(c.out, connection.Send, SendBufferSize);
NEW(c.in, connection.Receive, SendBufferSize);
END;
END;
END Connect;
END TCPSender;
PROCEDURE SendSMBHeader(ntb: INTEGER; cmd: CHAR; c: Connection);
BEGIN
c.out.Net16(0);
c.out.Net16(ntb);
c.out.Char(CHR(255));
c.out.String("SMB");
c.out.Char(cmd);
c.out.Net32(0);
c.out.Net8(24);
c.out.RawInt(1);
c.out.Net32(0);
c.out.Net32(0);
c.out.Net32(0);
c.out.RawInt(c.tid);
c.out.RawInt(PID);
c.out.RawInt(c.uid);
c.out.RawInt(0);
END SendSMBHeader;
PROCEDURE RecieveResponse(cmd: CHAR; c: Connection): BOOLEAN;
VAR
check: BOOLEAN;
variable: INTEGER;
BEGIN
check := FALSE;
c.in.Reset();
c.in.SkipBytes(4);
check := CheckFFSMB(c);
IF ~check THEN
IF Trace THEN KernelLog.String("SMB Header does not start with 0xFF SMB"); KernelLog.Ln(); END;
c.in.Reset();
RETURN FALSE;
END;
variable := SHORT(c.in.Net8());
IF CHR(variable) # cmd THEN
IF Trace THEN KernelLog.String("SMB Command is NOT "); KernelLog.Char(cmd); KernelLog.Ln(); END;
c.in.Reset();
RETURN FALSE;
END;
variable := SHORT(c.in.Net32());
IF variable # 0 THEN
IF Trace THEN KernelLog.String("There has been a DOS error"); KernelLog.Ln(); END;
c.in.Reset();
RETURN FALSE;
END;
c.in.SkipBytes(15);
c.in.RawInt(variable);
IF (c.tid = 0) & (variable > 0) THEN
c.tid := variable;
ELSIF (c.tid = variable) THEN
ELSIF (c.tid # variable) THEN
IF Trace THEN KernelLog.String(" -- TID does not match"); KernelLog.Ln(); END;
RETURN FALSE;
ELSE
IF Trace THEN KernelLog.String(" -- TID Error "); KernelLog.Int(variable, 0); KernelLog.Ln(); END;
RETURN FALSE;
END;
c.in.RawInt(variable);
IF variable # PID THEN
IF Trace THEN KernelLog.String(" -- PID does not match"); KernelLog.Ln(); END;
RETURN FALSE;
END;
c.in.RawInt(variable);
IF (c.uid = 0) & (variable > 0) THEN
c.uid := variable;
ELSIF (c.uid = variable) THEN
ELSIF (c.uid # variable) THEN
IF Trace THEN KernelLog.String(" -- UID does not match"); KernelLog.Ln(); END;
RETURN FALSE;
ELSE
IF Trace THEN KernelLog.String(" -- UID Error "); KernelLog.Int(variable, 0); KernelLog.Ln(); END;
RETURN FALSE;
END;
c.in.SkipBytes(2);
RETURN TRUE;
END RecieveResponse;
PROCEDURE CheckFFSMB(c: Connection): BOOLEAN;
VAR
variable: SHORTINT;
BEGIN
c.in.RawSInt(variable);
IF variable = -1 THEN
c.in.RawSInt(variable);
IF variable = 83 THEN
c.in.RawSInt(variable);
IF variable = 77 THEN
c.in.RawSInt(variable);
IF variable = 66 THEN
RETURN TRUE;
END;
END;
END;
END;
RETURN FALSE;
END CheckFFSMB;
PROCEDURE ReplaceSlash(VAR name: ARRAY OF CHAR);
VAR
i: LONGINT;
BEGIN
i := 0;
WHILE (i < Strings.Length(name)) DO
IF name[i] = CHR(2FH) THEN
name[i] := CHR(5CH);
END;
INC(i)
END;
END ReplaceSlash;
PROCEDURE NegotiateProtocol(c: Connection): BOOLEAN;
VAR
check : BOOLEAN;
variable: LONGINT;
BEGIN
IF Trace THEN KernelLog.String("Negotiate Protocol"); KernelLog.Ln(); END;
SendSMBHeader(47, 72X, c);
c.out.Net8(0);
c.out.Net8(12);
c.out.Net8(0);
c.out.Char(2X);
c.out.RawString("NT LM 0.12");
c.out.Update();
check := RecieveResponse(72X, c);
IF ~check THEN
RETURN FALSE;
END;
variable := c.in.Net8();
IF variable # 17 THEN
IF Trace THEN KernelLog.String(" -- Message Size is not 17: "); KernelLog.Int(variable, 2); KernelLog.Ln(); END;
RETURN FALSE;
ELSE
IF Trace THEN KernelLog.String(" -- Message Size is 17: NT LM 0.12"); KernelLog.Ln(); END;
RETURN TRUE;
END;
END NegotiateProtocol;
PROCEDURE SessionSetup(c: Connection): BOOLEAN;
VAR
byteCount: INTEGER;
check : BOOLEAN;
BEGIN
IF Trace THEN KernelLog.String("Session Setup"); KernelLog.Ln(); END;
byteCount := SHORT(
Strings.Length(c.user)
+ Strings.Length(c.pw)
+ Strings.Length(PrimaryDomain)
+ Strings.Length(NativeOS)
+ Strings.Length(NativeLanMan));
SendSMBHeader(66 + byteCount, 73X, c);
c.out.Net8(13);
c.out.Net8(255);
c.out.Net8(0);
c.out.RawInt(0);
c.out.RawInt(32767);
c.out.RawInt(2);
c.out.RawInt(0);
c.out.Net32(0);
c.out.RawInt(SHORT(Strings.Length(c.pw)+1));
c.out.RawInt(0);
c.out.Net32(0);
c.out.Net32(268435456);
c.out.Net8(byteCount + 5);
c.out.Net8(0);
c.out.RawString(c.pw);
c.out.RawString(c.user);
c.out.RawString(PrimaryDomain);
c.out.RawString(NativeOS);
c.out.RawString(NativeLanMan);
c.out.Update();
check := RecieveResponse(73X, c);
IF ~check THEN
RETURN FALSE;
END;
IF Trace THEN KernelLog.String(" -- UID: "); KernelLog.Int(c.uid, 0); KernelLog.Ln(); END;
RETURN TRUE;
END SessionSetup;
PROCEDURE TreeConnect(c: Connection): BOOLEAN;
VAR
check : BOOLEAN;
BEGIN
IF Trace THEN KernelLog.String("Tree Connect"); KernelLog.Ln(); END;
SendSMBHeader(54 + SHORT(Strings.Length(c.ipaddr) + Strings.Length(c.path) + Strings.Length(c.pw)), 75X, c);
c.out.Net8(4);
c.out.Net8(255);
c.out.Net8(0);
c.out.RawInt(0);
c.out.RawInt(0);
c.out.RawInt(SHORT(Strings.Length(c.pw)+1));
c.out.RawInt(SHORT(11 + Strings.Length(c.ipaddr) + Strings.Length(c.path) + Strings.Length(c.pw)));
c.out.RawString(c.pw);
c.out.String("\\");
c.out.String(c.ipaddr);
c.out.String("\");
c.out.RawString(c.path);
c.out.RawString("?????");
c.out.Update();
check := RecieveResponse(75X, c);
IF ~check THEN
RETURN FALSE;
END;
IF Trace THEN KernelLog.String(" -- TID : "); KernelLog.Int(c.tid, 0); KernelLog.Ln(); END;
RETURN TRUE;
END TreeConnect;
PROCEDURE Trans2Find(c: Connection; cmd: INTEGER): BOOLEAN;
VAR
check : BOOLEAN;
len: INTEGER;
BEGIN
IF Trace THEN KernelLog.String("TRANS 2 - "); END;
IF cmd = 1 THEN
len := SHORT(Strings.Length(c.mask));
IF Trace THEN KernelLog.String("FIND FIRST"); KernelLog.Ln; END;
ELSIF cmd = 2 THEN
len := SHORT(Strings.Length(c.fnLast));
IF Trace THEN KernelLog.String("FIND NEXT"); KernelLog.Ln; END;
ELSE
RETURN FALSE;
END;
SendSMBHeader(81 + len, 32X, c);
c.out.Net8(15);
c.out.RawInt(13+len);
c.out.RawInt(0);
c.out.RawInt(10);
c.out.RawInt(-1);
c.out.Net8(0);
c.out.Net8(0);
c.out.RawInt(0);
c.out.Net32(0);
c.out.RawInt(0);
c.out.RawInt(13+len);
c.out.RawInt(68);
c.out.RawInt(0);
c.out.RawInt(0);
c.out.Net8(1);
c.out.Net8(0);
c.out.RawInt(cmd);
c.out.RawInt(16+len);
c.out.Net8(0);
c.out.Net8(0);
c.out.Net8(0);
IF cmd = 1 THEN
c.out.RawInt(22);
c.out.RawInt(25);
c.out.RawInt(6);
c.out.RawInt(260);
c.out.Net32(0);
c.out.RawString(c.mask);
ELSIF cmd = 2 THEN
c.out.RawInt(c.sid);
c.out.RawInt(25);
c.out.RawInt(260);
c.out.Net32(0);
c.out.RawInt(6);
c.out.RawString(c.fnLast);
ELSE
RETURN FALSE;
END;
c.out.Update();
check := RecieveResponse(32X, c);
IF ~check THEN
RETURN FALSE;
END;
RETURN TRUE;
END Trans2Find;
PROCEDURE OpenAndX(c: Connection; name: ARRAY OF CHAR; access: INTEGER; create: BOOLEAN): INTEGER;
VAR
check: BOOLEAN;
fid: INTEGER;
BEGIN
IF Trace THEN
KernelLog.String("Open AndX"); KernelLog.Ln();
KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
KernelLog.String(" -- Access: "); KernelLog.Int(access, 0); KernelLog.Ln();
KernelLog.String(" -- Create: "); KernelLog.Boolean(create); KernelLog.Ln();
END;
ReplaceSlash(name);
SendSMBHeader(66 + SHORT(Strings.Length(name)), 2DX, c);
c.out.Net8(15);
c.out.Net8(255);
c.out.Net8(0);
c.out.RawInt(0);
c.out.RawInt(0);
c.out.RawInt(access);
c.out.RawInt(6);
c.out.RawInt(0);
c.out.Net32(0);
IF create THEN
c.out.RawInt(17);
ELSE
c.out.RawInt(1);
END;
c.out.Net32(0);
c.out.Net32(0);
c.out.Net32(0);
c.out.RawInt(1 + SHORT(Strings.Length(name)));
c.out.RawString(name);
c.out.Update();
check := RecieveResponse(2DX, c);
IF ~check THEN
IF Trace THEN KernelLog.String(" -- ERROR on Open AndX - FID: 0"); KernelLog.Ln(); END;
RETURN 0;
END;
c.in.SkipBytes(5);
c.in.RawInt(fid);
IF Trace THEN KernelLog.String(" -- FID: "); KernelLog.Int(fid, 0); KernelLog.Ln(); END;
RETURN fid;
END OpenAndX;
PROCEDURE CloseFile(c: Connection; key: LONGINT);
VAR
check: BOOLEAN;
BEGIN
IF Trace THEN KernelLog.String("Close File"); KernelLog.Ln(); END;
SendSMBHeader(41, 04X, c);
c.out.Net8(3);
c.out.RawInt(SHORT(key));
c.out.Net32(0);
c.out.RawInt(0);
c.out.Update();
check := RecieveResponse(04X, c);
END CloseFile;
PROCEDURE NewFS*(context: Files.Parameters);
VAR
fs: FileSystem;
connection: TCP.Connection;
c: Connection;
check: BOOLEAN;
BEGIN
IF Files.This(context.prefix) = NIL THEN
NEW(c);
context.arg.SkipWhitespace; context.arg.String(c.ipaddr);
context.arg.SkipWhitespace; context.arg.String(c.path);
context.arg.SkipWhitespace; context.arg.String(c.user);
context.arg.SkipWhitespace; context.arg.String(c.pw);
IF Trace THEN
KernelLog.String("Connecting to "); KernelLog.String(c.ipaddr); KernelLog.Ln();
KernelLog.String("Path: "); KernelLog.String(c.path); KernelLog.Ln();
END;
check := StartClient(c, connection);
IF (~check) OR (connection = NIL) THEN
context.error.String("CONNECTION ERROR!"); context.error.Ln;
RETURN;
END;
NEW(fs);
fs.desc := "SmbFS";
fs.c := c;
NEW(fs.lock);
fs.connection := connection;
Files.Add(fs, context.prefix);
ELSE
context.error.String("DiskFS: "); context.error.String(context.prefix); context.error.String(" already in use");
context.error.Ln;
END;
END NewFS;
PROCEDURE StartClient(VAR c: Connection; VAR connection: TCP.Connection): BOOLEAN;
VAR
tcpsender: TCPSender;
check: BOOLEAN;
BEGIN
c.tid := 0;
c.uid := 0;
NEW(tcpsender);
tcpsender.Connect(c.ipaddr, 445, c);
IF (c.in # NIL) & (c.out # NIL) THEN
connection := tcpsender.connection;
check := NegotiateProtocol(c);
check := check & SessionSetup(c);
check := check & TreeConnect(c);
RETURN check;
ELSE
RETURN FALSE;
END;
END StartClient;
PROCEDURE GetDateTime(t: ARRAY OF LONGINT; VAR datetime: Dates.DateTime);
VAR
second, minute, hour, day, month, year, totalDays, NofDaysMnth: LONGINT;
tsh: HUGEINT;
ts: LONGINT;
continue: BOOLEAN;
BEGIN
tsh := Machine.MulH(t[1], 100000000H) + t[0];
tsh := Machine.DivH(tsh, 10000000);
tsh := tsh - 11644473600;
ts := SHORT(tsh);
second := ts MOD 60;
minute := (ts MOD 3600) DIV 60;
hour := (ts MOD 86400) DIV 3600;
ts := ts - (hour * 3600) - (minute * 60) - second;
totalDays := ts DIV 86400;
year := 1970;
continue := TRUE;
WHILE (totalDays > 365) & continue DO
IF Dates.LeapYear(year) THEN
IF totalDays > 366 THEN
totalDays := totalDays - 366;
ELSE
DEC(year);
continue := FALSE;
END;
ELSE
totalDays := totalDays - 365;
END;
INC(year);
END;
month := 1;
continue := TRUE;
WHILE (totalDays > 28) & continue DO
NofDaysMnth := Dates.NofDays(year, month);
IF totalDays >= NofDaysMnth THEN
INC(month);
totalDays := totalDays - NofDaysMnth;
ELSE
continue := FALSE;
END;
END;
day := totalDays + 1;
datetime.year := year;
datetime.month := month;
datetime.day := day;
datetime.hour := hour;
datetime.minute := minute;
datetime.second := second;
END GetDateTime;
END SambaClient.
SystemTools.Free SambaClient ~
FSTools.Mount SMB SmbFS 192.168.1.99 test ~
FSTools.Mount SMB SmbFS 192.168.1.99 d ~
FSTools.Mount SMB SmbFS 129.132.50.25 test guest guest ~
FSTools.Mount SMB SmbFS 129.132.50.7 test ~
FSTools.Mount SMB SmbFS 192.168.1.102 test ~
FSTools.Unmount SMB ~