-- BringOverImpl.Mesa
-- last edit February 4, 1983 2:42 pm
-- last edit May 22, 1983 3:49 pm, Russ Atkinson
-- changed short STRING into LONG STRING
-- Pilot 6.0/ Mesa 7.0
-- Switch Meaning
-- /a do NOT confirm any transfers!!!
-- /o file retrieve only file "file"
-- /p retrieve only the Public files
-- /v verify mode - simply confirm that df file has no errors
-- (e.g. file not found, etc.) Does not transfer anything.
-- default is to retrieve both Public and non-Public files
-- note that calling procedures in BringOverInterface will cause a start trap,
-- which will run Exec.AddCommand [BringOver]
-- this BringOver.~ can be run without any problems
DIRECTORY
BareBringOver: TYPE USING[State],
CIFS: TYPE USING[Error],
CWF: TYPE USING [SWF1, SWF2, SWF3, SWF4, WF0, WF1,
WF2, WF3, WF4, WFC, WFCR],
DFSubr: TYPE USING [AllocateDFSeq, CopyUsing, Criterion,
DF, DFEntryProcType, DFSeq, FreeDFSeq, FreeUsingSeq,
InterestingNestedDFProcType, IntersectUsing, NextDF, ParseStream, ReadInDir,
UsingEmpty, UsingSeq, WriteOut],
Directory: TYPE USING[DeleteFile, Error, Lookup, ignore, Rename, RemoveFile],
File: TYPE USING[Capability, nullCapability, Unknown],
FileStream: TYPE USING [SetLeaderPropertiesForCapability],
FQ: TYPE USING[FileQuery, FileQueryBangH, Result],
IO: TYPE USING[UserAbort],
KernelFile: TYPE USING[MakeTemporary],
LongString: TYPE USING [EquivalentString],
Runtime: TYPE USING[GetBcdTime, GetBuildTime],
Space: TYPE USING [Handle],
UnsafeSTP: TYPE USING [FileInfo, GetFileInfo, Handle],
STPSubr: TYPE USING [EnumerateForRetrieve, RetrieveProcType,
WriteStreamToDisk],
Stream: TYPE USING [Delete, Handle],
Subr: TYPE USING [AbortMyself, AllocateString, CheckForModify, CopyString, debugflg,
EndsIn, FreeString, GetCreateDateWithSpace,
NewStream, numberofleaders, Prefix, Read,
SetRemoteFilenameProp, strcpy, TTYProcs,
Write];
-- should really be a monitor on BringOverState
BringOverImpl: PROGRAM
IMPORTS CIFS, CWF, DFSubr, Directory, File, FileStream, FQ,
KernelFile, IO, LongString, Runtime,
STP: UnsafeSTP, STPSubr, Stream, Subr
EXPORTS BareBringOver = {
MAXFILES: CARDINAL = 500;
-- no mds usage
-- exported to BareBringOver
CheckThisFile: PUBLIC SIGNAL[checkfilename: LONG STRING] = CODE;
RecursiveLoop: PUBLIC SIGNAL[loopfilename: LONG STRING] = CODE;
BringOverDF: PUBLIC PROC[dfseq: DFSubr.DFSeq, state: BareBringOver.State, ldspace: Space.Handle,
h: Subr.TTYProcs] = {
nretrieved, nRenamed: CARDINAL ← 0;
NestedDFFileProc: DFSubr.InterestingNestedDFProcType = {
sh: Stream.Handle ← NIL;
dfseq, dfseqInner: DFSubr.DFSeq ← NIL;
newUsing: DFSubr.UsingSeq ← NIL;
{
ENABLE UNWIND => {
IF sh ~= NIL THEN Stream.Delete[sh];
sh ← NIL;
IF newUsing ~= NIL AND innerUsingSeq ~= NIL THEN
DFSubr.FreeUsingSeq[newUsing];
DFSubr.FreeDFSeq[@dfseqInner];
DFSubr.FreeDFSeq[@dfseq];
};
-- don't continue if q typed, df not on disk,
-- (wrong version on disk and there is a remote host)
IF state.quit THEN RETURN;
IF dfEntry ~= NIL AND
(NOT dfEntry.presentonlocaldisk
OR (dfEntry.need AND NOT EmptyString[dfEntry.host])) THEN {
CWF.WF1["Warning - unable to analyze contents of %s\n"L, dfEntry.shortname];
RETURN;
};
-- using list processing
IF driverUsingSeq ~= NIL AND innerUsingSeq ~= NIL THEN {
-- must do intersection
newUsing ← DFSubr.IntersectUsing[driverUsingSeq, innerUsingSeq];
IF newUsing = NIL THEN RETURN; -- no intersection
-- newUsing should be freed
}
ELSE IF innerUsingSeq ~= NIL THEN { -- driverUsingSeq = NIL
-- this is an imported DF file with a using list
newUsing ← DFSubr.CopyUsing[innerUsingSeq];
-- allows first level to be non-public as well
publicOnly ← FALSE;
-- newUsing should be freed
}
ELSE IF driverUsingSeq ~= NIL THEN { -- innerUsingSeq = NIL
IF DFSubr.UsingEmpty[driverUsingSeq] THEN RETURN; -- already empty
newUsing ← driverUsingSeq;
-- newUsing should NOT be freed
};
SIGNAL CheckThisFile[shortname];
CWF.WF1["\nBringOver of %s"L, shortname];
IF newUsing ~= NIL THEN CWF.WF0[" (with Using list)"L]
ELSE IF publicOnly THEN CWF.WF0[" (Exports only)"L]
ELSE IF state.verify THEN CWF.WF0[" (Verify)"L];
CWF.WFCR[];
IF dfEntry = NIL THEN {
-- this calls RetrieveDF for those DF files that appear in no DFseq
dfseqInner ← BuildFakeDFSeq[host, directory, shortname, version,
createtime, criterion];
dfEntry ← @dfseqInner[0];
DFEntryProc[dfEntry];
};
-- don't continue if q typed, df not on disk, wrong version on disk
IF state.quit THEN RETURN;
IF dfEntry ~= NIL AND
(NOT dfEntry.presentonlocaldisk
OR (dfEntry.need AND NOT EmptyString[dfEntry.host])) THEN {
CWF.WF1["Warning - unable to analyze contents of %s\n"L, dfEntry.shortname];
RETURN;
};
sh ← Subr.NewStream[dfEntry.shortname, Subr.Read];
dfseq ← DFSubr.AllocateDFSeq[maxEntries: MAXFILES, zoneType: shared];
DFSubr.ParseStream[sh: sh, dfseq: dfseq, dffilename: shortname,
using: newUsing, noremoteerrors: FALSE,
forceReadonly: entryIsReadonly,
omitNonPublic: publicOnly,
h: h,
interestingNestedDF: IF state.verify THEN NIL ELSE NestedDFFileProc,
dfEntryProc: IF state.verify THEN NIL ELSE DFEntryProc,
nLevel: nLevel + 1,
ancestor: IF ancestor = NIL THEN shortname ELSE ancestor
! CheckThisFile =>
IF LongString.EquivalentString[shortname, checkfilename] THEN
ERROR RecursiveLoop[checkfilename]
];
Stream.Delete[sh];
sh ← NIL;
IF state.verify THEN {
ProcessVerify[dfseq, h, ldspace, state];
GOTO leave;
};
IF dfseq.trailingcomment ~= NIL AND newUsing = NIL THEN {
-- only print if non-blank
FOR i: CARDINAL IN [0 .. dfseq.trailingcomment.length) DO
IF dfseq.trailingcomment[i] ~= '\n AND dfseq.trailingcomment[i] ~= ' THEN {
CWF.WF1["%s"L, dfseq.trailingcomment];
EXIT;
};
ENDLOOP;
};
-- now append in command stream any @file.cm files in the DF file
-- IF NOT state.quit AND newUsing = NIL THEN {
-- stemp: STRING ← [100];
-- FOR i: CARDINAL IN [0 .. dfseq.size) DO
-- df: DFSubr.DF ← @dfseq[i];
-- IF NOT df.atsign OR df.need OR NOT df.presentonlocaldisk THEN LOOP;
-- IF NOT Subr.EndsIn[df.shortname, "cm"L] THEN LOOP;
-- CWF.SWF1[stemp, "@%s\n"L, df.shortname];
-- Exec.AppendCommands[stemp];
-- ENDLOOP;
-- };
IF Subr.debugflg THEN
CWF.WF2["%u leaders read, dfseq.size = %u.\n"L,
@Subr.numberofleaders, @dfseq.size];
IF newUsing ~= NIL AND innerUsingSeq ~= NIL THEN {
FreeUsingSeqWithError[newUsing];
};
EXITS
leave => NULL;
};
CWF.WF1["End of BringOver of %s\n"L, shortname];
DFSubr.FreeDFSeq[@dfseqInner];
DFSubr.FreeDFSeq[@dfseq];
};
-- derived files: .bcd, .signals, .boot, .press
-- source files are anything else
DFEntryProc: DFSubr.DFEntryProcType = {
broughtover, renamed: BOOL;
IF state.quit THEN RETURN;
-- called for every entry in the sequence, including @ df files
-- these @ df files cause NestedDFFileProc to be called ALSO
IF state.justReadOnlys
AND NOT dfEntry.readonly
AND NOT dfEntry.atsign THEN
RETURN;
IF state.justNonReadOnlys AND dfEntry.readonly THEN
RETURN;
IF state.justSources
AND (Subr.EndsIn[dfEntry.shortname, ".Bcd"L]
OR Subr.EndsIn[dfEntry.shortname, ".Signals"L]
OR Subr.EndsIn[dfEntry.shortname, ".Boot"L]
OR Subr.EndsIn[dfEntry.shortname, ".Press"L]) THEN
RETURN;
IF state.justObjects
AND NOT dfEntry.atsign
AND NOT (Subr.EndsIn[dfEntry.shortname, ".Bcd"L]
OR Subr.EndsIn[dfEntry.shortname, ".Signals"L]
OR Subr.EndsIn[dfEntry.shortname, ".Boot"L]
OR Subr.EndsIn[dfEntry.shortname, ".Press"L]) THEN
RETURN;
[broughtover, renamed] ← RetrieveDF[dfEntry, ldspace, h, state];
IF broughtover THEN nretrieved ← nretrieved + 1;
IF renamed THEN nRenamed ← nRenamed + 1;
};
{
df: DFSubr.DF;
-- the main body
FOR i: CARDINAL IN [0 .. dfseq.size) DO
df ← @dfseq[i];
DFEntryProc[df];
IF df.presentonlocaldisk AND df.atsign THEN {
NestedDFFileProc[host: df.host, directory: df.directory,
shortname: df.shortname,
ancestor: NIL, immediateParent: NIL, version: df.version, nLevel: 0,
createtime: 0, driverUsingSeq: df.using, innerUsingSeq: NIL,
dfEntry: df, entryIsReadonly: FALSE, publicOnly: state.publicOnly,
criterion: none];
IF df.using ~= NIL THEN FreeUsingSeqWithError[df.using];
df.using ← NIL;
};
ENDLOOP;
IF nretrieved > 0 THEN {
CWF.WF1["%u files retrieved.*n"L, @nretrieved];
}
ELSE CWF.WF0["No files retrieved.*n"L];
IF nRenamed > 0 THEN
CWF.WF1["%u files had '$$' appended to their names.\n"L, @nRenamed];
}};
EmptyString: PROC[s: LONG STRING] RETURNS[empty: BOOL] = {
RETURN[s = NIL OR s.length = 0];
};
FreeUsingSeqWithError: PUBLIC PROC[newUsing: DFSubr.UsingSeq] = {
IF NOT DFSubr.UsingEmpty[newUsing] THEN {
CWF.WF0["Error - cannot find "L];
FOR i: CARDINAL IN [0 .. newUsing.size) DO
IF newUsing[i] = NIL THEN LOOP;
CWF.WF1["%s "L, newUsing[i]];
ENDLOOP;
CWF.WF0["in any nested DF file.\n"L];
};
DFSubr.FreeUsingSeq[newUsing];
};
BuildFakeDFSeq: PROC[host, directory, shortname: LONG STRING, version: CARDINAL,
createtime: LONG CARDINAL, criterion: DFSubr.Criterion]
RETURNS[dfseq: DFSubr.DFSeq] = {
df: DFSubr.DF;
dfseq ← DFSubr.AllocateDFSeq[maxEntries: 1, zoneType: shared];
df ← DFSubr.NextDF[dfseq];
df.host ← IF host.length = 0 THEN NIL ELSE Subr.CopyString[host, dfseq.dfzone];
df.directory ← IF directory.length = 0 THEN NIL ELSE Subr.CopyString[directory, dfseq.dfzone];
df.shortname ← Subr.CopyString[shortname, dfseq.dfzone];
df.version ← version;
df.createtime ← createtime;
df.criterion ← criterion;
df.atsign ← TRUE;
};
-- df.need will be TRUE if the file is not found on the remote server or the user
-- declines to bring it over
RetrieveDF: PROC[df: DFSubr.DF, ldspace: Space.Handle, h: Subr.TTYProcs, state: BareBringOver.State]
RETURNS[broughtover, renamed: BOOL] = {
refused: BOOL ← FALSE;
localCreateTime: LONG CARDINAL ← 0;
remoteCreateTime: LONG CARDINAL ← 0;
remoteVersion: CARDINAL;
fres: FQ.Result;
targetFileName: LONG STRING ← Subr.AllocateString[125];
sfn: LONG STRING ← Subr.AllocateString[100];
{ENABLE {
File.Unknown => {
CWF.WF1["ERROR File.Unknown - problem reading %s,\n"L, df.shortname];
GOTO out;
};
UNWIND => {Subr.FreeString[targetFileName]; Subr.FreeString[sfn]};
};
broughtover ← renamed ← FALSE;
df.presentonlocaldisk ← TRUE;
df.cap ← Directory.Lookup[fileName: df.shortname, permissions: Directory.ignore
! Directory.Error => {
df.presentonlocaldisk ← FALSE;
IF EmptyString[df.host] THEN
CWF.WF1["Error - cannot open %s.\n"L, df.shortname];
CONTINUE;
}];
IF state.updateOnly AND NOT df.atsign AND NOT df.presentonlocaldisk THEN
RETURN; -- not on local disk
IF state.forceRetrieval THEN
df.need ← TRUE
ELSE
[df.need, localCreateTime] ← ComputeNeed[df, ldspace];
IF NOT df.need OR EmptyString[df.host] THEN GO TO out;
[fres: fres, remoteVersion: remoteVersion, remoteCreateTime: remoteCreateTime]
← FQ.FileQuery[df.host, df.directory, df.shortname, df.version, df.createtime,
df.criterion = none AND df.createtime = 0, h,
targetFileName, state.useCIFS];
SELECT fres FROM
foundCorrectVersion => {
CWF.SWF4[sfn, "<%s>%s%s%u"L, df.directory, df.shortname,
IF Subr.Prefix[df.host, "maxc"L] THEN ";"L ELSE "!"L, @remoteVersion];
[broughtover, refused, renamed] ← RetrieveIfWanted[df, sfn,
remoteCreateTime, localCreateTime, h, ldspace, state];
df.need ← refused;
};
foundWrongVersion => {
CWF.WF2["\nError - %s (%lt) not available -- will offer the latest."L,
df.shortname, @df.createtime];
CWF.SWF3[sfn, "<%s>%s%sH"L, df.directory, df.shortname,
IF Subr.Prefix[df.host, "maxc"L] THEN ";"L ELSE "!"L];
[broughtover, refused, renamed] ← RetrieveIfWanted[df, sfn,
remoteCreateTime, localCreateTime, h, ldspace, state];
df.need ← refused;
};
notFound => CWF.WF1["Error - %s: file not found.\n"L, targetFileName];
ENDCASE => ERROR;
EXITS out => NULL}; -- of ENABLE UNWIND
Subr.FreeString[targetFileName]; Subr.FreeString[sfn];
};
RetrieveIfWanted: PROC[df: DFSubr.DF, remoteName: LONG STRING,
remoteCreateTime, localCreateTime: LONG CARDINAL,
h: Subr.TTYProcs, ldspace: Space.Handle, state: BareBringOver.State]
RETURNS[broughtover, refused, renamed: BOOL] = {
stemp: LONG STRING ← Subr.AllocateString[100];
fullname: LONG STRING ← Subr.AllocateString[125];
{ENABLE UNWIND => {Subr.FreeString[stemp]; Subr.FreeString[fullname]};
-- this is only called once
OneFile: STPSubr.RetrieveProcType = {
skipRest ← TRUE;
renamed ← ProceedWithBringOver[df, STP.GetFileInfo[stp],
h, remoteCreateTime, localCreateTime, remoteStream, fullname, state];
broughtover ← TRUE;
};
broughtover ← refused ← renamed ← FALSE;
IF df.presentonlocaldisk THEN {
IF localCreateTime = 0 THEN
[create: localCreateTime] ← Subr.GetCreateDateWithSpace[df.cap, ldspace];
CWF.SWF1[stemp, "%lt"L, @localCreateTime]
}
ELSE {
Subr.strcpy[stemp, "New"L];
localCreateTime ← 0;
};
CWF.SWF2[fullname, "[%s]%s"L, df.host, remoteName];
CWF.WF2["\n%s (%lt)\n"L, fullname, @remoteCreateTime];
CWF.WF2[" to local file %s (%s)"L, df.shortname, stemp];
IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself;
IF NOT state.forceRetrieval
AND ((df.criterion = update AND localCreateTime >= remoteCreateTime) -- not newer version
OR localCreateTime = remoteCreateTime -- already here
OR (df.newOnly AND df.presentonlocaldisk)) THEN { -- new only, already here
CWF.WF0[" ... not retrieved.\n"L];
GO TO return;
};
IF df.createtime > 0 AND remoteCreateTime ~= df.createtime THEN
CWF.WF1["\n Error - you wanted (%lt) Retrieve it?"L,
@df.createtime];
IF state.mustconfirm THEN {
ch: CHAR;
ch ← h.Confirm[h.in, h.out, h.data, " ", 'y];
IF ch = 'q OR ch = 'Q THEN {
state.quit ← TRUE;
GO TO return;
};
IF ch = 'a THEN
state.mustconfirm ← FALSE
ELSE IF ch ~= 'y THEN {
refused ← TRUE;
GO TO return;
};
};
-- this will retrieve it
STPSubr.EnumerateForRetrieve[df.host, remoteName, OneFile, h];
EXITS return => {}}; -- of ENABLE UNWIND
Subr.FreeString[stemp]; Subr.FreeString[fullname];
};
ProceedWithBringOver: PROC[df: DFSubr.DF, info: STP.FileInfo,
h: Subr.TTYProcs, remoteCreateTime, localCreateDate: LONG CARDINAL,
remotestream: Stream.Handle, fullname: LONG STRING, state: BareBringOver.State]
RETURNS[renamed: BOOL] = {
renamed ← FALSE;
CWF.WF0[" ... "L];
IF df.presentonlocaldisk
AND NOT Subr.CheckForModify[df.shortname, h] THEN {
CWF.WF1[" ... %s not transferred (can't be modified).\n"L,
df.shortname];
RETURN;
};
-- the runtime calls are a hack to tell if this is BringOver
-- being run from the boot file, in which case the new version
-- cannot modify the BringOver in the boot file
IF LongString.EquivalentString[df.shortname, "BringOver.Bcd"L]
AND Runtime.GetBcdTime[] ~= Runtime.GetBuildTime[] THEN
HandleBringOverSpecialCase[df];
-- check to see if local file is newer version
-- don't rename if the file is a bcd file
IF df.presentonlocaldisk AND localCreateDate > remoteCreateTime
AND NOT Subr.EndsIn[df.shortname, ".bcd"L] THEN {
RenameSpecialCase[df];
renamed ← TRUE;
};
IF state.useCIFS THEN
[df.cap,] ← STPSubr.WriteStreamToDisk[remotestream, df.shortname, info.size, h
! CIFS.Error => TRUSTED {
IF code = fileBusy THEN {
CWF.WF1[" ... %s not transferred (CIFS says file is busy).\n"L,
df.shortname];
GOTO out
}}]
ELSE
[df.cap,] ← STPSubr.WriteStreamToDisk[remotestream, df.shortname, info.size, h];
df.presentonlocaldisk ← TRUE;
Subr.SetRemoteFilenameProp[df.cap, fullname];
FileStream.SetLeaderPropertiesForCapability[cap: df.cap, create: LOOPHOLE[remoteCreateTime]];
CWF.WF1["%lu bytes.\n"L, @info.size];
EXITS
out => NULL;
};
-- called whenever there is a local version that is newer than
-- the one being retrieved
RenameSpecialCase: PROC[df: DFSubr.DF] = {
dollar: LONG STRING ← Subr.AllocateString[100];
{ENABLE UNWIND => {Subr.FreeString[dollar]};
CWF.SWF1[dollar, "%s$$"L, df.shortname];
Directory.DeleteFile[dollar ! Directory.Error => CONTINUE];
Directory.Rename[oldName: df.shortname, newName: dollar];
CWF.WF1["(local version renamed to %s)"L, dollar];
df.cap ← File.nullCapability;
}; -- of ENABLE UNWIND
Subr.FreeString[dollar];
};
-- this means BringOver is about to replace the BringOver.Bcd on the local disk
-- by a different version. This kludge is required to avoid overwriting
-- the backing file for the code segment for the loaded BringOver.Bcd
HandleBringOverSpecialCase: PROC[df: DFSubr.DF] = {
-- Directory.Error here indicates BringOver.Bcd was renamed or a messed up directory
cap: File.Capability;
cap ← Directory.Lookup[fileName: "BringOver.Bcd"L, permissions: Directory.ignore
! Directory.Error => GOTO out];
Directory.RemoveFile[fileName: "BringOver.Bcd"L, file: cap];
-- this begins a critical section where, if the system crashes, BringOver.Bcd is not on the disk
KernelFile.MakeTemporary[cap];
df.presentonlocaldisk ← FALSE; -- just in case
df.cap ← File.nullCapability;
CWF.WF0["Warning - you have just retrieved a new version of BringOver.Bcd.\n"L];
CWF.WF0[" If you want to use the new version, you must either (1) type the\n"L];
CWF.WF0[" command 'Run BringOver.Bcd;' to the Executive, or\n"L];
CWF.WF0[" (2) boot this volume.\n"L];
EXITS
out => NULL;
};
ProcessVerify: PROC[dfseq: DFSubr.DFSeq, h: Subr.TTYProcs, ldspace: Space.Handle,
state: BareBringOver.State] = {
localdiskdate, remoteCreateTime: LONG CARDINAL;
newerversions, fillinvers: BOOL;
df: DFSubr.DF;
fres: FQ.Result;
remoteVersion: CARDINAL;
targetFileName: LONG STRING ← Subr.AllocateString[125];
{ENABLE UNWIND => {Subr.FreeString[targetFileName]};
fillinvers ← newerversions ← FALSE;
DFSubr.ReadInDir[dfseq];
FOR i: CARDINAL IN [0 .. dfseq.size) DO
df ← @dfseq[i];
IF EmptyString[df.host] THEN {
CWF.WF1["Warning - unable to verify %s on remote server.\n"L, df.shortname];
LOOP;
};
IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself;
CWF.WFC['+];
[fres: fres, remoteVersion: remoteVersion, remoteCreateTime: remoteCreateTime]
← FQ.FileQuery[df.host, df.directory, df.shortname, df.version, df.createtime,
df.criterion = none AND df.createtime = 0, h,
targetFileName, state.useCIFS];
SELECT fres FROM
foundCorrectVersion => {
IF df.createtime > 0 AND df.version > 0 AND df.version ~= remoteVersion THEN
CWF.WF4["%s Warning: Version !%u has date %lt, but DF file says !%u.\n"L,
targetFileName, @remoteVersion, @remoteCreateTime, @df.version];
IF df.criterion = none AND (df.version = 0 OR df.version ~= remoteVersion) THEN {
df.version ← remoteVersion;
fillinvers ← TRUE;
};
-- fill in for those with no create time
IF df.createtime = 0 AND df.criterion = none AND df.version = 0 THEN {
df.createtime ← remoteCreateTime;
df.version ← remoteVersion;
fillinvers ← TRUE;
};
};
foundWrongVersion =>
CWF.WF2["\n%s of %lt not found.\n"L, targetFileName, @df.createtime];
notFound =>
CWF.WF1["\n%s not found.\n"L, targetFileName];
ENDCASE => ERROR;
IF fres ~= notFound THEN {
highfres: FQ.Result;
highdate: LONG CARDINAL;
highversion: CARDINAL;
-- find out the highest version, and complain
[fres: highfres, remoteVersion: highversion, remoteCreateTime: highdate] ←
FQ.FileQueryBangH[df.host, df.directory, df.shortname, df.createtime,
h, state.useCIFS];
IF fres = foundWrongVersion THEN {
CWF.WF2["%s: highest version is %lt"L,
targetFileName, @highdate];
df.createtime ← highdate;
df.version ← highversion;
newerversions ← TRUE;
}
ELSE IF highversion > remoteVersion THEN {
CWF.WF3["%s: newer version !%u\n\tof %lt is available"L,
targetFileName, @highversion, @highdate];
df.createtime ← highdate;
df.version ← highversion;
newerversions ← TRUE;
};
};
IF df.createtime = 0 AND df.criterion ~= none THEN
df.version ← 0; -- these are confusing to users
IF df.presentonlocaldisk THEN
[create: localdiskdate] ← Subr.GetCreateDateWithSpace[df.cap, ldspace];
IF df.presentonlocaldisk AND localdiskdate = remoteCreateTime
AND fres = foundCorrectVersion THEN
Subr.SetRemoteFilenameProp[df.cap, targetFileName];
ENDLOOP;
IF newerversions OR fillinvers THEN {
CWF.WF0["Storing new dffile with the newest versions \n"L];
CWF.WF0["and/ or filled in version numbers as 'NewDFFile.DF' ... "L];
IF Subr.CheckForModify["NewDFFile.DF"L, h] THEN {
sh: Stream.Handle;
sh ← Subr.NewStream["NewDFFile.DF"L, Subr.Write];
DFSubr.WriteOut[dfseq, NIL, sh, FALSE];
Stream.Delete[sh];
CWF.WF0["NewDFFile.DF created.\n"L];
};
};
}; -- of ENABLE UNWIND
Subr.FreeString[targetFileName];
};
ComputeNeed: PROC[df: DFSubr.DF, ldspace: Space.Handle]
RETURNS[need: BOOL, localCreateDate: LONG CARDINAL] = {
IF df.createtime = 0
OR NOT df.presentonlocaldisk
OR df.criterion = update THEN
RETURN[TRUE, 0];
[create: localCreateDate] ← Subr.GetCreateDateWithSpace[df.cap, ldspace];
RETURN[localCreateDate ~= df.createtime, localCreateDate];
};
}.