// FileIOSubrs.bcpl
// Last change August 2, 1981 12:43 AM by Beau Sheil
// Tone change March 17, 1981 4:49 PM by Beau Sheil
// Chord change November 20, 1980 2:52 PM by Beau Sheil
// Previous last change August 18, 1980 12:31 PM by Beau Sheil
get "AltoFileSys.d"
get "Disks.d"
get "LispBcpl.decl"
get "Stats.decl"
get "Streams.d"
external [ // defined here
AddDISKPAGES; CREATEFILE0; GETPAGEHINT; READDISKPAGE
RELEASEPAGES; WRITEDISKPAGE; COPYSYS0
OutputStream // used by stats to access log file
// statics used
@lvNIL; @TopLevelFrame
EmuDiskVp; EmuDiskBuffer; sysDisk; LispFmap; @MiscSTATSbase
// O.S. procedures used
Resets; Closes; WriteBlock; Zero; CallSwat; Min; MyFrame
TruncateDiskStream; DeleteDiskPages; PositionPage; SetBlock
CreateDiskFile; CreateDiskStream; ActOnDiskPages; WriteDiskPages
// procedures used
@BGetBase; @BSetBR; @XSetBR; @RRead; @RWrite; @XGetBase; @XPutBase
EqNIL; IGetBase; IPutBase; Timer; WriteStatsX; RAIDCode
SmallUnbox; SmallNegUnbox; MkSmallPos; MkSmallNeg
VP; MovePage; SysErr; IndexedPageIO; FlushVM; MakeVmemRO
]
let AddDISKPAGES(lvFid, lvPn, lvNpages, lvAptr) = valof
[
let fp = vec lFP; GetFptrArg(lvFid, fp)
// lvPn is first page to write, but since lisp numbers pages with leader
// page = -1, lvPn=lastKnown page for the BFS and ge 0, since even empty
// files contain one data page
let lastKnown = SmallUnbox(lvPn)
XSetBR(lvAptr)
let DAs = vec 102
DAs!0 = RRead(lastKnown-1); DAs!1 = fillInDA
[
let nC = 0 // number of Chars
// read last page so we can write it back with new next page addr in label
ActOnDiskPages(sysDisk, 0, DAs-lastKnown, fp, lastKnown, lastKnown,
DCreadD, lv nC, 0, EmuDiskBuffer, 0, lv HintError, false, lastKnown)
// BFS does not zero page trailers as Lisp requires if included in file.
let nW = nC rshift 1 // number of words used
Zero(EmuDiskBuffer+nW, WordsPerPage-nW)
]
// CA and DA format: last but 1 page, last page, 100 new pages, dummy entry
let ca = vec WordsPerPage-1; Zero(ca, WordsPerPage)
let CAs = vec 102; SetBlock(CAs, ca, 103)
CAs!1 = EmuDiskBuffer // old last page data
let nPages = SmallUnbox(lvNpages)
while nPages gr 0 do
[
let dopages = (nPages gr 100 ? 100, nPages)
let lastPage = lastKnown + dopages
DAs!0 = lastKnown gr 1 ? RRead(lastKnown-2), fp>>FP.leaderVirtualDa
DAs!1 = RRead(lastKnown-1); SetBlock(DAs+2, fillInDA, dopages+1)
WriteDiskPages(sysDisk, CAs+1-lastKnown, DAs+1-lastKnown, fp, lastKnown,
lastPage, DCwriteD, 0, 0, 0, 0, lv HintError, 0, lastKnown)
for i = 2 to dopages+1 do RWrite(lastKnown+i-2, DAs!i)
CAs!1 = ca // page of zeroes now
lastKnown = lastKnown + dopages
nPages = nPages - dopages
]
resultis lvNIL
]
and CREATEFILE0(lvFptr, makeDir) = valof
[
let dir = 0
unless EqNIL(makeDir) do dir<<SN.directory = 1
let fp = vec lFP
CreateDiskFile(sysDisk,"$.",fp,0,dir)
SetFptrArg(lvFptr,fp)
resultis lvFptr
]
and GETPAGEHINT(lvFid, lvPn, lvNpages, lvAptr) = valof
[
let fp = vec lFP; GetFptrArg(lvFid, fp)
XSetBR(lvAptr)
let apn = MakeBFSPageN(lvPn)
let DAs = vec 101
DAs!0 = apn ? RRead(apn-1), fp>>FP.leaderVirtualDa
let nPages = SmallUnbox(lvNpages)
let pagesLeft = nPages
let donePages = 0
while pagesLeft gr 0 do
[
SetBlock(DAs+1, fillInDA, 101)
let nPagestoRead = (pagesLeft gr 100 ? 100, pagesLeft)
pagesLeft = pagesLeft - nPagestoRead
let lastPageRead =
ActOnDiskPages(sysDisk, 0, DAs-apn, fp, apn, apn+nPagestoRead,
DCreadD, 0, 0, EmuDiskBuffer, 0, lv HintError)
// write DAs into Aptr - adjust page numbers for LISP
for i = apn+1 to lastPageRead do RWrite(i-1, DAs!(i-apn))
donePages = donePages + lastPageRead - apn
apn = lastPageRead
DAs!0 = RRead(lastPageRead-1)
]
resultis MkSmallPos(donePages)
]
and READDISKPAGE(lvFid, lvPn, lvBptr, lvDA) = valof
[
let fp = vec lFP; GetFptrArg(lvFid, fp)
let apn = MakeBFSPageN(lvPn)
let DAs = vec 1; DAs!1 = fillInDA
DAs!0 = apn ? SmallUnbox(lvDA), fp>>FP.leaderVirtualDa
let lvNumChars = vec 1
unless EqNIL(lvBptr) do
[ if lvBptr>>VA.wordN ne 0 then RAIDCode("Not page aligned", lvBptr)
XPutBase(lvBptr, 0) // write ref the page buffer
]
// Necessary to do XPutBase before ActOnDiskPages
// because faulting might cause disk action
ActOnDiskPages(sysDisk, 0, DAs-apn, fp, apn, apn,
DCreadD, lvNumChars, 0, EmuDiskBuffer, 0, lv HintError)
unless EqNIL(lvBptr) do MovePage(VP(lvBptr), EmuDiskVp)
resultis MkSmallPos(lvNumChars!0)
]
// Releases pages of Fid, starting at page pn.
// Can be used to delete a whole file
and RELEASEPAGES(lvFid, lvPn, lvDA) = valof
[
let fp = vec 5; GetFptrArg(lvFid, fp)
let apn = MakeBFSPageN(lvPn)
let DA = apn ? SmallUnbox(lvDA), fp>>FP.leaderVirtualDa
DeleteDiskPages(sysDisk, EmuDiskBuffer, DA, fp, apn)
resultis lvNIL
]
and WRITEDISKPAGE(lvFid, lvPn, lvBptr, lvDA, lvNbytes) = valof
[
let fp = vec lFP; GetFptrArg(lvFid, fp)
let apn = MakeBFSPageN(lvPn)
let DAs = vec 2; DAs!0, DAs!2 = fillInDA, fillInDA
DAs!1 = apn ? SmallUnbox(lvDA), fp>>FP.leaderVirtualDa
if lvBptr>>VA.wordN ne 0 then RAIDCode("Not page aligned", lvBptr)
XGetBase(lvBptr) // read ref the page buffer!!
let n = SmallUnbox(lvNbytes)
MovePage(EmuDiskVp, VP(lvBptr))
WriteDiskPages(sysDisk, 0, DAs-apn+1, fp, apn, apn, DCwriteD,
0, n, EmuDiskBuffer, 0, lv HintError)
resultis lvNbytes
]
and MakeBFSPageN(lvPn) =
(lvPn>>VA.vahi eq SMALLPOSspace) ?
lvPn>>VA.valo + 1, // lisp starts pns at -1 for leader page
(SmallNegUnbox(lvPn) eq -1 ? 0, RAIDCode("Invalid page #", lvPn) )
and GetFptrArg(lvFptr, f) be
[
XSetBR(lvFptr)
for i = 0 to lFP-1 do f!i = RRead(i)
]
and SetFptrArg(lvFptr, f) be
[
XSetBR(lvFptr)
for i = 0 to lFP-1 do RWrite(i, f!i)
]
and HintError(s, cb, code) = valof // BFS errors - diff args from SysErr
[
MyFrame()!0 = TopLevelFrame // set return addr to return from SUBR
resultis selecton code into // error code switch
[ case 1102: MkSmallNeg(-22) // error 22 if disk full
case 1105: MkSmallNeg(-41) // error 41 if protected
default: SysErr(0, code) ]
]
and OutputStream(lvFid) = valof
[
let fp = vec lFP; GetFptrArg(lvFid, fp)
let st = CreateDiskStream(fp, ksTypeWriteOnly, wordItem, 0, StreamError)
unless st do RAIDCode("Cant create stream", lvFid)
resultis st
]
and COPYSYS0(lvFid) = valof
[
FlushVM()
let st = OutputStream(lvFid)
Zero(EmuDiskBuffer, WordsPerPage)
WriteBlock(st, EmuDiskBuffer, WordsPerPage) // page 1 <- isf index page
let pvec = vec 4*WordsPerPage
let Last = IGetBase(IFPNActivePages) + FirstVmemBlock - 1
let i = FirstVmemBlock
[ let np = Min(Last - i, 4)
IndexedPageIO(LispFmap, i, pvec, np, 1)
WriteBlock(st, pvec, np*WordsPerPage)
i = i + np
] repeatuntil i ge Last
TruncateDiskStream(st) // in case using old file
Resets(st); Closes(st)
MakeVmemRO()
resultis lvNIL
]
and StreamError(s, code) = HintError(s, 0, code) // adjust args for HE