-- File TfsCreate.mesalast edited August 6, 1982 11:16 AM by GWilliams
--tuned up Delete pages
DIRECTORY
InlineDefs: FROM "inlinedefs" USING [COPY, BITAND, BITOR, BITNOT],
MiscDefs: FROM "miscdefs" USING [Zero, DAYTIME, SetBlock],
StringDefs: FROM "stringdefs" USING[AppendChar, BcplSTRING, MesaToBcplString],
TridentDefs: FROM "tridentdefs" USING [CheckDirectory, dcReadHLD, dcReadnD, dcWriteD, ddMgrPtr, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, DV, eofDA, fillInDA, FP, freePageFP, lFP, LD, lSN, NoopTfsCleanupRtn, oneBits, PAGE, TfsActOnPages, tfsdskPtr, TfsLockDD, TfsReadDDPage, TfsUnlockDD, TFSwordsPerPage, TfsWritePages, VDA, WordNumInPage];

TfsCreate: PROGRAM
IMPORTS MiscDefs, TridentDefs, InlineDefs, StringDefs
EXPORTS TridentDefs =

BEGIN OPEN MiscDefs, TridentDefs, InlineDefs, StringDefs;

TfsCreateFile: PUBLIC PROCEDURE [tfsDsk: tfsdskPtr, name: STRING, filePtr, dirFP: POINTER TO FP, word1: WORD, useOldFP: BOOLEAN, pageBuf: POINTER TO LD] =

BEGIN

-- Create a file by writing the Leader Page and and 1st data page for it. IF
-- useOldFP is TRUE, then use the pages of an existing file, but change the File
-- Pointer(FP). IF pageBuf is not NIL, then it is used as a buffer and the last
-- 3/4 of its contents are written onto the Leader Page

buffer: LD;-- buffer for a leader page
oldFP: FP;
caS: DESCRIPTOR FOR ARRAY OF POINTER;
daS: DESCRIPTOR FOR ARRAY OF PAGE;
pages: ARRAY [-1..3) OF PAGE;
--pagPtr: POINTER TO ARRAY [-1..3) OF PAGE;
da: PAGE;-- 1st disk address of new file
numCharsPtr: POINTER;
numChars: CARDINAL;
dummy: UNSPECIFIED;

-- See if we have been passed a Leader Page buffer

IF pageBuf = NIL THEN pageBuf ← @buffer;-- Use our own buffer
COPY[filePtr, lFP, @oldFP];-- Save FP of old file

--
Make a new File Pointer

Zero[filePtr, lFP];-- Clear FP passed to us
filePtr.version ← 1;
IF (tfsDsk.tfskd.kdh.lastSn.part2 ← tfsDsk.tfskd.kdh.lastSn.part2 + 1) = 0 THEN
tfsDsk.tfskd.kdh.lastSn.part1 ← tfsDsk.tfskd.kdh.lastSn.part1 +1;
COPY[@tfsDsk.tfskd.kdh.lastSn, lSN, @filePtr.serialNumber];
filePtr.serialNumber.word1 ← BITOR[filePtr.serialNumber.word1,word1];

--Make an array of disk addresses
pages[-1] ← pages[2] ← eofDA;
pages[0] ← pages[1] ← fillInDA;
--pagPtr ← @pages;
--
pagPtr ← pagPtr + 2;
daS ← DESCRIPTOR[@pages[0], 3];

--If we’re using an existing file, ’rename’ it
IF useOldFP THEN-- (bitmap won’t be affected)
BEGIN
da ← oldFP.leaderVirtualDA;-- 1st page of file
TfsDeletePages[tfsDsk, pageBuf, da, oldFP, filePtr↑, 0, 0];
daS[0] ← da;-- 1st page, new file (we want pages[0])
END;

--Set up the Leader Page
Zero[pageBuf, 256];-- Clear 1st 1/4 of the page
pageBuf.created ← DAYTIME[];-- Store creation date
MesaToBcplString[name, LOOPHOLE[@pageBuf.name]];-- Make a BCPL string
IF dirFP # NIL THEN COPY[dirFP, lFP, @pageBuf.dirFp];--Put in directory hint
pageBuf.propertyBegin ← @pageBuf.leaderProps[0] - @pageBuf.created.high;
-- pageBuf.propertyBegin ← 3*lTIME + maxLengthFnInWords;
pageBuf.propertyLength ← LENGTH[pageBuf.leaderProps];

--Write the leader and first data page
numCharsPtr ← @numChars;
IF useOldFP THEN
[] ← TfsActOnPages [tfsDsk, caS, daS, filePtr↑, 0, 1, dcWriteD,
numCharsPtr, dcWriteD, pageBuf, NoopTfsCleanupRtn,DefaultTfsErrorRtn,FALSE,0]
ELSE
[] ← TfsWritePages [tfsDsk, caS, daS, filePtr↑, 0, 1, dcWriteD,
NIL, 0, pageBuf, dummy, DefaultTfsErrorRtn, dummy, 0];
--
[] ← TfsWritePages [tfsDsk, caS, daS, filePtr↑, 0, 1, dcWriteD,
--
NIL, 0, pageBuf, dummy, DefaultTfsErrorRtn, dummy, 0];

filePtr.leaderVirtualDA ← daS[0];-- Modify file pointer

END;
-- of TfsCreateFile

TfsDeleteFile
: PUBLIC PROCEDURE[tfsDisk: tfsdskPtr, fileName: STRING]
RETURNS[found: BOOLEAN ← FALSE]=
BEGIN
-- Search the file SysDir sequentially for fileName. If found, delete the name from sysdir and reset all the file’s labels to free.
sysBuf: ARRAY [0..1024) OF WORD;-- Input buffer
overSysPtr, sysPtr: POINTER TO WORD;-- Pointer to sysBuf
pag: CARDINAL;-- page counter
tempSiz, siz: CARDINAL;-- where we are in a page
dirPtr: POINTER TO DV;-- pointer to directory entry
pages: ARRAY [0..30) OF PAGE;-- SysDir’s pages
dAs: DESCRIPTOR FOR ARRAY OF PAGE;
cAs: DESCRIPTOR FOR ARRAY OF POINTER;
numChars: INTEGER ← 2048;--TfsActOnPages never writes this # of chars:
numCharsPtr: POINTER ← @numChars;--only fills it during read
fpTfsSysdir: FP ← tfsDisk.tfskd.fpTFSSysDir;-- file pointer for Sysdir
overFlag: BOOLEAN ← FALSE;-- directory entry overflowed a page
dirEntry: DV;-- directory entry
dirEntryPtr: POINTER TO DV;--for resetting type field in buffer


-- Build the Array of diskaddresses for SysDir
SetBlock[@pages[0], fillInDA, 29];
dAs ← DESCRIPTOR[@pages[1], 27];
dAs[0] ← 1;
dAs[1] ← 2;

-- Fix up the filename STRING, initialize for create mode
IF fileName[fileName.length-1] # ’.
THEN AppendChar[fileName, ’.];-- Argument has been altered, OK?

-- Read the first page of Sysdir
[]←TfsActOnPages[tfsDisk,cAs,dAs,fpTfsSysdir,1,1,dcReadHLD,numCharsPtr,dcReadHLD,@sysBuf, DefaultTfsCleanupRtn, DefaultTfsErrorRtn,FALSE,0];

-- search Sysdir sequentially for fileName
pag ← 1;-- page counter
sysPtr ← @sysBuf[0];-- input Buffer
overFlag ← FALSE;-- overflow flag

-- Two loops: the first handles pages, 2nd directory entries within a page
-- N.B.: Rather than read the file of headers, or read the header page for hintLastPage, read on page at a time, letting the called code fill
--
in the next disk address until it hits EOF
UNTIL pag >= 27 DO
siz ← 0;-- size of current page
sysPtr ← @sysBuf[0];-- re-init pointer to buffer
IF overFlag THEN-- see if we’re doing a split entry
BEGIN
COPY[sysPtr, tempSiz, dirPtr];-- copy in the rest of the entry
siz ← siz + tempSiz;
sysPtr ← sysPtr + tempSiz;-- point to next entry
found←CheckDirectory[fileName,dirEntry];-- see if this is it
IF foundTHEN EXIT--save state of overFlag so as to reset correct page.
ELSE overFlag ← FALSE;-- otherwise reset flag for next iter
END;

DO-- look at directory entries in a page

COPY[sysPtr, 26, @dirEntry];-- copy in the next entry
IF dirEntry.length + siz > 1024 THEN
BEGIN-- entry spills onto next page
dirPtr ← @dirEntry + 1024 - siz;
tempSiz ← dirEntry.length-(1024-siz);-- and amount left over
overSysPtr ← sysPtr;
overFlag ← TRUE;-- set the overflow flag
EXIT;--NB: looks like we’ll never create an entry on page bounds with
--this logic. Go read next page
END;

found←CheckDirectory[fileName,dirEntry];-- check this directory entry
IF found THEN EXIT;-- finished if TRUE

--fix directory if no good
IF dirEntry.type = 0 AND dirEntry.length = 0 AND siz<TFSwordsPerPage
THEN
{dirEntry.length ← TFSwordsPerPage-siz;--mal-formed directory, fix up.
COPY [@dirEntry, TFSwordsPerPage-siz, sysPtr];--re-set the length
};

sysPtr ← sysPtr + dirEntry.length;-- point to next entry (source)
siz ← siz + dirEntry.length;-- add size of next entry
IF siz >= 1024 THEN EXIT;-- can’t have an overflow
ENDLOOP;

IF (found) OR dAs[pag] = eofDA THEN EXIT;-- finished if TRUE or EOF
pag ← pag + 1;
[]←TfsActOnPages[tfsDisk,cAs,dAs,fpTfsSysdir,pag,pag,dcReadHLD,
numChars
Ptr,dcReadHLD,@sysBuf,DefaultTfsCleanupRtn,DefaultTfsErrorRtn,FALSE,0];
ENDLOOP;


IF ~found THEN RETURN [FALSE];
dirEntryPtr ← LOOPHOLE[sysPtr];
IF overFlag
THEN--the page that has the header is on disk. Read it in.
{pag ← pag-1;
[] ←TfsActOnPages[tfsDisk,cAs,dAs,fpTfsSysdir,pag,pag,dcReadHLD, numCharsPtr, dcReadHLD, @sysBuf,
DefaultTfsCleanupRtn, DefaultTfsErrorRtn, FALSE, 0];
dirEntryPtr ← LOOPHOLE[overSysPtr];
};

dirEntryPtr.type ← 0;
--that’s all it takes to delete an entry from sysdir.
--write the page back into sysdir.
[] ← TfsActOnPages[tfsDisk, cAs, dAs, fpTfsSysdir, pag, pag, dcWriteD, numChars
Ptr, dcWriteD, @sysBuf, NoopTfsCleanupRtn,
DefaultTfsErrorRtn, FALSE, 0];

TfsDeletePages[tfsDisk, @sysBuf, dirEntry.fp.leaderVirtualDA, dirEntry.fp, freePageFP, 0, 0];

END;
--of TfsDeleteFile

TfsDeletePages
: PUBLIC PROCEDURE [tfsDsk: tfsdskPtr, cA: POINTER, firstDA: PAGE, fp: FP, newFP: FP ← freePageFP, firstPage, hintLastPage: CARDINAL ← 0] =

--Delete pages starting at firstPage and continue to the end of file. cA points to
-- a page-sized buffer, and newFP, if not NIL, is the ’new’ File Pointer to
-- install (used by TfsCreateFile).

BEGIN

biteSize: CARDINAL = 100;-- maxpages to delete at once
dasLength: CARDINAL ← biteSize+2;
numChars, lastNumChars: CARDINAL ← 0;
i, lastPageFound: CARDINAL;
pages: ARRAY [0..biteSize + 2) OF PAGE;
dAs: DESCRIPTOR FOR ARRAY OF PAGE;

-- Loop until we bump into eofDA
WHILE firstDA # eofDA
DO
dAs ← DESCRIPTOR[((@pages)+1)-firstPage, dasLength];
SetBlock[@pages[0], fillInDA, biteSize+2];-- fill Array w/fillInDA
dAs[firstPage] ← firstDA;

-- Find the last page in the file
lastNumChars ← 0;
lastPageFound ← TfsActOnPages[tfsDsk, NIL, dAs, fp, firstPage, firstPage+ biteSize-1, dcReadnD, @lastNumChars, dcReadnD, cA, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, FALSE, hintLastPage];

-- Write newFP in all the labels (either a real one from TfsCreateFile or
-- freePageFP. Data pages are zeroed in case a file is being renamed.
Zero[cA, TFSwordsPerPage];
[] ← TfsWritePages [tfsDsk, NIL, dAs, newFP, firstPage, lastPageFound, 177777B, NIL, lastNumChars, cA, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, NIL, 0];

-- Alter the bitmap if we are deleting (not renaming) the file.
IF newFP = freePageFP THEN
FOR i IN [firstPage..lastPageFound] DO
TfsReleaseDiskPage[tfsDsk, LOOPHOLE[dAs[i]]];
ENDLOOP;
firstPage ← lastPageFound + 1;
firstDA ← dAs[firstPage];
dasLength ← dasLength + lastPageFound + 1;
ENDLOOP;
END;
-- of TfsDeletePages


TfsReleaseDiskPage: PUBLIC PROCEDURE [tfsDsk: tfsdskPtr, vda: VDA] =

--
Alter the disk’s bit map to show that a page has been released

BEGIN

ddMgr: ddMgrPtr;-- Disk descriptor manager pointer
bufferPtr: POINTER TO ARRAY [0..1024) OF WORD;-- POINTER to buffer
mask: WORD;
wa: WordNumInPage;

ddMgr ← tfsDsk.tfskd.ddMgr;-- Get the DD Manager
TfsLockDD[ddMgr, tfsDsk];-- Lock access to bitmap

--Get the right bitmap page into memory
bufferPtr ← TfsReadDDPage[ddMgr, tfsDsk, vda.pageNum + 2];
--buffer ← bufferPtr↑;

--Turn off the bit corresponding to page being released
wa ← vda.wordNumInPage;-- Extract word number
mask ← oneBits[vda.bitNum];-- 1-bit mask: this page
IF BITAND[bufferPtr[wa], mask] # 0 THEN
{
bufferPtr[wa] ← BITAND[bufferPtr[wa], BITNOT[mask]];-- Turn off the bit
tfsDsk.tfskd.kdh.freePages ← tfsDsk.tfskd.kdh.freePages + 1;
}
ELSE
tfsDsk.tfskd.nBTErrors ← tfsDsk.tfskd.nBTErrors + 1;-- error

-- Note that the bit table is dirty (needs to be written).
TfsUnlockDD[ddMgr, tfsDsk, TRUE];-- ddMgr, diskobject, dirty

END;
-- of TfsReleasePage

END.
-- of TfsCreate
-- File TfsCreate.mesalast edited July 31, 1981 6:23 PM by GWilliams