DIRECTORY PrincOpsUtils USING [ByteBlt], IFSFile USING [Buffer, ByteCount, Completer, CompleterArg, Position, Problem], IFSFilePrivate USING [FileHandle, FileObject, FileState, FreeIORequestBlock, GetIORequestBlock, IORequest], Leaf USING [Answer, ByteCount, FileAddress, LeafType, OpSpecificFileAddress, readOp, readAns, Request, writeOp, WriteRequest], PrincOps USING [zEXCH], Sequin USING [Broken, Buffer, Get, GetEmptyBuffer, Put, ReleaseBuffer]; IFSFileImplC: MONITOR LOCKS file.LOCK USING file: IFSFilePrivate.FileHandle IMPORTS PrincOpsUtils, IFSFilePrivate, Sequin EXPORTS IFSFile, IFSFilePrivate = { OPEN IFSFilePrivate; InvalidFile: ERROR = CODE; LeafGibberish: ERROR = CODE; TheWellIsDry: ERROR = CODE; FileObject: PUBLIC TYPE = IFSFilePrivate.FileObject; Error: PUBLIC ERROR [reason: IFSFile.Problem] = CODE; StartRead: PUBLIC PROC [file: FileHandle, pos: IFSFile.Position, bytes: IFSFile.ByteCount, buffer: IFSFile.Buffer, callback: IFSFile.Completer, arg: IFSFile.CompleterArg] = { request: IORequest; ValidateFile[file]; request _ GetIORequestBlock[]; request^ _ [link: , buffer: buffer, address: PositionToFileAddress[pos], op: read, bytesToGo: bytes, proc: callback, arg: arg]; DoRead[file, request]; }; StartWrite: PUBLIC PROC [file: FileHandle, pos: IFSFile.Position, bytes: IFSFile.ByteCount, buffer: IFSFile.Buffer, callback: IFSFile.Completer, arg: IFSFile.CompleterArg] = { request: IORequest; ValidateFile[file]; request _ GetIORequestBlock[]; request^ _ [link: , buffer: buffer,address: PositionToFileAddress[pos], op: write, bytesToGo: bytes, proc: callback, arg: arg]; DoWrite[file, request]; }; DoRead: PUBLIC PROC [file: FileHandle, request: IORequest] = { sequinBuffer: Sequin.Buffer _ Sequin.GetEmptyBuffer[]; sequinRequest: Leaf.Request _ LOOPHOLE[sequinBuffer.data]; AcquireIOLock[file]; EnqueueRequest[file, request]; sequinRequest^ _ [op: Leaf.readOp, opSpecific: read[handle: file.leafHandle, address: request.address, length: request.bytesToGo]]; sequinBuffer.nBytes _ Leaf.readOp.length; Sequin.Put[file.sequin, sequinBuffer ! Sequin.Broken => CONTINUE]; ReleaseIOLock[file]; }; DoWrite: PUBLIC PROC [file: FileHandle, request: IORequest] = { OPEN IFSFile; bytesSent: Leaf.ByteCount _ 0; bytesToGo: Leaf.ByteCount = request.bytesToGo; initialPosition: Position = FileAddressToPosition[request.address]; positionAfterWrite: Position = initialPosition + request.bytesToGo; AcquireIOLock[file]; IF file.length < positionAfterWrite THEN file.length _ positionAfterWrite; EnqueueRequest[file, request]; DO positionThisTime: Position = initialPosition + bytesSent; buffer: Sequin.Buffer _ Sequin.GetEmptyBuffer[]; sequinRequest: Leaf.WriteRequest _ LOOPHOLE[buffer.data]; bytesThisTime: Leaf.ByteCount; buffer.nBytes _ Leaf.writeOp.length; bytesThisTime _ MIN[buffer.maxBytes - buffer.nBytes, bytesToGo - bytesSent]; sequinRequest^ _ [op: Leaf.writeOp, opSpecific: write[handle: file.leafHandle, address: PositionToFileAddress[positionThisTime, request.address.opSpecific], length: bytesThisTime, writeBody: ]]; [] _ PrincOpsUtils.ByteBlt[ to: [blockPointer: @sequinRequest.writeBytes, startIndex: 0, stopIndexPlusOne: bytesThisTime], from: [blockPointer: request.buffer, startIndex: bytesSent, stopIndexPlusOne: bytesSent+bytesThisTime]]; sequinRequest.op.length _ buffer.nBytes _ buffer.nBytes + bytesThisTime; Sequin.Put[file.sequin, buffer ! Sequin.Broken => EXIT]; bytesSent _ bytesSent + bytesThisTime; IF bytesSent = bytesToGo THEN EXIT; ENDLOOP; ReleaseIOLock[file]; }; FileWatcher: PUBLIC PROC [file: FileHandle] RETURNS [BOOL] = { current: IORequest _ NIL; fatalError: BOOL _ FALSE; offset: CARDINAL; DO buffer: Sequin.Buffer; outcome: IFSFile.Problem; CheckState: ENTRY PROC [file: FileHandle] RETURNS [FileState] = { DO SELECT file.state FROM alive => IF fatalError THEN file.state _ flush; flush => NULL; closing => { IF file.ioPending = NIL THEN {file.state _ closed; BROADCAST file.ioSynch}; EXIT }; ENDCASE; IF file.ioPending ~= NIL THEN EXIT; WAIT file.ioSynch; ENDLOOP; RETURN[file.state] }; CompleteRequest: PROC = { request: IORequest = DequeueRequest[file]; request.proc[request.arg, outcome]; FreeIORequestBlock[request]; current _ NIL; }; SELECT CheckState[file] FROM alive => { answer: Leaf.Answer; position: IFSFile.Position; EnsureCurrent: ENTRY PROC [file: FileHandle] = { IF current ~= NIL THEN RETURN; IF file.ioPending = NIL THEN ERROR TheWellIsDry; current _ file.ioPending.link; position _ FileAddressToPosition[current.address]; offset _ 0; }; ValidateArrival: PROC [address: Leaf.FileAddress, bytes: Leaf.ByteCount] = { pos: IFSFile.Position = FileAddressToPosition[address]; IF current.op = answer.op.type AND pos = position THEN { outcome _ ok; current.bytesToGo _ current.bytesToGo - bytes; position _ position + bytes; } ELSE fatalError _ TRUE; }; EnsureCurrent[file]; outcome _ other; buffer _ Sequin.Get[file.sequin ! Sequin.Broken => {outcome _ io; fatalError _ TRUE; LOOP}]; answer _ LOOPHOLE[buffer.data]; IF answer.op.sense ~= reply THEN GO TO protocolViolation; WITH ans: answer SELECT answer.op.type FROM error => { IF current.op ~= ans.errorOp.type THEN GO TO protocolViolation; SELECT ans.error FROM accessDenied, fileBusy, IN [userName .. connectPassword] => outcome _ credentials; allocExceeded, fileSystemFull => outcome _ resources; brokenLeaf => {outcome _ io; GO TO broken}; illegalRead, illegalWrite => outcome _ illegalIO; IN [unimplementedOp..illegalTruncate] => ERROR LeafGibberish; ENDCASE; current.bytesToGo _ 0; }; read => { dataBytes: Leaf.ByteCount = ans.op.length - Leaf.readAns.length; ValidateArrival[ans.address, dataBytes]; [] _ PrincOpsUtils.ByteBlt[ to: [blockPointer: current.buffer, startIndex: offset, stopIndexPlusOne: offset+dataBytes], from: [blockPointer: @ans.readBytes, startIndex: 0, stopIndexPlusOne: dataBytes]]; offset _ offset + dataBytes; }; write => ValidateArrival[ans.address, ans.length]; ENDCASE => GO TO protocolViolation; IF current.bytesToGo = 0 THEN CompleteRequest[]; Sequin.ReleaseBuffer[buffer]; EXITS protocolViolation, broken => {fatalError _ TRUE; Sequin.ReleaseBuffer[buffer]}; }; flush => CompleteRequest[]; closing => {outcome _ other; CompleteRequest[]}; closed => EXIT; ENDCASE; ENDLOOP; RETURN[~fatalError] }; ValidateFile: PUBLIC PROC [file: FileHandle] = {IF file.seal ~= openSeal THEN ERROR InvalidFile}; FileAddressToPosition: PUBLIC PROC [fa: Leaf.FileAddress] RETURNS [pos: IFSFile.Position] = { Flip: PROC [Leaf.FileAddress] RETURNS [IFSFile.Position] = MACHINE CODE { PrincOps.zEXCH; }; fa.opSpecific _ Leaf.OpSpecificFileAddress[open[fill: IF fa.high > 1777B THEN 37B ELSE 0]]; RETURN[Flip[fa]] }; PositionToFileAddress: PUBLIC PROC [ pos: IFSFile.Position, opSpecific: Leaf.OpSpecificFileAddress _ [read[]]] RETURNS [fa: Leaf.FileAddress] = { Flip: PROC [IFSFile.Position] RETURNS [Leaf.FileAddress] = MACHINE CODE { PrincOps.zEXCH; }; fa _ Flip[pos]; fa.opSpecific _ opSpecific; }; AcquireIOLock: ENTRY PROC [file: FileHandle] = { WHILE file.locked DO WAIT file.ioSynch ENDLOOP; file.locked _ TRUE; }; ReleaseIOLock: ENTRY PROC [file: FileHandle] = { file.locked _ FALSE; BROADCAST file.ioSynch; }; EnqueueRequest: ENTRY PROC [file: FileHandle, request: IORequest] = { IF file.ioPending = NIL THEN request.link _ request ELSE {request.link _ file.ioPending.link; file.ioPending.link _ request}; file.ioPending _ request; BROADCAST file.ioSynch; }; DequeueRequest: ENTRY PROC [file: FileHandle] RETURNS [request: IORequest] = { IF file.ioPending = NIL THEN ERROR TheWellIsDry; request _ file.ioPending.link; file.ioPending.link _ request.link; IF request = file.ioPending THEN file.ioPending _ NIL; }; }. ¨IFSFileImplC.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Levin - 14-Sep-81 13:51:35 Russ Atkinson, March 7, 1985 2:19:32 pm PST Miscellaneous Procedures, Types, and Signals Exported to IFSFile Procedures Exported to IFSFilePrivate Note: regards 'fa' as a signed quantity (to allow leader page access). Note: regards 'pos' as a signed quantity (to allow leader page access). Internal Procedures ÊÕ˜codešœ™Kšœ Ïmœ1™K˜6Kšœžœ˜:K˜K˜˜˜˜CK˜———K˜)Kšœ8žœ˜BK˜Kšœ˜K˜—šŸœžœžœ+˜?Kšžœ ˜ K˜K˜.K˜CK˜CK˜Kšžœ"žœ"˜JK˜šž˜K˜9K˜0Kšœ#žœ˜9K˜K˜$Kšœžœ9˜L˜K˜=K˜MK˜%—˜˜-K˜0—˜$K˜C——K˜HKšœ2žœ˜8K˜&Kšžœžœžœ˜#Kšžœ˜—K˜Kšœ˜K˜—š Ÿ œžœžœžœžœ˜>Kšœžœ˜Kšœ žœžœ˜Kšœžœ˜šž˜K˜K˜K˜šŸ œžœžœžœ˜Ašž˜šžœ ž˜Kšœ žœ žœ˜/Kšœ žœ˜šœ ˜ Kšžœžœžœž œ˜KKšž˜Kšœ˜—Kšžœ˜—Kšžœžœžœžœ˜#Kšžœ˜Kšžœ˜—Kšžœ ˜Kšœ˜K˜—šŸœžœ˜K˜*K˜#K˜Kšœ žœ˜Kšœ˜K˜—šžœž˜šœ ˜ K˜K˜K˜šŸ œžœžœ˜0Kšžœ žœžœžœ˜Kšžœžœžœžœ˜0K˜K˜2K˜ Kšœ˜K˜—šŸœžœ7˜LK˜7šžœžœžœ˜8K˜ K˜.K˜Kšœ˜—Kšžœžœ˜Kšœ˜K˜—K˜K˜˜2Kšœžœžœ˜)—Kšœ žœ˜Kšžœžœžœžœ˜9šžœ žœž˜+šœ ˜ Kšžœ žœžœžœ˜?šžœ ž˜K˜Kšžœ8˜:K˜5Kšœžœžœ ˜+K˜1Kšžœ'žœ˜=Kšžœ˜—K˜Kšœ˜—šœ ˜ K˜@K˜(˜˜"K˜8—˜$K˜-——K˜Kšœ˜—K˜2Kšžœžœžœ˜#—Kšžœžœ˜0K˜šž˜˜Kšœžœ ˜2——Kšœ˜—K˜K˜0Kšœ žœ˜Kšžœ˜—Kšžœ˜—Kšžœ ˜Kšœ˜K˜—šŸ œžœžœ˜.Kšœžœžœžœ˜2K˜—šŸœžœžœžœ˜]KšœG™GšŸœžœžœ˜:Kšžœžœ˜!—Kšœ6žœžœžœ˜[Kšžœ ˜Kšœ˜K˜—šŸœžœžœLžœ˜‘KšœH™HšŸœžœžœ˜:Kšžœžœ˜!—K˜K˜Kšœ˜K˜K˜——šœ™K˜šŸ œžœžœ˜0Kšžœ žœžœžœ˜/Kšœžœ˜Kšœ˜K˜—šŸ œžœžœ˜0Kšœžœ˜Kšž œ˜Kšœ˜K˜—šŸœžœžœ+˜EKšžœžœžœ˜3KšžœE˜IK˜Kšž œ˜Kšœ˜K˜—šŸœžœžœžœ˜NKšžœžœžœžœ˜0K˜K˜#Kšžœžœžœ˜6Kšœ˜K˜—Kšœ˜K˜——…—'ƒ