12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253 |
- MODULE SambaClient; (** AUTHOR "mancos"; PURPOSE "SMB Client"; *)
- IMPORT
- SYSTEM, Streams, KernelLog, Dates, Strings, Locks, Files, DNS, IP, TCP;
- CONST
- PID = 9876;
- NativeOS = "A2";
- NativeLanMan = "STECIFS";
- PrimaryDomain = "WORKGROUP";
- Trace = FALSE;
- SendBufferSize = 32000;
- RWLimit = 2048;
- SMBPort* = 445;
- TYPE
- Connection = POINTER TO RECORD
- out: Streams.Writer;
- in: Streams.Reader;
- tid, uid, sid: INTEGER;
- ipaddr: ARRAY 16 OF CHAR;
- user, pw: ARRAY 64 OF CHAR;
- path, mask, fnLast: ARRAY 256 OF CHAR;
- END;
- FileSystem* = OBJECT(Files.FileSystem) (** shareable *)
- VAR
- c: Connection;
- connection: TCP.Connection;
- lock: Locks.RecursiveLock;
- (** Create a new file with the specified name. End users use Files.New instead. *)
- 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;
- (** Open an existing file. The same file descriptor is returned if a file is opened multiple times. End users use Files.Old instead. *)
- 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;
- (** Delete a file. res = 0 indicates success. End users use Files.Delete instead. *)
- PROCEDURE Delete0*(name: ARRAY OF CHAR; VAR key: LONGINT; VAR res: WORD);
- 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();
- (* SEND *)
- SendSMBHeader(SHORT(39 + Strings.Length(name)), 06X, c);
- c.out.Net8(1); (* Word count *)
- c.out.RawInt(22); (* search attributes *)
- c.out.RawInt(SHORT(2 + Strings.Length(name)));
- c.out.Net8(4); (* ascii *)
- c.out.RawString(name); (* name *)
- c.out.Update();
- (* RECEIVE *)
- 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;
- (** Rename a file. res = 0 indicates success. End users use Files.Rename instead. *)
- PROCEDURE Rename0*(old, new: ARRAY OF CHAR; f: Files.File; VAR res: WORD);
- 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();
- (* SEND *)
- SendSMBHeader(SHORT(41 + Strings.Length(new) + Strings.Length(old)), 07X, c);
- c.out.Net8(1); (* Word count *)
- c.out.RawInt(22); (* search attributes *)
- c.out.RawInt(SHORT(4 + Strings.Length(new) + Strings.Length(old)));
- c.out.Net8(4); (* ascii *)
- c.out.RawString(old); (* old name *)
- c.out.Net8(4); (* ascii *)
- c.out.RawString(new); (* new name *)
- c.out.Update();
- (* RECEIVE *)
- 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;
- (** Enumerate canonical file names. mask may contain * wildcards. For internal use only. End users use Enumerator instead. *)
- PROCEDURE Enumerate0*(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
- VAR
- check, endOfSearch, findFirst: BOOLEAN;
- 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;
- dirMask, filename: ARRAY 256 OF CHAR;
- 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;
- (* RECEIVE *)
- c.in.SkipBytes(1); (* wct *)
- c.in.SkipBytes(2); (* parameter count *)
- c.in.SkipBytes(2); (* data count *)
- c.in.SkipBytes(2); (* reserved *)
- c.in.SkipBytes(2); (* parameter count *)
- c.in.RawInt(paraOff); (* parameter offset *)
- c.in.SkipBytes(2); (* parameter displacement *)
- c.in.RawInt(byteCount); (* data count *)
- c.in.RawInt(dataOff); (* data offset *)
- c.in.SkipBytes(2); (* data displacement *)
- c.in.SkipBytes(1); (* setup count *)
- c.in.SkipBytes(1); (* reserved *)
- c.in.SkipBytes(2); (* byte count *)
- c.in.SkipBytes(paraOff - 55);
- IF findFirst THEN
- c.in.RawInt(c.sid); (* search id *)
- END;
- c.in.SkipBytes(2); (* search count *)
- c.in.RawInt(eos); (* end of search *)
- IF eos = 1 THEN
- endOfSearch := TRUE;
- END;
- c.in.SkipBytes(2); (* EA error *)
- c.in.SkipBytes(2); (* last name offset *)
- 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; (* next entry offset *)
- curPos := curPos + nextEntryOff;
- END;
- c.in.SkipBytes(4); (* file index *)
- c.in.SkipBytes(8); (* creation time *)
- c.in.SkipBytes(8); (* last access *)
- c.in.RawLInt(t[0]);
- c.in.RawLInt(t[1]); (* last write *)
- 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); (* change *)
- c.in.RawLInt(size);
- c.in.SkipBytes(4); (* end of file *)
- c.in.SkipBytes(8); (* allocation *)
- c.in.RawLInt(attr); (* attributes *)
- 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); (* name len *)
- c.in.SkipBytes(4); (* ea len *)
- c.in.SkipBytes(1); (* short file len *)
- c.in.SkipBytes(1); (* reserved *)
- c.in.SkipBytes(24); (* short file name *)
- 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;
- (** Return the unique non-zero key of the named file, if it exists. *)
- 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;
- (** Create a new directory structure. May not be supported by the actual implementation.
- End users use Files.CreateDirectory instead.*)
- PROCEDURE CreateDirectory0*(name: ARRAY OF CHAR; VAR res: WORD);
- VAR check: BOOLEAN;
- BEGIN
- IF Trace THEN
- KernelLog.String("FileSystem.CreateDirectory"); KernelLog.Ln();
- KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
- END;
- lock.Acquire();
- (* SEND *)
- SendSMBHeader(SHORT(37+ Strings.Length(name)), 00X, c);
- c.out.Net8(0); (* Word count *)
- c.out.RawInt(SHORT(2 + Strings.Length(name))); (* byte count *)
- c.out.Net8(4); (* buffer format *)
- c.out.RawString(name);
- c.out.Update();
- (* RECEIVE *)
- 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;
- (** Remove a directory. If force=TRUE, any subdirectories and files should be automatically deleted.
- End users use Files.RemoveDirectory instead. *)
- PROCEDURE RemoveDirectory0*(name: ARRAY OF CHAR; force: BOOLEAN; VAR key: LONGINT; VAR res: WORD);
- VAR check: BOOLEAN;
- BEGIN
- IF Trace THEN
- KernelLog.String("FileSystem.DeleteDirectory"); KernelLog.Ln();
- KernelLog.String(" -- Name: "); KernelLog.String(name); KernelLog.Ln();
- END;
- lock.Acquire();
- (* SEND *)
- SendSMBHeader(SHORT(37+ Strings.Length(name)), 01X, c);
- c.out.Net8(0); (* Word count *)
- c.out.RawInt(SHORT(2 + Strings.Length(name))); (* byte count *)
- c.out.Net8(4); (* buffer format *)
- c.out.RawString(name);
- c.out.Update();
- (* RECEIVE *)
- 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;
- (** Finalize the file system. *)
- PROCEDURE Finalize*;
- BEGIN
- Finalize^;
- connection.Close();
- END Finalize;
- END FileSystem;
- TYPE
- File* = OBJECT(Files.File) (** sharable *)
- VAR
- c: Connection;
- filename: ARRAY 256 OF CHAR;
- openRead: BOOLEAN;
- (** Position a Rider at a certain position in a file. Multiple Riders can be positioned at different locations in a file. A Rider cannot be positioned beyond the end of a file. *)
- PROCEDURE Set*(VAR r: Files.Rider; pos: LONGINT);
- BEGIN
- r.apos := pos;
- r.file := SELF;
- END Set;
- (** Return the offset of a Rider positioned on a file. *)
- PROCEDURE Pos*(VAR r: Files.Rider): LONGINT;
- BEGIN
- RETURN r.apos;
- END Pos;
- (** Read a byte from a file, advancing the Rider one byte further. R.eof indicates if the end of the file has been passed. *)
- 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;
- (** Read a sequence of len bytes into the buffer x at offset ofs, advancing the Rider. Less bytes will be read when reading over the end of the file. r.res indicates the number of unread bytes. x must be big enough to hold all the bytes. *)
- 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;
- r.res := 0;
- WHILE len > 0 DO
- IF len > RWLimit THEN
- adjLen := RWLimit;
- ELSE
- adjLen := SHORT(len);
- END;
- (* SEND *)
- SendSMBHeader(55, 2EX, c);
- c.out.Net8(10); (* word count *)
- c.out.Net8(255); (* andx*)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(0); (* andx offset *)
- c.out.RawInt(SHORT(key)); (* fid *)
- c.out.RawLInt(r.apos); (* offset *)
- c.out.RawInt(adjLen); (* max count low *)
- c.out.RawInt(adjLen); (* min count *)
- c.out.Net32(0); (* max count 64k *)
- c.out.RawInt(0); (* remaining *)
- c.out.RawInt(0); (* byte count *)
- c.out.Update();
- (* RECEIVE *)
- check := RecieveResponse(2EX, c);
- IF ~check THEN
- IF Trace THEN KernelLog.String(" -- ERROR on Read AndX"); KernelLog.Ln(); END;
- r.res := 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 := 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 := r.res + adjLen - i;
- len := len - adjLen;
- adjOff := adjOff + adjLen;
- END;
- fs(FileSystem).lock.Release();
- END ReadBytes;
- (** Write a byte into the file at the Rider position, advancing the Rider by one. *)
- 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;
- (** Write the buffer x containing len bytes (starting at offset ofs) into a file at the Rider position. *)
- 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;
- (* Send *)
- SendSMBHeader(59 + adjLen, 2FX, c);
- c.out.Net8(12); (* word count *)
- c.out.Net8(255); (* andx*)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(0); (* andx offset *)
- c.out.RawInt(SHORT(key)); (* fid *)
- c.out.RawLInt(r.apos); (* offset *)
- c.out.RawLInt(0); (* reserved *)
- c.out.RawInt(0); (* write mode *)
- c.out.RawInt(0); (* remaining *)
- c.out.RawInt(0); (* max count 64k *)
- c.out.RawInt(adjLen); (* max count low *)
- c.out.RawInt(59); (* data offset*)
- c.out.RawInt(adjLen); (* byte count *)
- 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();
- (* RECEIVE *)
- 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;
- (** Return the current length of a file. *)
- 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;
- (* SEND *)
- SendSMBHeader(37 + SHORT(Strings.Length(filename)), 08X, c);
- c.out.Net8(0); (* word count *)
- c.out.RawInt(SHORT(Strings.Length(filename)) + 1); (* byte count *)
- c.out.Net8(4); (* buffer format ascii *)
- c.out.RawString(filename); (* filename *)
- c.out.Update();
- IF Trace THEN KernelLog.String(" -- Query Information Request sent"); KernelLog.Ln(); END;
- (* RECEIVE *)
- 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;
- (** Return the time (t) and date (d) when a file was last modified. *)
- PROCEDURE GetDate*(VAR t, d: LONGINT);
- BEGIN HALT(301) END GetDate; (* abstract *)
- (** Set the modification time (t) and date (d) of a file. *)
- PROCEDURE SetDate*(t, d: LONGINT);
- BEGIN HALT(301) END SetDate; (* abstract *)
- (** Return the canonical name of a file. *)
- 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;
- (** Register a file created with New in the directory, replacing the previous file in the directory with the same name. The file is automatically updated. End users use Files.Register instead. *)
- PROCEDURE Register0*(VAR res: WORD);
- BEGIN END Register0;
- (** Flush the changes made to a file from its buffers. Register0 will automatically update a file. *)
- 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: WORD;
- 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
- (* NETBIOS *)
- c.out.Net16(0);
- c.out.Net16(ntb);
- (* SMB *)
- c.out.Char(CHR(255));
- c.out.String("SMB");
- c.out.Char(cmd); (* Command *)
- c.out.Net32(0); (* status code *)
- c.out.Net8(24); (* FLAGS *)
- c.out.RawInt(1); (* FLAGS 2 *)
- c.out.Net32(0);
- c.out.Net32(0); (* EXTRA *)
- c.out.Net32(0);
- c.out.RawInt(c.tid); (* TID *)
- c.out.RawInt(PID); (* PID *)
- c.out.RawInt(c.uid); (* UID *)
- c.out.RawInt(0); (* MID *)
- END SendSMBHeader;
- PROCEDURE RecieveResponse(cmd: CHAR; c: Connection): BOOLEAN;
- VAR
- check: BOOLEAN;
- variable: INTEGER;
- BEGIN
- check := FALSE;
- c.in.Reset();
- (* NETBIOS *)
- c.in.SkipBytes(4);
- (* SMB *)
- 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
- (* OK *)
- 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
- (* OK *)
- 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;
- (* SEND *)
- SendSMBHeader(47, 72X, c);
- c.out.Net8(0); (* Word count *)
- c.out.Net8(12); (* Byte count *)
- c.out.Net8(0);
- c.out.Char(2X);
- c.out.RawString("NT LM 0.12");
- c.out.Update();
- (* RECEIVE *)
- 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;
- (* SEND *)
- 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); (* Word count *)
- c.out.Net8(255); (* no andx *)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(0); (* andx offset *)
- c.out.RawInt(32767); (* buffersize *)
- c.out.RawInt(2); (* mpx *)
- c.out.RawInt(0); (* Vc *)
- c.out.Net32(0); (* session key *)
- c.out.RawInt(SHORT(Strings.Length(c.pw)+1)); (* ANSI len *)
- c.out.RawInt(0); (* UNICODE len *)
- c.out.Net32(0); (* reserved *)
- c.out.Net32(268435456); (* capabilities *)
- 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();
- (* RECEIVE *)
- 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;
- (* SEND *)
- SendSMBHeader(54 + SHORT(Strings.Length(c.ipaddr) + Strings.Length(c.path) + Strings.Length(c.pw)), 75X, c);
- c.out.Net8(4); (* Word count *)
- c.out.Net8(255); (* no andx *)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(0); (* andx offset *)
- c.out.RawInt(0); (* disconnected tid *)
- c.out.RawInt(SHORT(Strings.Length(c.pw)+1)); (* pw length *)
- c.out.RawInt(SHORT(11 + Strings.Length(c.ipaddr) + Strings.Length(c.path) + Strings.Length(c.pw))); (* bcc *)
- 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();
- (* RECEIVE *)
- 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 (* FIND FIRST *)
- len := SHORT(Strings.Length(c.mask));
- IF Trace THEN KernelLog.String("FIND FIRST"); KernelLog.Ln; END;
- ELSIF cmd = 2 THEN (* FIND NEXT *)
- len := SHORT(Strings.Length(c.fnLast));
- IF Trace THEN KernelLog.String("FIND NEXT"); KernelLog.Ln; END;
- ELSE
- RETURN FALSE;
- END;
- (* SEND *)
- SendSMBHeader(81 + len, 32X, c);
- c.out.Net8(15); (* Word count *)
- c.out.RawInt(13+len); (* parameter count 18 *)
- c.out.RawInt(0); (* data count *)
- c.out.RawInt(10); (* max par count *)
- c.out.RawInt(-1); (* max data count *)
- c.out.Net8(0); (* max setup *)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(0); (* flags *)
- c.out.Net32(0); (* timeout *)
- c.out.RawInt(0); (* reserved *)
- c.out.RawInt(13+len); (* parameter count 18 *)
- c.out.RawInt(68); (* par offset *)
- c.out.RawInt(0); (* data count *)
- c.out.RawInt(0); (* data offset 86 *)
- c.out.Net8(1); (* setup count *)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(cmd); (* subcommand *)
- c.out.RawInt(16+len); (* byte cnt 21 *)
- c.out.Net8(0); (* padding *)
- c.out.Net8(0); (* padding *)
- c.out.Net8(0); (* padding *)
- IF cmd = 1 THEN
- c.out.RawInt(22); (* search attri *)
- c.out.RawInt(25); (* search count 10 *)
- c.out.RawInt(6); (* flags *)
- c.out.RawInt(260); (* loi *)
- c.out.Net32(0); (* storage *)
- c.out.RawString(c.mask);
- ELSIF cmd = 2 THEN
- c.out.RawInt(c.sid); (* sid *)
- c.out.RawInt(25); (* search count 10 *)
- c.out.RawInt(260); (* loi *)
- c.out.Net32(0); (* resume *)
- c.out.RawInt(6); (* flags *)
- c.out.RawString(c.fnLast);
- ELSE
- RETURN FALSE;
- END;
- c.out.Update();
- (* RECEIVE *)
- 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);
- (* SEND *)
- SendSMBHeader(66 + SHORT(Strings.Length(name)), 2DX, c);
- c.out.Net8(15); (* word count *)
- c.out.Net8(255); (* andx*)
- c.out.Net8(0); (* reserved *)
- c.out.RawInt(0); (* andx offset *)
- c.out.RawInt(0); (* flags *)
- c.out.RawInt(access); (* desired access *)
- c.out.RawInt(6); (* search attributes *)
- c.out.RawInt(0); (* file attributes *)
- c.out.Net32(0); (* create.time *)
- IF create THEN
- c.out.RawInt(17);
- ELSE
- c.out.RawInt(1); (* open function *)
- END;
- c.out.Net32(0); (* allocation size *)
- c.out.Net32(0); (* timeout *)
- c.out.Net32(0); (* reserved *)
- c.out.RawInt(1 + SHORT(Strings.Length(name))); (* byte count *)
- c.out.RawString(name);
- c.out.Update();
- (* RECEIVE *)
- 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;
- (* SEND *)
- SendSMBHeader(41, 04X, c);
- c.out.Net8(3); (* Word count *)
- c.out.RawInt(SHORT(key)); (* fid *)
- c.out.Net32(0); (* last write *)
- c.out.RawInt(0); (* byte count *)
- c.out.Update();
- (* RECEIVE *)
- 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, SMBPort, 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 := t[1] * 100000000H + t[0];
- tsh := tsh DIV 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.
- System.Free SambaClient ~
- FSTools.Mount SMB SmbFS 192.168.1.1 sharename userid password~
- FSTools.Mount SMB2 SmbFS 127.0.0.1 SBMShared id pwd~
- FSTools.Mount SMB SmbFS 192.168.1.1 ~
- 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.Mount SMB SmbFS 127.0.0.1 ~
- FSTools.Mount SMB SmbFS 127.0.0.1 ~
- FSTools.Unmount SMB ~
|