-- DirectoryPropsImpl.mesa (last edited by: Keith on: January 4, 1981 1:53 PM) DIRECTORY CommonSoftwareFileTypes USING [CommonSoftwareFileType, tDirectory], DCSFileTypes USING [tLeaderPage], Directory, DirectoryContexts, DirectoryFiles, DirectoryInternal, DirectoryTrees, DirectoryProps, Environment USING [bytesPerPage, wordsPerPage], File USING [Capability, GetAttributes, GetSize, grow, LimitPermissions, nullCapability, read, shrink, Type, Unknown, Permissions, write], FileStream USING [Subtype], Inline USING [BITAND, LongCOPY, LongMult, LowHalf], PropertyTypes, Space USING [Create, Handle, LongPointer, Map, Unmap, virtualMemory], System USING [GetGreenwichMeanTime, gmtEpoch, GreenwichMeanTime], Volume USING [Unknown]; DirectoryPropsImpl: MONITOR LOCKS DirectoryInternal.DirectoryLock IMPORTS Directory, DirectoryContexts, DirectoryFiles, DirectoryTrees, DirectoryInternal, File, Inline, Space, System, Volume EXPORTS Directory, DirectoryProps SHARES File = BEGIN eType: Directory.ErrorType; leaderPageSpace: Space.Handle; leaderPageWords: CARDINAL = Environment.wordsPerPage*DirectoryInternal.leaderPageSize; pLeaderPage: LONG POINTER TO LPEntry; LPEntry: TYPE = MACHINE DEPENDENT RECORD [ type(0: 0.. 15): Directory.PropertyType, length(1: 0.. 15): CARDINAL, value(2: 0.. 15): UNSPECIFIED]; leaderVersionID: CARDINAL =25280; pVersion: LONG POINTER TO CARDINAL; -- file stream impl information -- if file stream can no longer read leader pages, the error may lie here! Check the formats fsLeaderVersionID: CARDINAL = 01240; pFSLeaderPage: LONG POINTER TO FSLeaderPage; FSLeaderPage: TYPE = MACHINE DEPENDENT RECORD [ versionID: CARDINAL, dataType: FileStream.Subtype, create, write, read: System.GreenwichMeanTime, length: LONG CARDINAL, nameLength: CARDINAL, name: PACKED ARRAY [0.. Directory.maxDirectoryNameLength) OF CHARACTER]; FileType: TYPE = {noLP, fsLP, fullLP}; -- indicates how to construct leader page: -- noLP indicates file has no leader page -- fsLP indicates that File Stream maintains some properties -- fullLP indicates that Directory maintains the full property list -- entry procedures GetNextProperty: PUBLIC ENTRY PROC [file: File.Capability, currentProperty: Directory.PropertyType] RETURNS [nextProperty: Directory.PropertyType] = -- Stateless Property List Type enumerator BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType _ type; GOTO AnError}}; pLP: LONG POINTER TO LPEntry _ pLeaderPage+DirectoryInternal.leaderPageOffset+1; SELECT TestFileType[file] FROM = fullLP => { MapCap[file, fullLP]; IF currentProperty = Directory.nullProperty THEN nextProperty _ pLP.type ELSE { pLP _ FindProp[currentProperty]; IF pLP = NIL THEN nextProperty _ Directory.nullProperty ELSE {pLP _ pLP + pLP.length+2; nextProperty _ pLP.type}}; Space.Unmap[leaderPageSpace]; RETURN [nextProperty]}; = fsLP => { SELECT currentProperty FROM = Directory.nullProperty => RETURN [PropertyTypes.tReadDate]; = PropertyTypes.tReadDate => RETURN [PropertyTypes.tWriteDate]; = PropertyTypes.tWriteDate => RETURN [PropertyTypes.tCreateDate]; = PropertyTypes.tCreateDate => RETURN [PropertyTypes.tByteLength]; = PropertyTypes.tByteLength => RETURN [PropertyTypes.tFileName]; = PropertyTypes.tFileName => RETURN [PropertyTypes.tParentDirectory]; ENDCASE; MapCap[file, fullLP]; pLP _ FindProp[currentProperty]; IF pLP = NIL THEN nextProperty _ Directory.nullProperty ELSE {pLP _ pLP + pLP.length+2; nextProperty _ pLP.type}; Space.Unmap[leaderPageSpace]; RETURN [nextProperty]}; ENDCASE => RETURN [Directory.nullProperty]; EXITS AnError => RETURN WITH ERROR Directory.Error[eType]; END; GetProperty: PUBLIC ENTRY PROC [file: File.Capability, property: Directory.PropertyType, propertyValue: LONG DESCRIPTOR FOR ARRAY OF UNSPECIFIED] = -- Return the value of a property BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType _ type; GOTO AnError}}; pLP: LONG POINTER TO LPEntry; SELECT TestFileType[file] FROM = fullLP => { IF property = Directory.nullProperty THEN RETURN WITH ERROR Directory.Error[invalidProperty]; MapCap[file, fullLP]; pLP _ FindProp[property]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[ from: @pLP.value, to: BASE[propertyValue], nwords: MIN[LENGTH[propertyValue], pLP.length]]; IF LENGTH[propertyValue] < pLP.length THEN { Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[propertyTooSmall]}; Space.Unmap[leaderPageSpace]; RETURN}; = fsLP => { time: System.GreenwichMeanTime; name: STRING _ [Directory.maxDirectoryNameLength]; MapCap[file, fsLP]; SELECT property FROM = Directory.nullProperty => { Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; = PropertyTypes.tReadDate, = PropertyTypes.tWriteDate, = PropertyTypes.tCreateDate => { SELECT property FROM = PropertyTypes.tReadDate => time _ pFSLeaderPage.read; = PropertyTypes.tWriteDate => time _ pFSLeaderPage.write; = PropertyTypes.tCreateDate => time _ pFSLeaderPage.create; ENDCASE; Inline.LongCOPY[ to: BASE[propertyValue], from: @time, nwords: MIN[LENGTH[propertyValue], SIZE[System.GreenwichMeanTime]]]; Space.Unmap[leaderPageSpace]; IF LENGTH[propertyValue] < SIZE[System.GreenwichMeanTime] THEN RETURN WITH ERROR Directory.Error[propertyTooSmall]; RETURN}; = PropertyTypes.tByteLength => { Inline.LongCOPY[ to: BASE[propertyValue], from: @pFSLeaderPage.length, nwords: MIN[LENGTH[propertyValue], 2]]; Space.Unmap[leaderPageSpace]; IF LENGTH[propertyValue] < 2 THEN RETURN WITH ERROR Directory.Error[propertyTooSmall]; RETURN}; = PropertyTypes.tFileName => { FOR i: CARDINAL IN [0.. pFSLeaderPage.nameLength) DO name[i]_pFSLeaderPage.name[i] ENDLOOP; name.length_pFSLeaderPage.nameLength; Inline.LongCOPY[ to: BASE[propertyValue], from: name, nwords: MIN[LENGTH[propertyValue], SIZE[StringBody[name.maxlength]]]]; Space.Unmap[leaderPageSpace]; IF LENGTH[propertyValue] < SIZE[StringBody[name.maxlength]] THEN RETURN WITH ERROR Directory.Error[propertyTooSmall]; RETURN}; ENDCASE; pLP _ FindProp[property]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[from: @pLP.value, to: BASE[propertyValue], nwords: MIN[LENGTH[propertyValue], pLP.length]]; IF LENGTH[propertyValue] < pLP.length THEN { Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[propertyTooSmall]}; Space.Unmap[leaderPageSpace]; RETURN}; ENDCASE => { -- file has no leader page! Grovel around directories for values name: STRING _ [Directory.maxDirectoryNameLength]; parentCap: File.Capability; SELECT property FROM = PropertyTypes.tFileName => { propertyValue[0] _ 0; -- in case SearchForName bombs parentCap _ SearchForName[file, name]; Inline.LongCOPY[ to: BASE[propertyValue], from: name, nwords: MIN[LENGTH[propertyValue], SIZE[StringBody[name.maxlength]]]]; IF LENGTH[propertyValue] < SIZE[StringBody[name.maxlength]] THEN RETURN WITH ERROR Directory.Error[propertyTooSmall]; RETURN}; = PropertyTypes.tParentDirectory => { parentCap _ SearchForName[file, name]; IF LENGTH[propertyValue] < SIZE[File.Capability] THEN RETURN WITH ERROR Directory.Error[propertyTooSmall]; Inline.LongCOPY[from: @parentCap, to: BASE[propertyValue], nwords: SIZE[File.Capability]]}; ENDCASE => FOR i: CARDINAL IN [0.. LENGTH[propertyValue]) DO propertyValue[i] _ 0 ENDLOOP}; EXITS AnError => RETURN WITH ERROR Directory.Error[eType]; END; GetProps: PUBLIC ENTRY PROC [file: File.Capability, name: LONG STRING] RETURNS [readDate, writeDate, createDate: System.GreenwichMeanTime, byteLength: LONG CARDINAL, parent: File.Capability] = -- Return the value of a set of properties BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType _ type; GOTO AnError}}; [readDate: readDate, writeDate: writeDate, createDate: createDate, byteLength: byteLength, parent: parent] _ GetPropsInternal[file: file, name: name]; EXITS AnError => RETURN WITH ERROR Directory.Error[eType]; END; GetPropsInternal: PUBLIC INTERNAL PROC [file: File.Capability, name: LONG STRING] RETURNS [readDate, writeDate, createDate: System.GreenwichMeanTime, byteLength: LONG CARDINAL, parent: File.Capability] = -- Return the value of a set of properties BEGIN pLP: LONG POINTER TO LPEntry; SELECT TestFileType[file] FROM = fullLP => { MapCap[file, fullLP]; pLP _ FindProp[PropertyTypes.tReadDate]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[from: @pLP.value, to: @readDate, nwords: SIZE[System.GreenwichMeanTime]]; pLP _ FindProp[PropertyTypes.tWriteDate]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[from: @pLP.value, to: @readDate, nwords: SIZE[System.GreenwichMeanTime]]; pLP _ FindProp[PropertyTypes.tCreateDate]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[from: @pLP.value, to: @readDate, nwords: SIZE[System.GreenwichMeanTime]]; pLP _ FindProp[PropertyTypes.tParentDirectory]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[from: @pLP.value, to: @parent, nwords: SIZE[File.Capability]]; pLP _ FindProp[PropertyTypes.tFileName]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; DirectoryTrees.MoveLongString[from: LOOPHOLE[@pLP.value], to: name]; Space.Unmap[leaderPageSpace]; RETURN}; = fsLP => { MapCap[file, fsLP]; readDate _ pFSLeaderPage.read; writeDate _ pFSLeaderPage.write; createDate _ pFSLeaderPage.create; byteLength _ pFSLeaderPage.length; FOR i: CARDINAL IN [0.. pFSLeaderPage.nameLength) DO name[i] _ pFSLeaderPage.name[i] ENDLOOP; name.length _ pFSLeaderPage.nameLength; pLP _ FindProp[PropertyTypes.tParentDirectory]; IF pLP = NIL THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; Inline.LongCOPY[from: @pLP.value, to: @parent, nwords: SIZE[File.Capability]]; Space.Unmap[leaderPageSpace]; RETURN}; ENDCASE => { readDate _ writeDate _ createDate _ System.gmtEpoch; parent _ File.nullCapability; -- in case SearchForName bombs parent _ SearchForName[file, name]; RETURN}; END; PutProperty: PUBLIC ENTRY PROC [file: File.Capability, property: Directory.PropertyType, propertyValue: LONG DESCRIPTOR FOR ARRAY OF UNSPECIFIED, new: BOOLEAN] = -- Puts a property in the Property list BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType _ type; GOTO AnError}}; PutPropertyInternal[file: file, property: property, propertyValue: propertyValue, new: new]; EXITS AnError => RETURN WITH ERROR Directory.Error[eType]; END; PutPropertyInternal: PUBLIC INTERNAL PROC [file: File.Capability, property: Directory.PropertyType, propertyValue: LONG DESCRIPTOR FOR ARRAY OF UNSPECIFIED, new: BOOLEAN] = -- Puts a property in the Property list BEGIN pLP: LONG POINTER TO LPEntry; SELECT TestFileType[file] FROM = fullLP => { MapCap[file, fullLP]; pLP _ FindProp[property]; IF (pLP = NIL) AND ~ new THEN {Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; PutProp[property, propertyValue]; Space.Unmap[leaderPageSpace]; RETURN}; = fsLP => { name: STRING _ [Directory.maxDirectoryNameLength]; MapCap[file, fsLP]; SELECT property FROM = Directory.nullProperty => RETURN WITH ERROR Directory.Error[invalidProperty]; = PropertyTypes.tReadDate => Inline.LongCOPY[ from: BASE[propertyValue], to: @pFSLeaderPage.read, nwords: SIZE[System.GreenwichMeanTime]]; = PropertyTypes.tWriteDate => Inline.LongCOPY[ from: BASE[propertyValue], to: @pFSLeaderPage.write, nwords: SIZE[System.GreenwichMeanTime]]; = PropertyTypes.tCreateDate => Inline.LongCOPY[ from: BASE[propertyValue], to: @pFSLeaderPage.create, nwords: SIZE[System.GreenwichMeanTime]]; = PropertyTypes.tByteLength => Inline.LongCOPY[from: BASE[propertyValue], to: @pFSLeaderPage.length, nwords: 2]; = PropertyTypes.tFileName => { Inline.LongCOPY[ from: BASE[propertyValue], to: name, nwords: LENGTH[propertyValue]]; FOR i: CARDINAL IN [0.. name.length) DO pFSLeaderPage.name[i] _ name[i] ENDLOOP; pFSLeaderPage.nameLength _ name.length}; ENDCASE => { pLP _ FindProp[property]; IF (pLP = NIL) AND ~ new THEN { Space.Unmap[leaderPageSpace]; RETURN WITH ERROR Directory.Error[invalidProperty]}; PutProp[property, propertyValue]}; Space.Unmap[leaderPageSpace]; RETURN}; ENDCASE; END; PutProps: PUBLIC ENTRY PROC [file: File.Capability, readDate, writeDate, createDate: System.GreenwichMeanTime] = -- Sets the dates of a file BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType _ type; GOTO AnError}}; SELECT TestFileType[file] FROM = fullLP => { MapCap[file, fullLP]; PutProp[PropertyTypes.tReadDate, DESCRIPTOR[@readDate, SIZE[System.GreenwichMeanTime]]]; PutProp[ PropertyTypes.tWriteDate, DESCRIPTOR[@writeDate, SIZE[System.GreenwichMeanTime]]]; PutProp[ PropertyTypes.tCreateDate, DESCRIPTOR[@createDate, SIZE[System.GreenwichMeanTime]]]; Space.Unmap[leaderPageSpace]; RETURN}; = fsLP => { MapCap[file, fsLP]; pFSLeaderPage.read _ readDate; pFSLeaderPage.write _ writeDate; pFSLeaderPage.create _ createDate; Space.Unmap[leaderPageSpace]; RETURN}; ENDCASE => RETURN; EXITS AnError => RETURN WITH ERROR Directory.Error[eType]; END; UpdateDates: PUBLIC ENTRY PROC [file: File.Capability, permissions: File.Permissions] RETURNS [File.Capability] = -- Updates the dates of a file BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType _ type; GOTO AnError}}; newCap: File.Capability; newCap _ IF permissions = Directory.ignore THEN file ELSE File.LimitPermissions[file, permissions]; SetTimes[newCap]; RETURN [newCap]; EXITS AnError => RETURN WITH ERROR Directory.Error[eType]; END; -- internal procedures FindProp: INTERNAL PROC [type: Directory.PropertyType] RETURNS [pLP: LONG POINTER TO LPEntry] = -- Return a pointer to leader page entry of indicated property (or NIL if doesn't exist) BEGIN size: CARDINAL _ DirectoryInternal.leaderPageOffset; pLP _ pLeaderPage+DirectoryInternal.leaderPageOffset+1; WHILE pLP.type # Directory.nullProperty DO IF pLP.type = type THEN RETURN; pLP _ pLP+pLP.length+2; size _ size + pLP.length+2; IF size >= leaderPageWords THEN { -- a size field is wrong, so zero this leader page and continue pLP _ pLeaderPage+DirectoryInternal.leaderPageOffset+1; pLP.type _ Directory.nullProperty; RETURN [NIL]}; ENDLOOP; RETURN [NIL] END; MapCap: INTERNAL PROC[file: File.Capability, type: FileType] = -- map the file leader page to the leader page space BEGIN pLP: LONG POINTER TO LPEntry _ pLeaderPage+DirectoryInternal.leaderPageOffset+1; file.permissions _ Directory.fileMaxPermissions; Space.Map[leaderPageSpace, [file, 0]]; IF pVersion^ # leaderVersionID THEN { -- set up an empty leader page (and you can kiss page zero good-bye!) pVersion^ _ leaderVersionID; pLP^ _ [type: Directory.nullProperty, length: 0, value:]}; IF type = fsLP AND (pFSLeaderPage.versionID # fsLeaderVersionID) THEN { pFSLeaderPage.versionID _ fsLeaderVersionID; pFSLeaderPage.nameLength _ 0; pFSLeaderPage.read _ pFSLeaderPage.write _ pFSLeaderPage.create _ System.GreenwichMeanTime[0]; pFSLeaderPage.dataType _ unknown; pFSLeaderPage.length _ Inline.LongMult[Inline.LowHalf[File.GetSize[file]],Environment.bytesPerPage]}; RETURN END; PutProp: INTERNAL PROC [type: Directory.PropertyType, value: LONG DESCRIPTOR FOR ARRAY OF UNSPECIFIED] = -- place/replace property with value BEGIN pLP: LONG POINTER TO LPEntry _ pLeaderPage+DirectoryInternal.leaderPageOffset+1; copySize: CARDINAL _ 0; addToCopy: BOOLEAN _ FALSE; pCopyLP: LONG POINTER TO LPEntry; WHILE pLP.type # Directory.nullProperty DO IF pLP.type = type THEN {addToCopy _ TRUE; pCopyLP _ pLP}; IF addToCopy THEN copySize _ copySize+pLP.length+2; pLP _ pLP+pLP.length+2; ENDLOOP; IF addToCopy THEN { pLP _ pLP - pCopyLP.length - 2; Inline.LongCOPY[from: pCopyLP+pCopyLP.length+2, to: pCopyLP, nwords: copySize]}; pLP^ _ [type: type, length: LENGTH[value], value:]; Inline.LongCOPY[from: BASE[value], to: @pLP.value, nwords: LENGTH[value]]; pLP _ pLP+pLP.length+2; pLP^ _ [type: Directory.nullProperty, length: 0, value:]; RETURN END; SearchForName: PUBLIC INTERNAL PROC [file: File.Capability, name: LONG STRING] RETURNS [parent: File.Capability] = -- returns a file's name and parent capability by searching the directories for an entry with -- the same ID as file. -- Current Limitation: the only directory searched is the default working directory BEGIN pDD: LONG POINTER TO DirectoryInternal.DirectoryDescriptor; gnFile: File.Capability; pDD _ @DirectoryFiles.directoryCache[DirectoryContexts.contextTable[0].pDC].dir; name.length _ 0; DO gnFile _ DirectoryTrees.BTreeGetNext[pDD, name, name]; IF name.length = 0 THEN ERROR Directory.Error[invalidProperty]; -- couldn't find the file! IF gnFile.fID = file.fID THEN EXIT; ENDLOOP; parent _ DirectoryFiles.directoryCache[DirectoryContexts.contextTable[0].pDC].cap; RETURN END; SetCreateDate: PUBLIC INTERNAL PROC [file: File.Capability, name: LONG STRING, parent: File.Capability] = -- Define all the properties for this file BEGIN time: System.GreenwichMeanTime _ System.GetGreenwichMeanTime[]; emptyByteLength: LONG CARDINAL _ (File.GetSize[file]-DirectoryInternal.leaderPageSize)*Environment.wordsPerPage*2; pLP: LONG POINTER TO LPEntry _ pLeaderPage+DirectoryInternal.leaderPageOffset+1; SELECT TestFileType[file] FROM = fsLP => { file.permissions _ Directory.fileMaxPermissions; Space.Map[leaderPageSpace, [file, 0]]; pFSLeaderPage.versionID _ fsLeaderVersionID; pVersion^ _ leaderVersionID; pFSLeaderPage.read _ pFSLeaderPage.write _ pFSLeaderPage.create _ time; pFSLeaderPage.dataType _ unknown; pFSLeaderPage.length _ emptyByteLength; FOR i: CARDINAL IN [0.. name.length) DO pFSLeaderPage.name[i] _ name[i] ENDLOOP; pFSLeaderPage.nameLength _ name.length; pLP^ _ [type: Directory.nullProperty, length: 0, value:]; PutProp[PropertyTypes.tParentDirectory, DESCRIPTOR[@parent, SIZE[File.Capability]]]; Space.Unmap[leaderPageSpace]}; = fullLP => { file.permissions _ Directory.fileMaxPermissions; Space.Map[leaderPageSpace, [file, 0]]; pVersion^ _ leaderVersionID; pLP^ _ [type: Directory.nullProperty, length: 0, value:]; PutProp[PropertyTypes.tReadDate, DESCRIPTOR[@time, SIZE[System.GreenwichMeanTime]]]; PutProp[PropertyTypes.tWriteDate, DESCRIPTOR[@time, SIZE[System.GreenwichMeanTime]]]; PutProp[PropertyTypes.tCreateDate, DESCRIPTOR[@time, SIZE[System.GreenwichMeanTime]]]; PutProp[PropertyTypes.tByteLength, DESCRIPTOR[@emptyByteLength, 2]]; PutProp[PropertyTypes.tFileName, DESCRIPTOR[name, SIZE[StringBody[name.length]]]]; PutProp[PropertyTypes.tParentDirectory, DESCRIPTOR[@parent, SIZE[File.Capability]]]; Space.Unmap[leaderPageSpace]}; ENDCASE; RETURN END; SetNameAndCap: PUBLIC INTERNAL PROC [file: File.Capability, name: LONG STRING, parent: File.Capability] = -- set the leader page name and parent capability BEGIN SELECT TestFileType[file] FROM = fsLP => { MapCap[file, fsLP]; FOR i: CARDINAL IN [0.. name.length) DO pFSLeaderPage.name[i] _ name[i] ENDLOOP; pFSLeaderPage.nameLength _ name.length; PutProp[PropertyTypes.tParentDirectory, DESCRIPTOR[@parent, SIZE[File.Capability]]]; Space.Unmap[leaderPageSpace]}; = fullLP => { MapCap[file, fullLP]; PutProp[PropertyTypes.tFileName, DESCRIPTOR[name, SIZE[StringBody[name.length]]]]; PutProp[PropertyTypes.tParentDirectory, DESCRIPTOR[@parent, SIZE[File.Capability]]]; Space.Unmap[leaderPageSpace]}; ENDCASE; RETURN END; SetTimes: PUBLIC INTERNAL PROC [file: File.Capability] = -- set the leader page times from the file capability BEGIN time: System.GreenwichMeanTime _ System.GetGreenwichMeanTime[]; setRead: BOOLEAN _ Inline.BITAND[file.permissions, File.read]; setCreate: BOOLEAN _ Inline.BITAND[file.permissions, File.write+File.grow+File.shrink]; SELECT TestFileType[file] FROM = fsLP => { MapCap[file, fsLP]; IF setRead THEN pFSLeaderPage.read _ time; IF setCreate THEN pFSLeaderPage.write _ pFSLeaderPage.create _ time; Space.Unmap[leaderPageSpace]}; = fullLP => { MapCap[file, fullLP]; IF setRead THEN PutProp[PropertyTypes.tReadDate, DESCRIPTOR[@time, SIZE[System.GreenwichMeanTime]]]; IF setCreate THEN { PutProp[PropertyTypes.tWriteDate, DESCRIPTOR[@time, SIZE[System.GreenwichMeanTime]]]; PutProp[PropertyTypes.tCreateDate, DESCRIPTOR[@time, SIZE[System.GreenwichMeanTime]]]}; Space.Unmap[leaderPageSpace]}; ENDCASE; RETURN END; TestFileType: INTERNAL PROC [file: File.Capability] RETURNS [FileType] = -- return how leader page is to be constructed BEGIN ft: File.Type; ftValue: CARDINAL; IF File.GetSize[file ! File.Unknown => ERROR Directory.Error[fileNotFound]; Volume.Unknown => ERROR Directory.Error[volumeNotFound]] = 0 THEN RETURN [noLP]; ft _ File.GetAttributes[file].type; IF ft = DCSFileTypes.tLeaderPage THEN RETURN [fsLP]; [ftValue] _ ft; IF ftValue IN CommonSoftwareFileTypes.CommonSoftwareFileType THEN RETURN [fullLP]; RETURN [noLP] END; ValidLP: PUBLIC INTERNAL PROC [file: File.Capability] RETURNS [BOOLEAN] = -- Check if the file is of type tDirectory and has a good leader page BEGIN ft: File.Type; ft _ File.GetAttributes[file ! File.Unknown => GOTO NotValid].type; IF ft # CommonSoftwareFileTypes.tDirectory THEN GOTO NotValid; Space.Map[leaderPageSpace, [file, 0]]; IF pVersion^ # leaderVersionID THEN {Space.Unmap[leaderPageSpace]; GOTO NotValid}; Space.Unmap[leaderPageSpace]; RETURN [TRUE]; EXITS NotValid => RETURN [FALSE] END; -- Initialization leaderPageSpace _ Space.Create[DirectoryInternal.leaderPageSize, Space.virtualMemory]; pLeaderPage _ Space.LongPointer[leaderPageSpace]; pFSLeaderPage _ LOOPHOLE[pLeaderPage]; pVersion _ LOOPHOLE[pLeaderPage]; pVersion _ pVersion + DirectoryInternal.leaderPageOffset; END. LOG Time: August 28, 1980 11:25 AM By: Keith Action: Created File(1792)\4b18B6i52I1381b3i28B96I420i230I6bi17BI2b17B144i39I1367b13B147i30I2912i66I169i29I803b10B199i39I539i39I2042i28I58b13B161i36I440i36I1710b10B115i24I769b13B113i27I338bi20BI106i85I317i70I221i51I228i69I645i33I932i112I12bi18B63I350i24I284i39I1844i48I673i52I957i45I533i68I401b4i14BI290i Time: October 8, 1980 10:13 AM By: Keith Action: MapCap initializes leader page rather than raising DirectoryNeedsScavenging if leader page is trashed (ARs 6046, 6183).\i51b7B44b24B Time: October 20, 1980 6:28 PM By: Keith Action: Changed GetProps and GetProperty so that files with no leader pages will return somewhat meaningful property values for parent directory and file name.\i59b8B5b11B Time: December 7, 1980 4:34 PM By: Fay Action: Changed GetProps and PutProperty to call monitor-internal procedures, so that the scavenger can call these internal procs from inside the monitor.\i57b8B5b11B Time: AugustJanuary 4, 1981 2:05 PM By: Keith Action: Fixed FindProp so that a funny property length dies gracefully.\i