-- File: AlpineCmds.mesa -- Last edited by: -- MBrown on March 16, 1983 5:19 pm -- Kolling on April 27, 1983 2:51 pm -- Procs that might usefully be called from the interpreter. -- Procs for use by any Alpine user: -- Copy: PROC [to: ROPE, from: ROPE] ("to" and "from" may Alpine or local files). -- Delete: PROC [file: ROPE] ("file" must be an Alpine file) -- List: PROC [pattern: ROPE] RETURNS [LIST OF REF ANY] (* allowed in "pattern") -- ReadQuota: PROC [directory: ROPE] RETURNS [pageLimit, spaceInUse: PageCount] -- Procs for use by administrators: -- CreateOwner: PROC [directory: ROPE, pageLimit: PageCount] -- WriteQuota: PROC [directory: ROPE, pageLimit: PageCount] -- ListOwners: PROC [fileStore: ROPE] RETURNS [LIST OF REF ANY] -- ReorganizeOwnerDB: PROC [fileStore: ROPE, nEntries: NAT] DIRECTORY AlpFile USING[Handle, Open, ReadPages, ReadProperties, SetSize, WritePages, WriteProperties], AlpineEnvironment USING[ByteCount, bytesPerPage, FileID, FileStore, nullVolumeGroupID, OwnerPropertyValuePair, Outcome, PageCount, PropertyValuePair, TransID, VolumeID, wordsPerPage], AlpineInterimDirectory USING[Delete, EnumerateDirectory, OpenUnderTrans], AlpInstance USING[Create, Handle], AlpTransaction USING[AssertAlpineWheel, Create, CreateOwner, CreateWithTransID, Finish, GetNextVolumeGroup, Handle, ReadNextOwner, ReadOwnerProperties, ReorganizeOwnerDB, WriteOwnerProperties], Directory USING[GetProperty, PutProperty], Environment USING[Comparison], File USING[Capability, SetSize], FileIO USING[CapabilityFromStream, CreateOptions, minimumStreamBufferParms, Open], IO USING[Close, PutFR, STREAM, text], List USING[Cons, Sort], PropertyTypes USING[tByteLength, tCreateDate], RefText USING[TrustTextAsRope], Rope USING[Compare, Equal, Fetch, Find, IsEmpty, Match, ROPE, SkipTo, Substr], Space USING[CopyIn, CopyOut, Create, Delete, Handle, LongPointer, Map, Unmap, virtualMemory], System USING[GreenwichMeanTime]; AlpineCmds: PROGRAM IMPORTS AE: AlpineEnvironment, AlpF: AlpFile, AlpI: AlpInstance, AlpT: AlpTransaction, Directory, File, FileIO, AlpineInterimDirectory, IO, Lists: List, RefText, Rope, Space = BEGIN ROPE: TYPE = Rope.ROPE; CreateOptions: TYPE = FileIO.CreateOptions; VolumeID: TYPE = AE.VolumeID; FileID: TYPE = AE.FileID; PageCount: TYPE = AE.PageCount; ByteCount: TYPE = AE.ByteCount; wordsPerPage: INT = AE.wordsPerPage; bytesPerPage: INT = AE.bytesPerPage; PropertyValuePair: TYPE = AE.PropertyValuePair; PagesForBytes: PROC [byteLength: ByteCount] RETURNS [pageCount: PageCount] = { RETURN [(byteLength+bytesPerPage-1)/bytesPerPage]; }; Copy: PROC [to: ROPE, from: ROPE] = { coordinator: AE.FileStore _ ""; coordinatorTransHandle: AlpT.Handle _ NIL; transHandle: AlpT.Handle _ NIL; -- Inner procs use transHandle. FileStateObject: TYPE = RECORD [ SELECT type: {alpine, pilot} FROM alpine => [fileHandle: AlpF.Handle], pilot => [fc: File.Capability], ENDCASE]; AlpineFileStateObject: TYPE = FileStateObject.alpine; PilotFileStateObject: TYPE = FileStateObject.pilot; FileState: TYPE = REF FileStateObject; AlpineFileState: TYPE = REF AlpineFileStateObject; PilotFileState: TYPE = REF PilotFileStateObject; CreateFileState: PROC [file: ROPE, createOptions: CreateOptions, createLength: INT _ 0] RETURNS [FileState] = { IF file.Fetch[0] = '[ THEN { volumeID: VolumeID; fileID: FileID; alpineFileState: AlpineFileState; fileStore: AE.FileStore; leftSquareBracket: INT _ file.Find["]", 1]; IF leftSquareBracket IN [-1..1] THEN ERROR Error[illegalFileName]; fileStore _ file.Substr[start: 1, len: leftSquareBracket - 1]; IF coordinator.IsEmpty[] THEN BEGIN transHandle _ AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker: TRUE]; coordinator _ fileStore; coordinatorTransHandle _ transHandle; END ELSE BEGIN IF NOT Rope.Equal[fileStore, coordinator, FALSE] THEN BEGIN transHandle _ AlpT.CreateWithTransID[instHandle: AlpI.Create[fileStore: fileStore], transID: coordinatorTransHandle.transID, createLocalWorker: TRUE] END; END; [volumeID, fileID, ] _ AlpineInterimDirectory.OpenUnderTrans[ transHandle, file, createOptions, createLength]; alpineFileState _ NEW[AlpineFileStateObject _ [alpine[fileHandle: AlpF.Open[transHandle, volumeID, fileID, IF createOptions = oldOnly THEN readOnly ELSE readWrite, [IF createOptions = oldOnly THEN read ELSE write, wait], log, sequential]]]]; IF createOptions # oldOnly THEN alpineFileState.fileHandle.SetSize[PagesForBytes[createLength]]; RETURN [alpineFileState]; } ELSE { stream: IO.STREAM; pilotFileState: PilotFileState; stream _ FileIO.Open[ fileName: file, accessOptions: IF createOptions = oldOnly THEN read ELSE overwrite, createOptions: createOptions, createLength: createLength, streamBufferParms: FileIO.minimumStreamBufferParms]; pilotFileState _ NEW[PilotFileStateObject _ [pilot[fc: FileIO.CapabilityFromStream[stream]]]]; stream.Close[]; IF createOptions # oldOnly THEN File.SetSize[pilotFileState.fc, 1+PagesForBytes[createLength]]; RETURN [pilotFileState]; }; }; GetFileProperties: PROC [fileState: FileState] RETURNS [ byteLength: ByteCount, createTime: System.GreenwichMeanTime] = { WITH fileState SELECT FROM alpineFileState: AlpineFileState => { fileProperties: LIST OF PropertyValuePair = alpineFileState.fileHandle.ReadProperties[[byteLength: TRUE, createTime: TRUE]]; byteLength _ NARROW[ fileProperties.first, PropertyValuePair.byteLength].byteLength; createTime _ NARROW[ fileProperties.rest.first, PropertyValuePair.createTime].createTime; }; pilotFileState: PilotFileState => { Directory.GetProperty[file: pilotFileState.fc, property: PropertyTypes.tByteLength, propertyValue: DESCRIPTOR[ LOOPHOLE[LONG[@byteLength], LONG POINTER TO UNSPECIFIED], SIZE[ByteCount]]]; Directory.GetProperty[file: pilotFileState.fc, property: PropertyTypes.tCreateDate, propertyValue: DESCRIPTOR[ LOOPHOLE[LONG[@createTime], LONG POINTER TO UNSPECIFIED], SIZE[System.GreenwichMeanTime]]]; }; ENDCASE => ERROR; }; SetFileProperties: PROC [fileState: FileState, byteLength: ByteCount, createTime: System.GreenwichMeanTime] = { WITH fileState SELECT FROM alpineFileState: AlpineFileState => { alpineFileState.fileHandle.WriteProperties[LIST[[byteLength[byteLength]], [createTime[createTime]]]]; }; pilotFileState: PilotFileState => { Directory.PutProperty[file: pilotFileState.fc, property: PropertyTypes.tByteLength, propertyValue: DESCRIPTOR[ LOOPHOLE[LONG[@byteLength], LONG POINTER TO UNSPECIFIED], SIZE[ByteCount]]]; Directory.PutProperty[file: pilotFileState.fc, property: PropertyTypes.tCreateDate, propertyValue: DESCRIPTOR[ LOOPHOLE[LONG[@createTime], LONG POINTER TO UNSPECIFIED], SIZE[System.GreenwichMeanTime]]]; }; ENDCASE => ERROR; }; buffer: Space.Handle; bufferPtr: LONG POINTER; pagesCopied: INT; FillBuffer: PROC [fromFile: FileState, pagesToMove: CARDINAL] = { WITH fromFile SELECT FROM alpineFileState: AlpineFileState => { alpineFileState.fileHandle.ReadPages[ pageRun: [firstPage: pagesCopied, count: pagesToMove], pageBuffer: DESCRIPTOR [ bufferPtr, pagesToMove*wordsPerPage]]; }; pilotFileState: PilotFileState => { Space.CopyIn[buffer, [pilotFileState.fc, pagesCopied+1]]; }; ENDCASE => ERROR; }; EmptyBuffer: PROC [toFile: FileState, pagesToMove: CARDINAL] = { WITH toFile SELECT FROM alpineFileState: AlpineFileState => { alpineFileState.fileHandle.WritePages[ pageRun: [firstPage: pagesCopied, count: pagesToMove], pageBuffer: DESCRIPTOR [ bufferPtr, pagesToMove*wordsPerPage]]; }; pilotFileState: PilotFileState => { Space.CopyOut[buffer, [pilotFileState.fc, pagesCopied+1]]; }; ENDCASE => ERROR; }; toFile, fromFile: FileState; byteLength: ByteCount; createTime: System.GreenwichMeanTime; fromFile _ CreateFileState[file: from, createOptions: oldOnly]; [byteLength, createTime] _ GetFileProperties[fromFile]; toFile _ CreateFileState[file: to, createOptions: none, createLength: byteLength]; { pageCount: PageCount = PagesForBytes[byteLength]; bufferLen: CARDINAL = 12; buffer _ Space.Create[bufferLen, Space.virtualMemory]; bufferPtr _ Space.LongPointer[buffer]; Space.Map[buffer]; pagesCopied _ 0; UNTIL pagesCopied = pageCount DO pagesLeft: CARDINAL _ pageCount-pagesCopied; pagesToMove: CARDINAL _ MIN [bufferLen, pagesLeft]; FillBuffer[fromFile, pagesToMove]; EmptyBuffer[toFile, pagesToMove]; pagesCopied _ pagesCopied + pagesToMove; ENDLOOP; Space.Unmap[buffer]; Space.Delete[buffer]; SetFileProperties[toFile, byteLength, createTime]; IF (coordinatorTransHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR; }; }; Delete: PROC [file: ROPE] = { AlpineInterimDirectory.Delete[file]; }; List: PROC [pattern: ROPE] RETURNS [LIST OF REF ANY] = { directory, restOfPattern: ROPE; resultList: LIST OF REF ANY _ NIL; EnumProc: PROC [fileName: REF TEXT, volumeID: VolumeID, fileID: FileID] RETURNS [quit: BOOL] = { IF Rope.Match[pattern: restOfPattern, object: RefText.TrustTextAsRope[fileName], case: FALSE] THEN { resultRope: ROPE _ IO.PutFR["%g", IO.text[fileName]]; resultList _ CONS[first: resultRope, rest: resultList]; }; RETURN [quit: FALSE]; }; CompareProc: SAFE PROC [ref1, ref2: REF ANY] RETURNS [Environment.Comparison] = CHECKED { RETURN [Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]]; }; resultRope: ROPE _ NIL; [directory, restOfPattern] _ DecomposePattern[pattern]; AlpineInterimDirectory.EnumerateDirectory[ directoryName: directory, enumProc: EnumProc]; resultList _ Lists.Sort[resultList, CompareProc]; RETURN [resultList]; }; DecomposePattern: PROC [pattern: ROPE] RETURNS [directory, restOfPattern: ROPE] = { rightAngleBracket: INT; IF NOT Rope.Match[pattern: "[*]<*>*", object: pattern, case: FALSE] THEN ERROR Error[illegalFileName]; rightAngleBracket _ pattern.SkipTo[1, ">"]; directory _ pattern.Substr[start: 0, len: rightAngleBracket+1]; restOfPattern _ pattern.Substr[start: rightAngleBracket+1]; IF restOfPattern.IsEmpty[] THEN restOfPattern _ "*"; }; Error: ERROR [what: ErrorType] = CODE; ErrorType: TYPE = {illegalFileName}; OwnerPropertyValuePair: TYPE = AE.OwnerPropertyValuePair; OwnerPropertyValuePairList: TYPE = LIST OF OwnerPropertyValuePair; CreateOwner: PROC [directory: ROPE, pageLimit: PageCount] = { p: REF OwnerPropertyValuePair = NEW[ OwnerPropertyValuePair _ [quota[quota: pageLimit]]]; -- crock to make it compile properties: OwnerPropertyValuePairList = LIST[[quota[pageLimit]]]; transHandle: AlpT.Handle; fileStore, owner: ROPE; [fileStore, owner] _ DecomposeDirectory[directory]; transHandle _ AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker: TRUE]; transHandle.AssertAlpineWheel[TRUE]; [] _ transHandle.CreateOwner[ volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none, wait]], owner: owner, properties: properties]; IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR; }; DecomposeDirectory: PROC [directory: ROPE] RETURNS [fileStore, owner: ROPE] = { rightSquareBracket, rightAngleBracket: INT; restOfFileName: ROPE; IF NOT Rope.Match[pattern: "[*]<*>*", object: directory, case: FALSE] THEN ERROR Error[illegalFileName]; rightSquareBracket _ directory.SkipTo[1, "]"]; fileStore _ directory.Substr[start: 1, len: rightSquareBracket-1]; rightAngleBracket _ directory.SkipTo[1, ">"]; owner _ directory.Substr[ start: rightSquareBracket+2, len: rightAngleBracket-rightSquareBracket-2]; restOfFileName _ directory.Substr[start: rightAngleBracket+1]; IF fileStore.IsEmpty[] OR owner.IsEmpty[] OR NOT restOfFileName.IsEmpty[] THEN ERROR Error[illegalFileName]; }; ReadQuota: PROC [directory: ROPE] RETURNS [pageLimit, spaceInUse: PageCount] = { properties: OwnerPropertyValuePairList; transHandle: AlpT.Handle; fileStore, owner: ROPE; [fileStore, owner] _ DecomposeDirectory[directory]; transHandle _ AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker: TRUE]; properties _ transHandle.ReadOwnerProperties[ volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none, wait]], owner: owner, desiredProperties: [quota: TRUE, spaceInUse: TRUE]]; UNTIL properties = NIL DO -- because ReadOwnerProperties does not sort them yet ... WITH properties.first SELECT FROM q: OwnerPropertyValuePair.quota => pageLimit _ q.quota; s: OwnerPropertyValuePair.spaceInUse => spaceInUse _ s.spaceInUse; ENDCASE => ERROR; properties _ properties.rest; ENDLOOP; IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR; }; WriteQuota: PROC [directory: ROPE, pageLimit: PageCount] = { properties: OwnerPropertyValuePairList = LIST[[quota[pageLimit]]]; transHandle: AlpT.Handle; fileStore, owner: ROPE; [fileStore, owner] _ DecomposeDirectory[directory]; transHandle _ AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker: TRUE]; transHandle.AssertAlpineWheel[TRUE]; transHandle.WriteOwnerProperties[ volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none, wait]], owner: owner, properties: properties]; IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE]) # commit THEN ERROR; }; ListOwners: PROC [fileStore: ROPE] RETURNS [LIST OF REF ANY] = { CompareProc: SAFE PROC [ref1, ref2: REF ANY] RETURNS [Environment.Comparison] = CHECKED { RETURN [Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]]; }; result: LIST OF REF ANY _ NIL; owner: ROPE; transHandle: AlpT.Handle _ AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker: TRUE]; transHandle.AssertAlpineWheel[TRUE]; owner _ NIL; DO [owner, ] _ transHandle.ReadNextOwner[ volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none, wait]], previousOwner: owner, desiredProperties: ALL [FALSE]]; IF owner = NIL THEN EXIT; result _ Lists.Cons[owner, result]; ENDLOOP; IF transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit THEN ERROR; RETURN [Lists.Sort[result, CompareProc]]; }; ReorganizeOwnerDB: PROC [fileStore: ROPE, nEntries: NAT] = { transHandle: AlpT.Handle _ AlpT.Create[instHandle: AlpI.Create[fileStore: fileStore], createLocalWorker: TRUE]; transHandle.AssertAlpineWheel[TRUE]; [] _ transHandle.ReorganizeOwnerDB[ volumeGroupID: transHandle.GetNextVolumeGroup[previousGroup: AE.nullVolumeGroupID, lock: [none, wait]], nEntries: nEntries]; IF (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN ERROR; }; END. Êw˜Jš—Ïcyœ³œÏk œžœnžœ×žœEžœ,žœ×žœ3žœžœ)žœKžœžœžœžœžœ'žœ/žœ#žœVžœožœÐbl œžœžœŒžœ(žœÐknœžœžœÏn œžœ¡œžœ¡œžœ¡ œžœ¡ œžœ¡ œžœ¡ œžœ¡œžœ¡ œžœžœ žœ7¡œžœžœžœTžœ!žœœ œ ¡œžœžœ žœžœ^žœ¡œžœ¡œžœ¡ œžœžœ¡œžœžœ¡œžœžœ¡œžœžœ.žœ žœžœžœ“žœžœžœžœ žœžœhžœ!ž œ„žœVžœ žœ ž œžœ$žœž œížœžœžœžœjžœžœ žœžœžœžœ6žœžœTžœ$žœžœžœ{žœžœžœ²žœužœžœSžœ,¡œžœžœPžœ žœžœIžœžœVžœžœžœežœ…ž œžœžœžœžœžœž œžœˆž œžœžœžœžœžœž œžœ3žœžœ¡œžœežœ žœžœdžœöž œžœžœžœžœžœž œžœˆž œžœžœžœžœžœž œžœ3žœžœ7žœžœžœ¡ œžœ$žœ žœ žœžœºž œÊžœžœ¡ œžœ"žœ žœžœžœ»ž œËžœžœšžœ§žœžœžœ/žœžœ§žœxžœDžœžœžœ¡œžœžœ9¡œžœ žœžœžœžœžœžœ$žœžœžœžœžœžœ¡œžœ žœžœ,žœžœ žœ]žœžœžœžœ žœ'žœ8žœžœ¡ œžœžœžœžœžœžœ žœžœžœžœžœžœÜžœ¡œžœ žœžœžœžœžœžœ7žœžœžœÑžœžœ ¡œžœžœ¡ œžœ¡œžœ ¡œžœžœžœ¡ œžœ žœ#žœžœ=œ-žœJžœ¡žœ%žœÓžœ9žœ žœžœ ¡œžœ žœžœžœ1žœžœžœžœ9žœžœžœûžœžœžœžœžœžœ#¡ œžœ žœžœˆžœ¡žœážœžœžœžœžœ:œžœžœžœ”žœžœ,žœžœ9žœ žœžœ ¡ œžœ žœIžœJžœ¡žœ%žœ×žœ9žœ žœžœ ¡ œžœ žœžœžœžœžœžœ ¡ œžœžœžœžœžœžœ žœžœžœžœžœžœžœžœžœ žœužœ%žœžœžœàžœžœ žœ žœžœžœ2žœžœ8žœ žœžœžœ.ž¡œžœ žœ žœzžœ%žœÄžœ9žœ žœžœ ž œ˜ßƒ—…—AâH_