-- Salvager.mesa; --Maurice Herlihy August 29, 1982 --Mike Schroeder, October 6, 1982 9:17 am --Roy Levin, November 2, 1982 4:35 pm DIRECTORY CedarInitOps USING [salvageLSD], CIFS USING [Error, ErrorCode], ConvertUnsafe USING [ToRope], Directory USING [DeleteFile, Error, GetProperty, PropertyType], File USING [Capability, Delete, nullCapability], FileStream USING [GetLeaderPropertiesForCapability], FT USING [GetBaseFreeSpace], FtpMan USING [GetFileInfo], KernelFile USING [GetNextFile], LSD USING [Create, Entry, Lookup, SetDirty, Unlock], PupDefs USING [PupPackageMake], Rope USING [Find, ROPE, Substr], Volume USING [ID, SystemID]; Salvager: MONITOR IMPORTS CedarInitOps, CIFS, ConvertUnsafe, Directory, File, FileStream, FT, FtpMan, KernelFile, LSD, PupDefs, Rope, Volume = { -- Remote Name Property from Eric's code RemoteNameProperty: Directory.PropertyType = LOOPHOLE[213B]; ROPE: TYPE = Rope.ROPE; Salvage: PROC[] = { -- Strategy: -- Delete the LSD. -- Iterate through each file on the disk, -- putting remote files in the lsd with create date 0. -- If duplicates are encountered, keep the most recently written. -- Build up a list of files to be deleted at the end. VictimList: TYPE = REF VictimRec; VictimRec: TYPE = RECORD[ file: File.Capability, next: VictimList ]; volume: Volume.ID _ Volume.SystemID[]; file: File.Capability _ File.nullCapability; victim: File.Capability _ File.nullCapability; fileName: STRING _ [125]; name: ROPE; entry: LSD.Entry; victims: VictimList _ NIL; remoteState: {exists, doesNotExist, noResponse}; localCreate, remoteCreate: LONG CARDINAL; -- Crank up the pup package. PupDefs.PupPackageMake[]; -- Delete existing lsd, if any. Directory.DeleteFile["lsd.dir" ! Directory.Error => CONTINUE]; -- Krock to start FT so it will initialize session start time [] _ FT.GetBaseFreeSpace[]; -- Iterate through the files on the volume WHILE (file _ KernelFile.GetNextFile[volume, file]) # File.nullCapability DO remoteState _ exists; remoteCreate _ 0; fileName.length _ 0; Directory.GetProperty[file: file, property: RemoteNameProperty, propertyValue: DESCRIPTOR[fileName, SIZE[StringBody[fileName.maxlength]]] -- in case of error, charge! ! Directory.Error => LOOP]; -- If the name doesn't start with '/, skip it. IF fileName.length = 0 OR fileName[0] # '/ THEN LOOP; name _ ConvertUnsafe.ToRope[fileName]; localCreate _ FileStream.GetLeaderPropertiesForCapability[file].create; entry _ LSD.Lookup[name]; IF entry # NIL THEN { -- Found a duplicate. IF FileStream.GetLeaderPropertiesForCapability[entry.fc].create >= localCreate THEN { -- One in lsd is more current. victims _ NEW [VictimRec _ [file: file, next: victims]]; LOOP; -- nothing more to do. } -- Mark lsd entry for deletion and insert new entry below. ELSE victims _ NEW [VictimRec _ [file: entry.fc, next: victims]]; }; [remoteCreate, ] _ APPLY [FtpMan.GetFileInfo, Split[name] ! CIFS.Error => CHECKED {remoteState _ IF code = CIFS.ErrorCode[noSuchFile] THEN doesNotExist ELSE noResponse; CONTINUE} ]; SELECT remoteState FROM noResponse => -- it may be dirty -- MakeLSDEntry[name, file, 0, dirty]; doesNotExist => IF localCreate = 0 THEN -- probably still clean -- MakeLSDEntry[name, file, 0, clean] ELSE -- a new dirty file -- MakeLSDEntry[name, file, localCreate - 1, dirty]; exists => SELECT localCreate FROM < remoteCreate => -- local file has been superceded -- MakeLSDEntry[name, file, localCreate, recheck]; = remoteCreate => -- same as file on remote server -- MakeLSDEntry[name, file, localCreate, clean]; > remoteCreate => -- local file is more recent -- MakeLSDEntry[name, file, remoteCreate, dirty]; ENDCASE => ERROR; ENDCASE => ERROR; ENDLOOP; -- Delete unwanted files. WHILE victims # NIL DO File.Delete[victims.file]; victims _ victims.next; ENDLOOP; }; LSDFull: ERROR = CODE; MakeLSDEntry: PROC[n: ROPE, f: File.Capability, cr: LONG CARDINAL, state: {clean, recheck, dirty} ] -- make new LSD entry. ={ e: LSD.Entry = LSD.Create [name: n, fc: f, create: cr]; IF e = NIL THEN ERROR LSDFull; SELECT state FROM clean => NULL; recheck => e.checked _ 0; dirty => LSD.SetDirty[e]; ENDCASE => ERROR; LSD.Unlock[e]; }; Split: PROC[file: ROPE] RETURNS [server, name: ROPE] -- Take in CIFS name, split off server name. ={ fileNameStart: INT _ Rope.Find[file, "/", 1]; -- second slash in name name _ file.Substr[start: fileNameStart+1]; server _ file.Substr[start: 1, len: fileNameStart - 1 ]; }; --Split-- -- Start code. IF CedarInitOps.salvageLSD THEN Salvage[]; }.