-- file OSMiscOpsImpl.Mesa -- last modified by Satterthwaite, December 10, 1982 10:53 am DIRECTORY DCSFileTypes: TYPE USING [tLeaderPage], Directory: TYPE USING [ CreateFile, DeleteFile, Error, Lookup, RemoveFile, Rename, UpdateDates, defaultContext, fileMaxPermissions, ignore], File: TYPE USING [Capability, nullCapability, Permissions, read], Inline: TYPE USING [LongNumber, BITXOR], KernelFile: TYPE USING [MakeTemporary], OSMiscOps: TYPE USING [Address, FileAccess, Permissions], ProcessorFace: TYPE USING [processorID], Runtime: TYPE USING [GetBcdTime, GetTableBase], Space: TYPE USING [ Create, Delete, GetHandle, Handle, LongPointer, Map, PageFromLongPointer, virtualMemory, wordsPerPage], Time: TYPE USING [Current], TimeStamp: TYPE USING [Stamp]; OSMiscOpsImpl: PROGRAM IMPORTS Directory, Inline, KernelFile, ProcessorFace, Runtime, Space, Time EXPORTS OSMiscOps SHARES ProcessorFace = { PageSize: CARDINAL = Space.wordsPerPage; -- bulk free storage management Pages: PUBLIC PROC [n: CARDINAL] RETURNS [base: OSMiscOps.Address] = { IF n = 0 THEN base ← NIL ELSE { space: Space.Handle = Space.Create[size: n, parent: Space.virtualMemory]; space.Map[]; base ← space.LongPointer}; RETURN}; FreePages: PUBLIC PROC [base: OSMiscOps.Address] = { IF base # NIL THEN Space.Delete[Space.GetHandle[Space.PageFromLongPointer[base]]]}; -- binary table management GetTableBase: PUBLIC PROC [p: PROGRAM] RETURNS [LONG POINTER] = { RETURN [Runtime.GetTableBase[p]]}; -- version stamp management GetNetAndHost: PROC RETURNS [net, host: CARDINAL] = { sum: WORD = Inline.BITXOR[ ProcessorFace.processorID.a, Inline.BITXOR[ProcessorFace.processorID.b, ProcessorFace.processorID.c]]; net ← sum/256; host ← sum MOD 256}; lastTime: LONG CARDINAL ← 0; GenerateUniqueId: PUBLIC PROC RETURNS [TimeStamp.Stamp] = { net, host: CARDINAL; time: LONG CARDINAL; [net, host] ← GetNetAndHost[]; DO time ← Time.Current[]; IF lastTime = 0 OR time # lastTime THEN EXIT; ENDLOOP; lastTime ← time; RETURN [[net: net, host: host, time: time]]}; BcdCreateTime: PUBLIC PROC RETURNS [time: LONG CARDINAL] = { RETURN [Runtime.GetBcdTime[]]}; ImageId: PUBLIC PROC RETURNS [TimeStamp.Stamp] = { RETURN [[0, 0, BcdCreateTime[]]]}; -- new version stamp operations StampSize: NAT = 3; Stamp: PUBLIC TYPE = RECORD [word: ARRAY [0..StampSize) OF CARDINAL]; AddStamps: PROC [s1, s2: Stamp] RETURNS [sum: Stamp] = { carry: [0..1] ← 0; i: NAT; FOR i DECREASING IN [0..StampSize) DO t: Inline.LongNumber ← [lc[LONG[s1.word[i]] + LONG[s2.word[i]] + LONG[carry]]]; sum.word[i] ← t.lowbits; carry ← t.highbits; ENDLOOP; FOR i DECREASING IN [0..StampSize) WHILE carry # 0 DO t: Inline.LongNumber ← [lc[LONG[sum.word[i]] + LONG[carry]]]; sum.word[i] ← t.lowbits; carry ← t.highbits; ENDLOOP}; RotateStamp: PROC [s: Stamp] RETURNS [Stamp] = INLINE {RETURN [AddStamps[s, s]]}; MergeStamps: PUBLIC PROC [sum, item: Stamp] RETURNS [Stamp] = { RETURN [AddStamps[RotateStamp[sum], item]]}; -- exception processing SignalArgs: PUBLIC PROC RETURNS [signal, message: UNSPECIFIED] = { RETURN [0, 0]}; -- file interface FileError: PUBLIC ERROR [name: LONG STRING] = CODE; FindFile: PUBLIC PROC [name: LONG STRING, access: OSMiscOps.FileAccess] RETURNS [File.Capability] = { file: File.Capability; permissions: File.Permissions = OSMiscOps.Permissions[access]; old: BOOL ← (permissions = File.read); IF ~old THEN { file ← Directory.CreateFile[name, DCSFileTypes.tLeaderPage, 0 ! Directory.Error => { IF type = fileAlreadyExists THEN GOTO fileExists ELSE GO TO fileProblem}]; EXITS fileExists => old ← TRUE}; IF old THEN file ← Directory.Lookup[fileName: name, permissions: Directory.ignore ! Directory.Error => {GO TO fileProblem}]; RETURN [Directory.UpdateDates[file, permissions]] EXITS fileProblem => ERROR FileError[name]}; RenameFile: PUBLIC PROC [newName, oldName: LONG STRING] = { DeleteFile[newName]; -- in case one already exists Directory.Rename[oldName, newName, Directory.defaultContext ! Directory.Error => {GOTO fileProblem}] EXITS fileProblem => ERROR FileError[oldName]}; UnnameFile: PUBLIC PROC [oldName: LONG STRING, file: File.Capability] = { IF file = File.nullCapability THEN file ← Directory.Lookup[fileName: oldName, permissions: Directory.fileMaxPermissions ! Directory.Error => {GOTO fileProblem}]; KernelFile.MakeTemporary[file]; Directory.RemoveFile[oldName, file ! Directory.Error => {GOTO fileProblem}]; EXITS fileProblem => NULL}; DeleteFile: PUBLIC PROC [name: LONG STRING] = { -- this is an enormously robust delete routine! IF name # NIL THEN { OPEN Directory; failed: BOOL ← FALSE; file: File.Capability; file ← Directory.Lookup[name, defaultContext, fileMaxPermissions ! ANY => {failed ← TRUE; CONTINUE}]; IF ~failed THEN Directory.DeleteFile[name ! ANY => {Directory.RemoveFile[name, file ! ANY => {CONTINUE}]}]}}; }.