// IfsLeafRead.bcpl - Leaf Read - SWAPPABLE // Copyright Xerox Corporation 1979, 1981, 1982 // Last modified April 9, 1982 12:49 PM by Taft get FD, mode, modeReadWrite, modeWrite, modeReadWriteShared from "IfsDirs.decl" get ecIllegalLeafRead, ecLeafFileTooLong from "IfsLeafErrors.decl"; get "IfsLeaf.decl"; get "IfsSequin.decl"; external [ //outgoing procedures SetModeLength; ReadLeaf; //incoming procedures AnswerSetOp; ByteBlt; CheckHandle; DoubleAdd; DoubleDifference; DoubleIncrement; DoubleSubtract; DoubleUsc; LeafError; LeafGetPage; Umin; MoveBlock; Zero; ] //---------------------------------------------------------------------------- let ReadLeaf(sequin, answerPBI, op) = valof //---------------------------------------------------------------------------- [ let fh = CheckHandle(sequin, answerPBI, op); let address = lv op>>FileRequest.address; let contentEvenLength = ((answerPBI>>PBI.pup.length + 1) & -2) - pupOvBytes; let answer = lv answerPBI>>PBI.pup.words + contentEvenLength/2; let pupDataMax = sequin>>Sequin.pupDataBytes - readAnswerOv; let readLength = Umin(Umin(bytesPerUserPage, pupDataMax), op>>FileRequest.length) if readLength ugr (pupDataMax-contentEvenLength) then resultis leafOpPupFull; unless SetModeLength(op, fh, false, lv readLength) do resultis LeafError(answerPBI, op, ecIllegalLeafRead); let readByte = address>>LeafAddress.low & bytesPerPage-1 let readPage = address>>LeafAddress.highAddr lshift logPagesPerWord + address>>LeafAddress.low rshift logBytesPerPage let firstLength = (readByte + readLength ule bytesPerPage ? readLength, bytesPerPage - readByte) let pageAddress = LeafGetPage(fh>>FH.lvmd, readPage + 1, cleanPage); if pageAddress eq 0 then resultis LeafError(answerPBI, op, ecLeafFileTooLong); ByteBlt(lv answer>>FileAnswer.words, 0, pageAddress, readByte, firstLength) if readLength ugr firstLength then [ pageAddress = LeafGetPage(fh>>FH.lvmd, readPage + 2, cleanPage); if pageAddress eq 0 then resultis LeafError(answerPBI, op, ecLeafFileTooLong); ByteBlt(lv answer>>FileAnswer.words, firstLength, pageAddress, 0, readLength - firstLength) ] //no thirds allowed (since bytesPerPage >= bytesPerPup) AnswerSetOp(answerPBI, op, readAnswerOv + readLength); MoveBlock(lv answer>>FileAnswer.address, address, size FileAnswer.address/bitsPerWord + size FileAnswer.length/bitsPerWord); DoubleIncrement(address, readLength); address>>LeafAddress.signExtend = 0; op>>FileRequest.length = op>>FileRequest.length - readLength; resultis (op>>FileRequest.length eq 0? leafOpComplete, leafOpPupNotFull); ] //---------------------------------------------------------------------------- and SetModeLength(op, fh, writeFlag, lvLength; numargs na) = valof //---------------------------------------------------------------------------- [ if na ls 4 then lvLength = lv op>>FileRequest.length; let lastAddress = lv fh>>FH.lvmd>>LVMD.lastAddress let maxAddress = table [ #3777; #174000; ] // 2**27 - 2048 words of address let length = op>>FileRequest.length; let address = lv op>>FileRequest.address; let mode = address>>LeafAddress.mode; let readOnly = true; let noNewEOFs = true; switchon fh>>FH.fd>>FD.mode into [ case modeWrite: case modeReadWrite: noNewEOFs = false; case modeReadWriteShared: readOnly = false; default: endcase; ] let newEOF = address>>LeafAddress.newEOF; address>>LeafAddress.signExtend = 0; let funnyAddress = DoubleUsc(address, maxAddress) ge 0; if funnyAddress then [ //** writes cannot occur on the first 3/4 of the IFS leader page unless //** the special change create date and type hack is being invoked... if writeFlag & address!1 uls -512 then [ let leaderPagePos = address!1 + bytesPerPage; unless (leaderPagePos eq offset ILD.created/8 & length eq 2*lTIME) % (leaderPagePos eq offset ILD.type/8 & length eq 4) do resultis false; ] address>>LeafAddress.signExtend = -1; ] let nextAddress = vec 1; nextAddress!0 = 0; nextAddress!1 = length; DoubleAdd(nextAddress, address); let extendEOF = (DoubleDifference(lastAddress, nextAddress) & signBit) ne 0; // Check here to see: // 1) if trying to write onto anywhere but the leaderpage in readOnly mode. // 2) if trying to set newEOF in readOnly or on leaderpage. // Make 'writes' mean writes to file data itself. if funnyAddress & nextAddress!1 le 0 then writeFlag = false; if (readOnly & writeFlag) % (newEOF & (noNewEOFs % nextAddress!0 ls 0)) then resultis false; switchon mode into [ case checkExtend: if extendEOF then resultis false; endcase; case dontExtend: if extendEOF then [ let difference = vec 1; nextAddress = lastAddress; MoveBlock(difference, lastAddress, 2); DoubleSubtract(difference, address); test difference!0 eq 0 ifso length = difference!1; ifnot [ MoveBlock(address, lastAddress, 2); length = 0; ] if @lvLength ugr length then @lvLength = length; op>>FileRequest.length = length; ] endcase; case noHoles: if (DoubleDifference(lastAddress, address) & signBit) ne 0 then resultis false; case anywhere: unless extendEOF do endcase; if noNewEOFs resultis false; // Only allow extends in write mode. if (DoubleDifference(maxAddress, nextAddress) & signBit) ne 0 then resultis false; ] if writeFlag then fh>>FH.lvmd>>LVMD.written = true; if newEOF % extendEOF then MoveBlock(lastAddress, nextAddress, 2); address>>LeafAddress.signExtend = 0; address>>LeafAddress.newEOF = DoubleUsc(lastAddress, nextAddress) eq 0; // use newEOF to report whether address plus length equals last address resultis true; ]