-- 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];
};
}.