-- MoveFilesImpl.mesa -- last edit by Schmidt, January 6, 1983 2:02 pm -- last edit by Satterthwaite, February 9, 1983 10:33 am DIRECTORY ConvertUnsafe: TYPE USING[ToRope], CWF: TYPE USING [FWF1, FWF2, SWF1, SWF2, SWF4, WF0, WF1, WF2, WF3, WF4], DateAndTimeUnsafe: TYPE USING [Parse], Dir: TYPE USING [FileInfo], Directory: TYPE USING [DeleteFile, Error, Handle, ignore, Lookup, Rename], File: TYPE USING [Capability, Unknown], FileStream: TYPE USING [GetLength, SetIndex], MDModel: TYPE USING [GetBcdCreate, GetFileInfo, GetSrcCreate, LOCSymbol, MODELSymbol, NarrowToLOC, Symbol, SymbolSeq, TraverseTree], MDUtil: TYPE USING [PrintNewModelStream], MoveFiles: TYPE USING [], IO: TYPE USING[Handle], STPSubr: TYPE USING [AddUserName, CachedRetrieve, Connect, HandleSTPError, StpStateRecord, StopSTP, Store], Stream: TYPE USING [Delete, Handle, PutChar], Subr: TYPE USING [AbortMyself, CheckForModify, errorflg, FileError, GetCreateDate, NewStream, SetRemoteFilenameProp, TTYProcs, Write], Time: TYPE USING [Current], TypeScript: TYPE USING[TS, UserAbort], UnsafeSTP: TYPE USING [Enumerate, Error, FileInfo, GetFileInfo, Handle, NoteFileProcType], ViewerClasses: TYPE USING[Viewer], ViewerOps: TYPE USING[FindViewer, RestoreViewer]; MoveFilesImpl: PROGRAM IMPORTS ConvertUnsafe, CWF, DateAndTimeUnsafe, Directory, File, FileStream, MDModel, MDUtil, STP: UnsafeSTP, STPSubr, Stream, Subr, Time, TypeScript, ViewerOps EXPORTS MoveFiles = { useCIFS: BOOL = FALSE; -- think of this as running in the monitor of MDMainImpl InternalPermanentOrTemporary: PUBLIC PROC[symbolseq: MDModel.SymbolSeq, working: MDModel.LOCSymbol, temporary, force: BOOL, typeScript: TypeScript.TS, ttyout: IO.Handle, window: Subr.TTYProcs] = { ENABLE { STP.Error => { CWF.WF0["FTP Error. "L]; IF error ~= NIL THEN CWF.WF1["message: %s\n"L,error]; GOTO leave; }; }; nxfer: CARDINAL ← 0; changes: BOOL ← FALSE; outofspace: BOOL ← FALSE; logsh: Stream.Handle ← NIL; fi: Dir.FileInfo; ProcFile: PROC[spl: MDModel.Symbol, spmodel: MDModel.MODELSymbol] RETURNS[proceed: BOOL ← TRUE] = { sploc: MDModel.LOCSymbol; name: STRING ← [100]; IF spl.stype ~= typeLOC THEN RETURN; sploc ← MDModel.NarrowToLOC[spl]; IF sploc.nestedmodel ~= NIL THEN { -- this may make a new model IF sploc.nestedmodel.modelchanged OR force THEN { changes ← TRUE; MakeANewModel[sploc, symbolseq, typeScript, ttyout, window]; }; -- given there may be a new model, -- we must update the next model higher up with -- the new version stamp IF sploc.nestedmodel.modelcreate ~= sploc.createtime THEN { fi ← MDModel.GetFileInfo[sploc]; fi.srcNotSaved ← TRUE; sploc.createtime ← sploc.nestedmodel.modelcreate; }; }; IF temporary OR outofspace THEN RETURN; fi ← MDModel.GetFileInfo[sploc]; IF fi.srcPresent AND fi.srcNotSaved THEN { -- transfer it stored: BOOL ← FALSE; [stored, logsh] ← StoreTheFile[sploc, typeScript, window, logsh ! STP.Error => IF code = undefinedError OR code = requestRefused THEN { CWF.WF1["\nError - %s\n"L, error]; CWF.WF0["Only some of the files have been transferred.\n"L]; CWF.WF0["Go and clean up your remote directories, then run XPermanent\n"L]; CWF.WF0["EXACTLY as you did this time.\n"L]; Subr.errorflg ← TRUE; outofspace ← TRUE; GOTO out; }]; IF stored THEN nxfer ← nxfer + 1; fi.srcNotSaved ← FALSE; EXITS out => NULL; }; }; -- IF temporary THEN Dir.WriteOutUnsavedFiles[]; IF temporary AND force THEN [] ← ProcFile[working, NIL] -- only top one ELSE -- postorder is important here! MDModel.TraverseTree[symbolseq.toploc, symbolseq, ProcFile, FALSE]; IF NOT temporary THEN { IF logsh ~= NIL THEN Stream.Delete[logsh]; logsh ← NIL; STPSubr.StopSTP[]; CWF.WF1["%u files stored.\n"L, @nxfer]; IF NOT outofspace THEN Directory.DeleteFile["NonPermanentFiles"L ! File.Unknown => { -- bugs in directory package CWF.WF0["Log: File/Directory Error.\n"L]; CONTINUE; }; Directory.Error => CONTINUE ]; }; IF NOT changes THEN { CWF.WF0["Nothing has been changed in the file,"L]; CWF.WF0[" the model doesn't have to be saved.\n"L]; }; EXITS leave => NULL; }; -- called by InternalTemporaryOrPermanent MakeANewModel: PROC[sproot: MDModel.LOCSymbol, symbolseq: MDModel.SymbolSeq, typeScript: TypeScript.TS, ttyout: IO.Handle, window: Subr.TTYProcs] = { oldname: STRING ← [100]; sh: Stream.Handle; spmodel: MDModel.MODELSymbol; spmodel ← sproot.nestedmodel; CWF.SWF1[oldname, "%s$"L, spmodel.modelfilename]; CWF.WF1["Old model on %s,"L, oldname]; IF Subr.CheckForModify[oldname, window] THEN { Directory.DeleteFile[fileName: oldname ! Directory.Error => CONTINUE]; Directory.Rename[oldName: spmodel.modelfilename, newName: oldname]; IF Subr.CheckForModify[spmodel.modelfilename, window] THEN { log: ViewerClasses.Viewer; sh ← Subr.NewStream[spmodel.modelfilename, Subr.Write]; -- printing w/o defaults MDUtil.PrintNewModelStream[symbolseq, sproot, sh, NIL, TRUE, typeScript, ttyout]; Stream.Delete[sh]; spmodel.modelcap ← Directory.Lookup[fileName: spmodel.modelfilename, permissions: Directory.ignore]; spmodel.modelcreate ← Subr.GetCreateDate[spmodel.modelcap]; spmodel.modelchanged ← FALSE; -- reset CWF.WF1[" new model on %s.\n"L, spmodel.modelfilename]; log ← ViewerOps.FindViewer[ConvertUnsafe.ToRope[spmodel.modelfilename]]; IF log ~= NIL THEN ViewerOps.RestoreViewer[log]; }; }; }; -- called by MakeDepSeqForFile in MDDBImpl BringOverRemoteFile: PUBLIC PROC[sploc: MDModel.LOCSymbol, makethismodel: BOOL, typeScript: TypeScript.TS, window: Subr.TTYProcs] = { retrieved, present: BOOL; fn: LONG STRING; time: LONG CARDINAL; fi: Dir.FileInfo ← MDModel.GetFileInfo[sploc]; fi.alreadyLookedFor ← TRUE; IF (fi.isBcd AND (NOT fi.bcdPresent OR MDModel.GetBcdCreate[fi] ~= sploc.createtime)) THEN { fn ← fi.bcdFileName; time ← MDModel.GetBcdCreate[fi]; present ← fi.bcdPresent; } ELSE IF (NOT fi.isBcd AND (NOT fi.srcPresent OR MDModel.GetSrcCreate[fi] ~= sploc.createtime)) THEN { fn ← fi.srcFileName; time ← MDModel.GetSrcCreate[fi]; present ← fi.srcPresent; } ELSE RETURN; -- files already here IF TypeScript.UserAbort[typeScript] THEN SIGNAL Subr.AbortMyself; IF NOT present THEN { -- retrieve from remote servers retrieved ← RetrieveTheFile[sploc, typeScript, window]; IF NOT retrieved THEN { CWF.WF1["RemoteRetrieve: Can't find %s.\n"L, fn]; RETURN; }; time ← IF fi.isBcd THEN MDModel.GetBcdCreate[fi] ELSE MDModel.GetSrcCreate[fi]; }; IF time ~= sploc.createtime THEN { IF makethismodel AND sploc.createtime ~= 0 THEN { -- retrieve from remote servers [] ← RetrieveTheFile[sploc, typeScript, window]; time ← IF fi.isBcd THEN MDModel.GetBcdCreate[fi] ELSE MDModel.GetSrcCreate[fi]; }; }; IF sploc.createtime ~= 0 AND time ~= sploc.createtime THEN CWF.WF3["RemoteRetrieve: You wanted %s of %lt but %lt is on the disk.\n"L, fn, @sploc.createtime, @time]; }; -- these are procedures to retrieve and store files RetrieveTheFile: PROC[sploc: MDModel.LOCSymbol, typeScript: TypeScript.TS, window: Subr.TTYProcs] RETURNS[retrieved: BOOL] = { stpStateRecord: STPSubr.StpStateRecord ← []; cap: File.Capability; fi: Dir.FileInfo; retrieved ← FALSE; IF useCIFS THEN { -- will use Cedar features -- cap ← RetFiles[sploc, srcsfn, usedirseq, window]; RETURN; }; IF sploc.host = NIL OR sploc.path = NIL THEN RETURN[FALSE]; IF TypeScript.UserAbort[typeScript]THEN SIGNAL Subr.AbortMyself; fi ← MDModel.GetFileInfo[sploc]; -- look for source IF NOT fi.isBcd THEN { cap ← STPSubr.CachedRetrieve[sploc.host, sploc.path, fi.srcFileName, 0, sploc.createtime, window, @stpStateRecord, FALSE, TRUE ! Subr.FileError => { IF error = notFound THEN CWF.WF3["File/Directory [%s]<%s>%s not found.\n"L, sploc.host, sploc.path, fi.srcFileName] ELSE CWF.WF4["File [%s]<%s>%s of %lt not found.\n"L, sploc.host, sploc.path, fi.srcFileName, @sploc.createtime]; GOTO leave }]; fi.srcDepSeq ← NIL; fi.srcPresent ← TRUE; fi.srcCap ← cap; fi.srcCreate ← sploc.createtime; }; IF TypeScript.UserAbort[typeScript] THEN SIGNAL Subr.AbortMyself; -- now consider the bcd IF TypeScript.UserAbort[typeScript] THEN SIGNAL Subr.AbortMyself; cap ← STPSubr.CachedRetrieve[sploc.host, sploc.path, fi.bcdFileName, 0, 0, window, @stpStateRecord, FALSE, TRUE ! Subr.FileError => { CWF.WF3["File/Directory [%s]<%s>%s not found.\n"L, sploc.host, sploc.path, fi.bcdFileName]; GOTO leave; }]; fi.bcdDepSeq ← NIL; fi.bcdPresent ← TRUE; fi.bcdCap ← cap; fi.bcdCreate ← 0; -- will be recomputed retrieved ← TRUE; EXITS leave => RETURN[FALSE]; }; -- first look and see if the file is already out there, -- if not, store it StoreTheFile: PROC[sploc: MDModel.LOCSymbol, typeScript: TypeScript.TS, window: Subr.TTYProcs, oldlogsh: Stream.Handle] RETURNS[actuallyxferred: BOOL ← FALSE, newlogsh: Stream.Handle] = { nbytes: LONG CARDINAL; longname: STRING ← [100]; fullname: STRING ← [125]; stphandle: STP.Handle; info: STP.FileInfo; found: BOOL ← FALSE; pattern: STRING ← [100]; time: LONG CARDINAL; logfile: STRING ← [100]; fi: Dir.FileInfo; WFStore: PROC[ch: CHAR] = { Stream.PutChar[newlogsh, ch]; }; EnumProcessFile: STP.NoteFileProcType = { info: STP.FileInfo; continue ← yes; info ← STP.GetFileInfo[stphandle]; IF found OR time ~= DateAndTimeUnsafe.Parse[info.create].dt THEN RETURN; found ← TRUE; }; newlogsh ← oldlogsh; IF TypeScript.UserAbort[typeScript] THEN SIGNAL Subr.AbortMyself[]; IF sploc.host = NIL OR sploc.path = NIL THEN RETURN[FALSE, newlogsh]; fi ← MDModel.GetFileInfo[sploc]; IF NOT fi.srcPresent THEN ERROR; CWF.SWF2[longname, "<%s>%s"L, sploc.path, fi.srcFileName]; time ← MDModel.GetSrcCreate[fi]; CWF.SWF1[pattern, "%s!**"L, longname]; -- first look and see where it is stphandle ← STPSubr.Connect[host: sploc.host, h: window, onlyOne: TRUE]; STP.Enumerate[stphandle, pattern, EnumProcessFile ! STP.Error => IF code = noSuchFile THEN CONTINUE ELSE IF STPSubr.HandleSTPError[stphandle, code, error, window] THEN RETRY; ]; IF found THEN { CWF.WF2["Store [%s]%s ... not necessary.\n"L, sploc.host, longname]; RETURN; -- need to xfer it }; -- -- aha we must xfer it -- actuallyxferred ← TRUE; IF TypeScript.UserAbort[typeScript] THEN SIGNAL Subr.AbortMyself; IF oldlogsh = NIL THEN { time: LONG CARDINAL; STPSubr.AddUserName[logfile, "%s-modeller.files$"L, window]; newlogsh ← Subr.NewStream[logfile, Subr.Write]; FileStream.SetIndex[newlogsh, FileStream.GetLength[newlogsh]]; time ← Time.Current[]; CWF.FWF1[WFStore, "\n(Last run on %lt)\n"L, @time]; CWF.WF1["Files to be transferred are recorded on '%s'\n"L, logfile]; } ELSE newlogsh ← oldlogsh; CWF.FWF2[WFStore, "[%s]%s"L, sploc.host, longname]; CWF.WF2["Store [%s]%s ... "L, sploc.host, longname]; nbytes ← STPSubr.Store[stphandle: stphandle, remoteName: longname, localCap: fi.srcCap, createDate: MDModel.GetSrcCreate[fi], h: window ! STP.Error => IF STPSubr.HandleSTPError[stphandle, code, error, window] THEN RETRY]; info ← STP.GetFileInfo[stphandle]; CWF.WF2["!%s, %lu bytes.\n"L, info.version, @nbytes]; CWF.SWF4[fullname, "[%s]<%s>%s!%s"L, sploc.host, info.directory, info.body, info.version]; Subr.SetRemoteFilenameProp[fi.srcCap, fullname ! Directory.Error => { CWF.WF1["Directory Error for %s.\n"L, fi.srcFileName]; CONTINUE; } ]; RETURN[actuallyxferred, newlogsh]; }; }.