-- CatalogUtil.Mesa -- Gifford, June 16, 1982 11:17 am -- Schroeder, February 3, 1983 1:36 pm DIRECTORY CatalogComm, CIFS USING [Connect, Login], ConvertUnsafe USING [AppendRope], FileIO USING [Open, OpenFailed], IO USING [Close, EndOfStream, Error, GetChar, GetToken, IDProc, Handle, int, PutChar, PutF, PutFR, rope, SetEcho, Signal, string], LongString USING [AppendChar], Process USING [Pause, SecondsToTicks, Yield], Rope USING [Compare, Fetch, Find, FromChar, Length, ROPE, Substr], Runtime USING [BoundsFault], Storage USING [FreeString, StringLength], STP USING [Connect, Create, Destroy, Enumerate, Error, ErrorCode, FileInfo, GetFileInfo, Handle, Login, NoteFileProcType, Open], UserExec USING [ResetUserAbort, UserAbort]; CatalogUtil: PROGRAM IMPORTS CatalogComm, CIFS, ConvertUnsafe, FileIO, IO, LongString, Process, Rope, Runtime, Storage, STP, UserExec EXPORTS CatalogComm = { GetLine: PUBLIC PROC[h: CatalogComm.Handle, sh: IO.Handle, line: LONG STRING] RETURNS [noteof: BOOL] = { char: CHAR; eos: BOOL _ FALSE; line.length _ 0; DO char _ sh.GetChar[ ! IO.Error, IO.EndOfStream => GOTO lose]; IF char='\n THEN EXIT; IF eos THEN LOOP; line[line.length] _ char; line.length _ SUCC[line.length]; eos _ line.length>=line.maxlength; ENDLOOP; IF line.length >= line.maxlength THEN { line.length _ line.maxlength; h.out.PutF["*nGetLine-- line '%s' is too long.\n", IO.string[line]]; }; RETURN[TRUE]; EXITS lose => RETURN[FALSE]; }; FindFirst: PUBLIC PROC [s: Rope.ROPE, c: CHAR, start: INT] RETURNS [loc: INT] = { loc _ Rope.Find[s1: s, s2: Rope.FromChar[c], pos1: start]; IF loc=s.Length[] THEN SIGNAL CatalogComm.NoneFound; }; FindLast: PUBLIC PROC [s: Rope.ROPE, c: CHAR] RETURNS [loc: INT] = { FOR loc _ s.Length[] - 1, PRED[loc] DO IF s.Fetch[loc]=c THEN EXIT; IF loc = 0 THEN {SIGNAL CatalogComm.NoneFound; EXIT; }; ENDLOOP; }; SubStringCopy: PUBLIC PROC [s: Rope.ROPE, start, stop: INT] RETURNS [ns: Rope.ROPE] = { IF start>stop THEN RETURN[NIL]; RETURN[s.Substr[start: start, len: stop-start+1]]; }; LFindFirst: PUBLIC PROC [s: LONG STRING, c: CHAR, start: NAT] RETURNS [loc: NAT] = { loc _ start; WHILE locstop THEN RETURN; FOR i: NAT IN [start..stop] DO LongString.AppendChar[s: to, c: from[i]]; ENDLOOP; }; CatalogList: PUBLIC PROC [h: CatalogComm.Handle, key: Rope.ROPE, entry: Rope.ROPE, depth: INTEGER, dirsOnly: BOOL, comment: Rope.ROPE _ NIL] = { tt: LIST OF REF CatalogComm.Directory; pp: LIST OF REF; t: REF CatalogComm.Directory; p: REF CatalogComm.Node; FOR tt _ h.root, tt.rest WHILE tt#NIL DO t _ tt.first; IF Rope.Compare[s1: t.name, s2: key, case: FALSE]=equal THEN EXIT; REPEAT FINISHED => ERROR CatalogComm.CatalogError[cantFindDirectory]; ENDLOOP; IF dirsOnly THEN h.out.PutF["%4d %4d %4d %4d ", IO.int[t.fileCount], IO.int[t.directoryCount], IO.int[t.linkCount], IO.int[t.commentCount]]; THROUGH [0..depth-2) DO h.out.PutChar[' ]; ENDLOOP; h.out.PutF["%s ", IO.rope[entry]]; IF comment.Length[]>0 THEN h.out.PutF["%s", IO.rope[comment]]; h.out.PutChar['\n]; FOR pp _ t.chain, pp.rest WHILE pp#NIL DO Process.Yield[]; p _ NARROW[pp.first]; SELECT p.what FROM file, link => { IF dirsOnly THEN LOOP; THROUGH [0..depth) DO h.out.PutChar[' ]; ENDLOOP; h.out.PutF["%s ", IO.rope[p.name]]; IF p.target.Length[]>0 THEN h.out.PutF["%s ", IO.rope[p.target]]; IF p.comment.Length[]>0 THEN h.out.PutF["%s ", IO.rope[p.comment]]; h.out.PutChar['\n]; }; directory => CatalogList[h: h, key: p.directory, entry: p.name, depth: depth+2, dirsOnly: dirsOnly, comment: p.comment]; ENDCASE => ERROR; ENDLOOP; }; FreeWorld: PUBLIC PROC [h: CatalogComm.Handle] = { a, b: LIST OF REF CatalogComm.Directory; c, d: LIST OF REF; e: REF CatalogComm.Node; FOR a _ h.root, b WHILE a#NIL DO b _ a.rest; IF a.first#NIL THEN { FOR c _ a.first.chain, d WHILE c#NIL DO Process.Yield[]; d _ c.rest; e _ NARROW[c.first]; IF e#NIL THEN FREE[@e]; FREE[@c]; ENDLOOP; FREE[@a.first]; }; FREE[@a]; ENDLOOP; h.root _ NIL; }; CatalogErrorString: PUBLIC PROC [error: CatalogComm.CatalogErrorType] RETURNS [Rope.ROPE] = { str: ARRAY CatalogComm.CatalogErrorType OF Rope.ROPE = [ "nilDirectory", "nilFilename", "cantFindDirectory", "badDirectoryName", "parentNotFound", "unknownTopLevelDirectory", "topLevelDirectoryFoundTwice", "cantCreateLocalFile", "unKnownError", "implementationRestriction", "cantEnumerate", "dirdirFoundTwice", "catalogAborted", "cantResume" ]; RETURN [str[error]]; }; HandleSTPError: PUBLIC PROC[h: CatalogComm.Handle, stphandle: STP.Handle, stpError: STP.ErrorCode, message: STRING] RETURNS [retryit: BOOL] ={ oldEcho: IO.Handle; locname, locpassword: Rope.ROPE; Cred: TYPE = {login, connect, none}; cred: Cred _ none; resume: BOOL; IF stpError = illegalUserPassword OR stpError = illegalUserName OR stpError = illegalUserAccount OR stpError = credentailsMissing THEN cred _ login ELSE IF stpError = illegalConnectName OR stpError = illegalConnectPassword OR stpError = accessDenied THEN cred _ connect; IF cred=none OR stphandle=NIL THEN RETURN[FALSE]; -- if user hits DEL, then don't resume (give up) { ENABLE IO.Signal => TRUSTED {GOTO BailOut}; resume _ TRUE; h.out.PutF["Catalog: STP Error: %s\n", IO.string[message]]; h.out.PutF["Hit DEL to abort request or enter name and password\n"]; h.out.PutF["Name: "]; locname _ h.in.GetToken[IO.IDProc]; h.out.PutF["\nPassword: "]; oldEcho _ h.in.SetEcho[NIL]; locpassword _ h.in.GetToken[IO.IDProc]; [] _ h.in.SetEcho[oldEcho]; h.out.PutF["\nThanks!"]; -- set credentials EXITS BailOut => resume _ FALSE; }; IF NOT resume THEN RETURN[FALSE]; { ENABLE Runtime.BoundsFault => GOTO Fault; nameString: STRING _ [100]; passwordString: STRING _ [100]; ConvertUnsafe.AppendRope[to: nameString, from: locname]; ConvertUnsafe.AppendRope[to: passwordString, from: locpassword]; IF cred=login THEN { h.name _ locname; h.password _ locpassword; CIFS.Login[name: locname, password: locpassword]; STP.Login[stphandle, nameString, passwordString]; } ELSE { STP.Connect[stphandle, nameString, passwordString]; CIFS.Connect[name: locname, password: locpassword]; }; EXITS Fault => { h.out.PutF["Catalog: Name or password string too long!\n"]; resume _ FALSE; }; }; RETURN[resume]; }; MAXNTRIES: CARDINAL = 3; NSECPAUSE: CARDINAL = 10; Connect: PUBLIC PROC[h: CatalogComm.Handle, host: Rope.ROPE] RETURNS [stphandle: STP.Handle] = { herald: STRING; shorthost: STRING _ [30]; user: STRING _ [40]; password: STRING _ [40]; ntries: CARDINAL _ 0; stphandle _ NIL; { ENABLE UNWIND => IF stphandle#NIL THEN [] _ STP.Destroy[stphandle ! STP.Error => CONTINUE]; IF host.Length[] = 0 THEN { h.out.PutF["Error: remote host has not been specified.\n"]; RETURN[NIL]; }; h.out.PutF["Opening connection to %s.\n", IO.rope[host]]; ConvertUnsafe.AppendRope[to: shorthost, from: host ! Runtime.BoundsFault => { h.out.PutF["Catalog: host name too long!\n"]; GOTO GiveUp; }]; stphandle _ STP.Create[]; herald _ STP.Open[stphandle, shorthost ! STP.Error => IF code = connectionRejected THEN { h.out.PutF["Connection rejected by %s.\n", IO.rope[host]]; ntries _ ntries + 1; IF ntries < MAXNTRIES THEN { h.out.PutF["Will pause and try again.\n"]; IF CatalogComm.CheckForAbort[h] THEN ERROR CatalogComm.CatalogError[catalogAbort]; Process.Pause[Process.SecondsToTicks[NSECPAUSE]]; IF CatalogComm.CheckForAbort[h] THEN ERROR CatalogComm.CatalogError[catalogAbort]; RETRY; } ELSE h.out.PutF["Connection rejected too many times.\n"]; }]; h.out.PutF["%s\n", IO.string[herald]]; Storage.FreeString[herald]; { ENABLE Runtime.BoundsFault => { h.out.PutF["Catalog: name or password too long!\n"]; [] _ STP.Destroy[stphandle ! STP.Error => CONTINUE]; stphandle _ NIL; CONTINUE; }; spassword: STRING _ [80]; suser: STRING _ [80]; ConvertUnsafe.AppendRope[to: suser, from: h.name]; ConvertUnsafe.AppendRope[to: spassword, from: h.password]; STP.Login[stphandle, suser, spassword]; } EXITS GiveUp => NULL; }; }; CheckForAbort: PUBLIC PROC [h: CatalogComm.Handle] RETURNS [BOOL] = { a: BOOL _ UserExec.UserAbort[h.eh]; IF a THEN UserExec.ResetUserAbort[h.eh]; RETURN[a]; }; EnumFromRemoteFile: PUBLIC PROC [h: CatalogComm.Handle] = { lsfn: STRING _ [100]; stphandle: STP.Handle _ NIL; locEnumStream: IO.Handle _ NIL; aborted: BOOL _ FALSE; { ENABLE UNWIND => { IF stphandle#NIL THEN [] _ STP.Destroy[stphandle ! STP.Error => CONTINUE]; IF locEnumStream#NIL THEN { locEnumStream.Close[! IO.Error => CONTINUE]; h.out.PutF["Remember to delete %s!\n", IO.rope[h.locEnumFileName]]; }; }; -- NoteFileProcType: TYPE = PROCEDURE [file: STRING] RETURNS [continue: Continue]; EnumProcessFile: STP.NoteFileProcType = { info: STP.FileInfo _ STP.GetFileInfo[stphandle]; IF Storage.StringLength[info.version]#0 THEN locEnumStream.PutF["<%s>%s!%s\n", IO.string[info.directory], IO.string[info.body], IO.string[info.version]] ELSE locEnumStream.PutF["<%s>%s\n", IO.string[info.directory], IO.string[info.body]]; CatalogComm.ParseFile[h: h, vf: info]; IF CatalogComm.CheckForAbort[h] THEN aborted _ TRUE; RETURN[IF aborted THEN no ELSE yes]; }; locEnumStream _ FileIO.Open[h.locEnumFileName, overwrite ! FileIO.OpenFailed => CHECKED { ERROR CatalogComm.CatalogError[cantCreateLocalFile]; }]; h.out.PutF["Catalog: creating local enumeration file: %s\n", IO.rope[h.locEnumFileName]]; lsfn.length _ 0; ConvertUnsafe.AppendRope[to: lsfn, from: IO.PutFR["<%s>**.**", IO.rope[h.directory]] ! Runtime.BoundsFault => { h.out.PutF["Catalog: Enumeration pattern too long!\n"]; ERROR CatalogComm.CatalogError[implementationRestriction]; }]; FOR i: NAT IN [0..lsfn.length) DO IF lsfn[i] = '/ THEN lsfn[i] _ '>; ENDLOOP; stphandle _ CatalogComm.Connect[h, h.filesystem]; h.out.PutF["Catalog: Enumerating [%s]%s\n", IO.rope[h.filesystem], IO.string[lsfn]]; STP.Enumerate[stphandle, lsfn, EnumProcessFile ! STP.Error => IF CatalogComm.HandleSTPError[h: h, stphandle: stphandle, stpError: code, message: error] THEN RETRY ELSE REJECT ]; locEnumStream.Close[]; locEnumStream _ NIL; h.out.PutF["Closing connection to %s ... ", IO.rope[h.filesystem]]; [] _ STP.Destroy[stphandle ! STP.Error => CONTINUE]; stphandle _ NIL; h.out.PutF["closed.\n"]; IF aborted THEN { h.out.PutF["Remember to delete %s!\n", IO.rope[h.locEnumFileName]]; ERROR CatalogComm.CatalogError[catalogAbort]; }; }; }; }. 10-Feb-82 9:20:33, Stewart, carved out from CatalogImpl March 21, 1982 3:52 pm, Stewart, added HandleSTPError 25-Mar-82 15:56:04, Stewart, added Connect March 26, 1982 4:25 pm, Stewart, bulletproofing June 16, 1982 10:04 am, Gifford, new BTree Dir System