<> <> <> <> <> DIRECTORY BasicTime USING [GetClockPulses, GMT, Now, nullGMT, PulsesToMicroseconds], Basics USING [UnsafeBlock], CrRPC USING [BulkDataSink, BulkDataSource, BulkDataValueProc, CreateClientHandle, DestroyClientHandle, Handle, ReadBulkDataStream], FilingP10V5, FilingAttributesP10V5 USING [Attribute, AttributeSequence, AttributeSequenceObject, AttributeValue, FileID, InterpretedAttributeType, Version], IO USING [EndOf, PutFR, rope, UnsafeGetBlock, UnsafePutBlock], QuickFilingP10V5 USING [QuickGetAttributes], PFS USING [Error, UniqueID], PFSNames USING [PATH], RefText USING [ReleaseScratch], Rope USING [Fetch, FromRefText, ROPE, Substr], RuntimeError USING [ ], UserCredentials USING [GetIdentity], XNS USING [Address, unknownAddress], XNSAuth USING [Conversation, Credentials, GetCredentials, GetNextVerifier, Identity, Initiate, Refresh, SetRecipientHostNumber, Verifier], XNSCH USING [LookupAddressFromRope], XNSCHName USING [Name, RopeFromName], XNSFilingAttributes USING [BuildAttribute, BuildScope, EncapsulateFileID, Interpreted, nullAttributes, nullControls], XNSFilingFileMgr USING [OpenFile, OpenFileObject], XNSFilingNames USING [ParseName, UnparseName], XNSFilingOps USING [EnumProc, Info, Op, ServerData, ServerDataObject], XNSFilingPrivate USING [ConvertFSNameToXNS, InfoFromAttributeStream]; XNSFilingOpsImpl: CEDAR MONITOR IMPORTS BasicTime, CrRPC, FilingP10V5, IO, PFS, QuickFilingP10V5, RefText, Rope, UserCredentials, XNSAuth, XNSCH, XNSCHName, XNSFilingAttributes, XNSFilingNames, XNSFilingPrivate EXPORTS XNSFilingFileMgr, XNSFilingOps ~ { OPEN FilingP10V5, FilingAttributesP10V5, XNSFilingAttributes, XNSFilingFileMgr, XNSFilingOps, XNSFilingPrivate; ROPE: TYPE ~ Rope.ROPE; <> BangStarFile: PROC [file: ROPE] RETURNS [pattern: PFSNames.PATH _ NIL] ~ { NULL }; ConvertToPattern: PROC [pattern: PFSNames.PATH, op: Op] RETURNS [pat: PFSNames.PATH] ~ { }; BuildPath: PROC [mnt: ServerData, rope: ROPE, isDir: BOOL] RETURNS [pathy: PFSNames.PATH] ~ { <> <> format: ROPE ~ IF ( isDir ) THEN "/%g/" ELSE "/%g"; rope _ IO.PutFR[format, IO.rope[rope] ]; pathy _ XNSFilingNames.ParseName[rope]; }; RemoveLeadingSlash: PROC [withSlash: ROPE] RETURNS [matcher: ROPE] ~ { matcher _ IF ( withSlash.Fetch[0] # '/ ) THEN withSlash ELSE withSlash.Substr[1]; <> }; <> OpenInternal: ENTRY PROC [mnt: XNSFilingOps.ServerData] ~ { ENABLE UNWIND => { NULL }; mnt.admin.files _ mnt.admin.files.SUCC; }; CloseInternal: ENTRY PROC [mnt: XNSFilingOps.ServerData] ~ { ENABLE UNWIND => { NULL }; mnt.admin.files _ mnt.admin.files.PRED; }; <> ReadFileOp: PUBLIC PROC [mnt: ServerData, xnsFile: OpenFile, filePosition, nBytes: CARD, to: POINTER] RETURNS [bytesRead: INT _ 0] ~ { range: FilingP10V5.ByteRange ~ [filePosition, nBytes]; Sink: CrRPC.BulkDataSink ~ TRUSTED { block: Basics.UnsafeBlock ~ [to, 0, nBytes]; abort _ checkAbort[h]; bytesRead _ s.UnsafeGetBlock[block]; }; RetrieveBytesOp[mnt, xnsFile.fileH, range, Sink]; }; WriteFileOp: PUBLIC PROC [mnt: ServerData, xnsFile: OpenFile, filePosition, nBytes: CARD, from: POINTER] RETURNS [bytesWritten: INT _ 0] ~ { range: FilingP10V5.ByteRange ~ [filePosition, nBytes]; Source: CrRPC.BulkDataSource ~ TRUSTED { block: Basics.UnsafeBlock ~ [from, 0, nBytes]; abort _ checkAbort[h]; s.UnsafePutBlock[block]; bytesWritten _ nBytes; }; ReplaceBytesOp[mnt, xnsFile.fileH, range, Source]; }; CloseFileOp: PUBLIC PROC [mnt: ServerData, xnsFile: OpenFile] ~ { IF ( mnt.session # NIL ) THEN CloseOp[mnt, xnsFile.fileH]; <> CloseInternal[mnt]; }; OpenFileOp: PUBLIC PROC [mnt: ServerData, fullFName: PFSNames.PATH] RETURNS [xnsFile: OpenFile _ NIL] ~ { withSlash: ROPE ~ XNSFilingNames.UnparseName[fullFName]; newFile: ROPE ~ RemoveLeadingSlash[withSlash]; <> attributes: AttributeSequence ~ BuildAttribute[newFile, Interpreted.pathname.ORD]; fileH: FilingP10V5.Handle ~ OpenOp[mnt, attributes]; now: BasicTime.GMT ~ BasicTime.Now[]; xfile: OpenFile ~ NEW[OpenFileObject _ [fileH, now]]; OpenInternal[mnt]; xnsFile _ xfile; <> }; <> EnumerateOp: PUBLIC PROC [mnt: ServerData, pattern: PFSNames.PATH, proc: EnumProc, op: Op] ~ { Listing: CrRPC.BulkDataSink ~ { EachElement: CrRPC.BulkDataValueProc ~ { info: Info ~ InfoFromAttributeStream[s]; { nonEmpty: BOOL ~ ( ( info.isDir ) AND ( info.numKids # 0 ) ); pathy: PFSNames.PATH ~ BuildPath[mnt, info.pathName, info.isDir]; IF ( pathy = NIL ) THEN { abort _ FALSE; RETURN }; <> abort _ NOT proc[pattern, info, pathy]; }; }; IF ( s.EndOf[] ) THEN { abort _ FALSE; RETURN }; -- "Services" feature workaround abort _ CrRPC.ReadBulkDataStream[h, s, checkAbort, EachElement]; }; root: FilingP10V5.Handle ~ mnt.root; types: AttributeTypeSequence ~ GetCedarATS[op]; withSlash: ROPE ~ XNSFilingNames.UnparseName[pattern]; matcher: ROPE ~ RemoveLeadingSlash[withSlash]; scope: FilingP10V5.ScopeSequence ~ BuildScope[$matches, matcher, InterpretedAttributeType.pathname.ORD]; ListOp[mnt, root, types, scope, Listing]; }; <> LogonOp: PUBLIC PROC [server: ROPE] RETURNS [mnt: ServerData _ NIL] ~ { qualified: XNSCHName.Name; add: XNS.Address; LogonOpInner: PROC ~ { name: ROPE ~ XNSCHName.RopeFromName[qualified]; address: REF XNS.Address ~ NEW[XNS.Address _ add]; crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, address]; <> realId: XNSAuth.Identity ~ UserCredentials.GetIdentity[]; conversation: XNSAuth.Conversation ~ XNSAuth.Initiate[realId, qualified]; credentials: XNSAuth.Credentials ~ XNSAuth.GetCredentials[conversation]; verifier: XNSAuth.Verifier; session: REF FilingP10V5.Session; timeToLive: CARD32; XNSAuth.SetRecipientHostNumber[conversation, address.host]; verifier _ XNSAuth.GetNextVerifier[conversation]; session _ NEW[Session _ FilingP10V5.Logon[crH, qualified, credentials, verifier]]; session.verifier _ XNSAuth.GetNextVerifier[conversation]; timeToLive _ FilingP10V5.Continue[crH, session^]; XNSAuth.Refresh[conversation, timeToLive]; CrRPC.DestroyClientHandle[crH]; mnt _ NEW[ServerDataObject _ [name, qualified, address, conversation, session, timeToLive, FilingP10V5.nullHandle, ]]; }; [qualified, add] _ XNSCH.LookupAddressFromRope[server]; IF ( add = XNS.unknownAddress ) THEN GOTO NoCanDo; LogonOpInner[]; EXITS NoCanDo => { ERROR }; }; MountRootOp: PUBLIC PROC [mnt: ServerData] ~ { <> crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; mnt.session.verifier _ XNSAuth.GetNextVerifier[mnt.tkt]; mnt.root _ FilingP10V5.Open[crH, nullAttributes, FilingP10V5.nullHandle, nullControls, mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; ContinueOp: PUBLIC PROC [mnt: ServerData] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; mnt.session.verifier _ XNSAuth.GetNextVerifier[mnt.tkt]; mnt.admin.trTTL _ mnt.timeToLive _ FilingP10V5.Continue[crH, mnt.session^]; XNSAuth.Refresh[conversation: mnt.tkt, seconds: mnt.admin.trTTL]; CrRPC.DestroyClientHandle[crH]; }; OpenOp: PUBLIC PROC [mnt: ServerData, attributes: AttributeSequence] RETURNS [fileH: FilingP10V5.Handle] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; fileH _ FilingP10V5.Open[h: crH, attributes: attributes, directory: mnt.root, controls: nullControls, session: mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; OpenFIDOp: PUBLIC PROC [mnt: ServerData, fid: FileID] RETURNS [fileH: FilingP10V5.Handle] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; attributes: AttributeSequence _ NEW[AttributeSequenceObject[1]]; attributes[0] _ [type: InterpretedAttributeType.fileID.ORD, value: EncapsulateFileID[fid]]; mnt.session.verifier _ XNSAuth.GetNextVerifier[mnt.tkt]; fileH _ FilingP10V5.Open[h: crH, attributes: attributes, directory: FilingP10V5.nullHandle, controls: nullControls, session: mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; ListOp: PUBLIC PROC [mnt: ServerData, fileH: FilingP10V5.Handle, types: AttributeTypeSequence, scope: ScopeSequence, listing: CrRPC.BulkDataSink] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; mnt.session.verifier _ XNSAuth.GetNextVerifier[mnt.tkt]; FilingP10V5.List[crH, fileH, types, scope, listing, mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; QuickInfoOp: PUBLIC PROC [mnt: ServerData, fileH: FilingP10V5.Handle, types: AttributeTypeSequence] RETURNS [info: Info] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; text: REF TEXT; mnt.session.verifier _ XNSAuth.GetNextVerifier[mnt.tkt]; [info.version, info.bytes, info.created, info.fileType, text, info.fID, info.isDir, info.numKids] _ QuickFilingP10V5.QuickGetAttributes[crH, fileH, types, mnt.session^]; info.pathName _ Rope.FromRefText[text]; RefText.ReleaseScratch[text]; CrRPC.DestroyClientHandle[crH]; }; DeleteOp: PUBLIC PROC [mnt: ServerData, fileH: FilingP10V5.Handle] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; mnt.session.verifier _ XNSAuth.GetNextVerifier[mnt.tkt]; FilingP10V5.Delete[h: crH, file: fileH, session: mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; CloseOp: PUBLIC PROC [mnt: ServerData, fileH: FilingP10V5.Handle] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; FilingP10V5.Close[h: crH, file: fileH, session: mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; RetrieveBytesOp: PUBLIC PROC [mnt: ServerData, file: FilingP10V5.Handle, range: FilingP10V5.ByteRange, sink: CrRPC.BulkDataSink] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; FilingP10V5.RetrieveBytes[crH, file, range, sink, mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; ReplaceBytesOp: PUBLIC PROC [mnt: ServerData, file: FilingP10V5.Handle, range: ByteRange, source: CrRPC.BulkDataSource] ~ { crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, mnt.address]; FilingP10V5.ReplaceBytes[crH, file, range, source, mnt.session^]; CrRPC.DestroyClientHandle[crH]; }; LogoffOp: PUBLIC PROC [mnt: ServerData] ~ { ENABLE PFS.Error => { GOTO GiveUp }; <> IF ( mnt.session = NIL ) THEN RETURN; { session: REF Session ~ mnt.session; address: REF XNS.Address ~ mnt.address; crH: CrRPC.Handle ~ CrRPC.CreateClientHandle[$CMUX, address]; FilingP10V5.Logoff[h: crH, session: session^]; CrRPC.DestroyClientHandle[crH]; }; mnt.session _ NIL; EXITS GiveUp => { NULL }; }; <> XNSDelete: PUBLIC PROC [mnt: ServerData, file: ROPE, wantedUniqueID: PFS.UniqueID] ~ { fileH: FilingP10V5.Handle; info: Info; withKids: BOOL; [fileH, info, withKids] _ FindFile[mnt, file, wantedUniqueID.egmt.time, $delete]; <> < { CloseOp[mnt, fileH] };>> <> <> <<};>> <<{>> <> <> <<};>> }; XNSEnumerateForInfo: PUBLIC PROC ~ { << P: PROC [file: ROPE, bytes: INT, created: BasicTime.GMT, fileType: FileType, version: Version, fID: FileID, isDir: BOOL, withKids: BOOL, pathName: REF TEXT] RETURNS [continue: BOOL] = { continue _ proc[file, bytes, created, fileType]; }; EnumerateOp[h, pattern, P, $enumerate]; >> }; <> openTime: CARD; startO, endO: CARD; FindFile: PROC [mnt: ServerData, file: ROPE, wantedTime: BasicTime.GMT, op: Op] RETURNS [fileH: FilingP10V5.Handle _ FilingP10V5.nullHandle, info: Info, withKids: BOOL] = { Note: EnumProc ~ { IF ( wantedTime # eInfo.created ) THEN RETURN; <> fileH _ OpenFIDOp[mnt, eInfo.fID]; info _ eInfo; continue _ FALSE; }; timeSearch: BOOL ~ ( wantedTime # BasicTime.nullGMT ); newFile: ROPE _ ConvertFSNameToXNS[file, op]; attributes: AttributeSequence _ BuildAttribute[newFile, Interpreted.pathname.ORD]; startO _ BasicTime.GetClockPulses[]; fileH _ OpenOp[mnt, attributes]; IF ( fileH # FilingP10V5.nullHandle ) THEN { endO _ BasicTime.GetClockPulses[]; openTime _ BasicTime.PulsesToMicroseconds[endO] - BasicTime.PulsesToMicroseconds[startO]; info _ InfoFromOpenFile[mnt, fileH, op]; withKids _ ( ( info.isDir ) AND ( info.numKids # 0 ) ); IF ( ( NOT timeSearch ) OR ( wantedTime = info.created ) ) THEN { RETURN }; }; <> <<>> CloseOp[mnt, fileH]; fileH _ FilingP10V5.nullHandle; <<>> IF ( timeSearch ) THEN { <> pattern: PFSNames.PATH ~ ConvertToPattern[BangStarFile[file], $enumerate]; EnumerateOp[mnt, pattern, Note, op]; endO _ BasicTime.GetClockPulses[]; openTime _ BasicTime.PulsesToMicroseconds[endO] - BasicTime.PulsesToMicroseconds[startO]; IF ( fileH # FilingP10V5.nullHandle ) THEN RETURN; }; ERROR; }; infoTime: CARD; startE, endE: CARD; InfoFromOpenFile: PROC [mnt: ServerData, fileH: FilingP10V5.Handle, op: Op] RETURNS [info: Info] = { types: AttributeTypeSequence ~ GetCedarATS[op]; <> <<[...] _ InfoFromAttributeSequence[attributes];>> startE _ BasicTime.GetClockPulses[]; info _ QuickInfoOp[mnt, fileH, types]; endE _ BasicTime.GetClockPulses[]; infoTime _ BasicTime.PulsesToMicroseconds[endE] - BasicTime.PulsesToMicroseconds[startE]; }; <> deleteATS: AttributeTypeSequence; enumerateATS: AttributeTypeSequence; enumerateNamesATS: AttributeTypeSequence; retrieveATS: AttributeTypeSequence; storeATS: AttributeTypeSequence; GetCedarATS: PROC [op: Op] RETURNS [attributes: AttributeTypeSequence] = { attributes _ SELECT op FROM delete => deleteATS, enumerate => enumerateATS, enumerateNames => enumerateNamesATS, rename => enumerateATS, retrieve => retrieveATS, store => storeATS, ENDCASE => ERROR; }; MakeCedarATS: PROC RETURNS [delete, enumerate, enumerateNames, retrieve, store: AttributeTypeSequence] ~ { CardAT: PROC [iat: InterpretedAttributeType] RETURNS [card: CARD32] ~ INLINE { card _ iat.ORD }; delete _ NEW[AttributeTypeSequenceObject[6]]; enumerate _ NEW[AttributeTypeSequenceObject[8]]; enumerateNames _ NEW[AttributeTypeSequenceObject[2]]; retrieve _ NEW[AttributeTypeSequenceObject[5]]; store _ NEW[AttributeTypeSequenceObject[1]]; delete[0] _ CardAT[createdOn]; delete[1] _ CardAT[fileID]; delete[2] _ CardAT[isDirectory]; delete[3] _ CardAT[numberOfChildren]; delete[4] _ CardAT[version]; delete[5] _ CardAT[pathname]; enumerate[0] _ CardAT[createdOn]; enumerate[1] _ CardAT[dataSize]; enumerate[2] _ CardAT[name]; enumerate[3] _ CardAT[pathname]; enumerate[4] _ CardAT[type]; enumerate[5] _ CardAT[isDirectory]; enumerate[6] _ CardAT[version]; enumerate[7] _ CardAT[fileID]; enumerateNames[0] _ CardAT[pathname]; enumerateNames[1] _ CardAT[isDirectory]; retrieve[0] _ CardAT[createdOn]; retrieve[1] _ CardAT[dataSize]; retrieve[2] _ CardAT[version]; retrieve[3] _ CardAT[pathname]; retrieve[4] _ CardAT[fileID]; store[0] _ CardAT[version]; }; <> Init: PROC = { [deleteATS, enumerateATS, enumerateNamesATS, retrieveATS, storeATS] _ MakeCedarATS[]; }; Init[]; }.