|
|
DataMuseum.dkPresents historical artifacts from the history of: Bogika Butler |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Bogika Butler Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 110976 (0x1b180)
Types: TextFile
Names: »UNIXFS.SA«
└─⟦311ba069f⟧ Bits:30009789/_.ft.Ibm2.50006625.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »UNIXFS.SA«
└─⟦49237ce80⟧ Bits:30009789/_.ft.Ibm2.50006627.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »UNIXFS.SA«
└─⟦714bbb381⟧ Bits:30009789/_.ft.Ibm2.50006595.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »UNIXFS.SA«
æ*****************************************************************
Copyright 1984 by
NCR Corporation
Dayton, Ohio U.S.A.
All Rights Reserved
******************************************************************
EOS Software produced by:
NCR Systems Engineering - Copenhagen
Copenhagen
DENMARK
*****************************************************************å
æ$H=0å æ no heap space å
OBJECT PROGRAM UnixFs;
æ
U N I X - F S
Change history: 83-09-09, EAR first version
83-09-22, EAR change after inspection
83-09-26, EAR i-node handling
83-10-03, EAR pascal error, fillInoList
83-10-10, EAR sbGate
83-10-14, EAR update super block after getFreeInode
83-10-27, EAR reject -> status on error upd.super block
83-10-28, EAR abort before terminateFao
83-10-31, EAR new proc 'cutFile'
83-11-02, EAR testprint off
83-11-03, EAR re-entrant fao
vers.01.01 83-11-09, EAR allocBlock: VAR fd param (stack overflow)
vers.01.02 83-11-10, EAR automatic call of InitUnixSys
vers.01.03 83-11-21, EAR illegal const value of nicinod
vers.01.04 83-11-23, EAR new entry FStat
vers.01.05 83-11-24, EAR allocBlock, get next free block problem
vers.01.07 83-11-25, EAR releaseBlock, same problem
vers.01.08 83-11-25, ERN write assign to dir allowed, w.o. writeright
vers.01.09 83-11-26, ERN clear fd.iTabÆ*Å.tabÆ*Å in new or emptied fao
also free to allocsize instead of eospos.
vers.01.10 83-11-30, EAR assign: don't create file when readMode
vers.01.11 83-12-01, EAR exclude: moveMan in terminate loop
vers.01.12 83-12-02, EAR in-/exclude: check for space in device name
vers.01.13 83-12-02, EAR assign: create all files with all rights
vers.01.14 83-12-09, EAR fileType, testprint on
vers.01.15 83-12-09, EAR change fileType algorithm
vers.01.16 83-12-21, EAR createLink, error in change filetype
å
CONST
ProcId = 'unixfs vers.01.16 83-12-21 ';
ResultId = 'UNIXFS: sNo OrgSy Au Ar OrgNo Fa Ma';
OrgSys = 4005;
æ
The UNIX FS Module is a low level file system for the UNIX disc format.
UnixFs contains the following entries:
OBJECT UnixFs;
ENTRY Include ( ; devName, rootName Æ, readOnlyÅ );
This procedure includes the disc volume which is currently
placed on the device specified by 'devName'.
The disc volume must contain a UNIX file system, i.e. the
second 512-byte block (block 1) of the disc volume must
contain the so-called "super-block" with a format as
described in "UNIX for the 68000".
The 'rootName' (max 30 chars) is inserted in the device table to
be used as shortcut for the pathName of all files on this disc.
'rootName' need neither be a legal unix path name, nor a filename
on a currently mounted disc, as in a normal unix system. But the
name must be used as prefix of all filenames on that disc (see
also Assign).
ENTRY Assign (ownedFao ; pathName, ioMode Æ, createModeÅ );
Creates a File Access Object (FAO) to the file named by
'pathName'. The disc must have been included previously.
'pathName' is always a full path name, i.e. job handler or
run-time system supplies directory names from root to current
directory:
root / dir1 /.../ dir-n / file
UnixFs maintains a list of root names corresponding to the
devices currently included (see Include). Each name in this
device table is compared to the 'pathName', and the longest
matching name is used as shortcut to the disc. This will
save access to the root device(s), and it will be possible
to remove an "intermediate" disc without destroying the path.
This implies however, that a removable disc can only be accessed
through the path name specified at include, but not through an
arbitrary path ending in the root of the disc as in a normal
unix system.
When a file is to be created, all directories in the path name
must exist. An empty datafile is automatically changed into a
directory file when a file name is linked into it.
The file is reserved according to 'ioMode':
Write reservation demands that no othed FAO have any access to
the same file; read reservation demands only that no other FAO
have write access to the file.
ENTRY Exclude ( ; devName Æ, abortAllowedÅ );
This procedure removes the disc specified by 'devName' from the
system.
The value of the optional parameter 'abortAllowed' determines
the reaction on any open FAO on the disc: If 'abortAllowed'
= 1 all open FAOs on the disc are aborted, and the termination
procedure is called. Otherwise Exclude is rejected if any
open FAO is found. Default is 0.
The Disc Access Object (DAO) corresponding to 'devName' is
deallocated, if the necessary resources are available.
ENTRY CreateLink ( ; pathName, newPathName );
ENTRY DeleteLink ( ; pathName );
OBJECT Fao;
ENTRY ReadSeq ( segment ; byteCount );
This procedure reads one or more bytes from the file starting
in the file position defined by current position. The bytes
are read into the buffer specified by 'segment'. The size of
the buffer defines how many bytes are read. Current position
is updated corresponding to the number of bytes read, and the
parameter 'byteCount' returns this number.
Current position need not point to a page boundary. So the
first and/or last physical blocks read may be shorter than
the page size.
The procedure minimizes the calls to the driver by reading
possibly consecutive physical blocks in one call.
When reaching the logical end-of-file a block shorter than
the buffer may be read, and a correspondingly smaller value
of 'byteCount' is returned. Reading beyond end-of-file but
within the allocation limit returns a 'byteCount' of zero.
An attempt to read beyond the allocation limit is rejected.
This situation can only occur after a seek operation.
The FAO must have read or readWrite reservation, otherwise
the call is rejected.
ENTRY WriteSeq ( segment ; byteCount );
This procedure writes one or more bytes from the buffer
specified by 'segment', into the file from current position
and on. The size of the buffer defines how many bytes are
written. Current position is updated correspondingly.
If the new bytes written exceed the current allocation limit
new physical blocks are allocated automatically, and the
filesize (logical end-of-file) is changed according to the
last byte written.
Current position need not point to a page boundary, so the
first and/or last blocks written may be shorter than the
page size.
This first version of the procedure does NOT minimize the
calls to the driver by writing consecutive physical blocks
in one call.
The FAO must have write or readWrite reservation, otherwise
the call is rejected.
ENTRY ReadRandom ( segment ; byteCount, pos, actualPos );
ENTRY WriteRandom ( segment ; byteCount, pos, actualPos );
ENTRY Seek ( ; baseMode, offset, pos );
ENTRY DataSize ( ; dataBytes );
This procedure cuts the size of the file. In this first
version 'dataBytes' = 0 is the only value allowed.
END Fao;
END UnixFs;
å
æ$Eå
æ$L-å
æ**********************************************************å
æ***** I M P O R T D E S C R I P T I O N S *****å
æ**********************************************************å
æ$F=FAMILY.UNIV.IDå
æ$Eå
æ$F=FAMILY.KNEL.IDå
æ$Eå
æ$F=FAMILY.ALLOC.IDå
æ$Eå
æ$F=FAMILY.SCHED.IDå
æ$Eå
æ$F=FAMILY.OBJDIR.IDå
æ$Eå
æ$F=FAMILY.CLOCK.IDå
æ$Eå
æ$L+å
æ********************************************************å
æ***** E X P O R T D E S C R I P T I O N *****å
æ********************************************************å
æ$F=PRIVATE.UNIXFS.IDå
æ$Eå
æ**********************************************************å
æ***** S T A N D A R D P R O C E D U R E S *****å
æ**********************************************************å
æ$F=PASINCLU.CHKPROCS.SAå
FUNCTION equal (s1, s2 : fullId) : boolean;
VAR
i : integer;
b : boolean;
BEGIN
æ*b* printvar ('equal, s1 = ', s1);
printvar ('s2 = ', s2); *e*å
b := elements(s1) = elements(s2);
i := 1;
WHILE b AND (i <= elements(s1)) DO
BEGIN
b := s1ÆiÅ = s2ÆiÅ;
i := i+1;
END;
equal := b;
END; æequalå
FUNCTION vEqual (s1, s2 : fullId;
ls2 : integer ) : boolean;
VAR
i : integer;
b : boolean;
æ vEqual becomes true if 'ls2' characters of 's2' are included in 's1' å
BEGIN
b := elements(s1) >= ls2;
i := 1;
WHILE b AND (i <= ls2) DO
BEGIN
b := s1ÆiÅ = s2ÆiÅ;
i := i+1;
END;
vEqual := b;
END; ævEqualå
PROCEDURE zeroFill (UNIV a : blockPtr;
f, t : integer );
VAR
i : integer;
æ inserts zero in all bytes of array 'a' from byteindex 'f' to
byteindex 't' å
BEGIN
FOR i := f TO t DO aÆiÅ := 0;
END; æzeroFillå
æ$Eå
æ******************************************************å
æ***** U N I X D E S C R I P T I O N S *****å
æ******************************************************å
CONST
maxIdLength = 48; æmax length of device nameå
maxPathLength= 30; æmax length of root nameå
nameSize = 14; æ# of chars in file name partå
dirSize = 16; æsize of directory entryå
inoSize = 64; æsize of i-node entryå
inoLSize = 8;
inoFSize = 56;
unixPageSize = 512;
nicFree = 50;
freeBfSize = 202; ænicFree*4+2å
freeLstSize = 49; ænicFree-1å
nicInod = 100;
inoLstSize = 99; ænicInod-1å
rootIno = 2;
egoDir = 1;
parentDir = 2;
maxDisc = 5;
superAddr = 512; æbytePos of super blockå
space = ' ';
p12 = 16#1000;
p16 = 16#10000;
dirType = 16#4000;
dirMode = 16#41ff;
dataType = 16#8000;
dataMode = 16#81ff;
TYPE
name6 = packed array Æ1..6Å of char;
name14 = packed array Æ1..14Å of char;
name30 = packed array Æ1..maxPathLengthÅ of char;
fullName = packed array Æ1..maxIdLengthÅ of char;
ino = word;
time = long;
blockNo = long;
choice = (a, b);
æ$Eå
freeRec = RECORD
CASE choice OF
a: ( freeBuf : array Æ1..freeBfSizeÅ of byte );
b: ( nFree : word;
freeList: array Æ0..freeLstSizeÅ of blockNo );
END;
superBlock = RECORD
inodSize : word; æblockno of first block after i-listå
volSize : blockNo; ætotal no.of blocks in volumeå
freeBlock : freeRec; æfree listå
nIno : word; æ# used entries in ino listå
inoList : array Æ0..inoLstSizeÅ of ino; æino listå
dummy1 : long; æunix flags not used by eoså
sTime : time; ælast super block updateå
tFreeBl : long; ætotal # free blockså
tInode : word; æ - # i-nodeså
sM : word; æinterleave factorå
sN : word; æ - moduloå
volName : name6; ævolume nameå
packName : name6; ædisc pack nameå
dummy2 : arrayÆ1..72Å of byte; æfill to 512 byteså
END;
iLnk = RECORD
iMode : word; æmode, type of fileå
iNLink : word; æ# links to fileå
iUserId : word; æowners userIdå
iGroupId : word; æ - groupIdå
END;
iFl = RECORD
iSize : long; æ logical eof: # bytes in fileå
iAddr : array Æ1..40Å of byte; æ13 disc block addr, each 3 byteså
iAccTime : time; ælast accessedå
iModTime : time; ælast modifiedå
iCreTime : time; ælast createdå
END;
iNode = RECORD
iLink : iLnk;
iFil : iFl;
END;
iNodeArray = array Æ1..8Å of iNode;
æ$Eå
bAddress = RECORD
CASE choice OF
a: ( bAddr : array Æ0..3Å of byte );
b: ( blockAddr : blockNo );
END;
b13Array = array Æ0..12Å of bAddress;
b128Array = array Æ0..127Å of blockNo;
dirEntry = RECORD
dIno : ino; æi-numberå
dName : name14; æfileNameå
END;
dirEntArray = array Æ1..32Å of dirEntry;
æ$Eå
æ*********************************************************å
æ***** F A O L O C A L P O I N T E R S *****å
æ*********************************************************å
TYPE
pFaoLocals = ^^ faoLocals;
pUnixLocals = ^^ unixLocals;
pUxDatType = ^^ unixData;
pGateType = ^^ Gate;
faoLocals = RECORD
code : ^^;
pFaoData : ^^ faoData;
unixEnv : pUnixLocals;
daoRef : faoRefType;
sbGateRef : pGateType;
faoGate : pGateType;
END;
indirect = RECORD
tab : b128Array;
curIb : blockNo;
update : boolean;
END;
faoData = RECORD
iNumber : ino;
blockTab : b13Array; æ10 direct, 3 indirect blockså
iTab : array Æ1..3Å of indirect;
inx : array Æ0..3Å of word;
level : word;
curPos : long; ælast transferred byte positionå
eofPos : long; ælast data byte positionå
allocSize : long; ælast allocated byte positionå
daoIndex : word;
localId : word;
rwMode : ioType;
devReadOnly : byte;
terminated: boolean; ætrue when terminateFao has been calledå
readMark : boolean; ætrue when ReadSeq/ReadRandom has been calledå
writeMark : boolean; ætrue when WriteSeq/WriteRandom has been calledå
inoUpdate : boolean; ætrue when i-node changed, but not on discå
inoLink : iLnk;
inoFile : iFl;
END;
æ$Eå
æ*************************************************************å
æ***** I O S Y S L O C A L P O I N T E R S *****å
æ*************************************************************å
TYPE
unixLocals = RECORD
code : ^^;
ioGate : ^^Gate;
dao : array Æ1..maxDiscÅ of faoRefType;
faoMan : array Æ1..maxDiscÅ of pFaoLocals;
sbGate : array Æ1..maxDiscÅ of pGateType;
nextFao : pFaoLocals; æused only as work.ptr.in countOpenFaoså
pUnixData : ^^unixData;
pUnixDir : bufRef; æ^^dirBlock, subsegment of unixDataå
objDirRef : ^^ObjDir;
allocRef : ^^Allocate;
schedRef : ^^Scheduler;
clockRef : ^^Clock;
egoEnv : pUnixLocals;
END;
deviceData = RECORD
devName : fullName;
pathLength : word; æ# chars used in pathNameå
pathName : name30;
devReadOnly: word;
super : superBlock;
END;
unixData = RECORD
dirBlock : dirEntArray;
faoWork : faoData; æfor use by create/deleteLinkå
lastLocalId : integer;
devTable : array Æ1..maxDiscÅ of deviceData;
END;
æ$Eå
æ************************************************************å
æ***** F O R W A R D D E C L A R A T I O N S *****å
æ************************************************************å
FUNCTION allocBlock (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData
) : blockNo; FORWARD;
FUNCTION checkFileName (VAR pathName : fullId;
charno : integer
) : integer; FORWARD;
FUNCTION countDirEntries (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData
) : integer; FORWARD;
PROCEDURE cutFile (VAR dao : faoRefType;
VAR dummyGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData;
VAR sb : superBlock ); FORWARD;
FUNCTION fileType (modeWord : word) : integer; FORWARD;
FUNCTION fillInoList (VAR dao : faoRefType;
VAR sb : superBlock
) : integer; FORWARD;
FUNCTION getBlockNo (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData;
relBlock : long
) : BlockNo; FORWARD;
FUNCTION getFreeInum (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData
) : ino; FORWARD;
PROCEDURE getInoFile (VAR dao : faoRefType;
VAR fd : faoData;
iNum : ino ); FORWARD;
PROCEDURE getInoLink (VAR dao : faoRefType;
VAR fd : faoData;
iNum : ino ); FORWARD;
FUNCTION getNamePart ( VAR pathName : fullId;
VAR fName : name14;
VAR cNo : integer
) : boolean; FORWARD;
PROCEDURE getOneBlock (VAR dao : faoRefType;
UNIV buf : blockPtr;
first, last : integer;
block : blockNo;
relByte : integer ); FORWARD;
PROCEDURE getOneSegment (VAR dao : faoRefType;
VAR segment : bufRef;
first, last : integer;
block : blockNo;
relByte : integer ); FORWARD;
PROCEDURE newDirEntry ( VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData;
dirIno : ino;
dirPos : integer;
fileIno : ino;
fName : name14 ); FORWARD;
PROCEDURE putInoFile (VAR dao : faoRefType;
VAR fd : faoData ); FORWARD;
PROCEDURE putInoLink (VAR dao : faoRefType;
VAR fd : faoData ); FORWARD;
FUNCTION putOneBlock (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
buf : blockPtr;
VAR fd : faoData;
first, last : integer;
block : blockNo;
relByte : integer
) : blockNo; FORWARD;
FUNCTION putOneSegment (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR segment : bufRef;
VAR fd : faoData;
first, last : integer;
block : blockNo;
relByte : integer
) : blockNo; FORWARD;
PROCEDURE readSegment (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR segment : bufRef;
VAR fd : faoData;
VAR byteCount : integer ); FORWARD;
PROCEDURE releaseBlock (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData ;
VAR sb : superBlock ;
absBlock : long ); FORWARD;
PROCEDURE remDirEntry ( VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData;
dirIno : ino;
dirPos : integer ); FORWARD;
PROCEDURE removeFile ( VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR dummyGate : pGateType;
VAR pUNixData : pUxDatType;
VAR fd : faoData); FORWARD;
FUNCTION searchDevTab ( VAR ux : unixData;
pathName : fullId;
VAR charNo : integer
) : integer; FORWARD;
FUNCTION searchDirectory (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData;
VAR fName : name14;
VAR dirPos : integer
) : ino; FORWARD;
FUNCTION segLength (VAR segment : bufRef) : integer; FORWARD;
PROCEDURE writeSegment (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR segment : bufRef;
VAR fd : faoData;
VAR byteCount : integer); FORWARD;
æ$Eå
æ******************************************************å
æ***** G L O B A L P R O C E D U R E S *****å
æ******************************************************å
FUNCTION allocBlock; æ( VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData
) : blockNo; å
VAR
i, ix : integer;
bl : blockNo;
res : resultType;
BEGIN
æ*b* printText ('allocBlock '); *e*å
ix := fd.daoIndex;
res.main := ok;
æ critical region for update super block å
xCheck ( sbGate.Lock );
IN
WITH ux = pUnixData^^, sb = ux.devTableÆixÅ.super DO
BEGIN
WITH xb = sb.freeBlock DO
BEGIN
xb.nFree := xb.nFree - 1;
bl := xb.freeListÆxb.nFreeÅ;
IF bl = 0 THEN BEGIN
xb.nFree := xb.nFree + 1;
Exception ( makeRes ( Reject*NoVolumeSpace, IoFamily, entryA, 0));
END;
sb.tFreeBl := sb.tFreeBl - 1;
IF xb.nFree = 0 THEN
BEGIN
æ the allocated block was a free-chain block, which must be
read into the super block å
IN
æ#ern# printVar ('Alloc: get freeBuf from ', bl ); &ern&å
getOneBlock (dao, xb.freeBuf, 1, freeBfSize, bl, 0);
æ#ern# printVar ('Updated superblock ', sb ); &ern&å
DO
BEGIN æif input no ok, the block has not been allocated,
so increase free count å
xb.nFree := xb.nFree + 1;
sb.tFreeBl := sb.tFreeBl + 1;
exception (getException);
END;
END;
æ put super blockå
xCheck ( dao.WriteRandom
(VAR IN OUT pUnixData^^.devTableÆixÅ.super ;
OUT i, IN superAddr, OUT i));
allocBlock := bl;
æ!b! printVar ('allocBlock: super block = ', sb); !e!å
END; æwith xbå
END; æwith sbå
DO
BEGIN
res := GetException;
IF res.main < 0 THEN res.main := -res.main;
END;
æ leave critical region å
sCheck ( sbGate.Open );
IF res.main <> ok THEN Exception (res);
æ*b* printVar ('end allocBlock, blockNo = ', bl); *e*å
END; æallocBlockå
FUNCTION checkFileName; æ (VAR pathName : fullId;
charno : integer
) : integer; å
VAR
i, k, parts, tLength : integer;
ch : char;
error : boolean;
æ This function analyses the 'pathName', which may contain any number of
name parts separated by '/'. Each name part may contain up to 14 chars.
An empty name part (//) is not allowed. A '/' after the last name part is
not allowed. The file name may be terminated by a null char.
'charNo' points to the base of the file name.
The return value of the function is the number of name parts if name ok,
-1 if an error is found.
å
BEGIN
æ*b* printVar ('checkFileName : pathName = ', pathName);
printVar ('charNo = ', charNo); *e*å
k := charNo;
i := 0;
parts := 0;
error := false;
tLength := elements (pathName);
WHILE k < tLength DO
BEGIN
k := k + 1;
ch := pathNameÆkÅ;
IF (ch <> '/') AND (ch <> CHR(0)) THEN
BEGIN
parts := parts + 1;
REPEAT
i := i + 1;
k := k + 1;
IF k <= tLength THEN ch := pathNameÆkÅ;
UNTIL (ch = '/') OR (ch = CHR(0)) OR (k>=tLength);
END;
æ check name partå
IF (i > 14) OR ætoo longå
(i = 0) AND (k > charNo+1) æemptyå
THEN error := true;
IF ch = CHR(0) THEN k := tLength
ELSE
IF ch = '/' THEN i := 0;
END; æWHILEå
IF (i=0) AND (parts>0) THEN error := true; æ'/' after last partå
IF error THEN checkFileName := -1
ELSE checkFileName := parts;
æ*b* printVar ('end checkFileName, parts = ', parts); *e*å
END; æcheckFileNameå
FUNCTION countDirEntries; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData
) : integer; å
VAR
bytesRead, count, i, ix, lastIx : integer;
æ This function reads through the entries of the directory file pointed to
by 'fd', to count the number of used entries. 'lastPos' returns the
position after the last used directory entry.
å
BEGIN
WITH dir = pUnixData^^.dirBlock DO
BEGIN
æ*b* printVar ('countDirEntries : eofPos = ', fd.eofPos); *e*å
fd.curPos := 0;
count := 0;
WHILE fd.curPos < fd.eofPos DO
BEGIN
readSegment (dao, sbGate, pUnixData, pUnixDir, fd, bytesRead);
æ*b* printVar ('dir block = ', dir); *e*å
lastIx := bytesRead DIV dirSize;
FOR ix := 1 TO lastIx DO
BEGIN
IF dirÆixÅ.dIno <> 0 THEN count := count + 1;
END; æfor ixå
END; æwhileå
countDirEntries := count;
END; æwith dirå
æ*b* printVar ('end countDirEntries, count = ', count); *e*å
END; æcountDirEntrieså
PROCEDURE cutFile; æ (VAR dao : faoRefType;
VAR dummyGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData;
VAR sb : superBlock ); å
VAR
absBlock, lastBlock, relBlock, bl : integer;
æ This procedure releases all data blocks and index blocks of the file å
BEGIN
WITH fd DO
BEGIN
lastBlock := fd.allocSize DIV unixPageSize - 1;
FOR relBlock := lastBlock DOWNTO 0 DO
BEGIN
absBlock := getBlockNo (dao, dummyGate, pUnixData, fd, relBlock);
IF absBlock <> 0 THEN
releaseBlock (dao, dummyGate, pUnixData, fd, sb, absBlock);
IF level > 0 THEN
BEGIN ælevel and iTab.curIb have been assigned by getBlockNoå
IF (relBlock - 10) MOD 128 = 0 THEN
BEGIN ærelease 1st level indexBlockå
bl := iTabÆ1Å.curIb;
IF bl <> 0 THEN
releaseBlock (dao, dummyGate, pUnixData, fd, sb, bl);
IF level > 1 THEN
BEGIN
IF (relBlock - 138) MOD 16384 = 0 THEN
BEGIN ærelease 2nd level index blockå
bl := iTabÆ2Å.curIb;
IF bl <> 0 THEN
releaseBlock (dao, dummyGate, pUnixData, fd, sb, bl);
IF level > 2 THEN
BEGIN
IF relBlock = 16522 THEN
BEGIN
bl := iTabÆ3Å.curIb;
IF bl <> 0 THEN
releaseBlock (dao, dummyGate, pUnixData, fd, sb, bl);
END; ærelease 3rd levelå
END; ælevel > 2å
END; ærelease 2nd levelå
END; ælevel > 1å
END; ærelease 1st levelå
END; ælevel > 0å
END; æfor relBlockå
END; æwith fdå
END; æcutFileå
FUNCTION fileType; æ (modeWord : word) : integer; å
VAR
t : integer;
BEGIN
t := ((modeWord + p16) DIV p12 * p12) MOD p16;
fileType := t;
æ*b* printVar ('unixfs.fileType = ', t); *e*å
END;
FUNCTION fillInoList; æ (VAR dao : faoRefType;
VAR sb : superBlock
) : integer; å
LABEL
100; æ listFull; å
VAR
inoBuf : inodeArray;
i : ino;
bl, k, n : integer;
æ This function fills the inode-list in the super buffer with free
i-numbers.
The return value is a count of i-numbers filled into the super buffer.
å
BEGIN
æ*b* printText ('fillInoList '); *e*å
k := 0;
i := 0;
FOR bl := 2 TO sb.inodSize - 1 DO
BEGIN
getOneBlock (dao, inoBuf, 1, unixPageSize, bl, 0);
FOR n := 1 TO 8 DO
BEGIN
i := i + 1;
IF inoBufÆnÅ.iLink.iNLink = 0 THEN
BEGIN
IF k <= nicInod THEN sb.inoListÆkÅ := i
ELSE GOTO 100; æ listFull; å
k := k + 1;
END; æfreeå
END; æfor nå
END; æfor blå
100: æ listFull: å
fillInoList := k;
sb.nIno := k;
æ*b* printVar ('end fillInoList, free nodes = ', k); *e*å
END; æfillInoListå
FUNCTION getBlockNo; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData;
relBlock : long
) : blockNo; å
CONST
bLimit1 = 10;
bLimit2 = 138; æ bLimit1 + 128 å
bLimit3 = 16522; æ bLimit2 + 128*128 å
VAR
i, l, x : integer;
bl : blockNo;
æ This function finds the actual block number on disc corresponding
to the relative block number in the file, specified by 'relBlock'.
If 'relBlock' < 10 then the block table in 'fd' gives directly
the actual block number, otherwise the block number is found
through 1, 2, or 3 indirect block references å
BEGIN
WITH fd DO
BEGIN
æ+b+ printVar ('getBlockNo : relBlock = ', relBlock); +e+å
IF relBlock < bLimit1 THEN
BEGHN
bl := blockTabÆrelBlockÅ.blockAddr;
inxÆ0Å := relBlock;
level := 0;
END ædirectå
ELSE
BEGIN æindirectå
IF relBlock < bLimit2 THEN
BEGIN
level := 1;
inxÆ1Å := relBlock - bLimit1;
END æ1st level, singly indirectå
ELSE
IF relBlock < bLimit3 THEN
BEGIN
level := 2;
i := relBlock - bLimit2;
inxÆ2Å := i DIV 128;
inxÆ1Å := i MOD 128;
END æ2nd level, doubly indirectå
ELSE
BEGIN
level := 3;
i := relBlock - bLimit3;
inxÆ3Å := i DIV 16384;
i := i MOD 16384;
inxÆ2Å := i DIV 128;
inxÆ1Å := i MOD 128;
END; æ3rd level, triply indirectå
bl := blockTab ÆbLimit1 + level - 1Å.blockAddr;
inxÆ0Å := bLimit1 + level - 1;
æ+b+ printVar ('abs block = ', bl);
printVar ('level = ', level);
printVar ('inx array = ', inx);
printVar ('blockTab = ', blockTab); +e+å
FOR l := level DOWNTO 1 DO
BEGIN
IF iTabÆlÅ.curIb <> bl THEN
BEGIN
IF iTabÆlÅ.update THEN
BEGIN
æ all i-tabs from lower levels up to this level, with
update mark, must be written to disc before new readå
FOR x := 1 TO l DO
BEGIN
IF iTabÆxÅ.update THEN
BEGIN
æ+b+ printVar ('indirect table index ÆxÅ = ', x);
printVar ('indirect table put = ', iTabÆxÅ); +e+å
i := putOneBlock (dao, sbGate, pUnixData, iTabÆxÅ.tab, fd,
1, unixPageSize, iTabÆxÅ.curIb, 0);
iTabÆxÅ.update := false;
END; æifå
END; æfor xå
END; æupdateå
getOneBlock (dao, iTabÆlÅ.tab, 1, unixPageSize, bl, 0);
iTabÆlÅ.curIb := bl;
æ+b+ printVar ('indirect table index ÆlÅ = ', l);
printVar ('indirect table read = ', iTabÆlÅ); +e+å
END; æcurIb <> blå
bl := iTabÆlÅ.tabÆinxÆlÅÅ;
END; æfor lå
END; æindirectå
END; æwith fdå
getBlockNo := bl;
æ+b+ printVar ('end getBlockNo, blockNo = ', bl); +e+å
END; ægetBlockNoå
FUNCTION getFreeInum; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData
) : ino; å
VAR
ix, k, n : integer;
res : resultType;
æ This function returns the i-number of the next free i-node å
BEGIN
æ*b* printText ('getFreeInum '); *e*å
ix := fd.daoIndex;
res.main := ok;
æ critical region for update super block å
xCheck ( sbGate.Lock );
IN
WITH ux = pUnixData^^, sb = ux.devTableÆixÅ.super DO
BEGIN
k := sb.nIno;
IF k = 0 THEN k := fillInoList (dao, sb);
IF k > 0 THEN
BEGIN
sb.nIno := k - 1;
k := sb.inoListÆsb.nInoÅ;
sb.tInode := sb.tInode - 1;
END;
getFreeInum := k;
fd.inoUpdate := true;
æ put super block å
xCheck ( dao.WriteRandom (VAR IN OUT pUnixData^^.devTableÆixÅ.super ;
OUT n, IN superAddr, OUT n));
æ!b! printVar ('getFreeInum, super block = ', sb); !e!å
END; æwith sbå
DO
BEGIN
res := GetException;
IF res.main < 0 THEN res.main := -res.main;
END;
æ leave critical region å
sCheck ( sbGate.Open );
IF res.main <> ok THEN Exception (res);
æ*b* printVar ('end getFreeInum = ', k); *e*å
END; ægetFreeInumå
PROCEDURE getInoFile; æ (VAR dao : faoRefType;
VAR fd : faoData;
iNum : ino ); å
VAR
i, j, block, relByte : integer;
æ This procedure reads the file description part of the i-node
specified by 'iNum' å
BEGIN
æ*b* printVar ('getInoFile, iNum = ', iNum); *e*å
WITH fd DO
BEGIN
iNumber := iNum;
block := (iNumber - 1) DIV 8 + 2;
relByte := ((iNumber - 1) MOD 8) * inoSize + inoLSize;
getOneBlock (dao, iNoFile, 1, inoFSize, block, relByte);
æ*b* printVar ('inoFile = ', inoFile); *e*å
FOR i := 0 TO 12 DO
BEGIN
blockTabÆiÅ.bAddrÆ0Å := 0;
FOR j := 1 TO 3 DO
blockTabÆiÅ.bAddrÆjÅ := inoFile.iAddrÆi*3+jÅ;
END; æfor iå
æ+b+ printVar ('blockTab = ', blockTab); +e+å
FOR i := 0 TO 3 DO inxÆiÅ := 0;
eofPos := inoFile.iSize;
allocSize := (eofPos + unixPageSize - 1) DIV unixPageSize * unixPageSize;
curPos := 0;
inoUpdate := false;
END; æwith fdå
æ+b+ printText ('end getInoFile '); +e+å
END; ægetInoFileå
PROCEDURE getInoLink; æ (VAR dao : faoRefType;
VAR fd : faoData;
iNum : ino ); å
VAR
block, relByte : integer;
æ This procedure reads the link description part of the i-node
specified by 'iNum' å
BEGIN
æ*b* printVar ('getInoLink, iNum = ', iNum); *e*å
WITH fd DO
BEGIN
iNumber := iNum;
block := (iNumber - 1) DIV 8 + 2;
relByte := ((iNumber - 1) MOD 8) * inoSize;
getOneBlock (dao, inoLink, 1, inoLSize, block, relByte);
æ*b* printVar ('end getInoLink = ', inoLink); *e*å
END; æwith fdå
END; ægetInoLinkå
FUNCTION getNamePart; æ ( VAR pathName : fullId;
VAR fName : name14;
VAR cNo : integer
) : boolean; å
VAR
totL, i : integer;
last : boolean;
ch : char;
æ This function returns in 'fName' the name part of 'pathName' pointed
to by 'cNo', which as return value is a pointer to the next name part.
The return value of the function is true when the last name part is
returned, otherwise false.
å
BEGIN
totL := elements (pathName);
æ*b* printVar ('getNamePart, totL = ', totL); *e*å
i := 1;
IF cNo < totL THEN
REPEAT
cNo := cNo + 1;
ch := pathNameÆcNoÅ;
IF ch <> '/' THEN
BEGIN
fNameÆiÅ := ch;
i := i + 1;
END;
UNTIL ((ch = '/') AND (i > 1)) OR
(ch = CHR(0)) OR
(cNo >= totL);
FOR i := i TO nameSize DO fNameÆiÅ := CHR(0);
last := (cNo >= totL) OR (ch = CHR(0));
getNamePart := last;
æ*b* printVar ('end getNamePart : fName = ', fName);
printVar (' new charNo = ', cNo);
IF last THEN printText ('last '); *e*å
END; ægetNamePartå
PROCEDURE getOneBlock; æ (VAR dao : faoRefType;
UNIV buf : blockPtr;
first, last : integer;
block : blockNo;
relByte : integer ); å
VAR
i, j : integer;
æ This procedure reads a number of consecutive bytes (max one page)
from disc to the array defined by 'buf'.
'block' = 0 designates an un-allocated block, otherwise 'block' and
'relByte' define the absolute disc position for start reading.
å
BEGIN
æ*b* printVar ('getOneBlock : blockNo = ', block); *e*å
æ+b+ printVar ('relByte = ', relByte);
printVar ('first = ', first);
printVar ('last = ', last); *e*å
IF block = 0 THEN æunallocated blockå
FOR i := first TO last DO
bufÆiÅ := 0
ELSE
xCheck ( dao.ReadRandom (VAR IN OUT bufÆfirst..lastÅ ; OUT i,
IN block*unixPageSize + relByte, OUT j));
æ*b* printVar ('end getOneBlock, bytecount = ', i); *e*å
END; ægetOneBlockå
PROCEDURE getOneSegment; æ (VAR dao : faoRefType;
VAR segment : bufRef;
first, last : integer;
block : blockNo;
relByte : integer ); å
VAR
i, j : integer;
æ This procedure reads a number of consecutive bytes (max one page)
from disc in the same way as getOneBlock, but data are read into
a sub segment (instead of into an array).
å
BEGIN
æ*b* printVar ('getOneSegment : blockNo = ', block); *e*å
æ+b+ printVar ('relByte = ', relByte);
printVar ('first = ', first);
printVar ('last = ', last); +e+å
IF block = 0 THEN æunallocated blockå
WITH buf = segment^^ DO
BEGIN
FOR i := first TO last DO
bufÆiÅ := 0;
END æwithå
ELSE
xCheck ( dao.ReadRandom (VAR IN OUT segment^^Æfirst..lastÅ ; OUT i,
IN block*unixPageSize + relByte, OUT j));
æ*b* printVar ('end getOneSegment, byteCount = ', i); *e*å
END; ægetOneSegmentå
PROCEDURE newDirEntry; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData;
dirIno : ino;
dirPos : integer;
fileIno : ino;
fName : name14 ); å
VAR
bytes, dirIx, i, saveEof, savePos : integer;
æ This procedure inserts the file specified by 'fileIno' and 'fName'
in the directory specified by 'dirIno' in the position specified by
'dirPos'.
å
BEGIN
æ*b* printVar ('newDirEntry, dirPos = ', dirPos); *e*å
æ+b+ printVar ('fileIno = ', fileIno);
printVar ('fName = ', fName); +e+å
getInoFile (dao, fd, dirIno);
getInoLink (dao, fd, dirIno);
IF fd.inoLink.iNLink < 1 THEN
Exception ( makeRes (Reject * EntryIllegal, Universal,
entryA, dirNotPermanent ));
savePos := dirPos DIV unixPageSize * unixPageSize;
fd.curPos := savePos;
saveEof := fd.eofPos;
dirIx := (dirPos - fd.curPos) DIV dirSize + 1;
readSegment (dao, sbGate, pUnixData, pUnixDir, fd, æoutå bytes);
WITH dir = pUnixData^^.dirBlock DO
BEGIN
IF bytes < unixPageSize THEN zeroFill (dir, bytes+1, unixPageSize);
dirÆdirIxÅ.dIno := fileIno;
dirÆdirIxÅ.dName := fName;
æ*b* printVar ('dirBlock after insert = ', dir); *e*å
END;
fd.curPos := savePos;
writeSegment (dao, sbGate, pUnixData, pUnixDir, fd, i);
æset new eofPoså
IF fd.eofPos > saveEof THEN
BEGIN
IF saveEof = dirPos THEN fd.eofPos := dirPos + dirSize
ELSE fd.eofPos := saveEof;
putInoFile (dao, fd);
END;
æ+b+ printText ('end newDirEntry '); +e+å
END; ænewDirEntryå
PROCEDURE putInoFile; æ (VAR dao : faoRefType;
VAR fd : faoData ); å
VAR
i, j, block, relByte : integer;
BEGIN
WITH fd DO
BEGIN
æ*b* printVar ('putInoFile : iNum = ', iNumber); *e*å
FOR i := 0 TO 12 DO
FOR j := 1 TO 3 DO
inoFile.iAddrÆi*3+jÅ := blockTabÆiÅ.bAddrÆjÅ;
inoFile.iSize := eofPos;
block := (iNumber-1) DIV 8 + 2;
relByte := ((iNumber-1) MOD 8) * inoSize + inoLSize;
æ+b+ printVar ('block = ', block);
printVar ('relByte = ', relByte); +e+å
inoUpdate := true;
xCheck ( dao.WriteRandom ( VAR IN OUT inoFile ; OUT i,
IN block * unixPageSize + relByte, OUT i));
inoUpdate := false;
æ*b* printVar ('end putInoFile, i-node = ', inoFile); *e*å
END; æwith fdå
END; æputInoFileå
PROCEDURE putInoLink; æ (VAR dao : faoRefType;
VAR fd : faoData ); å
VAR
block, i, relByte : integer;
æ This procedure writes to disc the link description part of the i-node
specified by fd.iNumber å
BEGIN
WITH fd DO
BEGIN
æ*b* printVar ('putInoLink, iNum = ', fd.iNumber); *e*å
block := (iNumber - 1) DIV 8 + 2;
relByte := ((iNumber - 1) MOD 8) * inoSize;
æ+b+ printVar ('block = ', block);
printVar ('relByte = ', relByte); +e+å
xCheck ( dao.WriteRandom (VAR IN OUT inoLink ; OUT i,
IN block * unixPageSize + relByte, OUT i));
æ*b* printVar ('end putInoLink = ', inoLink); *e*å
END; æwith fdå
END; æputInoLinkå
FUNCTION putOneBlock; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
buf : blockPtr;
VAR fd : faoData;
first, last : integer;
block : blockNo;
relByte : integer
) : blockNo; å
VAR
new : boolean;
i, j, count, pos : integer;
helpBuf : array Æ1..unixPageSizeÅ of byte;
æ This procedure writes a number of consecutive bytes (max
one page) to the disc, at the absolute block number defined by
'block'.
If 'block' = 0 a new block must be allocated from the pool of
free blocks. If 'buf' does not start and/or end at a page
boundary, all other bytes of that page are left unchanged if
existing block, or zeroed if new-allocated block.
å
BEGIN
æ*b* printVar ('putOneBlock : blockNo = ', block); *e*å
æ+b+ printVar ('relByte = ', relByte);
printVar ('first = ', first);
printVar ('last = ', last); +e+å
IF block = 0 THEN
BEGIN
block := allocBlock (dao, sbGate, pUnixData, fd);
new := true;
END
ELSE
new := false;
IF new AND
((relByte > 0) OR
(last - first + 1 < unixPageSize)) THEN
BEGIN
FOR i := 1 TO unixPageSize DO helpBufÆiÅ := 0;
j := relByte + 1;
FOR i := first TO last DO
BEGIN
helpBufÆjÅ := bufÆiÅ;
j := j + 1;
END;
æ*b* printVar ('helpBuf = ', helpBuf); *e*å
xCheck ( dao.WriteRandom (VAR IN OUT helpBuf ; OUT count,
IN block * unixPageSize, OUT pos));
END ænot full pageå
ELSE
æ*b* printVar ('buf = ', buf); *e*å
xCheck ( dao.WriteRandom (VAR IN OUT bufÆfirst..lastÅ ; OUT count,
IN block * unixPageSize + relByte, OUT pos));
putOneBlock := block; æused block numberå
æ*b* printVar ('end putOneBlock, used blockNo = ', block); *e*å
END; æputOneBlockå
FUNCTION putOneSegment; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR segment : bufRef;
VAR fd : faoData;
first, last : integer;
block : blockNo;
relByte : integer
) : blockNo; å
VAR
new : boolean;
i, j, count, pos : integer;
helpBuf : array Æ1..unixPageSizeÅ of byte;
æ This procedure writes a number of consecutive bytes (max one page)
to disc in the same way as putOneBlock, but the data are written
from a sub segment (instead of from an array).
å
BEGIN
æ*b* printVar ('putOneSegment : blockNo = ', block); *e*å
æ+b+ printVar ('relByte = ', relByte);
printVar ('first = ', first);
printVar ('last = ', last); +e+å
IF block = 0 THEN
BEGIN
block := allocBlock (dao, sbGate, pUnixData, fd);
new := true;
END
ELSE
new := false;
IF new AND
((relByte > 0) OR
(last - first + 1 < unixPageSize)) THEN
BEGIN
FOR i := 1 TO unixPageSize DO helpBufÆiÅ := 0;
j := relByte + 1;
WITH buf = segment^^ DO
BEGIN
FOR i := first TO last DO
BEGIN
helpBufÆjÅ := bufÆiÅ;
j := j + 1;
END;
END; æwithå
æ*b* printVar ('helpBuf = ', helpBuf); *e*å
xCheck ( dao.WriteRandom (VAR IN OUT helpBuf ; OUT count,
IN block * unixPageSize, OUT pos));
END ænot full pageå
ELSE
xCheck ( dao.WriteRandom (VAR IN OUT segment^^Æfirst..lastÅ ; OUT count,
IN block * unixPageSize + relByte, OUT pos));
putOneSegment := block; æused block numberå
æ*b* printVar ('end putOneSegment, used blockNo = ', block); *e*å
END; æputOneSegmentå
PROCEDURE readSegment; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR segment : bufRef;
VAR fd : faoData;
VAR byteCount : integer ); å
VAR
bufFirst, bufLast,bs, firstBlock, lastBlock, nextActual, pos,
relBlock, relPos, savedActual : integer;
æ This procedure reads into 'segment' from the file, one page (or less)
at a time. If two or more pages are placed consecutively on the
disc, they are read in one operation.
å
BEGIN
æ*b* printVar ('readSegment : fd.curPos = ', fd.curPos);
printVar ('fd.eofPos = ', fd.eofPos); *e*å
byteCount := 0;
æ check read reservation å
IF (fd.rwMode = NoRights) OR
(fd.rwMode = WriteMode) THEN
Exception ( makeRes ( Reject * EntryIllegal, Universal,
entryA, noReadReservation ));
æ check current position against eof position å
IF fd.curPos > fd.allocSize THEN
Exception ( makeRes ( Reject * PosOutsideRange, IoFamily,
0, 0));
fd.readMark := true;
IF fd.curPos >= fd.eofPos THEN
byteCount := 0
ELSE
BEGIN
pos := fd.curPos;
bs := segLength (segment);
æ*b* printVar ('segLength = ', bs); *e*å
IF pos + bs > fd.eofPos THEN bs := fd.eofPos - pos;
firstBlock := pos DIV unixPageSize;
relPos := pos MOD unixPageSize;
lastBlock := (pos + bs - 1) DIV unixPageSize;
bufFirst := 1;
bufLast := unixPageSize - relPos;
if bufLast >= bs THEN bufLast := bs;
savedActual := getBlockNo (dao, sbGate, pUnixData, fd, firstBlock);
FOR relBlock := firstBlock + 1 TO lastBlock DO
BEGIN
nextActual := getBlockNo (dao, sbGate, pUnixData, fd, relBlock);
IF nextActual - savedActual <> relBlock - firstBlock THEN
BEGIN
æ non consecutive blocks, read old block now å
getOneSegment (dao, segment, bufFirst, bufLast, savedActual, relPos);
fd.curPos := fd.curPos + bufLast - bufFirst + 1;
byteCount := byteCount + bufLast - bufFirst + 1;
savedActual := nextActual;
firstBlock := relBlock;
bufFirst := bufLast + 1;
relPos := 0;
END;
bufLast := bufLast + unixPageSize;
IF bufLast > bs THEN bufLast := bs;
END; æfor relBlockå
æ read final block å
getOneSegment (dao, segment, bufFirst, bufLast, savedActual, relPos);
fd.curPos := fd.curPos + bufLast - bufFirst + 1;
byteCount := byteCount + bufLast - bufFirst + 1;
END; ænot eofå
æ!b! printVar ('end readSegment, byteCount = ', byteCount); !e!å
END; æreadSegmentå
PROCEDURE releaseBlock; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData ;
VAR sb : superBlock;
absBlock : long ); å
VAR
i : integer;
æ This procedure releases a block, inserting the block number in the
free list in the super buffer å
BEGIN
æ*b* printVar ('releaseBlock : absBlock = ', absBlock); *e*å
WITH xb = sb.freeBlock DO
BEGIN
æ*b* printVar ('freeList before release = ', xb); *e*å
IF xb.nFree = nicFree THEN
BEGIN
æ Free list in super block full, use the freed block as
new free chain å
æ#ern# printVar ('Release block: superblock: ', sb ); &ern&å
i := putOneBlock (dao, sbGate, pUnixData, xb.freeBuf, fd,
1, freeBfSize, absBlock, 0);
æ#ern# printVar ('to block ', absBlock ); &ern&å
xb.nFree := 0;
END;
xb.freeListÆxb.nFreeÅ := absBlock;
xb.nFree := xb.nFree + 1;
sb.tFreeBl := sb.tFreeBl + 1;
æ*b* printVar ('freeList after release = ', xb); *e*å
END; æwith xbå
æ*b* printText ('end releaseBlock '); *e*å
END; æreleaseBlockå
PROCEDURE remDirEntry; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData;
dirIno : ino;
dirPos : integer ); å
VAR
dirIx, i, saveEof : integer;
æ This procedure clears the directory entry defined by 'dirPos' from
the directory defined by 'dirIno'.
Note! The sub-segment pUnixDir is supposed to contain the directory
block from which the entry is to be removed, and the total
block is written to the file.
å
BEGIN
æ*b* printVar ('remDirEntry : dirPos = ', dirPos); *e*å
getInoFile (dao, fd, dirIno);
saveEof := fd.eofPos;
fd.curPos := dirPos DIV unixPageSize * unixPageSize;
dirIx := (dirPos - fd.curPos) DIV dirSize + 1;
æ*b* printVar ('dirIx = ', dirIx); *e*å
WITH dir = pUnixData^^.dirBlock DO
BEGIN
æ*b* printVar ('dir block before remove ', dir); *e*å
dirÆdirIxÅ.dIno := 0;
FOR i := 1 TO nameSize DO dirÆdirIxÅ.dNameÆiÅ := CHR(0);
æ*b* printVar ('dirBlock after remove ', dir); *e*å
END;
writeSegment (dao, sbGate, pUnixData, pUnixDir, fd, i);
æ restore eofPos å
IF fd.eofPos > saveEof THEN
BEGIN
fd.eofPos := saveEof;
putInoFile (dao, fd);
END;
æ*b* printText ('end remDirEntry'); *e*å
END; æremDirEntryå
PROCEDURE removeFile; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR dummyGate : pGateType;
VAR pUnixData : pUxDatType;
VAR fd : faoData ); å
VAR
empty : array Æ1..inoSizeÅ of byte;
block, i, ix, relByte : integer;
res : resultType;
æ This procedure clears the i-node defined by 'fd.iNumber' and calls
'cutFile' to release all data blocks belonging to this file.
å
BEGIN
æ*b* printVar ('removeFile : iNum = ', fd.iNumber); *e*å
æ put empty i-node å
FOR i := 1 TO inoSize DO emptyÆiÅ := 0;
block := (fd.iNumber - 1) DIV 8 + 2;
relByte := ((fd.iNumber - 1) MOD 8) * inoSize;
æ*b* printVar ('i-node position: blockNo = ', block);
printVar (' relByte = ', relByte); *e*å
xCheck ( dao.WriteRandom (VAR IN OUT empty ;
OUT i, IN block * UnixPageSize + relByte, OUT i));
æ critical region for update super block å
res.main := ok;
xCheck ( sbGate.Lock );
IN
æ release data blocks å
ix := fd.daoIndex;
WITH ux = pUnixData^^, sb = ux.devTableÆixÅ.super DO
BEGIN
æ release data blocks and index blocks å
cutFile (dao, dummyGate, pUnixData, fd, sb);
æ increase free inode count å
IF sb.nIno < nicInod THEN
BEGIN
sb.inoListÆsb.nInoÅ := fd.iNumber;
sb.nIno := sb.nIno + 1;
END;
sb.tInode := sb.tInode + 1;
æ put super block å
æ!b! printVar ('removeFile: super block = ', sb); !e!å
xCheck (dao.WriteRandom
(VAR IN OUT pUnixData^^.devTableÆixÅ.super ;
OUT i, IN superAddr, OUT i));
END; æwith sbå
DO
BEGIN
res := GetException;
IF res.main < 0 THEN res.main := -res.main;
END;
æ leave critical region å
sCheck ( sbGate.Open );
IF res.main <> ok THEN Exception (res);
æ*b* printText ('end removeFile '); *e*å
END; æremoveFileå
FUNCTION searchDevTab; æ (VAR ux : unixData;
VAR pathName : fullId;
VAR charNo : integer
) : integer; å
VAR
i, k, n : integer;
æ This function searches through the device table (list of mounted
devices) in 'ux' for the longest path name prefix matching 'pathName'.
The return value of 'charNo' is the position of the last char of
the prefix.
å
BEGIN
æ*b* printText ('searchDevTab '); *e*å
charNo := 0;
n := 0;
FOR i := 1 TO maxDisc DO
BEGIN
WITH dev = ux.devTableÆiÅ DO
BEGIN
k := dev.pathLength;
IF vEqual (pathName, dev.pathName, k) THEN
IF k > charNo THEN
BEGIN
charNo := k;
n := i;
END;
END; æwith devå
END; æfor iå
searchDevTab := n;
æ*b* printVar ('end searchDevTab, daoIndex = ', n);
printVar (' matching length = ', charNo); *e*å
END; æsearchDevTabå
FUNCTION searchDirectory; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR pUnixDir : bufRef;
VAR fd : faoData;
VAR fName : name14;
VAR dirPos : integer
) : ino; å
VAR
byteCount, ix, lastIx, pos : integer;
found : boolean;
iNum : ino;
æ This procedure reads through the entries of the directory file
pointed to by 'fd', to find the file with name 'fName'.
The return value of searchDirectory is the i-number of this file
if found, otherwise zero. The parameter 'dirPos' returns the
position of the entry found, or of the first free entry if not found.
å
BEGIN
æ*b* printVar ('searchDirectory : fName = ', fName); *e*å
WITH fd , dir = pUnixData^^.dirBlock DO
BEGIN
IF (fileType (inoLink.iMode) <> dirType) AND
(fd.eofPos > 0) THEN
exception ( makeRes ( Reject * DataValueIllegal, Universal,
fNameArg, notDirFile));
pos := 0;
dirPos := 0;
fd.curPos := 0;
found := false;
iNum := 0;
WHILE (pos < fd.eofPos) AND NOT found DO
BEGIN
readSegment (dao, sbGate, pUnixData, pUnixDir, fd, byteCount);
lastIx := byteCount DIV dirSize;
æ*b* printVar ('next dir block read, lastIx = ', lastIx);
printVar (' dir block = ', dir); *e*å
ix := 1;
REPEAT
IF equal (dirÆixÅ.dName, fName) THEN
BEGIN
iNum := dirÆixÅ.dIno;
found := true;
dirPos := pos + dirSize*(ix-1);
END
ELSE
IF dirPos = 0 THEN
IF dirÆixÅ.dIno = 0 THEN
dirPos := pos + dirSize*(ix-1);
ix := ix + 1;
UNTIL (ix > lastIx) OR found;
pos := pos + unixPageSize;
END; æwhileå
searchDirectory := iNum;
IF dirPos = 0 THEN dirPos := fd.eofPos;
æ*b* printVar ('end searchDirectory, i-number = ', iNum);
printVar (' dirPos = ', dirPos); *e*å
END; æwith fd, dirå
END; æsearchDirectoryå
FUNCTION segLength; æ (VAR segment : bufRef) : integer; å
VAR
addr, length, use : integer;
æ This function returns the length (in bytes) of 'segment' å
BEGIN
sCheck ( IoAddr (segment, addr, length, use));
segLength := length;
END; æsegLengthå
PROCEDURE writeSegment; æ (VAR dao : faoRefType;
VAR sbGate : pGateType;
VAR pUnixData : pUxDatType;
VAR segment : bufRef;
VAR fd : faoData;
VAR byteCount : integer ); å
VAR
actual, bl, bs, bufFirst, bufLast, firstBlock, l, lastBlock,
newPos, pos, relBlock, relPos, used : integer;
res : resultType;
æ This procedure writes the contents of 'buf' to the file, one page
at a time. (In this first version consecutive physical blocks are
NOT written in a single operation, because data blocks must be
written before possibly updated indirect blocks).
If a block has not been allocated before, a block from the free
pool is allocated, and if the block is placed beyond eof, the eof
position and the allocation limit are updated.
å
BEGIN
æ*b* printVar ('writeSegment : fd.curPos = ', fd.curPos);
printVar ('fd.eofPos = ', fd.eofPos); *e*å
res.main := ok;
byteCount := 0;
æ check write reservation å
IF (fd.rwMode < WriteMode) OR
(fd.devReadOnly > 0) THEN
exception ( makeRes ( Reject * EntryIllegal, Universal,
entryA, noWriteReservation ));
fd.writeMark := true;
pos := fd.curPos;
bs := segLength (segment);
firstBlock := pos DIV unixPageSize;
relPos := pos MOD unixPageSize;
lastBlock := (pos + bs - 1) DIV unixPageSize;
bufFirst := 1;
bufLast := unixPageSize - relPos;
IF bufLast > bs THEN bufLast := bs;
IN
FOR relBlock := firstBlock TO lastBlock DO
BEGIN
actual := getBlockNo (dao, sbGate, pUnixData, fd, relBlock);
used := putOneSegment (dao, sbGate, pUnixData, segment, fd,
bufFirst, bufLast, actual, relPos);
æ data block written, now update indirect blocks, if
new data block allocated å
IF actual = 0 THEN
BEGIN
WITH fd DO
BEGIN
FOR l :=1 TO level DO
BEGIN
WITH iTabÆlÅ DO
BEGIN
IF tabÆinxÆlÅÅ = 0 THEN
BEGIN
tabÆinxÆlÅÅ := used;
bl := curIb;
IF bl = 0 THEN
BEGIN
used := putOneBlock (dao, sbGate, pUnixData, tab, fd,
1, unixPageSize, bl, 0);
curIb := used;
END
ELSE
iTabÆlÅ.update := true;
END; ænew tab elementå
END; æwith iTabå
END; æfor lå
IF blockTabÆinxÆ0ÅÅ.blockAddr = 0 THEN
BEGIN
blockTabÆinxÆ0ÅÅ.blockAddr := used;
inoUpdate := true;
END;
æ+b+ printVar ('updated fd = ', fd); +e+å
END; æwith fdå
END; æactual = 0å
fd.curPos := fd.curPos + bufLast - bufFirst + 1;
byteCount := byteCount + bufLast - bufFirst + 1;
relPos := 0;
bufFirst := bufLast + 1;
bufLast := bufLast + unixPageSize;
IF bufLast > bs THEN bufLast := bs;
END; æfor relBlockå
DO
BEGIN
res := GetException;
IF res.main < 0 THEN res.main := -res.main;
END;
æ update positionså
IF fd.curPos > fd.eofPos THEN
BEGIN
fd.inoUpdate := true;
fd.eofPos := fd.curPos;
fd.allocSize := (fd.eofPos + unixPageSize -1)
DIV unixPageSize * unixPageSize;
END;
IF fd.inoUpdate THEN
BEGIN
putInoFile (dao, fd);
fd.inoUpdate := false;
END;
IF res.main <> ok THEN exception (res);
æ*b* printVar ('end writeSegment, fd.eofPos = ', fd.eofPos); *e*å
END; æwriteSegmentå
æ$Eå
æ*********************************************************å
æ***** I M P L E M E N T U N I X F A O *****å
æ*********************************************************å
PROGRAM unixFaoImplement OBJECT Fao WITH faoLocals;
æ****************************å
æ***** READ SEQ *****å
æ****************************å
ENTRY ReadSeq
æ segment ; OUT byteCount å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
BEGIN
æ!b! printText ('----- unixFs.ReadSeq ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^ DO
BEGIN
readSegment (daoRef, sbGateRef, unixEnv^^.pUnixData,
segment, fd, byteCount);
æ!b! printVar ('after readSegment: byteCount = ', byteCount);
with buf = segment^^ do printVar ('buffer segment = ', buf);
printVar ('curPos = ', fd.curPos);
printVar ('eofPos = ', fd.eofPos);
printVar ('fd = ', fd); !e!å
END;
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.ReadSeq -----, res = ', res); !e!å
ObjReturn (res);
END; æReadSeqå
æ$Eå
æ*****************************å
æ***** WRITE SEQ *****å
æ*****************************å
ENTRY WriteSeq
æ segment ; OUT byteCount å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
BEGIN
æ!b! printText ('----- unixFs.WriteSeq ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^ DO
BEGIN
writeSegment (daoRef, sbGateRef, unixEnv^^.pUnixData,
segment, fd, byteCount);
æ!b! printVar ('after writeSeq, byteCount = ', byteCount);
with buf = segment^^ do printVar ('buffer segment = ', buf);
printVar ('curPos = ', fd.curPos);
printVar ('eofPos = ', fd.eofPos);
printVar ('fd = ', fd); !e!å
END;
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.WriteSeq -----, res = ', res); !e!å
ObjReturn (res);
END;
æ$Eå
æ*******************************å
æ***** READ RANDOM *****å
æ*******************************å
ENTRY ReadRandom
æ segment ; OUT byteCount, IN pos, OUT actualPos å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
BEGIN
æ!b! printText ('----- unixFs.ReadRandom ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^ DO
BEGIN
æ!b! printVar ('pos = ', pos); !e!å
æ Check position and assign current pos å
IF (pos < 0) OR
(pos > fd.allocSize) THEN
Exception ( makeRes (Reject * PosOutsideRange, IoFamily,
posArg, 0 ));
fd.curPos := pos;
æ Read data block å
readSegment (daoRef, sbGateRef, unixEnv^^.pUnixData,
segment, fd, bytecount);
æ!b! printVar ('after readRandom, byteCount = ', byteCount);
with buf = segment ^^ do printVar ('buffer segment = ', buf);
printRar ('curPos = ', fd.curPos);
printVar ('eofPos = ', fd.eofPos);
printVar ('fd = ', fd); !e!å
res := makeRes (ok, ok, ok, ok);
END; æwith fdå
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.ReadRandom -----, res = ', res); !e!å
ObjReturn (res);
END; æReadRandomå
æ$Eå
æ********************************å
æ***** WRITE RANDOM *****å
æ********************************å
ENTRY WriteRandom
æ segment ; OUT byteCount, IN pos, OUT actualPos å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
BEGIN
æ!b! printText ('----- unixFs.WriteRandom ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^ DO
BEGIN
æ!b! printVar ('pos = ', pos); !e!å
æ Check position and assign current pos å
IF pos < 0 THEN
Exception ( makeRes (Reject * PosOutsideRange, IoFamily,
posArg, 0 ));
fd.curPos := pos;
æ Write data block å
writeSegment (daoRef, sbGateRef, unixEnv^^.pUnixData,
segment, fd, byteCount);
æ!b! printVar ('after writeRandom, byteCount = ', byteCount);
with buf = segment^^ do printVar ('buffer segment = ', buf);
printVar ('curPos = ', fd.curPos);
printVar ('eofPos = ', fd.eofPos);
printVar ('fd = ', fd); !e!å
res := makeRes (ok, ok, ok, ok);
END; æwith fdå
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.WriteRandom -----, res= ', res); !e!å
ObjReturn (res);
END; æWriteRandomå
æ$Eå
æ************************å
æ***** SEEK *****å
æ************************å
ENTRY Seek
æ ; IN baseMode, IN offset, OUT pos å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
tPos : integer;
BEGIN
æ!b! printText ('----- unixFs.Seek ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^ DO
BEGIN
CASE baseMode OF
FromStart:
tPos := offSet;
FromCurrent:
tPos := fd.curPos + offset;
FromEnd:
tPos := fd.eofPos + offset;
otherwise
Exception ( makeRes (Reject * DataValueIllegal, IoFamily,
baseArg, illBaseMode ));
END; æcaseå
æ!b! printVar ('baseMode = ', baseMode);
printVar ('offset = ', offset);
printVar ('tPos = ', tPos); !e!å
IF tPos < 0 THEN
Exception ( makeRes (Reject * PosOutsideRange, IoFamily,
offsetArg, posNegative ));
fd.curPos := tPos;
pos := tPos;
END; æwith fdå
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.Seek -----, res = ', res); !e!å
ObjReturn (res);
END; æseekå
æ$Eå
æ*****************************å
æ***** DATA SIZE *****å
æ*****************************å
ENTRY DataSize
æ ; IN dataBytes å
WITH RECORD
t : ^^;
dummyGate : ^^;
END;
VAR
i, k, ix, block, relByte : integer;
empty : array Æ1..inoFSizeÅ of byte;
res : resultType;
BEGIN
æ!b! printText ('----- unixFs.DataSize ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^ DO
BEGIN
IF fileType (fd.inoLink.iMode) <> dataType THEN
Exception ( makeRes (Reject * EntryIllegal, Universal,
entryA, notDataFile ));
IF (fd.rwMode < WriteMode) THEN
exception ( makeRes ( Reject * EntryIllegal, Universal,
entryA, noWriteReservation ));
æ!b! printVar ('dataBytes = ', dataBytes);
printVar ('eofPos = ', fd.eofPos); !e!å
IF dataBytes <> 0 THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
sizeArg, cutSizeIllegal ));
IF fd.eofPos > 0 THEN
BEGIN
ix := fd.daoIndex;
res.main := ok;
æ put empty inoFile å
FOR i := 1 TO inoFSize DO emptyÆiÅ := 0;
block := (fd.iNumber - 1) DIV 8 + 2;
relByte := ((fd.iNumber - 1) MOD 8) * inoSize + inoLSize;
xCheck ( daoref.WriteRandom (VAR IN OUT empty ;
OUT i, IN block * unixPageSize + relByte, OUT i));
æ critical region for update super block å
xCheck ( sbGateRef.Lock );
IN
WITH ux = unixEnv^^.pUnixData^^,
sb = ux.devTableÆixÅ.super DO
BEGIN
cutFile (daoRef, dummyGate, unixEnv^^.pUnixData, fd, sb);
æ init empty fd å
WITH fd DO
BEGIN
FOR i := 0 TO 12 DO blockTabÆiÅ.blockAddr := 0;
FOR i := 1 TO 3 DO
BEGIN
WITH iTabÆiÅ DO BEGIN
curIb := 0;
update := false;
FOR k := 0 TO 127 DO tabÆkÅ := 0;
END;
inxÆiÅ := 0;
END;
level := 0;
curPos := 0;
eofPos := 0;
allocSize := 0;
END; æwith fdå
æ Put super block å
æ!b! printVar ('super block = ', sb); !e!å
xCheck (daoRef.WriteRandom
(VAR IN OUT unixEnv^^.pUnixData^^.devTableÆixÅ.super ;
OUT i, IN superAddr, OUT i ));
END; æwith sbå
DO
BEGIN
res := GetException;
IF res.main < 0 THEN res.main := -res.main;
END;
æ leave critical region å
sCheck ( sbGateRef.Open );
IF res.main <> ok THEN Exception (res);
END; æeofPos > 0å
END; æwith fd=å
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.DataSize -----, res= ', res); !e!å
ObjReturn (res);
END; ædataSizeå
æ$Eå
æ*************************å
æ***** FSTAT *****å
æ*************************å
ENTRY FStat æ IN stBuf å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
BEGIN
æ!b! ps ('----- unixFs.FStat ----- '); !e!å
sCheck ( faoGate.Lock );
IN
WITH fd = pFaoData^^, bf = stBuf^^ DO
BEGIN
bf.stDev := fd.daoIndex;
bf.stIno := fd.iNumber;
bf.stMode := fd.inoLink.iMode;
bf.stNLink := fd.inoLink.iNLink;
bf.stUId := fd.inoLink.iUserId;
bf.stGId := fd.inoLink.iGroupId;
bf.stRDev := 0;
bf.stSize := fd.inoFile.iSize;
bf.stATime := fd.inoFile.iAccTime;
bf.stMTime := fd.inoFile.iModTime;
bf.stCTime := fd.inoFile.iCreTime;
END; æwith fd, bfå
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck ( faoGate.Open );
æ!b! printVar ('----- end unixFs.FStat -----, res= ', res); !e!å
ObjReturn (res);
END; æFStatå
æ$Eå
OTHERWISE faoOther
WITH RECORD t : ^^; END;
BEGIN
Exception ( makeRes (Reject * EntryIllegal, Universal, entryA, 0 ));
END; æotherwiseå
END; æUnixFaoImplementå
æ$Eå
æ***********************************************************************å
æ***** I M P L E M E N T U N I X F I L E S Y S T E M *****å
æ***********************************************************************å
PROGRAM unixFilImplement OBJECT UnixFs WITH unixLocals;
PRIVATE Close
(IN fao : ownSet;
IN faoEnv : pFaoLocals
æoptional IN deleteMode : deleteType (not used in unixFs)å
);
FUNCTION countOpenFao (daoIndex : integer;
curIno : ino
) : integer;
VAR
fileCount : integer;
res : resultType;
æ This function searches through the fao manager set of the disc
specified by 'daoIndex' counting all faos opened to the file
specified by 'curIno'
å
BEGIN
æ#b# printVar ('countOpenFaos, curIno = ', curIno); *e*å
fileCount := 0;
res := FirstInSet (faoManÆdaoIndexÅ, nextFao);
IF res.main = ok THEN
BEGIN
REPEAT
WITH xfd = nextFao^^.pFaoData^^ DO
BEGIN
æ#b# printVar ('xfd.iNumber = ', xfd.iNumber); #e#å
IF xfd.iNumber = curIno THEN æ same file å
fileCount := fileCount + 1;
END; æwith xfdå
res := NextInSet (faoManÆdaoIndexÅ, nextFao);
UNTIL res.main <> ok;
END; æset not emptyå
countOpenFaos := fileCount;
æ#b# printVar ('fileCount = ', fileCount); #e#å
END; æcountOpenFaoså
æ$Eå
PROCEDURE creatFile (VAR dao : faoRefType;
VAR fd : faoData;
fType : integer );
VAR
i, k: integer;
BEGIN
æ*b* printVar ('creatFile : iNum = ', fd.iNumber); *e*å
WITH fd DO
BEGIN
FOR i := 0 TO 12 DO
blockTabÆiÅ.blockAddr := 0;
FOR i := 1 TO 3 DO
BEGIN
WITH iTabÆiÅ DO BEGIN
curIb := 0;
update := false;
FOR k := 0 TO 127 DO tabÆkÅ := 0;
END;
inxÆiÅ := 0;
END;
level := 0;
curPos := 0;
eofPos := 0;
allocSize := 0;
æ initialize i-node å
inoLink.iMode := fType; ædirMode/dataModeå
inoLink.iNLink := 1;
inoLink.iUserId := 0;
inoLink.iGroupId := 0;
sCheck ( clockRef.GetClock ( ; OUT i));
inoFile.iCreTime := i;
inoFile.iAccTime := i;
inoFile.iModTime := i;
putInoFile (dao, fd);
putInoLink (dao, fd);
END; æwith fdå
æ*b* printText ('end creatFile '); *e*å
END; æcreatFileå
æ$Eå
PROCEDURE InitUnixSys;
VAR
d, i : integer;
res : resultType;
size : sizeType;
BEGIN
printText (procId);
sCheck ( schedRef.NewGate (OUT ioGate));
FOR i := 1 TO maxDisc DO
sCheck ( schedRef.NewGate (OUT sbGateÆiÅ));
sCheck ( ioGate.Lock );
IN
æ Declare sub-segment of unixData å
sCheck ( ClearSize (size));
sCheck ( AddSub (size));
xCheck ( allocRef.NewObj (OUT pUnixDir ; IN size, OUT i));
xCheck ( DeclSub (pUnixDir, VAR IN OUT pUnixData^^.dirBlock ));
æ Initialize unixData å
WITH pUnixData^^ DO
BEGIN
lastLocalId := 0;
FOR i := 1 TO 3 DO
BEGIN
faoWork.iTabÆiÅ.curIb := 0;
faoWork.iTabÆiÅ.update := false;
END;
FOR d := 1 TO maxDisc DO
WITH devTableÆdÅ DO
BEGIN
pathLength := 0;
FOR i := 1 TO maxIdLength DO
devNameÆiÅ := CHR(0);
END; æfor då
END; æwith pUnixDataå
sCheck ( MakeReentrant (void) );
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
æ#b# printText ('----- end unixFs.InitUnixSys ----- '); #e#å
END; æInitUnixSyså
æ$Eå
æ***************************å
æ***** INCLUDE *****å
æ***************************å
ENTRY Include
æ ; IN devName, IN rootName Æ, readOnlyÅ å
WITH RECORD
t : ^^;
discDriver : ioSysRefType;
END;
VAR
roPtr : ^ integer;
readOnly : integer;
name, freeEntry : fullName;
accessMode, daoIndex, devClass, i, localId, k, kind,
minBufSize, pos, sz, used : integer;
driverOpen : boolean;
res : resultType;
BEGIN
æ#b# printText ('----- unixFs.Include ----- '); #e#å
WITH ux = pUnixData^^ DO
BEGIN
IN
xCheck ( ioGate.Lock );
DO
InitUnixSys;
IN
æ Take optional readOnly parameter å
IF nextValArg (roPtr) THEN readOnly := roPtr^
ELSE readOnly := 0;
æ Initialization å
k := elements (devName);
IF k > maxIdLength THEN k := maxIdLength;
i := 1;
REPEAT æremove space/null from devNameå
IF ORD(devNameÆiÅ) <= ORD(space) THEN k := i-1
ELSE i := i+1;
UNTIL i > k;
FOR i := 1 TO k DO nameÆiÅ := devNameÆiÅ;
FOR i := k+1 TO maxIdLength DO nameÆiÅ := CHR(0);
FOR i := 1 TO maxIdLength DO freeEntryÆiÅ := CHR(0);
æ Search deviceName in device table å
æ#b# printVar ('devName = ', devName);
printVar ('rootName = ', rootName); #e#å
daoIndex := 0;
FOR i := 1 TO maxDisc DO
BEGIN
æ+b+ printVar ('devTable.devName = ', ux.devTableÆiÅ.devName);
printVar ('i = ', i); +e+å
IF equal (ux.devTableÆiÅ.devName, name) THEN
Exception ( makeRes (Reject * FileNameExists, IoFamily,
dNameArg, volAlreadyIncluded ));
IF daoIndex = 0 THEN
IF equal (ux.devTableÆiÅ.devName, freeEntry) THEN
BEGIN
daoIndex := i;
ux.devTableÆiÅ.devName := name;
æ new entry ok, but rest of devTable must
still be searched for existing entry å
END; æfirst free entryå
END; æfor iå
æ#b# printVar ('daoIndex= ', daoIndex); #e#å
IF daoIndex = 0 THEN
Exception ( makeRes (Reject * NoResources, Universal,
entryA, devTabLimit) );
DO
BEGIN
sCheck ( ioGate.Open );
ObjReturn (GetException);
END;
æ Now an entry in devTable has been found, get driver ref and
assign disc driver å
IN
res.main := ok;
driverOpen := false;
xCheck ( objDirRef.GetRef (OUT discDriver ;
IN devName, OUT used, OUT kind) );
IF readOnly <> 0 THEN accessMode := ReadMode
ELSE accessMode := ReadWrite;
xCheck ( discDriver.Assign (OUT daoÆdaoIndexÅ ;
IN devNameÆused+1..kÅ, IN accessMode) );
driverOpen := true;
IN æ check device information å
xCheck ( daoÆdaoIndexÅ.GetFileInf (OUT discDriver ;
OUT localId, OUT name, OUT devClass,
OUT i æbytesAllocatedå, OUT minBufSize,
OUT i æcylSIzeå ));
DO æ if getFileInf not implemented then assign ok values å
BEGIN
minBufSize := unixPageSize;
devClass := Disc;
END;
IF devClass <> Disc THEN
Exception ( makeRes (Reject * GiveUp, Universal,
dNameArg, deviceClass ));
æ critical region for read "super-block" (sector 1)
and check UNIX format disc å
xCheck ( sbGateÆdaoIndexÅ.Lock );
IN
WITH sb = ux.devTableÆdaoIndexÅ.super DO
BEGIN
xCheck ( daoÆdaoIndexÅ.ReadRandom (VAR IN OUT sb ;
OUT sz, IN superAddr, OUT i ));
æ!b! printVar ('super block = ', sb); !e!å
IF (sz < unixPageSize) OR
(sb.inodSize > sb.volSize) OR
(sb.freeBlock.nFree > nicFree) OR
(sb.nIno > nicInod) OR
(sb.tFreeBl > sb.volSize)
THEN
Exception ( makeRes (Reject * VolumeFormatError, IoFamily,
dNameArg, notUnixDisc ));
END; æwith sbå
DO
res := GetException;
æ leave critical region for super block å
sCheck ( sbGateÆdaoIndexÅ.Open );
IF res.main <> ok THEN Exception (res);
æ Initialize devTable å
WITH ue = ux.devTableÆdaoIndexÅ DO
BEGIN
ue.devReadOnly := readOnly;
k := elements (rootName);
WHILE (rootNameÆkÅ = space) OR
(rootNameÆkÅ = CHR(0)) DO k := k-1;
ue.pathLength := k;
FOR i := 1 TO k DO ue.pathNameÆiÅ := rootNameÆiÅ;
FOR i := k+1 TO maxPathLength DO ue.pathNameÆiÅ := CHR(0);
END; æwith ueå
res := makeRes (ok, ok, ok, ok);
DO
BEGIN
æ Free dev table entry å
ux.devTableÆdaoIndexÅ.devName := freeEntry;
noCheck ( Dealloc (daoÆdaoIndexÅ, daoÆdaoIndexÅ ));
res := GetException;
END; æerrorå
END; æwith uxå
sCheck ( ioGate.Open );
æ#b# printVar ('----- end unixFs.Include -----, res = ', res); #e#å
ObjReturn (res);
END; æIncludeå
æ$Eå
æ**************************å
æ***** ASSIGN *****å
æ**************************å
ENTRY Assign
æ OUT ownedFao ; IN pathName, IN ioMode,
optional IN createMode, volume å
WITH RECORD
t : ^^;
faoEnv : pFaoLocals;
tmpFaoMan : ^^;
nextFao : pFaoLocals;
saveFaoPtr : pFaoLocals;
END;
VAR
res : resultType;
createMode : createType;
cmPtr : ^ createType;
charNo, daoIndex, foundLength, freePos, i, k, locId,
nameParts, readOnly : integer;
size, nullSize, voidSize : sizeType;
curIno, parentIno : ino;
exist, found, last : boolean;
fName : name14;
BEGIN
æ#b# printText ('----- unixFs.Assign ----- '); #e#å
IN
xCheck ( ioGate.Lock );
DO
InitUnixSys;
sCheck ( ioGate.Open );
æ Check ioMode parameter å
IF (ioMode < NoRights) OR (ioMode > ReadWrite) THEN
Exception (makeRes (Reject * DataValueIllegal, Universal,
ioModeArg, illIoMode ));
æ Take optional Create parameter å
IF NextValArg (cmPtr) THEN createMode := cmPtr^
ELSE createMode := NewOrOld;
IF (createMode < NewOrOld) OR (createMode > NewFile) THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
createArg, illCreateMode ));
æ Create fao and fao data å
nullSize.user := 0; nullSize.kernel := 0;
voidSize.user := -1; voidSize.kernel := -1;
sCheck ( ClearSize (size));
sCheck ( AddGen (size, refs(faoLocals)));
sCheck ( AddEmbSeg (size, bytes(faoData)));
rCheck ( allocRef.NewObj (OUT ownedFao ; IN size, OUT i));
rCheck ( DeclGen ( ownedFao, tmpFaoMan, faoEnv, refs(faoLocals), Close,
nullSize, voidSize, refs(unixFaoImplement),
bytes(unixFaoImplement), 0 ænoControlå,
addr(unixFaoImplement), nullSize, true));
æ create fao data segment å
rCheck ( NewSeg (faoEnv^^.pFaoData, bytes(faoData)));
rCheck ( copy (egoEnv, faoEnv^^.unixEnv));
æ create fao gate å
rCheck ( schedRef.NewGate ( OUT faoEnv^^.faoGate ));
æ Enter critical region before start search devTable å
sCheck ( ioGate.Lock );
IN
WITH ux = pUnixData^^ DO
BEGIN
daoIndex := searchDevTab (ux, pathName, æoutå charNo);
IF daoIndex = 0 THEN
Exception (makeRes (Reject * FileNotFound, IoFamily,
fNameArg, volNotIncluded ));
readOnly := ux.devTableÆdaoIndexÅ.devReadOnly;
END; æwith uxå
æ Now the proper dao is found (daoIndex). Search rest of fileName
through the directory hierarchy on this disc
å
nameParts := checkFileName (pathName, charNo);
IF nameParts < 0 THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
fNameArg, nameFormat ));
WITH fd = faoEnv^^.pFaoData^^ DO
BEGIN
æ Initialize new fd å
fd.daoIndex := daoIndex;
fd.devReadOnly := readOnly;
FOR i := 1 TO 3 DO
BEGIN
FOR k := 0 TO 127 DO fd.iTabÆiÅ.tabÆkÅ := 0;
fd.iTabÆiÅ.curIb := 0;
fd.iTabÆiÅ.update := false;
END;
curIno := rootIno; æi-number for root directory of discå
IF readOnly = 1 THEN fd.rwMode := ReadMode
ELSE fd.rwMode := ReadWrite;
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
IF nameParts = 0 THEN
exist := true æwanted file = root dirå
ELSE
BEGIN
exist := false;
REPEAT
last := getNamePart (pathName, æoutå fName, æin outå charNo);
nameParts := nameParts - 1;
curIno := searchDirectory (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, pUnixDir, fd,fName, freePos);
IF curIno > 0 THEN
BEGIN
IF last THEN exist := true;
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
END æfoundå
ELSE
BEGIN æfile not found: if last then create new i-node and fileå
IF (createMode = OldFile) OR
(ioMode = ReadMode) THEN
Exception ( makeRes (Reject * FileNotFound, IoFamily,
createArg, charNo-2 ));
IF NOT last THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
fNameArg, dirUnknown ));
parentIno := fd.iNumber;
curIno := getFreeInum (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, fd);
IF curIno = 0 THEN
Exception ( makeRes (Reject * NoVolumeSpace, IoFamily,
fNameArg, noInode ));
æ Initialize file and new i-node å
fd.iNumber := curIno;
creatFile (daoÆdaoIndexÅ, fd, dataMode);
æ Insert new i-node in current directory å
newDirEntry (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ, pUnixData, pUnixDir,
fd, parentIno, freePos, curIno, fName);
æget iNode of new fileå
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
END; æfile not foundå
UNTIL last;
END; ænameParts > 0å
IF exist THEN
BEGIN æcheck create mode and file typeå
IF createMode = NewFile Then
Exception ( makeRes (Reject * FileNameExists, IoFamily,
createArg, 0 ));
IF (fileType (fd.inoLink.iMode) = dirType) AND
(ioMode > ReadMode) THEN
ioMode := ioMode - WriteMode;
æ user not allowed to write in directory å
END; æexistå
END; æwith fdå
æ Now the wanted file has been found (curIno). Check file reservation
by searching all other faos connected to same disc å
æ#b# printVar ('search other faos, own i-number = ', curIno); #e#å
found := false;
res := FirstInSet (faoManÆdaoIndexÅ, nextFao);
IF res.main = ok THEN
BEGIN
REPEAT
WITH fd = nextFao^^.pFaoData^^ DO
BEGIN
æ#b# printVar ('fd.iNumber = ', fd.iNumber); #e#å
IF fd.iNumber = curIno THEN
BEGIN æsame fileå
IF (ioMode > ReadMode) OR
(fd.rwMode > ReadMode) THEN
Exception ( makeRes (Reject * RightsOccupied, IoFamily,
ioModeArg, 0 ));
IF NOT found THEN
BEGIN æfirst same, get localIdå
found := true;
locId := fd.localId;
END; æfirst foundå
END; æsame fileå
END; æwith fdå
res := NextInSet (faoManÆdaoIndexÅ, nextFao);
æ#b# printVar ('nextInSet, res = ', res); #e#å
UNTIL res.main <> ok;
END; æfaoMan set not emptyå
æ Assign fd å
WITH fd = faoEnv^^.pFaoData^^ DO
BEGIN
IF found THEN
fd.localId := locId
ELSE
BEGIN æfile not used before, create new localId and new file chainå
WITH ux = pUnixData^^ DO
BEGIN
ux.lastLocalId := ux.lastLocalId + 1;
fd.localId := ux.lastLocalId;
END; æwithå
END; ænot foundå
fd.rwMode := ioMode;
fd.terminated := false;
fd.readMark := false;
fd.writeMark := false;
æ#b# printVar ('new fd = ', fd); #e#å
END; æwith fdå
æ Reservation ok, move new fao manager and insert pointers in fao å
sCheck( MoveMan (tmpFaoMan, faoManÆdaoIndexÅ ));
sCheck( Copy (code, faoEnv^^.code ));
sCheck( Copy (daoÆdaoIndexÅ, faoEnv^^.daoRef ));
sCheck( Copy (sbGateÆdaoIndexÅ, faoEnv^^.sbGateRef ));
sCheck( MakeReentrant (faoEnv));
res := makeRes (ok, ok, ok, ok);
DO
BEGIN
æ Some error during Assign, undo everything å
noCheck ( DelEnv (ownedFao, tmpFaoMan ));
noCheck ( Dealloc (ownedFao, ownedFao ));
res := GetException;
END; æerrorå
æ Leave critical region å
sCheck ( ioGate.Open );
æ#b# printVar ('----- end unixFs.Assign -----, res = ', res); #e#å
ObjReturn (res);
END; æAssignå
æ$Eå
æ*******************************å
æ***** CREATE LINK *****å
æ*******************************å
ENTRY CreateLink
æ ; IN pathName, IN newPathName å
WITH RECORD
t : ^^;
END;
VAR
res : resultType;
last : boolean;
charNo1, charNo2, daoIndex, freePos, ft, i, k, p1, p2 : integer;
curIno, dirIno, foundIno : ino;
saveInoLink : iLnk;
fName : name14;
BEGIN
æ#b# printText ('----- unixFs.CreateLink ----- ');
printVar ('pathName = ', pathName);
printVar ('newPathName = ', newPathName); #e#å
IN
xCheck ( ioGate.Lock );
DO
InitUnixSys;
IN
WITH ux = pUnixData^^ DO
BEGIN
daoIndex := searchDevTab (ux, pathName, æoutå charNo1);
i := searchDevTab (ux, newPathName, æoutå charNo2);
IF DaoIndex <> i THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
newFileArg, notSameDevice ));
IF daoIndex = 0 THEN
Exception ( makeRes (Reject * FileNotFound, IoFamily,
fNameArg, volNotIncluded ));
IF ux.devTableÆdaoIndexÅ.devReadOnly = 1 THEN
Exception ( makeRes (Reject * EntryIllegal, Universal,
entryA, noWriteReservation ));
p1 := checkFileName (pathName, charNo1);
IF p1 < 0 THEN æsyntax errorå
Exception ( makeRes (Reject * DataValueIllegal, Universal,
fNameArg, nameFormat ));
p2 := checkFileName (newPathName, charNo2);
IF p2 <= 0 THEN æ<0 means syntax error, =0 means root dirå
Exception ( makeRes (Reject * DataValueIllegal, Universal,
newFileArg, nameFormat ));
WITH fd = ux.faoWork DO
BEGIN
æ find file pointed to by 'pathName' å
fd.daoIndex := daoIndex;
curIno := rootIno;
fd.rwmode := ReadWrite;
fd.devReadOnly := 0;
FOR i := 1 TO 3 DO
WITH fd.iTabÆiÅ DO
BEGIN
FOR k := 0 TO 127 DO tabÆkÅ := 0;
curIb := 0;
update := false;
END;
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
IF p1 > 0 THEN
REPEAT
last := getNamePart (pathName, æoutå fName, æin outå charNo1);
curIno := searchDirectory (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, pUnixDir, fd, fName, i);
IF curIno = 0 THEN
Exception ( makeRes (Reject * FileNotFound, IoFamily,
fNameArg, charNo1-2 ));
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
UNTIL last;
foundIno := curIno;
saveInoLink := fd.inoLink;
æ search lowest directory pointed to by 'newPathName' å
curIno := rootIno;
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
REPEAT
last := getNamePart (newPathName, fName, charNo2);
IF last THEN dirIno := curIno;
curIno := searchDirectory (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, pUnixDir, fd, fName, freePos);
IF last THEN
BEGIN
IF curIno > 0 THEN
Exception ( makeRes (Reject * FileNameExists, IoFamily,
newFileArg, 0 ));
END
ELSE
BEGIN
IF curIno = 0 THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
newFileArg, dirUnknown ));
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
END; ænot lastå
UNTIL last;
æ Now foundIno = i-number of actual file
fName = name - - -
saveInoLink = i-node - - -
dirIno = i-number of directory in which file is to
be inserted
freePos = position of first free entry in dirIno
fd.inoLink/File = i-node of directory file
å
æ#b# printVar ('foundIno = ', foundIno);
printVar ('fName = ', fName);
printVar ('saveInoLink= ', saveInoLink);
printVar ('dirIno = ', dirIno);
printVar ('freePos = ', freePos);
printVar ('fd.InoLink = ', fd.InoLink);
printVar ('fd.InoFile = ', fd.InoFile); #e#å
ft := fileType (fd.inoLink.iMode);
IF ft <> dirType THEN
BEGIN
æ change fileType into directory type, but only if empty data fileå
IF (ft <> dataType) OR
(fd.eofPos <> 0) THEN
Exception ( makeRes (Reject * DataValueIllegal, Universal,
newFileArg, notDirFile ));
ft := (fd.inoLink.iMode + p16) MOD p12 + dirType;
IF dirIno = foundIno THEN
saveInoLink.iMode := ft
ELSE
BEGIN
fd.inoLink.iMode := ft;
fd.iNumber := dirIno;
putInoLink (daoÆdaoIndexÅ, fd);
END;
END;
æ Increase link count in file's i-node å
saveInoLink.iNLink := saveInoLink.iNLink + 1;
æ Rewrite file's i-node å
fd.iNumber := foundIno;
fd.inoLink := saveInoLink;
putInoLink (daoÆdaoIndexÅ, fd);
newDirEntry (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ, pUnixData, pUnixDir,
fd, dirIno, freePos, foundIno, fName);
END; æwith fdå
END; æwith uxå
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
æ Leave critical region å
sCheck ( ioGate.Open );
æ#b# printVar ('----- end unixFs.CreateLink -----, res = ', res); #e#å
ObjReturn (res);
END; æ CreateLink å
æ$Eå
æ*******************************å
æ***** DELETE LINK *****å
æ*******************************å
ENTRY DeleteLink
æ ; IN pathName å
WITH RECORD
t : ^^;
dummyGate : ^^;
END;
VAR
res : resultType;
found, last : boolean;
curIno, dirIno : ino;
charNo, daoIndex, dirPos, fileCount, p : integer;
fName : name14;
BEGIN
æ#b# printText ('----- unixFs.DeleteLink ----- '); #e#å
IN
xCheck( ioGate.Lock );
DO
InitUnixSys;
IN
WITH ux = pUnixData^^ DO
BEGIN
daoIndex := searchDevTab (ux, pathName, æoutå charno);
IF daoIndex = 0 THEN
Exception (makeRes (Reject * FileNotFound, IoFamily,
fNameArg, volNotIncluded ));
IF ux.devTableÆdaoIndexÅ.devReadOnly = 1 THEN
Exception (makeRes (Reject * EntryIllegal, Universal,
entryA, noWriteReservation ));
p := checkFileName (pathName, charNo);
IF p <= 0 THEN æsyntax error or root directoryå
Exception ( makeRes (Reject * DataValueIllegal, Universal,
fNameArg, nameFormat ));
WITH fd = ux.faoWork DO
BEGIN
æ Search file through directory hierarchy å
curIno := rootIno;
fd.daoIndex := daoIndex;
fd.rwMode := ReadWrite;
fd.devReadOnly := 0;
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
REPEAT
last := getNamePart (pathName, æoutå fName, æin outå charNo);
IF last THEN dirIno := curIno;
curIno := searchDirectory (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, pUnixDir, fd, fName, dirPos );
IF curIno = 0 THEN
Exception ( makeRes (Reject * FileNotFound, IoFamily,
fNameArg, charNo-2 ));
getInoLink (daoÆdaoIndexÅ, fd, curIno);
getInoFile (daoÆdaoIndexÅ, fd, curIno);
UNTIL last;
æ Now curIno = i-number of actual file
fd.inoLink/File= i-node - - -
dirIno = i-number of directory file from which file
is to be removed
dirPos = position of dir entry in directory file
å
æ#b# printVar ('curIno = ', curIno);
printVar ('fd.inoLink= ', fd.inoLink);
printVar ('fd.inoFile= ', fd.inoFile);
printVar ('dirIno = ', dirIno);
printVar ('dirPos = ', dirPos);
printVar ('no of links = ', fd.inoLink.iNLink); #e#å
IF fd.inoLink.iNLink > 1 THEN
BEGIN æ not last permanent link,
remove directory entry, and decrease link count å
remDirEntry (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ, pUnixData,
pUnixDir, fd, dirIno, dirPos);
fd.iNumber := curIno;
fd.inoLink.iNLink := fd.inoLink.iNLink - 1;
putInoLink (daoÆdaoIndexÅ, fd);
END æ >1 å
ELSE
IF fd.inoLink.iNLink = 1 THEN
BEGIN æ last permanent link. If file not used by any fao,
the file is deleted. å
IF fileType (fd.inoLink.iMode) = dirType THEN
BEGIN æ a dir file is only removed if empty å
IF countDirEntries (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, pUnixDir, fd) > 0
THEN
Exception ( makeRes (Reject * EntryIllegal, Universal,
entryA, dirNotEmpty ));
END; ædirTypeå
æ Remove directory entry å
remDirEntry (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ, pUnixData,
pUnixDir, fd, dirIno, dirPos);
æ Search fao list for number of open faos connected to this file å
fileCount := countOpenFaos (daoIndex, curIno);
IF fileCount = 0 THEN
BEGIN
getInoFile (daoÆdaoIndexÅ, fd, curIno);
removeFile (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
dummyGate, pUnixData, fd);
END; æfileCount = 0å
æotherwise deletion is postponed until last fao deallocatedå
END; æiNLink = 1å
END; æwith fdå
END; æwith uxå
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
æ Leave critical region å
sCheck ( ioGate.Open );
æ#b# printVar ('----- end unixFs.DeleteLink -----, res = ', res); #e#å
ObjReturn (res);
END; æDeleteLinkå
æ$Eå
æ*********************************å
æ***** TERMINATE FAO *****å
æ*********************************å
PROCEDURE terminateFao (VAR faoEnv : pFaoLocals;
VAR dummyGate : pGateType;
VAR fd : faoData );
VAR
daoIndex, date, i, ix : integer;
res : resultType;
BEGIN
æ#b# printVar ('-- terminate fao --, iNum = ', fd.iNumber); #e#å
sCheck ( faoEnv^^.faoGate.Lock );
æ Prevent other users from accessing the fao during terminate å
sCheck ( Abort (faoEnv));
daoIndex := fd.daoIndex;
getInoLink (daoÆdaoIndexÅ, fd, fd.iNumber);
æ Check link-count in the file's i-node å
æ#b# printVar ('link-count = ', fd.inoLink.iNLink); #e#å
IF fd.inoLink.iNLink = 0 THEN
BEGIN
æ temporary file; delete if no other fao open to same file å
i := countOpenFaos (daoIndex, fd.iNumber);
IF i = 0 THEN
BEGIN
getInoFile (daoÆdaoIndexÅ, fd, fd.iNumber);
removeFile (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
dummyGate, pUnixData, fd);
END;
END ætemporaryå
ELSE
BEGIN
æ >0, permanent file; rewrite any updated indirect blocks
and the i-node å
IF fd.devReadOnly = 0 THEN
BEGIN
getInoFile (daoÆdaoIndexÅ, fd, fd.iNumber);
FOR ix := 1 TO 3 DO
BEGIN
IF fd.iTabÆixÅ.update THEN
BEGIN
æ#b# printVar ('indirect table index = ', ix);
printVar ('indirect table put = ', fd.iTabÆixÅ); #e#å
i := putOneBlock (daoÆdaoIndexÅ, sbGateÆdaoIndexÅ,
pUnixData, fd.iTabÆixÅ.tab, fd,
1, unixPageSize, fd.iTabÆixÅ.curIb, 0);
END; æifå
END; æfor ixå
æ Insert read/write date in i-node å
sCheck ( clockRef.GetClock ( ; OUT date) );
IF fd.readMark THEN fd.inoFile.iAccTime := date;
IF fd.writeMark THEN fd.inoFile.iModTime := date;
putInoFile (daoÆdaoIndexÅ, fd);
END; ænot devReadOnlyå
æ#b# printVar ('last fd = ', fd); #e#å
END; æpermanent fileå
æ put super block å
IF fd.devReadOnly = 0 THEN
BEGIN
æ critical region for update super block å
res.main := ok;
xCheck ( sbGateÆdaoIndexÅ.Lock );
IN
WITH ux = pUnixData^^, sb = ux.devTableÆdaoIndexÅ.super DO
BEGIN
xCheck (daoÆdaoIndexÅ.WriteRandom (
VAR IN OUT pUnixData^^.devTableÆdaoIndexÅ.super ;
OUT i, IN superAddr, OUT i ));
æ!b! printVar ('super block = ', sb); !e!å
END; æwith sbå
DO
BEGIN
res := GetException;
IF res.main < 0 THEN res.main := -res.main;
END;
æ leave critical region å
sCheck ( sbGateÆdaoIndexÅ.Open );
IF res.main <> ok THEN Exception (res);
END; ænot devReadOnlyå
æ remove faoGate å
sCheck ( faoEnv^^.faoGate.Open );
æ#b# printText ('-- end terminate fao -- '); #e#å
END; æterminateFaoå
æ$Eå
æ*************************å
æ***** CLOSE *****å
æ*************************å
PRIVATE Close
æ fao, faoEnv å
WITH RECORD
t : ^^;
dummyGate : pGateType;
END;
VAR
res : resultType;
BEGIN
æ#b# printText ('----- unixFs.Close ----- '); #e#å
sCheck ( ioGate.Lock );
IN
WITH fd = faoEnv^^.pFaoData^^ DO
BEGIN
IF fd.terminated THEN ænothingå
ELSE
BEGIN
terminateFao (faoEnv, dummyGate, fd);
fd.terminated := true;
END;
sCheck ( DelEnv (fao, faoManÆfd.daoIndexÅ ));
noCheck ( Dealloc (fao, fao ));
END; æwith fdå
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck ( ioGate.Open );
æ#b# printText ('----- end unixFs.Close ----- '); #e#å
ObjReturn (res);
END; æCloseå
æ$Eå
æ***************************å
æ***** EXCLUDE *****å
æ***************************å
ENTRY Exclude
æ ; IN deviceName Æ, abortAllowedÅ å
WITH RECORD
t : ^^;
dummyGate : pGateType;
tmpDao : faoRefType;
tmpMan : ^^;
tmpEnv : ^^;
faoEnv : pFaoLocals;
END;
VAR
daoIndex, i, k : integer;
aaPtr : ^integer;
abortAllowed : integer;
res : resultType;
name : fullName;
BEGIN
æ#b# printText ('----- unixFs.Exclude ----- '); #e#å
IN
xCheck ( ioGate.Lock );
DO
InitUnixSys;
IN
æ Take optional abortAllowed parameter å
IF NextValArg (aaPtr)
THEN abortAllowed := aaPtr^
ELSE abortAllowed := 0;
k := elements (devName);
IF k > maxIdLength THEN k := maxIdLength;
i := 1;
REPEAT æremove space/null from devNameå
IF ORD(devNameÆiÅ) <= ORD(space) THEN k := i-1
ELSE i := i+1;
UNTIL i > k;
FOR i := 1 TO k DO nameÆiÅ := devNameÆiÅ;
FOR i := k+1 TO maxIdLength DO nameÆiÅ := CHR(0);
æ Search devName in device table å
WITH ux = pUnixData^^ DO
BEGIN
daoIndex := 0;
FOR i := 1 TO maxDisc DO
BEGIN
IF equal (ux.devTableÆiÅ.devName, name) THEN
daoIndex := i;
END; æforå
æ#b# printVar ('daoIndex = ', daoIndex); #e#å
END; æwith uxå
IF daoIndex = 0 THEN
Exception (makeRes (Reject * FileNotFound, IoFamily,
entryA, volNotIncluded ));
æ Now the device name has been found in device table, check
if any open fao å
res := FirstInSet (faoManÆdaoIndexÅ, faoEnv);
IF res.main = ok THEN
BEGIN
IF abortAllowed = 0 THEN
Exception (makeRes (Reject * RightsOccupied, IoFamily,
entryA, filesOpen ));
REPEAT
WITH fd = faoEnv^^.pFaoData^^ DO
BEGIN
IF fd.terminated THEN ænothingå
ELSE
BEGIN
terminateFao (faoEnv, dummyGate, fd);
fd.terminated := true;
END;
END; æwith fdå
sCheck ( Copy (faoEnv, tmpEnv));
res := NextInSet (faoManÆdaoIndexÅ, faoEnv);
sCheck ( MoveMan (tmpEnv, tmpMan)); æremove from manSetå
UNTIL res.main <> ok;
END; æsome open faoå
æ Move owner to check if dealloc disc driver is possible å
sCheck ( MoveOwn (daoÆdaoIndexÅ, tmpDao ));
noCheck( Dealloc (tmpDao, tmpDao ));
WITH ux = pUnixData^^ DO
BEGIN
WITH ux.devTableÆdaoIndexÅ DO
BEGIN
FOR i := 1 TO maxIdLength DO
devNameÆiÅ := CHR(0);
pathLength := 0;
END; æwithå
END; æwith uxå
res := makeRes (ok, ok, ok, ok);
DO
res := GetException;
sCheck (ioGate.Open);
æ#b# printVar ('----- end unixFs.Exclude -----, res = ', res); #e#å
ObjReturn (res);
END; æExcludeå
æ$Eå
æ*****************************å
æ***** OTHERWISE *****å
æ*****************************å
OTHERWISE unixOther
WITH RECORD t : ^^; END;
BEGIN
Exception ( makeRes (Reject * EntryIllegal, Universal,
entryA, 0 ));
END;
END; æunixFilImplementå
æ$Eå
INITIALIZE
unixFilImplement 'unixfs' :
allocRef 'allocate' ,
schedRef 'scheduler' ,
objDirRef 'objDir' ,
clockRef 'clock' ,
egoEnv '**' ,
pUnixData
END.
«eof»